[
  {
    "path": ".github/workflows/Tests.yml",
    "content": "name: Tests\n  \non:\n  push:\n    branches: [master]\n  pull_request:\n    branches: ['*']\n\njobs:\n  danger_and_rubocop:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: ruby/setup-ruby@v1\n        with:\n          ruby-version: 3.3\n          bundler-cache: true\n      - name: Rubocop\n        run: |\n          bundle exec rake rubocop\n      - name: Danger\n        env:\n          DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          bundle exec danger --verbose\n\n  spec:\n    runs-on: macos-15\n    continue-on-error: true\n    strategy:\n      matrix:\n        spec: [\"objc_spec\", \"swift_spec\", \"cocoapods_spec\"]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: recursive\n          persist-credentials: false\n      - uses: maxim-lobanov/setup-xcode@v1\n        with:\n          xcode-version: '26.2'\n      - uses: ruby/setup-ruby@v1\n        with:\n          ruby-version: 3.3\n          bundler-cache: true\n      - name: Cache cocoapods\n        uses: actions/cache@v4\n        env:\n          cache-name: cocoapods\n        with:\n          path: ~/.cocoapods\n          key: ${{ matrix.spec }}-${{ env.cache-name }}\n      - name: Test\n        run: |\n          bundle exec rake ${{ matrix.spec }}\n"
  },
  {
    "path": ".gitignore",
    "content": "jazzy-docs/\n/docs/\nnode_modules\n\n*.gem\n*.rbc\n/.config\n/coverage/\n/InstalledFiles\n/pkg/\n/spec/reports/\n/test/tmp/\n/test/version_tmp/\n/tmp/\n\n## Specific to RubyMotion:\n.dat*\n.repl_history\nbuild/\n\n## Documentation cache and generated files:\n/.yardoc/\n/_yardoc/\n/doc/\n/rdoc/\n\n## Environment normalisation:\n/.bundle/\n/lib/bundler/man/\n\n# for a library or gem, you might want to ignore these files since the code is\n# intended to run in multiple environments; otherwise, check them in:\n# Gemfile.lock\n# .ruby-version\n# .ruby-gemset\n\n# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:\n.rvmrc\n\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n\n# Thumbnails\n._*\n\n# Files that might appear on external disk\n.Spotlight-V100\n.Trashes\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\nvendor\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"SourceKitten\"]\n\tpath = SourceKitten\n\turl = https://github.com/jpsim/SourceKitten.git\n[submodule \"spec/integration_specs\"]\n\tpath = spec/integration_specs\n\turl = https://github.com/realm/jazzy-integration-specs.git\n"
  },
  {
    "path": ".rubocop.yml",
    "content": "AllCops:\n  Exclude:\n    - ./spec/integration_specs/**/*\n    - ./spec/Moya.podspec\n    - ./vendor/**/*\n    - ./tmp/**/*\n    - ./SourceKitten/**/*\n  SuggestExtensions: false\n  TargetRubyVersion: 2.6\n\n#- Pending Cops as of 1.81.1 ---------------------------------------------#\n\nGemspec/AddRuntimeDependency: # new in 1.65\n  Enabled: true\nGemspec/AttributeAssignment: # new in 1.77\n  Enabled: true\nGemspec/DeprecatedAttributeAssignment: # new in 1.30\n  Enabled: true\nGemspec/DevelopmentDependencies: # new in 1.44\n  Enabled: false\nGemspec/RequireMFA: # new in 1.23\n  Enabled: true\nLayout/EmptyLinesAfterModuleInclusion: # new in 1.79\n  Enabled: true\nLayout/LineContinuationLeadingSpace: # new in 1.31\n  Enabled: false\nLayout/LineContinuationSpacing: # new in 1.31\n  Enabled: true\nLayout/SpaceBeforeBrackets: # (new in 1.7)\n  Enabled: true\nLint/AmbiguousAssignment: # (new in 1.7)\n  Enabled: true\nLint/AmbiguousRange: # (new in 1.19)\n  Enabled: true\nLint/ArrayLiteralInRegexp: # new in 1.71\n  Enabled: true\nLint/ConstantOverwrittenInRescue: # new in 1.31\n  Enabled: true\nLint/ConstantReassignment: # new in 1.70\n  Enabled: true\nLint/CopDirectiveSyntax: # new in 1.72\n  Enabled: true\nLint/DeprecatedConstants: # (new in 1.8)\n  Enabled: true\nLint/DuplicateBranch: # (new in 1.3)\n  Enabled: true\nLint/DuplicateMagicComment: # new in 1.37\n  Enabled: true\nLint/DuplicateMatchPattern: # new in 1.50\n  Enabled: true\nLint/DuplicateRegexpCharacterClassElement: # (new in 1.1)\n  Enabled: true\nLint/DuplicateSetElement: # new in 1.67\n  Enabled: true\nLint/EmptyBlock: # (new in 1.1)\n  Enabled: true\nLint/EmptyClass: # (new in 1.3)\n  Enabled: true\nLint/EmptyInPattern: # (new in 1.16)\n  Enabled: true\nLint/HashNewWithKeywordArgumentsAsDefault: # new in 1.69\n  Enabled: true\nLint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21\n  Enabled: true\nLint/ItWithoutArgumentsInBlock: # new in 1.59\n  Enabled: true\nLint/LambdaWithoutLiteralBlock: # (new in 1.8)\n  Enabled: true\nLint/LiteralAssignmentInCondition: # new in 1.58\n  Enabled: true\nLint/MixedCaseRange: # new in 1.53\n  Enabled: true\nLint/NonAtomicFileOperation: # new in 1.31\n  Enabled: true\nLint/NoReturnInBeginEndBlocks: # (new in 1.2)\n  Enabled: true\nLint/NumberedParameterAssignment: # (new in 1.9)\n  Enabled: true\nLint/NumericOperationWithConstantResult: # new in 1.69\n  Enabled: true\nLint/OrAssignmentToConstant: # (new in 1.9)\n  Enabled: true\nLint/RedundantDirGlobSort: # (new in 1.8)\n  Enabled: true\nLint/RedundantRegexpQuantifiers: # new in 1.53\n  Enabled: true\nLint/RedundantTypeConversion: # new in 1.72\n  Enabled: true\nLint/RefinementImportMethods: # new in 1.27\n  Enabled: true\nLint/RequireRangeParentheses: # new in 1.32\n  Enabled: true\nLint/RequireRelativeSelfPath: # new in 1.22\n  Enabled: true\nLint/SharedMutableDefault: # new in 1.70\n  Enabled: true\nLint/SuppressedExceptionInNumberConversion: # new in 1.72\n  Enabled: true\nLint/SymbolConversion: # (new in 1.9)\n  Enabled: true\nLint/ToEnumArguments: # (new in 1.1)\n  Enabled: true\nLint/TripleQuotes: # (new in 1.9)\n  Enabled: true\nLint/UnescapedBracketInRegexp: # new in 1.68\n  Enabled: true\nLint/UnexpectedBlockArity: # (new in 1.5)\n  Enabled: true\nLint/UnmodifiedReduceAccumulator: # (new in 1.1)\n  Enabled: true\nLint/UselessConstantScoping: # new in 1.72\n  Enabled: true\nLint/UselessDefaultValueArgument: # new in 1.76\n  Enabled: true\nLint/UselessDefined: # new in 1.69\n  Enabled: true\nLint/UselessNumericOperation: # new in 1.66\n  Enabled: true\nLint/UselessOr: # new in 1.76\n  Enabled: true\nLint/UselessRescue: # new in 1.43\n  Enabled: true\nLint/UselessRuby2Keywords: # new in 1.23\n  Enabled: true\nMetrics/CollectionLiteralLength: # new in 1.47\n  Enabled: true\nNaming/BlockForwarding: # new in 1.24\n  Enabled: true\nNaming/InclusiveLanguage: # (new in 1.18)\n  Enabled: true\nNaming/PredicateMethod: # new in 1.76\n  Enabled: true\nSecurity/CompoundHash: # new in 1.28\n  Enabled: true\nStyle/BitwisePredicate: # new in 1.68\n  Enabled: true\nStyle/CombinableDefined: # new in 1.68\n  Enabled: true\nStyle/ComparableBetween: # new in 1.74\n  Enabled: true\nStyle/ConcatArrayLiterals: # new in 1.41\n  Enabled: true\nSecurity/IoMethods: # new in 1.22\n  Enabled: true\nStyle/AmbiguousEndlessMethodDefinition: # new in 1.68\n  Enabled: true\nStyle/ArgumentsForwarding: # (new in 1.1)\n  Enabled: true\nStyle/ArrayIntersect: # new in 1.40\n  Enabled: true\nStyle/ArrayIntersectWithSingleElement: # new in 1.81\n  Enabled: true\nStyle/CollectionCompact: # (new in 1.2)\n  Enabled: true\nStyle/CollectionQuerying: # new in 1.77\n  Enabled: true\nStyle/ComparableClamp: # new in 1.44\n  Enabled: true\nStyle/DataInheritance: # new in 1.49\n  Enabled: true\nStyle/DigChain: # new in 1.69\n  Enabled: true\nStyle/DirEmpty: # new in 1.48\n  Enabled: true\nStyle/DocumentDynamicEvalDefinition: # (new in 1.1)\n  Enabled: true\nStyle/EmptyHeredoc: # new in 1.32\n  Enabled: true\nStyle/EmptyStringInsideInterpolation: # new in 1.76\n  Enabled: true\nStyle/EndlessMethod: # (new in 1.8)\n  Enabled: true\nStyle/EnvHome: # new in 1.29\n  Enabled: true\nStyle/ExactRegexpMatch: # new in 1.51\n  Enabled: true\nStyle/FetchEnvVar: # new in 1.28\n  Enabled: true\nStyle/FileEmpty: # new in 1.48\n  Enabled: true\nStyle/FileNull: # new in 1.69\n  Enabled: true\nStyle/FileRead: # new in 1.24\n  Enabled: true\nStyle/FileTouch: # new in 1.69\n  Enabled: true\nStyle/FileWrite: # new in 1.24\n  Enabled: true\nStyle/HashConversion: # (new in 1.10)\n  Enabled: true\nStyle/HashExcept: # (new in 1.7)\n  Enabled: true\nStyle/HashFetchChain: # new in 1.75\n  Enabled: true\nStyle/HashSlice: # new in 1.71\n  Enabled: true\nStyle/IfWithBooleanLiteralBranches: # (new in 1.9)\n  Enabled: true\nStyle/InPatternThen: # (new in 1.16)\n  Enabled: true\nStyle/ItAssignment: # new in 1.70\n  Enabled: true\nStyle/ItBlockParameter: # new in 1.75\n  Enabled: true\nStyle/KeywordArgumentsMerging: # new in 1.68\n  Enabled: true\nStyle/MagicCommentFormat: # new in 1.35\n  Enabled: true\nStyle/MapCompactWithConditionalBlock: # new in 1.30\n  Enabled: true\nStyle/MapIntoArray: # new in 1.63\n  Enabled: true\nStyle/MapToHash: # new in 1.24\n  Enabled: true\nStyle/MapToSet: # new in 1.42\n  Enabled: true\nStyle/MinMaxComparison: # new in 1.42\n  Enabled: true\nStyle/MultilineInPatternThen: # (new in 1.16)\n  Enabled: true\nStyle/NegatedIfElseCondition: # (new in 1.2)\n  Enabled: true\nStyle/NestedFileDirname: # new in 1.26\n  Enabled: true\nStyle/NilLambda: # (new in 1.3)\n  Enabled: true\nStyle/NumberedParameters: # new in 1.22\n  Enabled: true\nStyle/NumberedParametersLimit: # new in 1.22\n  Enabled: true\nStyle/ObjectThen: # new in 1.28\n  Enabled: true\nStyle/OpenStructUse: # new in 1.23\n  Enabled: true\nStyle/OperatorMethodCall: # new in 1.37\n  Enabled: true\nStyle/QuotedSymbols: # (new in 1.16)\n  Enabled: true\nStyle/RedundantArgument: # (new in 1.4)\n  Enabled: true\nStyle/RedundantArrayConstructor: # new in 1.52\n  Enabled: true\nStyle/RedundantArrayFlatten: # new in 1.76\n  Enabled: true\nStyle/RedundantConstantBase: # new in 1.40\n  Enabled: true\nStyle/RedundantCurrentDirectoryInPath: # new in 1.53\n  Enabled: true\nStyle/RedundantDoubleSplatHashBraces: # new in 1.41\n  Enabled: true\nStyle/RedundantEach: # new in 1.38\n  Enabled: true\nStyle/RedundantFilterChain: # new in 1.52\n  Enabled: true\nStyle/RedundantFormat: # new in 1.72\n  Enabled: true\nStyle/RedundantHeredocDelimiterQuotes: # new in 1.45\n  Enabled: true\nStyle/RedundantInitialize: # new in 1.27\n  Enabled: true\nStyle/RedundantInterpolationUnfreeze: # new in 1.66\n  Enabled: true\nStyle/RedundantLineContinuation: # new in 1.49\n  Enabled: true\nStyle/RedundantRegexpArgument: # new in 1.53\n  Enabled: true\nStyle/RedundantRegexpConstructor: # new in 1.52\n  Enabled: true\nStyle/RedundantSelfAssignmentBranch: # (new in 1.19)\n  Enabled: true\nStyle/RedundantStringEscape: # new in 1.37\n  Enabled: true\nStyle/ReturnNilInPredicateMethodDefinition: # new in 1.53\n  Enabled: true\nStyle/SafeNavigationChainLength: # new in 1.68\n  Enabled: true\nStyle/SelectByRegexp: # new in 1.22\n  Enabled: true\nStyle/SendWithLiteralMethodName: # new in 1.64\n  Enabled: true\nStyle/SingleLineDoEndBlock: # new in 1.57\n  Enabled: true\nStyle/StringChars: # (new in 1.12)\n  Enabled: true\nStyle/SuperArguments: # new in 1.64\n  Enabled: true\nStyle/SuperWithArgsParentheses: # new in 1.58\n  Enabled: true\nStyle/SwapValues: # (new in 1.1)\n  Enabled: true\nStyle/YAMLFileRead: # new in 1.53\n  Enabled: true\n\n# At the moment not ready to be used\n# https://github.com/bbatsov/rubocop/issues/947\nStyle/Documentation:\n  Enabled: false\n\n#- Jazzy -----------------------------------------------------------------#\n\n# 20 lines is more reasonable than rubocop's default of 10\nMetrics/MethodLength:\n  Max: 20\n\nMetrics/AbcSize:\n  Enabled: false\n\nMetrics/ModuleLength:\n  Enabled: false\n\nMetrics/BlockLength:\n  Enabled: false\n\nMetrics/ParameterLists:\n  CountKeywordArgs: false\n\nStyle/NumericPredicate:\n  Enabled: false\n\nLayout/HeredocIndentation:\n  Enabled: false\n\n# We adopted raise instead of fail.\nStyle/SignalException:\n  EnforcedStyle: only_raise\n\n# They are idiomatic\nLint/AssignmentInCondition:\n  Enabled: false\n\n# Allow backticks\nStyle/AsciiComments:\n  Enabled: false\n\n# Indentation clarifies logic branches in implementations\nStyle/IfUnlessModifier:\n  Enabled: false\n\n# No enforced convention here.\nStyle/SingleLineBlockParams:\n  Enabled: false\n\n# We only add the comment when needed.\nStyle/Encoding:\n  Enabled: false\n\n# Having these make it easier to *not* forget to add one when adding a new\n# value and you can simply copy the previous line.\nStyle/TrailingCommaInArrayLiteral:\n  EnforcedStyleForMultiline: comma\nStyle/TrailingCommaInHashLiteral:\n  EnforcedStyleForMultiline: comma\nStyle/TrailingCommaInArguments:\n  EnforcedStyleForMultiline: comma\n\nStyle/SpecialGlobalVars:\n  Enabled: false\n\nStyle/MultilineBlockChain:\n  Enabled: false\n\n# We prefer explicit `a, _ = arr` to `a, = arr` (which could be misread as a stray comma)\nStyle/TrailingUnderscoreVariable:\n  Enabled: false\n\n# For lambdas nested within certain expressions, this rule forces either ugly\n# parens or curly braces that violate the \"do/end for multiline blocks\" rule.\nStyle/Lambda:\n  Enabled: false\n\n# Disallowing indented \"when\" clauses destroys readability when using the\n# single-line \"when/then\" style.\nLayout/CaseIndentation:\n  Enabled: false\n\n# These are both subjective judgements that depend on the situation, and are\n# not appropriate as absolute rules.\nStyle/GuardClause:\n  Enabled: false\nStyle/Next:\n  Enabled: false\n\n# Avoid the least-readable varieties of regular expressions.\nStyle/RegexpLiteral:\n  EnforcedStyle: mixed\n\n# Sometimes easier to read either way\nStyle/AccessorGrouping:\n  Enabled: false\n\n# Avoid mandatory wide indentation\nLayout/MultilineMethodCallIndentation:\n  EnforcedStyle: indented\nLayout/LineEndStringConcatenationIndentation:\n  Enabled: true\n  EnforcedStyle: indented\n\n# Avoid false positives with `Pathname`\nStyle/StringConcatenation:\n  Mode: conservative\n\n# Compatibility with earlier Rubocops\nMetrics/CyclomaticComplexity:\n  Max: 10\nMetrics/PerceivedComplexity:\n  Max: 10\n\n# Too much firing on basic arithmetic\nLint/AmbiguousOperatorPrecedence:\n  Enabled: false\n\n#- Jazzy specs -----------------------------------------------------------#\n\n# Allow for `should.match /regexp/`.\nLint/AmbiguousRegexpLiteral:\n  Exclude:\n    - spec/**/*\n\n# Allow `object.should == object` syntax.\nLint/Void:\n  Exclude:\n    - spec/**/*\n\nStyle/ClassAndModuleChildren:\n  Exclude:\n    - spec/**/*\n\nLint/BinaryOperatorWithIdenticalOperands:\n  Exclude:\n    - spec/**/*\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## Master\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* None.\n\n## 0.15.4\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Allow `custom_categories` to specify a regex for a child.  \n  [Enrico Zannini](https://github.com/Enricoza)\n  [#688](https://github.com/realm/jazzy/issues/688)\n\n* Update Javascript: KaTeX 0.16.25  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* Don't call extension members that do not need documentation\n  'undocumented'.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Work around activesupport vs. concurrent-ruby crash.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1414](https://github.com/realm/jazzy/issues/1414)\n\n* Better identify default implementations.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1420](https://github.com/realm/jazzy/issues/1420)\n\n* Suppress warning on extensions providing default implementations.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1396](https://github.com/realm/jazzy/issues/1396)\n\n## 0.15.3\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Don't crash in SourceKitten when the Swift 6 compiler reports\n  educational notes.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1399](https://github.com/realm/jazzy/issues/1399)\n\n## 0.15.2\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Support Swift 6.0 / Xcode 16.0  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* None.\n\n## 0.15.1\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Restore compatibility with Ruby 2.6  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1388](https://github.com/realm/jazzy/issues/1388)\n\n## 0.15.0\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Update Javascript: typeahead.js 1.3.4, KaTeX 0.16.10  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Support Swift 5.10 with Swift Package Manager projects.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1381](https://github.com/realm/jazzy/issues/1381)\n\n* Support documentation of multiple modules in a single website.  Use\n  `--modules` or the config-file `modules` for more control.  See the\n  README 'Documenting multiple modules' for more details.  \n  [Argjira Mala](https://github.com/argjiramala-tomtom)\n  [Pedro Alcobia](https://github.com/PedroAlcobia-TomTom)\n  [John Fairhurst](https://github.com/johnfairh)\n  [#564](https://github.com/realm/jazzy/issues/564)\n\n* Improve page breadcrumbs to include parent pages and indicate source module\n  of extensions from other modules.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Add `--readme-title` and `--docset-title` to set the titles of the readme\n  docs page and the Dash docset independently of the module name.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Support Swift 5.9 symbolgraph extension symbols.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1368](https://github.com/realm/jazzy/issues/1368)\n\n##### Bug Fixes\n\n* Fix incorrect activesupport usage.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n## 0.14.4\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Update Javascript: jQuery 3.7.1, KaTeX 0.16.8  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Support Swift `package` access control level.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Initial support for Swift macro declarations.  Requires\n  `--swift-build-tool symbolgraph`.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Support Swift `@_documentation(visibility:)` attribute.  Requires\n  `--swift-build-tool spm|xcodebuild`.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* Issue a warning instead of crashing on declarations without names.  \n  [#1325](https://github.com/realm/jazzy/issues/1325)\n  [John Fairhurst](https://github.com/johnfairh)\n\n* Fix extension ordering in symbolgraph mode.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Fix symbolgraph mode crash involving tuple generic constraints.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n## 0.14.3\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Support Swift 5.7 and Xcode 14.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Update Javascript: jQuery 3.6.1, KaTeX 0.13.5  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* None.\n\n## 0.14.2\n\n##### Breaking\n\n* When building with Swift 5.6 and not passing `—-module` to Jazzy, declarations\n  may not be correctly identified as undocumented and docs may include unwanted\n  extensions.  Pass `—-module MyModuleName` to fix this.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Enhancements\n\n* Support using pre-generated symbolgraph files in Swift symbolgraph mode.  \n  [Nathan Wong](https://github.com/esteluk)\n\n* Issue a warning on some combinations of Objective-C flags.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#900](https://github.com/realm/jazzy/issues/900)\n\n* Support Swift 5.6.  The bundled `sourcekitten` is a universal binary.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* In Swift symbolgraph mode, stop including extensions to types that are beneath\n  the minimum ACL.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1291](https://github.com/realm/jazzy/issues/1291)\n\n## 0.14.1\n\n##### Breaking\n\n* Support Swift SPI groups.  Swift declarations marked `@_spi` are no longer\n  included in docs when `--min-acl` is set to `public` or `open`.  Use\n  `--include-spi-declarations` to include docs for these declarations.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1263](https://github.com/realm/jazzy/issues/1263)\n\n##### Enhancements\n\n* Correct line number references with Xcode 13.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Support `union` declarations in Objective-C headers.  \n  [Brian Osborn](https://github.com/bosborn)\n  [John Fairhurst](https://github.com/johnfairh)\n\n* Support Swift concurrency features: identify actors and asynchronous\n  methods.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* Improve HTML5 correctness, all themes.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1280](https://github.com/realm/jazzy/issues/1280)\n\n## 0.14.0\n\n##### Breaking\n\n* Require at least Ruby 2.6.3.  \n\n##### Enhancements\n\n* Support DocC-style autolinks and callouts in markdown.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Add `--source-host` option to support projects hosted on GitLab and\n  Bitbucket as well as GitHub.  Options `--source-host-url` and\n  `--source-host-files-url` and new Mustache tags replace the 'github' versions\n  which remain as back-compatibility aliases.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#314](https://github.com/realm/jazzy/issues/314)\n\n* Add `rel=\"noopener\"` to all `target=\"_blank\"` links.  \n  [JP Simard](https://github.com/jpsim)\n\n##### Bug Fixes\n\n* Fix source-host line number references in Swift symbolgraph mode, and\n  in ObjC mode for references to one-line declarations.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Fix crash with `` ` ` `` in markdown.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1270](https://github.com/realm/jazzy/issues/1270)\n\n* Fix symbolgraph mode with Xcode 13.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n## 0.13.7\n\nThe next release of Jazzy will require a minimum of Ruby 2.6.\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Update JavaScript libraries: jQuery 3.6.0, Lunr 2.3.9,\n  KaTeX 0.13.5.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Support the markdown [footnotes](https://www.markdownguide.org/extended-syntax/#footnotes) extension in all themes.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1246](https://github.com/realm/jazzy/issues/1246)\n\n##### Bug Fixes\n\n* Fix parameter doc comments in Swift symbolgraph mode.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1244](https://github.com/realm/jazzy/issues/1244)\n\n## 0.13.6\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Support documentation generation from `.swiftmodule` binaries using\n  `--swift-build-tool symbolgraph` with Swift 5.3.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* Always bypass codesigning when building Xcode projects.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1183](https://github.com/realm/jazzy/issues/1183)\n\n## 0.13.5\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Add search function to `apple` theme.  \n  [Giles Payne](https://github.com/komakai)\n  [#726](https://github.com/realm/jazzy/issues/726)\n\n* Add option `--[no-]separate-global-declarations` to always create separate\n  documentation pages for top-level declarations as well as classes,\n  structures, enums etc. even if they don't have members. As part of this,\n  improve the main page declaration in all modes.  \n  [Nikolay Volosatov](https://github.com/bamx23)\n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* Style fixes for `apple` and `jony` themes to codeblocks inside lists and\n  links.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#818](https://github.com/realm/jazzy/issues/818)\n  [#1177](https://github.com/realm/jazzy/issues/1177)\n\n## 0.13.4\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Update JavaScript libraries: jQuery 3.5.1 (all themes), Lunr 2.3.8,\n  typeahead.js 1.3.1 (`fullwidth` theme only).  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* Fix warnings from Ruby 2.7.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1185](https://github.com/realm/jazzy/issues/1185)\n\n* Accept `root_url` without trailing slash.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1188](https://github.com/realm/jazzy/issues/1188)\n\n## 0.13.3\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Added a config option to provide sources of privately hosted pod\n  dependencies when using the `--podspec` option.\n  `--pod-sources url1,url2,…urlN`.  \n  [Jonathan Bailey](https://github.com/jon889)\n  [#650](https://github.com/realm/jazzy/issues/650)\n\n* Improve Dash docset support: support online redirection when\n  `--root-url` is set, and provide `--docset-playground-url` to\n  support docset playground links.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* Fix module version not being used from podspec.  \n  [Jonathan Bailey](https://github.com/jon889)\n\n* Autolink Swift custom attributes/property wrappers.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n## 0.13.2\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Support Xcode 11.4.  Default Objective-C property attributes are now\n  stripped from declarations: turn this off with\n  `--keep-default-property-attributes`.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#829](https://github.com/realm/jazzy/issues/829)\n\n* Render LaTeX expressions written using `$equation$` or `$$equation$$`\n  syntax.  \n  [Arthur Guiot](https://github.com/arguiot)\n  [John Fairhurst](https://github.com/johnfairh)\n  [#1156](https://github.com/realm/jazzy/issues/1156)\n\n* Wrap long method names on category pages.  Use `name_html` in custom\n  mustache templates to take advantage of this.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#995](https://github.com/realm/jazzy/issues/995)\n\n* Support Dash-style `apple_ref` links to specific API items, for more\n  stable and human-readable links from external docs.  \n  [Paul Cantrell](https://github.com/pcantrell)\n\n##### Bug Fixes\n\n* Don't generate documentation if the `xcodebuild` command fails.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [jpsim/SourceKitten#643](https://github.com/jpsim/SourceKitten/issues/643)\n\n* Use multi-line parsed declarations in more places including protocol\n  methods and typealiases.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#896](https://github.com/realm/jazzy/issues/896)\n\n## 0.13.1\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Allow inline html tags in ObjC doc comments.  \n  [Chris Williams](https://github.com/ultramiraculous)\n  [#976](https://github.com/realm/jazzy/issues/976)\n\n* Support code formatting in ObjC doc comments with `@c`, `@code` and\n  `@endcode`.  \n  [Bryce Pauken](https://github.com/brycepauken)\n  [jpsim/SourceKitten#631](https://github.com/jpsim/SourceKitten/issues/631)\n\n* Add `custom_categories_unlisted_prefix` configuration setting. This\n  is the prefix for navigation section names that aren't explicitly\n  listed in `custom_categories`. Defaults to 'Other '.  \n  [JP Simard](https://github.com/jpsim)\n\n* Add `hide_unlisted_documentation` configuration setting. Setting this\n  to `true` hides documentation entries in the sidebar from the\n  `documentation` config value that aren't explicitly listed in\n  `custom_categories`.  \n  [JP Simard](https://github.com/jpsim)\n\n##### Bug Fixes\n\n* Fix crash when SourceKit returns out of bounds string byte offsets.  \n  [JP Simard](https://github.com/jpsim)\n\n* Pick the right version of declarations with type attributes.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1148](https://github.com/realm/jazzy/issues/1148)\n\n## 0.13.0\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Add section headings for members added by Swift conditional conformances.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#717](https://github.com/realm/jazzy/issues/717)\n\n* Parse markdown in MARK comments, make the html available to themes via\n  `name_html` mustache tag key for section headings.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Include protocol conformances added by extensions in Swift docs.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* Render bullet lists correctly when followed by a callout.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#785](https://github.com/realm/jazzy/issues/785)\n\n* Render markup of text inside double quotes.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#992](https://github.com/realm/jazzy/issues/992)\n\n* Fix `sourcekitten_sourcefile` used from config file.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1137](https://github.com/realm/jazzy/issues/1137)\n\n## 0.12.0\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Support for mixed Swift-ObjC modules: generate two sets of SourceKitten\n  json and pass them on using `--sourcekitten-sourcefile`.  \n  [Joe Susnick](https://github.com/joesus)\n  [John Fairhurst](https://github.com/johnfairh)\n  [#447](https://github.com/realm/jazzy/issues/447)\n\n##### Bug Fixes\n\n* Stop displaying type attributes on extension declarations.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Show ObjC and Swift classes (etc.) in the same category.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Merge Swift extensions into ObjC classes.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [Joe Susnick](https://github.com/joesus)\n\n## 0.11.2\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Generate Swift docs with Xcode 11 and paths with spaces.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1108](https://github.com/realm/jazzy/issues/1108)\n\n* Reinstate guessing of module name from podspec, broken in 0.11.0.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1109](https://github.com/realm/jazzy/issues/1109)\n\n## 0.11.1\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Don't use SwiftPM if there is an Xcode workspace or project in a non-root\n  directory.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1103](https://github.com/realm/jazzy/issues/1103)\n\n## 0.11.0\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Sass support now provided by `libsass` via `sassc` instead of the\n  deprecated Ruby Sass gem.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Update bundled jQuery to 3.4.1 (all themes).  \n  [Paul Idstein](https://github.com/idstein)\n\n* Support Xcode 11 Swift projects that pass a response file to the Swift\n  compiler.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1087](https://github.com/realm/jazzy/issues/1087)\n\n* Generate Swift docs from a Swift Package Manager package without\n  requiring an Xcode project file.  Add `--swift-build-tool` to choose\n  the build method if both `.xcodeproj` and `Package.swift` files are\n  present.  Add `--build-tool-flags` as a preferred alias for\n  `--xcodebuild-flags`.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#487](https://github.com/realm/jazzy/issues/487)\n\n##### Bug Fixes\n\n* Preserve non-latin characters in guide filenames and heading IDs.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1091](https://github.com/realm/jazzy/issues/1091)\n\n* Generate correct html for custom categories containing special\n  characters.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#945](https://github.com/realm/jazzy/issues/945)\n\n* Fix crash on files with misplaced documentation comments.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1083](https://github.com/realm/jazzy/issues/1083)\n\n## 0.10.0\n\n##### Breaking\n\n* The included `sourcekitten` binary is built with Xcode 10.2.  This means\n  it does not run on macOS earlier than 10.14.4 without the *Swift 5 Runtime\n  Support for Command Line Tools* being installed.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Enhancements\n\n* Support CocoaPods 1.6+.  Use the `swift_version[s]` dsl in `--podspec` mode\n  to set the Swift language version.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Show the extension declaration when documenting Swift extensions.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Allow docs title customization.  Include `--module-version` when it is set\n  and support `--title` to fully customize the title.  Pass `{{module_version}}`\n  and `{{docs_title}}` to templates.  \n  [Maximilian Alexander](https://github.com/mbalex99)\n  [John Fairhurst](https://github.com/johnfairh)\n  [#666](https://github.com/realm/jazzy/issues/666)\n  [#411](https://github.com/realm/jazzy/issues/411)\n\n##### Bug Fixes\n\n* Unfold member documentation when linked to from current web page.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#788](https://github.com/realm/jazzy/issues/788)\n\n* Generate docs when there are unusual characters in source pathnames.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1049](https://github.com/realm/jazzy/issues/1049)\n\n* Generate docs for signed modules with Xcode 10.2.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1057](https://github.com/realm/jazzy/issues/1057)\n\n* Use correct module name when only target name is supplied.  \n  [Chris Zielinski](https://github.com/chriszielinski)\n  [#422](https://github.com/realm/jazzy/issues/422)\n\n## 0.9.6\n\nThis is (probably) the last release to support Ruby earlier than 2.3.\nThis is due to a change in a dependency.\n\nThis is (probably) the last release to support macOS earlier than 10.14.4\nwithout the *Swift 5 Runtime Support for Command Line Tools* package installed.\nThis is a consequence of Swift 5 ABI stability.\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Swift 5 support: suppress unwanted newlines and `deinit` declarations.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Update JavaScript libraries: jQuery 3.3.1 (all themes), Lunr 2.3.5,\n  typeahead.js 1.2.1 (`fullwidth` theme only).  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#901](https://github.com/realm/jazzy/issues/901)\n\n* Avoid `clean build` when using the new Xcode build system.  \n  [Norio Nomura](https://github.com/norio-nomura)\n\n##### Bug Fixes\n\n* None.\n\n## 0.9.5\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Link to documentation pages from contents pages.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#730](https://github.com/realm/jazzy/issues/730)\n\n* Call out unavailable and deprecated Objective-C declarations.  \n  [Stefan Kieleithner](https://github.com/steviki)\n  [John Fairhurst](https://github.com/johnfairh)\n  [#843](https://github.com/realm/jazzy/issues/843)\n\n##### Bug Fixes\n\n* Support Swift 4.2 with `--podspec`.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#1015](https://github.com/realm/jazzy/issues/1015)\n\n* Fix multiline copyright for `apple` theme.  \n  [Fabien Lydoire](https://github.com/fabienlydoire)\n  [John Fairhurst](https://github.com/johnfairh)\n  [#1016](https://github.com/realm/jazzy/issues/1016)\n\n## 0.9.4\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Fix crash with pre-existing `Docs` directory.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#965](https://github.com/realm/jazzy/issues/965)\n\n* Fix crash with unicode scalars in string literals.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#972](https://github.com/realm/jazzy/issues/972)\n\n* Fix error compiling a Swift podspec in Xcode 10.  \n  [Minh Nguyễn](https://github.com/1ec5)\n  [#970](https://github.com/realm/jazzy/issues/970)\n\n## 0.9.3\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Fix crash when specifying empty Swift version. Now correctly uses the default\n  Swift version.  \n  [JP Simard](https://github.com/jpsim)\n\n* Fix jony theme selection.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#962](https://github.com/realm/jazzy/issues/962)\n\n## 0.9.2\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Add a new 'jony' theme similar to the 2017 Apple documentation style.  \n  [Harshil Shah](https://github.com/HarshilShah)\n\n* Add the ability to limit documentation to certain files by passing in an\n  `-i`/`--include` argument.  \n  [Nick Fox](https://github.com/nicholasffox)\n  [#949](https://github.com/realm/jazzy/issues/949)\n\n* Improve Swift declarations to look more like the Xcode Quick Help version,\n  for example including `{ get set }`, and include all attributes.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#768](https://github.com/realm/jazzy/issues/768)\n  [#591](https://github.com/realm/jazzy/issues/591)\n\n##### Bug Fixes\n\n* Preserve `MARK` comment headings associated with extensions and enum cases.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Fix issue where Overview items were invalidly being referenced with NULL\n  types in the generated Dash docset index.  \n  [Andrew De Ponte](https://github.com/cyphactor)\n\n* Don't display FIXME or TODO comments as section markers.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#658](https://github.com/realm/jazzy/issues/658)\n\n## 0.9.1\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Added a config option (`--undocumented-text UNDOCUMENTED_TEXT`) to set the\n  default text for undocumented symbols.  \n  [Akhil Batra](https://github.com/akhillies)\n  [#913](https://github.com/realm/jazzy/issues/913)\n\n* Added a config option to hide Objective-C or Swift declarations:\n  `--hide-declarations [objc|swift]`.  \n  [Ibrahim Ulukaya](https://github.com/ulukaya)\n  [#828](https://github.com/realm/jazzy/issues/828)\n\n* Automatically use Swift or Objective-C syntax highlighting for code blocks\n  in documentation comments.  Improve Swift highlighting with latest Rouge.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#218](https://github.com/realm/jazzy/issues/218)\n\n##### Bug Fixes\n\n* Fix Swift declarations when generating Objective-C docs for generic types.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#910](https://github.com/realm/jazzy/issues/910)\n\n* Don't create documentation nodes for generic type parameters.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#878](https://github.com/realm/jazzy/issues/878)\n\n## 0.9.0\n\n##### Breaking\n\n* Generate documentation coverage badge locally. Since this avoids the failable\n  HTTP request to shields.io previously used to obtain the badge, we've removed\n  the `--[no-]download-badge` flag and the corresponding `download_badge`\n  YAML configuration key.  \n  [Samuel Giddins](https://github.com/segiddins)\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Fixed issue that prevented Jazzy from running on case sensitive file systems.  \n  [Jeremy David Giesbrecht](https://github.com/SDGGiesbrecht)\n  [#891](https://github.com/realm/jazzy/issues/891)\n\n* Fixed issue preventing `--podspec` from working with `test_spec`s.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#894](https://github.com/realm/jazzy/issues/894)\n\n* Always display correct declaration for undocumented symbols.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#864](https://github.com/realm/jazzy/issues/864)\n\n* Trim common indentation in multiline declarations.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#836](https://github.com/realm/jazzy/issues/836)\n\n## 0.8.4\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Align jazzy terminology with Apple usage.  \n  [Xiaodi Wu](https://github.com/xwu)\n  [John Fairhurst](https://github.com/johnfairh)\n\n* Add `url` attribute that can be more accurate than `{{section}}.html` as a URL\n  in custom templates.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* Fix crash when specifying `swift_version` as a floating point value in\n  `.jazzy.yaml` rather than a string.  \n  [JP Simard](https://github.com/jpsim)\n  [#860](https://github.com/realm/jazzy/issues/860)\n\n* Autolink from parameter documentation and from external markdown documents\n  including README.  Autolink to symbols containing & < >.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#715](https://github.com/realm/jazzy/issues/715)\n  [#789](https://github.com/realm/jazzy/issues/789)\n  [#805](https://github.com/realm/jazzy/issues/805)\n\n* Fix Swift 4 declarations containing ampersands (`&`) being truncated.  \n  [JP Simard](https://github.com/jpsim)\n\n## 0.8.3\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Generate Swift declaration for more Objective-C declarations.  \n  [Zheng Li](https://github.com/ainopara)\n\n* Improve quality & accuracy of Swift interfaces for Objective-C declarations\n  when generating Objective-C docs.  \n  [Norio Nomura](https://github.com/norio-nomura)\n\n* Process Swift 3.2/4 doc comments.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n##### Bug Fixes\n\n* Fix missing doc comments on some extensions.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#454](https://github.com/realm/jazzy/issues/454)\n\n* Fix failure when attempting to download documentation coverage badge with\n  jazzy using macOS system Ruby, or a Ruby built with outdated versions of\n  OpenSSL.  \n  [JP Simard](https://github.com/jpsim)\n  [#824](https://github.com/realm/jazzy/issues/824)\n\n* Stop `--skip-undocumented` from skipping documented items nested\n  inside extensions of types from other modules.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#502](https://github.com/realm/jazzy/issues/502)\n\n* Fix members added to extensions of a nested type showing up in the parent.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#333](https://github.com/realm/jazzy/issues/333)\n\n## 0.8.2\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Report number of included and skipped declarations in CLI output.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#238](https://github.com/realm/jazzy/issues/238)\n\n* Build ObjC docs with clang modules enabled by default (`-fmodules` flag).  \n  [Maksym Grebenets](https://github.com/mgrebenets)\n  [#636](https://github.com/realm/jazzy/issues/636)\n\n* Shave ~1MB from jazzy's gem distribution.  \n  [JP Simard](https://github.com/jpsim)\n\n##### Bug Fixes\n\n* Fix support for Ruby 2.2.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#801](https://github.com/realm/jazzy/issues/801)\n\n* Fix many cases of incorrect, missing or superfluous docs on Swift\n  declarations.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n## 0.8.1\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Allow all markdown in returns and parameter description callouts.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#476](https://github.com/realm/jazzy/issues/476)\n\n##### Bug Fixes\n\n* Fix a crash that occurred when a documentation comment ended with an extended\n  grapheme cluster.  \n  [Lukas Stührk](https://github.com/Lukas-Stuehrk)\n  [#794](https://github.com/realm/jazzy/issues/794)\n  [SourceKitten#350](https://github.com/jpsim/SourceKitten/issues/350)\n\n## 0.8.0\n\n##### Breaking\n\n* `undocumented.json` is now only in the output directory and is no longer\n  copied into docsets.  \n  [Jeremy David Giesbrecht](https://github.com/SDGGiesbrecht)\n  [#754](https://github.com/realm/jazzy/issues/754)\n\n##### Enhancements\n\n* Add `--[no-]download-badge` flag to skip downloading the documentation\n  coverage badge from shields.io. Useful if generating docs offline.  \n  [JP Simard](https://github.com/jpsim)\n  [#765](https://github.com/realm/jazzy/issues/765)\n\n##### Bug Fixes\n\n* Blank line no longer needed before lists or code blocks.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#546](https://github.com/realm/jazzy/issues/546)\n\n* Linking to headers in apple theme gives correct vertical alignment.  \n  [John Fairhurst](https://github.com/johnfairh)\n\n* Headers in source code markdown no longer cause corruption.  \n  [John Fairhurst](https://github.com/johnfairh)\n  [#628](https://github.com/realm/jazzy/issues/628)\n\n## 0.7.5\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Fix issue where using a custom theme would crash jazzy when using Ruby 2.4.  \n  [Jason Wray](https://github.com/friedbunny)\n  [#752](https://github.com/realm/jazzy/issues/752)\n\n* Fix support for Ruby 2.0.0.  \n  [Jason Wray](https://github.com/friedbunny)\n  [#747](https://github.com/realm/jazzy/issues/747)\n\n* Fix issue where header files are not found if inside subdirectories of the\n  framework_root specified folder.  \n  [Christopher Gretzki](https://github.com/gretzki)\n  [#518](https://github.com/realm/jazzy/issues/518)\n\n## 0.7.4\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Generate shields.io badge for documentation coverage, unless\n  `hide_documentation_coverage` is set.  \n  [Harlan Haskins](https://github.com/harlanhaskins)\n  [#723](https://github.com/realm/jazzy/issues/723)\n\n* Add support for searching docs when using the `fullwidth` theme. A new option,\n  `--disable-search`, lets you turn this off.  \n  [Esad Hajdarevic](https://github.com/esad)\n  [Tom MacWright](https://github.com/tmcw)\n  [Nadia Barbosa](https://github.com/captainbarbosa)\n  [#14](https://github.com/realm/jazzy/issues/14)\n\n* New config option `use_safe_filenames` encodes unsafe characters when\n  generating filenames. By default, documentation may receive filenames like\n  `/(_:_:).html`. With `use_safe_filenames`, the same file will receive the name\n  `_2F_28_5F_3A_5F_3A_29.html` instead.  \n  [Jeremy David Giesbrecht](https://github.com/SDGGiesbrecht)\n  [#699](https://github.com/realm/jazzy/issues/699)\n  [#146](https://github.com/realm/jazzy/issues/146)\n  [#361](https://github.com/realm/jazzy/issues/361)\n  [#547](https://github.com/realm/jazzy/issues/547)\n\n* References to Objective-C methods are now autolinked.  \n  [Minh Nguyễn](https://github.com/1ec5)\n  [#362](https://github.com/realm/jazzy/issues/362)\n\n* Print documentation coverage percentage and the number of undocumented\n  methods to the command line when running jazzy.  \n  [Jason Wray](https://github.com/friedbunny)\n\n##### Bug Fixes\n\n* Fix issue where existing abstracts for non custom sections would be completely\n  overwritten when using extra abstract injection with --abstract.  \n  [Thibaud Robelain](https://github.com/thibaudrobelain)\n  [#600](https://github.com/realm/jazzy/issues/600)\n\n* Fix issue where generic type parameters registered as undocumented symbols.  \n  [Jeremy David Giesbrecht](https://github.com/SDGGiesbrecht)\n  [#429](https://github.com/realm/jazzy/issues/429)\n\n* Fix issue where parameter and return callouts were duplicated in documentation.  \n  [Jeremy David Giesbrecht](https://github.com/SDGGiesbrecht)\n  [#673](https://github.com/realm/jazzy/issues/673)\n\n* Fix issue where Objective-C superclass in declaration was unlinked.  \n  [Minh Nguyễn](https://github.com/1ec5)\n  [#706](https://github.com/realm/jazzy/issues/706)\n\n* Fix issue where multiple Objective-C categories of the same external class\n  in different files were merged into one and named after the first category\n  found.  \n  [Minh Nguyễn](https://github.com/1ec5)\n  [#539](https://github.com/realm/jazzy/issues/539)\n\n* String literals in code listings are no longer wrapped in `<q>` tags (`apple`\n  and `fullwidth` themes only).  \n  [Minh Nguyễn](https://github.com/1ec5)\n  [#714](https://github.com/realm/jazzy/issues/714)\n\n* Fix issue where passing a `--podspec` argument would use a malformed\n  `SWIFT_VERSION` value, causing compilation to fail.  \n  [JP Simard](https://github.com/jpsim)\n\n## 0.7.3\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Podspec-based documentation will take trunk's `pushed_with_swift_version`\n  attribute into account when generating documentation by default.  \n  [Orta Therox](https://github.com/orta)\n\n* Podspec-based documentation respects the `swift-version` config option.  \n  [Orta Therox](https://github.com/orta)\n\n##### Enhancements\n\n* Support Objective-C class properties.  \n  [Jérémie Girault](https://github.com/jeremiegirault)\n  [JP Simard](https://github.com/jpsim)\n\n* Support documenting Swift 3 operator precedence groups.  \n  [JP Simard](https://github.com/jpsim)\n\n##### Bug Fixes\n\n* Rename Dash typedef type from \"Alias\" to \"Type\".  \n  [Bogdan Popescu](https://github.com/Kapeli)\n\n* Fix crash when sorting multiple identically named declarations with no USR,\n  which is very common when generating docs for podspecs supporting multiple\n  platforms.  \n  [JP Simard](https://github.com/jpsim)\n  [#661](https://github.com/realm/jazzy/issues/661)\n\n* Fix Xcode not being found when specifying a custom Swift version\n  (`--swift-version`).  \n  [Samuel Giddins](https://github.com/segiddins)\n  [Paul Cantrell](https://github.com/pcantrell)\n  [#656](https://github.com/realm/jazzy/issues/656)\n\n* Fix crash when generating Objective-C docs for projects with \"@\" directives in\n  documentation comments with Xcode 8.1 or later.  \n  [Jérémie Girault](https://github.com/jeremiegirault)\n\n## 0.7.2\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Declarations marked `@available(..., unavailable, ...)` are no longer\n  documented.  \n  [JP Simard](https://github.com/jpsim)\n  [#654](https://github.com/realm/jazzy/issues/654)\n\n* Treat the `open` ACL as more public than `public`.  \n  [JP Simard](https://github.com/jpsim)\n\n## 0.7.1\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Added support for the new access control specifiers of fileprivate and open.  \n  [Shmuel Kallner](https://github.com/shmuelk)\n  [#645](https://github.com/realm/jazzy/issues/645)\n  [#646](https://github.com/realm/jazzy/issues/646)\n\n##### Bug Fixes\n\n* Fix issue where jazzy could not be installed from Gemfile due to\n  SourceKitten symlinks already being present.  \n  [William Meleyal](https://github.com/meleyal)\n  [#438](https://github.com/realm/jazzy/issues/438)\n\n* The lint report in `undocumented.json` is more human-readable: includes fully\n  qualified symbol names, pretty printed.  \n  [Paul Cantrell](https://github.com/pcantrell)\n  [#598](https://github.com/realm/jazzy/issues/598)\n\n* The `exclude` option now properly supports wildcards.  \n  [Paul Cantrell](https://github.com/pcantrell)\n  [#640](https://github.com/realm/jazzy/issues/640)\n\n## 0.7.0\n\n##### Breaking\n\n* The `docset_platform` option is no longer available. The module name will\n  now be used instead of `jazzy`.  \n  [JP Simard](https://github.com/jpsim)\n  [#423](https://github.com/realm/jazzy/issues/423)\n\n##### Enhancements\n\n* Improved auto-linking behavior to link declarations within declarations and\n  fix cases where declarations would link to themselves or their current page.  \n  [Esad Hajdarevic](https://github.com/esad)\n  [#483](https://github.com/realm/jazzy/issues/483)\n\n##### Bug Fixes\n\n* Fix issue where single-line declaration + bodies in Swift would include the\n  body in the parsed declaration.  \n  [JP Simard](https://github.com/jpsim)\n  [#226](https://github.com/realm/jazzy/issues/226)\n\n* Fix issue where some sections would become empty when using custom groups.  \n  [JP Simard](https://github.com/jpsim)\n  [#475](https://github.com/realm/jazzy/issues/475)\n\n* Fix issue where directories ending with `.swift` would be considered Swift\n  source files.  \n  [JP Simard](https://github.com/jpsim)\n  [#586](https://github.com/realm/jazzy/issues/586)\n\n## 0.6.3\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* `--exclude` flag now supports excluding directories in addition to files.  \n  [Gurrinder](https://github.com/gurrinder)\n  [#503](https://github.com/realm/jazzy/issues/503)\n\n* The `cocoapods` gem was updated to 1.0.1 and `rouge` to 1.11.0.  \n  [Samuel Giddins](https://github.com/segiddins)\n  [#568](https://github.com/realm/jazzy/issues/568)\n\n* Extra markdown documentation can now be included as their own pages in the\n  sidebar using the `--documentation` option and in the generated Dash docset\n  as Guides.  \n  [Karl Bowden](https://github.com/agentk)\n  [#435](https://github.com/realm/jazzy/issues/435)\n\n* Section headings can now include additional markdown content using the\n  `--abstract` option.  \n  [Karl Bowden](https://github.com/agentk)\n  [#435](https://github.com/realm/jazzy/issues/435)\n\n* If Swift version is not specified, look for Swift toolchain or clang location\n  in the following order:\n\n    * `$XCODE_DEFAULT_TOOLCHAIN_OVERRIDE`\n    * `$TOOLCHAIN_DIR`\n    * `xcrun -find swift`\n    * `/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain`\n    * `/Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain`\n    * `~/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain`\n    * `~/Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain`\n\n  This will be especially useful once jazzy supports generating docs for\n  Swift Package Manager modules with a toolchain not tied to an Xcode release.  \n  [JP Simard](https://github.com/jpsim)\n\n##### Bug Fixes\n\n* Don't document clang-unexposed Objective-C declarations.  \n  [JP Simard](https://github.com/jpsim)\n  [#573](https://github.com/realm/jazzy/issues/573)\n\n## 0.6.2\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Include one level of nested classes, structs, protocols and enums in the\n  navigation bar.  \n  [JP Simard](https://github.com/jpsim)\n  [#64](https://github.com/realm/jazzy/issues/64)\n\n##### Bug Fixes\n\n* None.\n\n## 0.6.1\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Objective-C documentation now also includes Swift declarations.  \n  [JP Simard](https://github.com/jpsim)\n  [#136](https://github.com/realm/jazzy/issues/136)\n\n* Default to the Xcode version selected in `xcode-select` if no Swift version is\n  specified.  \n  [Samuel Giddins](https://github.com/segiddins)\n  [#427](https://github.com/realm/jazzy/issues/427)\n\n##### Bug Fixes\n\n* Uses GitHub-Flavored Markdown syntax for anchors when rendering README pages.  \n  [Zachary Waldowski](https://github.com/zwaldowski)\n  [#524](https://github.com/realm/jazzy/issues/524)\n\n* Fix crash when using unexposed declarations in Objective-C.  \n  [JP Simard](https://github.com/jpsim)\n  [#543](https://github.com/realm/jazzy/issues/543)\n\n* No longer document Swift extensions on types with an ACL lower than `min-acl`\n  when they contain `MARK`s.  \n  [JP Simard](https://github.com/jpsim)\n  [#544](https://github.com/realm/jazzy/issues/544)\n\n## 0.6.0\n\n##### Breaking\n\n* Config files now use the same option names as the command line. If you are\n  using one of the keys that has changed in your `.jazzy.yaml`, you will receive\n  a warning. See the [pull request](https://github.com/realm/jazzy/pull/456) for\n  a complete list of changed options. As always, you can get a list of all\n  options with `jazzy --help config`.  \n  [Paul Cantrell](https://github.com/pcantrell)\n\n* Jazzy's undocumented.txt has been replaced with undocumented.json. This new\n  format includes contextual information that one might use to lint\n  documentation in an automated fashion.  \n  [Jeff Verkoeyen](https://github.com/jverkoey)\n\n* `--swift-version` now defaults to 2.2 instead of 2.1.1.  \n  [Tamar Nachmany](https://github.com/tamarnachmany)\n\n##### Enhancements\n\n* Add `--skip-documentation` flag. Skips site generation phase. `undocumented.json`\n  is still generated.  \n  [Jeff Verkoeyen](https://github.com/jverkoey)\n\n* Merge Objective-C categories into their parent type documentation to match\n  Swift behavior.  \n  [Esad Hajdarevic](https://github.com/esad)\n  [#457](https://github.com/realm/jazzy/issues/457)\n\n* Add support for documenting Swift 2.2 `associatedtype`s and infix, postfix &\n  prefix operators.  \n  [JP Simard](https://github.com/jpsim)\n\n##### Bug Fixes\n\n* Add support for Objective-C module imports.  \n  [JP Simard](https://github.com/jpsim)\n  [#452](https://github.com/realm/jazzy/issues/452)\n\n* Workaround for an apparent SourceKit bug which sometimes caused extensions\n  to be merged into the wrong type.  \n  [Paul Cantrell](https://github.com/pcantrell)\n  [#459](https://github.com/realm/jazzy/issues/459)\n  [#460](https://github.com/realm/jazzy/issues/460)\n\n## 0.5.0\n\n##### Breaking\n\n* `--swift-version` now defaults to 2.1.1 instead of 2.1.  \n  [Nikita Lutsenko](https://github.com/nlutsenko)\n  [#416](https://github.com/realm/jazzy/pull/416)\n\n* Swift 1.x is no longer supported.\n\n* `--templates-directory` and `--assets-directory` have been deprecated in favor\n  of `--theme`. Specify either 'apple' (default), 'fullwidth' or the path to\n  your mustache templates and other assets for a custom theme.  \n  [Karl Bowden](https://github.com/agentk)\n  [JP Simard](https://github.com/jpsim)\n  [#130](https://github.com/realm/jazzy/issues/130)\n\n##### Enhancements\n\n* Add `--sdk [iphone|watch|appletv][os|simulator]|macosx` option for Objective-C\n  projects.  \n  [Jeff Verkoeyen](https://github.com/jverkoey)\n\n* Add `--head` option to inject custom HTML into `<head></head>`.  \n  [JP Simard](https://github.com/jpsim)\n\n##### Bug Fixes\n\n* Fix an issue where extension documentation would use the original type\n  documentation block rather than the comment immediately preceding the\n  extension.  \n  [JP Simard](https://github.com/jpsim)\n  [#230](https://github.com/realm/jazzy/issues/230)\n  [#313](https://github.com/realm/jazzy/issues/313)\n  [#334](https://github.com/realm/jazzy/issues/334)\n\n* Fix multi-byte documentation issues.  \n  [Norio Nomura](https://github.com/norio-nomura)\n  [#403](https://github.com/realm/jazzy/issues/403)\n\n\n## 0.4.1\n\n*Note: this is the last official release of jazzy supporting Swift 1.x.*\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Support \"wall of asterisk\" documentation comments.  \n  [Jeff Verkoeyen](https://github.com/jverkoey)\n  [#347](https://github.com/realm/jazzy/issues/347)\n\n* Expanding a token no longer causes the document to 'jump' to the hash.  \n  [Jeff Verkoeyen](https://github.com/jverkoey)\n  [#352](https://github.com/realm/jazzy/issues/352)\n\n* Autolinking improvements:\n  - Autolinks only match `` `ThingsInBackticks` ``, and must match the entire\n    string. This prevents spurious matching in prose and sample code.\n  - Autolinks supports siblings, ancestors, top-level elements, and\n    dot-separated chains starting with any of the above: `someProperty`,\n    `SomeType.NestedType.someMethod(_:)`.\n  - New `...` wildcard prevents you from having to list all method parameters:\n    `someMethod(...)`\n\n  [Paul Cantrell](https://github.com/pcantrell)\n  [#327](https://github.com/realm/jazzy/issues/327)\n  [#329](https://github.com/realm/jazzy/issues/329)\n  [#359](https://github.com/realm/jazzy/issues/359)\n\n* Miscellaneous minor font size, weight, and color adjustments.  \n  [Jeff Verkoeyen](https://github.com/jverkoey)\n\n* In-page anchors now appear below the header.  \n  [Jeff Verkoeyen](https://github.com/jverkoey)\n\n##### Bug Fixes\n\n* Fix an out-of-bounds exception when generating pragma marks.  \n  [JP Simard](https://github.com/jpsim)\n  [#370](https://github.com/realm/jazzy/issues/370)\n\n* Add support for C/C++ struct, field & ivar types.  \n  [JP Simard](https://github.com/jpsim)\n  [#374](https://github.com/realm/jazzy/issues/374)\n  [#387](https://github.com/realm/jazzy/issues/387)\n\n* Links to source files on GitHub are no longer broken when `source_directory`\n  does not point to the current working directory.  \n  [Paul Cantrell](https://github.com/pcantrell)\n\n* When `excluded_files` is specified in a config file, it is now resolved\n  relative to the file (like other options) instead of relative to the working\n  directory.  \n  [Paul Cantrell](https://github.com/pcantrell)\n\n\n## 0.4.0\n\n##### Breaking\n\n* `--swift-version` now defaults to 2.1 instead of 2.0.  \n  [JP Simard](https://github.com/jpsim)\n\n##### Enhancements\n\n* Support for documenting Objective-C projects! 🎉\n  Pass `--objc`, `--umbrella-header ...` and `-framework-root ...`.  \n  [JP Simard](https://github.com/jpsim)\n  [#56](https://github.com/realm/jazzy/issues/56)\n\n* Mentions of top-level declarations in documentation comments are now\n  automatically hyperlinked to their reference.  \n  [JP Simard](https://github.com/jpsim)\n\n* Jazzy can now read options from a configuration file. The command line\n  provides comprehensive help for available options via `jazzy -h config`.  \n  [Paul Cantrell](https://github.com/pcantrell)\n  [#310](https://github.com/realm/jazzy/pull/310)\n\n* Render special list items (e.g. Throws, See, etc.). See\n  https://ericasadun.com/2015/06/14/swift-header-documentation-in-xcode-7/ for\n  a complete list.  \n  [JP Simard](https://github.com/jpsim)\n  [#317](https://github.com/realm/jazzy/issues/317)\n\n* Support for Swift 2.1.  \n  [JP Simard](https://github.com/jpsim)\n\n* Swift extensions are now merged with their extended type, rendering a note\n  to describe extension default implementations and extension methods.  \n  [Paul Cantrell](https://github.com/pcantrell)\n\n##### Bug Fixes\n\n* None.\n\n\n## 0.3.2\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Fixed an issue that prevented building projects with different schema & module\n  names.  \n  [JP Simard](https://github.com/jpsim)\n  [#259](https://github.com/realm/jazzy/issues/259)\n\n* Hide documentation coverage from header using `--hide-documentation-coverage`.  \n  [mbogh](https://github.com/mbogh)\n  [#129](https://github.com/realm/jazzy/issues/297)\n\n* Print a more informative error when unable to find an Xcode that has the\n  requested Swift version.  \n  [Samuel Giddins](https://github.com/segiddins)\n\n\n## 0.3.1\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Added missing Swift 2 declaration types.  \n  [JP Simard](https://github.com/jpsim)\n\n\n## 0.3.0\n\n##### Breaking\n\n* `--swift-version` now defaults to 2.0 instead of 1.2.  \n  [JP Simard](https://github.com/jpsim)\n\n##### Enhancements\n\n* Now supports Swift 2.0 (previous Swift versions are still supported).  \n  [JP Simard](https://github.com/jpsim)\n  [Samuel Giddins](https://github.com/segiddins)\n\n* Declarations can now be grouped by custom categories defined in a JSON or YAML\n  file passed to `--categories`.  \n  [Paul Cantrell](https://github.com/pcantrell)\n\n##### Bug Fixes\n\n* \"View on GitHub\" is now only generated if a GitHub URL is specified.  \n  [mbogh](https://github.com/mbogh)\n  [#244](https://github.com/realm/jazzy/issues/244)\n\n* Empty extensions are no longer documented.  \n  [Paul Cantrell](https://github.com/pcantrell)\n\n* Undocumented enum cases are now supported.  \n  [JP Simard](https://github.com/jpsim)\n  [#74](https://github.com/realm/jazzy/issues/74)\n\n\n## 0.2.4\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Improved how SourceKitten is vendored.  \n  [JP Simard](https://github.com/jpsim)\n\n* Show type declaration under its title.  \n  [Paul Cantrell](https://github.com/pcantrell)\n\n* Added support for custom assets: pass `--assets-directory` to jazzy.  \n  [gurkendoktor](https://github.com/gurkendoktor)\n\n* Added support for custom copyright text: pass `--copyright` to jazzy.  \n  [emaloney](https://github.com/emaloney)\n\n##### Bug Fixes\n\n* Fixed a crash when parsing an empty documentation comment.  \n  [JP Simard](https://github.com/jpsim)\n  [#236](https://github.com/realm/jazzy/issues/236)\n\n* `--exclude` now works properly if its argument is a relative path.  \n  [Paul Cantrell](https://github.com/pcantrell)\n\n\n## 0.2.3\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* The `jazzy` CLI now accepts a `--swift-version` option (defaulting to 1.2),\n  and will automatically find an appropriate Xcode installation.  \n  [Samuel Giddins](https://github.com/segiddins)\n  [#214](https://github.com/realm/jazzy/issues/214)\n\n##### Bug Fixes\n\n* Declarations with no USR will no longer be documented.  \n  [JP Simard](https://github.com/jpsim)\n\n\n## 0.2.2\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Added support for custom templates: use the `-t`/`--template-directory`\n  argument to jazzy.  \n  [JP Simard](https://github.com/jpsim)\n  [#20](https://github.com/realm/jazzy/issues/20)\n\n##### Bug Fixes\n\n* None.\n\n\n## 0.2.1\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Added the ability to ignore certain files by passing in an `-e`/`--exclude`\n  argument to jazzy.  \n  [JP Simard](https://github.com/jpsim)\n  [#173](https://github.com/realm/jazzy/issues/173)\n\n##### Bug Fixes\n\n* None.\n\n\n## 0.2.0\n\n##### Breaking\n\n* Jazzy now only supports projects using Swift 1.2.  \n  [JP Simard](https://github.com/jpsim)\n  [#170](https://github.com/realm/jazzy/issues/170)\n\n* Increase default minimum ACL to public.  \n  [JP Simard](https://github.com/jpsim)\n  [#186](https://github.com/realm/jazzy/issues/186)\n\n##### Enhancements\n\n* Use `key.accessibility` to determine ACL (value coming from SourceKit, which\n  is generally more accurate than parsing the declaration for an accessibility\n  keyword).  \n  [JP Simard](https://github.com/jpsim)\n  [#185](https://github.com/realm/jazzy/issues/185)\n\n##### Bug Fixes\n\n* None.\n\n\n## 0.1.6\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Make the gem installable.  \n  [Samuel Giddins](https://github.com/segiddins)\n\n\n## 0.1.5\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Added `--readme` command line option.  \n  [segiddins](https://github.com/segiddins)\n  [#196](https://github.com/realm/jazzy/issues/196)\n\n* Cleaned up front end HTML & CSS.  \n  [JP Simard](https://github.com/jpsim)\n  [#95](https://github.com/realm/jazzy/issues/95)\n\n* \"Show on GitHub\" links now link to line-ranges for multi-line definitions.  \n  [JP Simard](https://github.com/jpsim)\n  [#198](https://github.com/realm/jazzy/issues/198)\n\n##### Bug Fixes\n\n* Fixed issue where docset would contain duplicate files.  \n  [JP Simard](https://github.com/jpsim)\n  [#204](https://github.com/realm/jazzy/issues/204)\n\n* Fixed installation issues on case-sensitive file systems.  \n  [kishikawakatsumi](https://github.com/kishikawakatsumi)\n\n* Fixed out-of-bounds exception when parsing the declaration in files starting\n  with a declaration.  \n  [JP Simard](https://github.com/jpsim)\n  [#30](https://github.com/jpsim/SourceKitten/issues/30)\n\n* Fixed out-of-bounds exception and inaccurate parsed declarations when using\n  multibyte characters.  \n  [JP Simard](https://github.com/jpsim)\n  [#35](https://github.com/jpsim/SourceKitten/issues/35)\n\n* Fixed parsing issues with keyword functions such as `subscript`, `init` and\n  `deinit`.  \n  [JP Simard](https://github.com/jpsim)\n  [#27](https://github.com/jpsim/SourceKitten/issues/27)\n\n* Fixed issues where USR wasn't accurate because dependencies couldn't be\n  resolved.  \n  [JP Simard](https://github.com/jpsim)\n\n* Allow using a version of Xcode that is symlinked to\n  `/Applications/Xcode.app`.  \n  [Samuel Giddins](https://github.com/segiddins)\n\n\n## 0.1.4\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* No longer count undocumented externally declared tokens as undocumented.  \n  [JP Simard](https://github.com/jpsim)\n  [#188](https://github.com/realm/jazzy/issues/188)\n\n\n## 0.1.3\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Improve the styling of `dl` elements (parsed key-value pairs).  \n  [segiddins](https://github.com/segiddins)\n\n* Raise exceptions if Xcode requirements aren't met.  \n  [JP Simard](https://github.com/jpsim)\n\n##### Bug Fixes\n\n* No longer count initializers with parameters as undocumented.  \n  [JP Simard](https://github.com/jpsim)\n  [#183](https://github.com/realm/jazzy/issues/183)\n\n* No longer crash when a token is missing a USR.  \n  [JP Simard](https://github.com/jpsim)\n  [#171](https://github.com/realm/jazzy/issues/171)\n\n* Fixed encoding issues in some environments.  \n  [James Barrow](https://github.com/Baza207)\n  [#152](https://github.com/realm/jazzy/issues/152)\n\n* No longer count undocumented externally declared tokens as undocumented.  \n  [JP Simard](https://github.com/jpsim)\n  [#188](https://github.com/realm/jazzy/issues/188)\n\n* Fixed `--source-directory` CLI option.  \n  [JP Simard](https://github.com/jpsim)\n  [#177](https://github.com/realm/jazzy/issues/177)\n\n\n## 0.1.2\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Use Menlo for code everywhere.  \n  [beltex](https://github.com/beltex)\n  [#137](https://github.com/realm/jazzy/issues/137)\n\n##### Bug Fixes\n\n* (Really) fixes installation as a RubyGem.  \n  [beltex](https://github.com/beltex)\n  [#159](https://github.com/realm/jazzy/issues/159)\n\n\n## 0.1.1\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* None.\n\n##### Bug Fixes\n\n* Fixes installation as a RubyGem.  \n  [Samuel Giddins](https://github.com/segiddins)\n  [#159](https://github.com/realm/jazzy/issues/159)\n\n\n## 0.1.0\n\n[sourcekitten](https://github.com/jpsim/sourcekitten/compare/0.2.7...0.3.1)\n\n##### Breaking\n\n* None.\n\n##### Enhancements\n\n* Add the ability to document a Pod from just a podspec, which allows jazzy to\n  run on cocoadocs.org.  \n  [Samuel Giddins](https://github.com/segiddins)\n  [#58](https://github.com/realm/jazzy/issues/58)\n\n##### Bug Fixes\n\n* De-duplicate the sidebar list of extensions and show all children for an\n  extension, regardless of how many extensions on a type there are.  \n  [Samuel Giddins](https://github.com/segiddins)\n\n\n## 0.0.20\n\n[sourcekitten](https://github.com/jpsim/sourcekitten/compare/0.2.6...0.2.7)\n\n##### Breaking\n\n* Don't skip declarations with no documentation comments by default.\n  Allow skipping using `--skip-undocumented`.  \n  [JP Simard](https://github.com/jpsim)\n  [#129](https://github.com/realm/jazzy/issues/129)\n\n##### Enhancements\n\n* Combine abstract and discussion in page overview.  \n  [JP Simard](https://github.com/jpsim)\n  [#115](https://github.com/realm/jazzy/issues/115)\n\n##### Bug Fixes\n\n* Don't show 'Show in Github' link for types declared in system frameworks.  \n  [JP Simard](https://github.com/jpsim)\n  [#110](https://github.com/realm/jazzy/issues/110)\n\n## 0.0.19\n\n[sourcekitten](https://github.com/jpsim/sourcekitten/compare/0.2.3...0.2.6)\n\n##### Breaking\n\nNone.\n\n##### Enhancements\n\n* Added CHANGELOG.md.  \n  [JP Simard](https://github.com/jpsim)\n  [#125](https://github.com/realm/jazzy/issues/125)\n\n* Include parse errors in the JSON output & print to STDERR.  \n  [JP Simard](https://github.com/jpsim)\n  [jpsim/sourcekitten#16](https://github.com/jpsim/sourcekitten/issues/16)\n\n##### Bug Fixes\n\n* Fixed crash when files contained a declaration on the first line.  \n  [JP Simard](https://github.com/jpsim)\n  [jpsim/sourcekitten#14](https://github.com/jpsim/sourcekitten/issues/14)\n\n* Fixed invalid JSON issue when last file in an Xcode project failed to parse.  \n  [JP Simard](https://github.com/jpsim)\n\n* Fixed crash when attempting to parse the declaration of `extension Array`.  \n  [JP Simard](https://github.com/jpsim)\n  [#126](https://github.com/realm/jazzy/issues/126)\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "## Code of Conduct\n\nThis project adheres to the [Contributor Covenant Code of Conduct](https://realm.io/conduct).\nBy participating, you are expected to uphold this code. Please report\nunacceptable behavior to [info@realm.io](mailto:info@realm.io).\n\n## Tracking changes\n\nAll changes should be made via pull requests on GitHub.\n\nWhen issuing a pull request, please add a summary of your changes to\nthe `CHANGELOG.md` file.\n\nWe follow the same syntax as CocoaPods' CHANGELOG.md:\n\n1. One Markdown unnumbered list item describing the change.\n2. Two trailing spaces on the last line describing the change.\n3. A list of Markdown hyperlinks to the contributors to the change. One entry\n   per line (and there's usually just one contributor).\n4. A list of Markdown hyperlinks to the issues the change addresses. One entry\n   per line (and there's usually just one hyperlink). Don't link to PRs here.\n5. All CHANGELOG.md content is hard-wrapped at 80 characters.\n\n## Updating the integration specs\n\nJazzy heavily relies on integration tests, but since they're considerably large\nand noisy, we keep them in a separate repo\n([realm/jazzy-integration-specs](https://github.com/realm/jazzy-integration-specs)).\n\nIf you're making a PR towards jazzy that affects the generated docs, please\nupdate the integration specs using the following process:\n\n```shell\ngit checkout master\ngit pull\ngit checkout -\ngit rebase master\nrake bootstrap\nbundle exec rake rebuild_integration_fixtures\ncd spec/integration_specs\ngit checkout -b $jazzy_branch_name\ngit commit -a -m \"update for $jazzy_branch_name\"\ngit push\ncd ../../\ngit commit -a -m \"update integration specs\"\ngit push\n```\n\nYou'll need push access to the integration specs repo to do this. You can\nrequest access from one of the maintainers when filing your PR.\n\nYou must have Xcode 26.1 beta 1 installed to build the integration specs.\n\n## Making changes to SourceKitten\n\nWhen changes are landed in the https://github.com/jpsim/SourceKitten repo the\nSourceKitten framework located in jazzy must be updated.\n\nThe following may be executed from your `jazzy/` directory.\n\n```\ncd SourceKitten\ngit checkout master\ngit pull\ncd ..\nrake sourcekitten\ngit add .\ngit commit -m \"...\"\n```\n"
  },
  {
    "path": "Dangerfile",
    "content": "# frozen_string_literal: true\n\n# Warn when there is a big PR\nwarn('Big PR') if git.lines_of_code > 500\n\n# Don't let testing shortcuts get into master by accident\n(git.modified_files + git.added_files - %w[Dangerfile]).each do |file|\n  next unless File.file?(file)\n\n  contents = File.read(file)\n  if file.start_with?('spec')\n    failure(\"`xit` or `fit` left in tests (#{file})\") if contents =~ /^\\w*[xf]it/\n    failure(\"`fdescribe` left in tests (#{file})\") if contents =~ /^\\w*fdescribe/\n  end\nend\n\n# Sometimes its a README fix, or something like that - which isn't relevant for\n# including in a CHANGELOG for example\nhas_app_changes = !git.modified_files.grep(/lib/).empty?\nhas_test_changes = !git.modified_files.grep(/spec/).empty?\n\n# Add a CHANGELOG entry for app changes\nif !git.modified_files.include?('CHANGELOG.md') && has_app_changes\n  failure \"Please include a CHANGELOG entry. \\nYou can find it at [CHANGELOG.md](https://github.com/realm/jazzy/blob/master/CHANGELOG.md).\"\n  message 'Note, we hard-wrap at 80 chars and use 2 spaces after the last line.'\nend\n\n# Non-trivial amounts of app changes without tests\nif git.lines_of_code > 50 && has_app_changes && !has_test_changes\n  warn 'This PR may need tests.'\nend\n"
  },
  {
    "path": "Gemfile",
    "content": "# frozen_string_literal: true\n\nsource 'https://rubygems.org'\n\ngemspec\n\ngroup :development do\n  # Code style\n  gem 'rubocop', '~> 1.18'\n\n  # Tests\n  gem 'bacon'\n  gem 'mocha'\n  gem 'mocha-on-bacon'\n  gem 'prettybacon'\n  gem 'webmock'\n\n  # Integration tests\n  gem 'clintegracon', git: 'https://github.com/mrackwitz/CLIntegracon.git'\n  gem 'diffy'\n\n  # Code Review\n  gem 'danger'\nend\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Realm Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject 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,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "ObjectiveC.md",
    "content": "This document is about Jazzy's Objective-C documentation generation.\n\nIt's intended for users who are having problems after trying to follow the \nexamples in the [README](README.md#objective-c). It gives some solutions to\ncommon problems and explains how the system works to help users work through\nuncommon problems.\n\n* [How it works](#how-objective-c-docs-generation-works)\n* Common problems:\n    * [Apple SDK include failure](#problem-apple-sdk-importinclude-failure)\n    * [Non-SDK include failure](#problem-non-sdk-include-failure)\n    * [Argument list too long](#problem-argument-list-too-long-e2big-and-more)\n    * [Enum cases with wrong doc comment](#problem-enum-cases-have-the-wrong-doc-comment)\n    * [Swift API versions missing](#problem-swift-api-versions-are-all-missing)\n    * [Swift API versions use `Any`](#problem-swift-api-versions-have-any-instead-of-type-name)\n    * [Structural `NS_SWIFT_NAME` not working](#problem-structural-ns_swift_name-not-working)\n\n# How Objective-C docs generation works\n\nJazzy uses `libclang` to generate docs for Objective-C projects. You can think\nof this as running some parts of the `clang` compiler against a header file.\nJazzy refers to this header file as the _umbrella header_ but it does not have\nto be the umbrella header from a Clang module: it's just the header file that\nincludes everything to be documented.\n\nThis means there are two problems to solve:\n1. What `clang` flags are required; and\n2. How to pass them to the tools.\n\nJazzy has two modes here: a smart mode that covers 90% of projects and a direct mode where the user provides all the flags.\n\n> *Important*: Jazzy does _not_ use any Objective-C build settings from your\n  Xcode project or `Package.swift`. If your project needs special settings\n  such as `#define`s then you need to repeat those in the Jazzy invocation.\n\n## Direct mode\n\nPassing a basic set of `clang` flags looks like this:\n\n```shell\njazzy ...\n      --objc\n      --build-tool-arguments\n          --objc,MyProject/MyProject.h,--,-x,objective-c,\n          -isysroot,$(xcrun --show-sdk-path),\n          -I,$(pwd),\n          -fmodules\n```\nThe `--build-tool-arguments` are arguments to `sourcekitten`. Everything after\nthe `--` are the `clang` flags that will be used with the header file given \nbefore the `--`.\n\nYou can try these flags outside of Jazzy's environment:\n```shell\nclang -c -x objective-c -isysroot $(xcrun --show-sdk-path) -I $(pwd) MyProject/MyProject.h -fmodules\n```\n(The `-c` stops `clang` from trying to link an executable.)\n\nThis is a good method of experimenting with compiler flags to get a working\nbuild without getting bogged down in the Jazzy and SourceKitten layers.\n\n## Smart mode\n\nThe smart mode takes the variable parts of the basic set of flags and maps\nthem from Jazzy flags:\n```shell\njazzy ...\n      --objc\n      --umbrella-header MyProject/MyProject.h\n      --framework-root $(pwd)\n     [--sdk <sdk name>]\n```\n\nThe `--umbrella-header` maps directly to the file passed to `sourcekitten`.\n\nThe `--framework-root` is used for the `-I` include path, as well as every\ndirectory beneath it, recursively. So if your project structure looks like:\n```\nMyProject/\n         Sources/\n                Main/\n                Extension/\n```\n... and you pass `--framework-root MyProject`, then the `-I` flags passed to\n`clang` are `-I MyProject -I MyProject/Sources -I MyProject/Sources/Main -I\nMyProject/Sources/Extension`. This feature helps some projects resolve\n`#include` directives.\n\nFinally the `--sdk` option is passed through instead of the default `macosx` to\nfind the SDK.\n\n## Mixing modes\n\nDo not mix modes. For example do not set both `--umbrella-header` and\n`--build-tool-arguments`. Jazzy does not flag this as an error for\nhistorical compatibility reasons, but the results are at best confusing.\n\n# Problem: Apple SDK import/include failure\n\nFor example `fatal error: module 'UIKit' not found`.\n\nThis means Jazzy is using the wrong SDK: the default is for macOS which does\nnot have `UIKit`. Use `--sdk iphonesimulator`.\n\n# Problem: Non-SDK include failure\n\nFor example `fatal error: 'MyModule/SomeHeader.h' file not found`.\n\nThis means `clang` is not being passed the right flags to resolve a `#include` /\n`#import`.\n\nStart by finding the header file in the filesystem. You might be able to fix\nthe problem just by adding extra `-I <path>` flags.\n\nUsually though the problem is that Xcode has done something clever that needs\nto be worked around or replicated.\n\nXcode uses technology including Clang header maps to let files be found using\nlines like `#import <ModuleName/Header.h>` even when there is no such\nfilesystem directory.\n\nTo make the Jazzy build work you need to make these `#include`s work. The\nsolution depends on your project structure. Some suggestions in rough order\nof complexity:\n* Use symlinks to create an equivalent directory tree. For example if\n  `Header.h` is inside `Sources/include` then symlink that directory to\n  `ModuleName` and pass `-I $(pwd)`.\n\n* Copy/link your header files into a throwaway directory tree that matches\n  the required structure and is used just for building docs.\n\n* Create a 'docs header file' separate to the framework's regular umbrella\n  header that contains only filesystem-correct `#import`s.\n\n* If you are happy to build the framework project before generating docs and\n  all the problematic paths have the form `ModuleName/PublicHeader.h` then\n  have `clang` resolve those includes to the built framework by passing\n  `-F <path of directory containing ModuleName.framework>`.\n\n* If you are happy to build the project before generating docs then you may\n  be able to use the header maps Xcode has generated. Check the build log in\n  Xcode to find them and the invocation syntax.\n\n* Manually construct an equivalent header map. This is complex not least\n  because Apple does not make tools or proper documentation available.\n  [An open-source starting point](https://milen.me/writings/swift-module-maps-vfs-overlays-header-maps/).\n\n# Problem: Argument list too long `E2BIG` (and more...)\n\nFor example ``...open4.rb:49:in `exec': Argument list too long - [...]/bin/sourcekitten (Errno::E2BIG)``\n\nCan also manifest as 'generally weird' errors such as `sourcekitten` just\ncrashing and `fatal error: could not build module 'Foundation'`.\n\nThis means `--framework-root` is trying to add too many include directories:\nthere are too many subdirectories of its parameter. If you cannot change this\nto something more specific that works then you need to use Jazzy's\n[direct mode](#direct-mode) to pass in the correct directories.\n\n# Problem: Enum cases have the wrong doc comment\n\nIf you write an enum case with a doc comment followed by an enum case without\na doc comment, then both get the same doc comment.\n\nThis seems to be a bug in `libclang`. The only workaround is to add the missing\ndoc comment.\n\n# Problem: Swift API versions are all missing\n\nThis usually means the `clang` flags are malformed in a way that is ignored by\n`libclang` but not by the Swift Objective-C importer.\n\nOne easy way to accidentally do this is passing `-I` without a path, for\nexample `--build-tool-flags ...,-I,-I,Headers`,....\n\nThis also sometimes happens if you are frequently switching back and forth\nbetween some Swift / Xcode versions -- it's a bug somewhere in the Apple tools.\nThe bad state goes away with time / reboot.\n\n# Problem: Swift API versions have `Any` instead of type name\n\nJazzy finds the Swift version of an Objective-C API using the SourceKit\n`source.request.editor.open.interface.header` request on the header file that\ncontains the declaration, passing in the same `clang` flags used for the\numbrella header. [See the code](https://github.com/jpsim/SourceKitten/blob/bed112c313ca8c3c149f8cb84069f1c080e86a7e/Source/SourceKittenFramework/Clang%2BSourceKitten.swift#L202).\n\nThis means that each header file needs to compile standalone, without\nany implicit dependencies. For example:\n```\n MyModule.h      // umbrella, includes MyClass.h then Utils.h\n    MyClass.h    // @interface MyClass ... @end\n    Utils.h      // void my_function( MyClass * myClass);\n```\nHere, `Utils.h` has an implicit dependency on `MyClass.h` that is normally\nsatisfied by the include order of `MyModule.h`. One fix that allows `Utils.h`\nto compile standalone is to add `@class MyClass;`.\n\n# Problem: Structural `NS_SWIFT_NAME` not working\n\nThe `NS_SWIFT_NAME` macro is mostly used to give an Objective-C API a\ndifferent name in Swift. There are no known problems with this part.\n\nThe macro can also be used to change the 'structure' of an API, for example\nmake a C global function appear as a member function in Swift, or make a C\nclass appear as a nested type in Swift.\n\nJazzy doesn't understand or communicate these structural changes: you'll need\nto explain it in doc comments.\n"
  },
  {
    "path": "README.md",
    "content": "![jazzy](images/logo.jpg)\n\n[![Build Status](https://github.com/realm/jazzy/actions/workflows/Tests.yml/badge.svg)](https://github.com/realm/jazzy/actions/workflows/Tests.yml)\n\n*jazzy is a command-line utility that generates documentation for Swift or Objective-C*\n\n## About\n\nBoth Swift and Objective-C projects are supported.\n\nInstead of parsing your source files, `jazzy` hooks into [Clang][clang] and\n[SourceKit][sourcekit] to use the [AST][ast] representation of your code and\nits comments for more accurate results. The output matches the look and feel\nof Apple’s official reference documentation, post WWDC 2014.\n\nJazzy can also generate documentation from compiled Swift modules [using their\nsymbol graph](#docs-from-swiftmodules-or-frameworks) instead of source code.\n\n![Screenshot](images/screenshot.jpg)\n\nThis project adheres to the [Contributor Covenant Code of Conduct](https://realm.io/conduct).\nBy participating, you are expected to uphold this code. Please report\nunacceptable behavior to [info@realm.io](mailto:info@realm.io).\n\n## Requirements\n\nYou need development tools to build the project you wish to document.  Jazzy supports\nboth [Xcode][xcode] and [Swift Package Manager][spm] projects.\n\nJazzy expects to be running on __macOS__.  See [below](#linux) for tips to run Jazzy\non Linux.\n\n## Installation\n\n```shell\n[sudo] gem install jazzy\n```\n\nSee [Installation Problems](#installation-problems) for solutions to some\ncommon problems.\n\n## Usage\n\nRun `jazzy` from your command line. Run `jazzy -h` for a list of additional options.\n\nIf your Swift module is the first thing to build, and it builds fine when running\n`xcodebuild` or `swift build` without any arguments from the root of your project, then\njust running `jazzy` (without any arguments) from the root of your project should\nsucceed too!\n\nIf Jazzy generates docs for the wrong module then use `--module` to tell it which\none you'd prefer.  If this doesn't help, and you're using Xcode, then try passing\nextra arguments to `xcodebuild`, for example\n`jazzy --build-tool-arguments -scheme,MyScheme,-target,MyTarget`.\n\nIf you want to generate docs for several modules at once then see [Documenting multiple\nmodules](#documenting-multiple-modules).\n\nYou can set options for your project’s documentation in a configuration file,\n`.jazzy.yaml` by default. For a detailed explanation and an exhaustive list of\nall available options, run `jazzy --help config`.\n\n### Supported documentation keywords\n\nSwift documentation is written in markdown and supports a number of special keywords.\nHere are some resources with tutorials and examples, starting with the most modern:\n* Apple's [Writing Symbol Documentation in Your Source Files](https://developer.apple.com/documentation/xcode/writing-symbol-documentation-in-your-source-files) article.\n* Apple's [Formatting Your Documentation Content](https://developer.apple.com/documentation/xcode/formatting-your-documentation-content) article.\n* Apple's [Xcode Markup Formatting Reference](https://developer.apple.com/library/content/documentation/Xcode/Reference/xcode_markup_formatting_ref/).\n* Erica Sadun's [Swift header documentation in Xcode 7](https://ericasadun.com/2015/06/14/swift-header-documentation-in-xcode-7/) post and her [book on Swift Documentation Markup](https://itunes.apple.com/us/book/swift-documentation-markup/id1049010423).\n\nFor Objective-C documentation the same keywords are supported, but note that the format\nis slightly different. In Swift you would write `- returns:`, but in Objective-C you write `@return`. See Apple's [*HeaderDoc User Guide*](https://developer.apple.com/legacy/library/documentation/DeveloperTools/Conceptual/HeaderDoc/tags/tags.html) for more details. **Note: `jazzy` currently does not support _all_ Objective-C keywords listed in this document, only @param, @return, @warning, @see, @note, @code, @endcode, and @c.**\n\nJazzy can also generate cross-references within your documentation. A symbol name in\nbackticks generates a link, for example:\n* \\`MyClass\\` - a link to documentation for `MyClass`.\n* \\`MyClass.method(param1:)\\` - a link to documentation for that method.\n* \\`MyClass.method(...)\\` - shortcut syntax for the same thing.\n* \\`method(...)\\` - shortcut syntax to link to `method` from the documentation of another\n  method or property in the same class.\n* \\`[MyClass method1]\\` - a link to an Objective-C method.\n* \\`-[MyClass method2:param1]\\` - a link to another Objective-C method.\n\nJazzy understands Apple's DocC-style links too, for example:\n* \\`\\`MyClass/method(param1:)\\`\\` - a link to the documentation for that method\n  that appears as just `method(param1:)` in the rendered page.\n* \\`\\`\\<doc:method(_:)-e873\\>\\`\\` - a link to a specific overload of `method(_:)`.\n  Jazzy can't tell which overload you intend and links to the first one.\n\nIf your documentation is for multiple modules then symbol name resolution works\napproximately as though all the modules have been imported: you can use \\`TypeName\\`\nto refer to a top-level type in any of the modules, or \\`ModuleName.TypeName\\` to\nbe specific.  If there is an ambiguity then you can use a leading slash to\nindicate that the first part of the name should be read as a module name:\n\\`/ModuleName.TypeName\\`.\n\n### Math\n\nJazzy can render math equations written in LaTeX embedded in your markdown:\n* `` `$equation$` `` renders the equation in an inline style.\n* `` `$$equation$$` `` renders the equation in a display style, centered on a\n  line of its own.\n\nFor example, the markdown:\n```markdown\nInline: `$ax^2+bx+c=0$`\n\nBlock: `$$x={\\frac {-b\\pm {\\sqrt {b^{2}-4ac}}}{2a}}$$`\n```\n..renders as:\n\n![math](images/math.png)\n\nMath support is provided by [KaTeX](https://katex.org).\n\n### Swift\n\nSwift documentation is generated by default.\n\n##### Example\n\nThis is how Realm Swift docs are generated:\n\n```shell\njazzy \\\n  --clean \\\n  --author Realm \\\n  --author_url https://realm.io \\\n  --source-host github \\\n  --source-host-url https://github.com/realm/realm-cocoa \\\n  --source-host-files-url https://github.com/realm/realm-cocoa/tree/v0.96.2 \\\n  --module-version 0.96.2 \\\n  --build-tool-arguments -scheme,RealmSwift \\\n  --module RealmSwift \\\n  --root-url https://realm.io/docs/swift/0.96.2/api/ \\\n  --output docs/swift_output \\\n  --theme docs/themes\n```\n\nThis is how docs are generated for a project that uses the Swift Package Manager:\n\n```shell\njazzy \\\n  --module DeckOfPlayingCards \\\n  --swift-build-tool spm \\\n  --build-tool-arguments -Xswiftc,-swift-version,-Xswiftc,5\n```\n\n### Objective-C\n\nTo generate documentation for a simple Objective-C project, you must pass the\nfollowing parameters:\n* `--objc`\n* `--umbrella-header ...`\n* `--framework-root ...`\n\n...and optionally:\n* `--sdk [iphone|watch|appletv][os|simulator]|macosx` (default value\n   of `macosx`)\n* `--hide-declarations [objc|swift]` (hides the selected language declarations)\n\nFor example, this is how the `AFNetworking` docs are generated:\n\n```shell\njazzy \\\n  --objc \\\n  --author AFNetworking \\\n  --author_url http://afnetworking.com \\\n  --source-host github \\\n  --source-host-url https://github.com/AFNetworking/AFNetworking \\\n  --source-host-files-url https://github.com/AFNetworking/AFNetworking/tree/2.6.2 \\\n  --module-version 2.6.2 \\\n  --umbrella-header AFNetworking/AFNetworking.h \\\n  --framework-root . \\\n  --module AFNetworking\n```\n\nFor a more complicated Objective-C project, instead use `--build-tool-arguments`\nto pass arbitrary compiler flags.  For example, this is how Realm Objective-C\ndocs are generated:\n\n```shell\njazzy \\\n  --objc \\\n  --clean \\\n  --author Realm \\\n  --author_url https://realm.io \\\n  --source-host github \\\n  --source-host-url https://github.com/realm/realm-cocoa \\\n  --source-host-files-url https://github.com/realm/realm-cocoa/tree/v2.2.0 \\\n  --module-version 2.2.0 \\\n  --build-tool-arguments --objc,Realm/Realm.h,--,-x,objective-c,-isysroot,$(xcrun --show-sdk-path),-I,$(pwd) \\\n  --module Realm \\\n  --root-url https://realm.io/docs/objc/2.2.0/api/ \\\n  --output docs/objc_output \\\n  --head \"$(cat docs/custom_head.html)\"\n```\n\nSee [the Objective-C docs](ObjectiveC.md) for more information and some tips\non troubleshooting.\n\n### Mixed Objective-C / Swift\n\n*This feature has some rough edges.*\n\nTo generate documentation for a mixed Swift and Objective-C project you must first\ngenerate two [SourceKitten][sourcekitten] files: one for Swift and one for Objective-C.\n\nThen pass these files to Jazzy together using `--sourcekitten-sourcefile`.\n\n#### Example\n\nThis is how docs are generated from an Xcode project for a module containing both\nSwift and Objective-C files:\n\n```shell\n# Generate Swift SourceKitten output\nsourcekitten doc -- -workspace MyProject.xcworkspace -scheme MyScheme > swiftDoc.json\n\n# Generate Objective-C SourceKitten output\nsourcekitten doc --objc $(pwd)/MyProject/MyProject.h \\\n      -- -x objective-c  -isysroot $(xcrun --show-sdk-path --sdk iphonesimulator) \\\n      -I $(pwd) -fmodules > objcDoc.json\n\n# Feed both outputs to Jazzy as a comma-separated list\njazzy --module MyProject --sourcekitten-sourcefile swiftDoc.json,objcDoc.json\n```\n\n### Docs from `.swiftmodule`s or frameworks\n\nSwift 5.3 added support for symbol graph generation from `.swiftmodule` files.\n\nJazzy can use this to generate API documentation.  This is faster than using\nthe source code directly but does have limitations: for example documentation\ncomments are available only for `public` declarations, and the presentation of\nSwift extensions may not match the way they are written in code.\n\nSome examples:\n\n1. Generate docs for the Apple Combine framework for macOS:\n   ```shell\n   jazzy --module Combine --swift-build-tool symbolgraph\n   ```\n   The SDK's library directories are included in the search path by\n   default.\n2. Same but for iOS:\n   ```shell\n   jazzy --module Combine --swift-build-tool symbolgraph\n         --sdk iphoneos\n         --build-tool-arguments -target,arm64-apple-ios14.1\n   ```\n   The `target` is the LLVM target triple and needs to match the SDK.  The\n   default here is the target of the host system that Jazzy is running on,\n   something like `x86_64-apple-darwin19.6.0`.\n3. Generate docs for a personal `.swiftmodule`:\n   ```shell\n   jazzy --module MyMod --swift-build-tool symbolgraph\n         --build-tool-arguments -I,/Build/Products\n   ```\n   This implies that `/Build/Products/MyMod.swiftmodule` exists.  Jazzy's\n   `--source-directory` (default current directory) is searched by default,\n   so you only need the `-I` override if that's not enough.\n4. For a personal framework:\n   ```shell\n   jazzy --module MyMod --swift-build-tool symbolgraph\n         --build-tool-arguments -F,/Build/Products\n   ```\n   This implies that `/Build/Products/MyMod.framework` exists and contains\n   a `.swiftmodule`.  Again the `--source-directory` is searched by default\n   if `-F` is not passed in.\n5. With pre-generated symbolgraph files:\n    ```shell\n    jazzy --module MyMod --swift-build-tool symbolgraph\n          --symbolgraph-directory Build/symbolgraphs\n    ```\n    If you've separately generated symbolgraph files by the use of \n    `-emit-symbol-graph`, you can pass the location of these files using\n    `--symbolgraph-directory` from where they can be parsed directly.\n\nSee `swift symbolgraph-extract -help` for all the things you can pass via\n`--build-tool-arguments`: if your module has dependencies then you may need\nto add various search path options to let Swift load it.\n\n### Documenting multiple modules\n\n*This feature is new, bugs and feedback welcome*\n\nSometimes it's useful to document multiple modules together in the same site,\nfor example an app and its extensions, or an SDK that happens to be implemented\nas several modules.\n\nJazzy can build docs for all these together and create a single site with\nsearch, cross-module linking, and navigation.\n\n#### Build configuration\n\nIf all the modules share the same build flags then the easiest way to do this\nis with `--modules`, for example `jazzy --modules ModuleA,ModuleB,ModuleC`.\n\nIf your modules have different build flags then you have to use the config file.\nFor example:\n```yaml\nmodules:\n  - module: ModuleA\n  - module: ModuleB\n    build_tool_arguments:\n      - -scheme\n      - SpecialScheme\n      - -target\n      - ModuleB\n    source_directory: ModuleBProject\n  - module: ModuleC\n    objc: true\n    umbrella_header: ModuleC/ModuleC.h\n    framework_root: ModuleC\n    sdk: appletvsimulator\n  - module: ModuleD\n    sourcekitten_sourcefile: [ModuleD1.json, ModuleD2.json]\n```\nThis describes a four-module project of which one is 'normal', one requires\nspecial Xcode treatment, one is Objective-C, and one has prebuilt SourceKitten\nJSON.\n\nPer-module options set at the top level are inherited by each module unless\nalso set locally -- but you can't set both `--module` and `--modules`.\n\nJazzy doesn't support `--podspec` mode in conjunction with the multiple\nmodules feature.\n\n#### Presentation\n\nThe `--merge-modules` flag controls how declarations from multiple modules\nare arranged into categories.\n\nThe default of `all` has Jazzy combine declarations from the modules so there\nis one category of classes, one of structures, and so on.  To the user this means\nthey do not worry about which module exports a particular type, although that\ninformation remains available in the type's page.\n\nSetting `--merge-modules none` changes this so each module is a top-level\ncategory, with the module's symbols listed under it.  \n\nSetting `--merge-modules extensions` is like `none` except cross-module\nextensions are shown as part of their extended type.  For example if `ModuleA`\nextends `ModuleB.SomeType` then those extension members from `ModuleA` are shown\non the `ModuleB.SomeType` page along with the rest of `SomeType`.\n\nYou can use `--documentation` to include guides, `custom_categories` to customize\nthe layout with types from whichever modules you want, and `--abstract` to add\nadditional markdown content to the per-module category pages.\n\nUse the `--title`, `--readme-title`, and `--docset-title` flags to control the\ntop-level names of your documentation.  Without these, Jazzy uses the name of one\nof the modules being documented.\n\n### Themes\n\nThree themes are provided with jazzy: `apple` (default), `fullwidth` and `jony`.\n\n* `apple` example: <https://johnfairh.github.io/demo-jazzy-apple-theme/>\n* `fullwidth` example: <https://reduxkit.github.io/ReduxKit/>\n* `jony` example: <https://harshilshah.github.io/IGListKit/>\n\nYou can specify which theme to use by passing in the `--theme` option. You can\nalso provide your own custom theme by passing in the path to your theme\ndirectory.\n\n### Guides\n\n| Description | Command |\n| ---         | ---     |\n| Command line option | `--documentation={file pattern}` |\n| Example             | `--documentation=Docs/*.md` |\n| jazzy.yaml example  | `documentation: Docs/*.md` |\n\nBy default, jazzy looks for one of README.md, README.markdown, README.mdown or README (in that order) in the directory from where it runs to render the index page at the root of the docs output directory.\nUsing the `--documentation` option, extra markdown files can be integrated into the generated docs and sidebar navigation.\n\nAny files found matching the file pattern will be parsed and included as a document with the type 'Guide' when generated. If the files are not included using the `custom_categories` config option, they will be grouped under 'Other Guides' in the sidebar navigation.\n\nThere are a few limitations:\n- File names must be unique from source files.\n- Readme should be specified separately using the `readme` option.\n\nYou can link to a guide from other guides or doc comments using the name of the page\nas it appears in the site.  For example, to link to the guide generated from a file\ncalled `My Guide.md` you would write \\`My Guide\\`.\n\n### Section description abstracts\n\n| Description | Command |\n| ---         | ---     |\n| Command line option | `--abstract={file pattern}` |\n| Example             | `--abstract=Docs/Sections/*.md` |\n| jazzy.yaml example  | `abstract: Docs/Sections/*.md` |\n\nUsing the `--abstract` options, extra markdown can be included after the heading of section overview pages. Think of it as a template include.\n\nThe list of files matching the pattern is compared against the list of sections generated and if a match is found, it's contents will be included in that section before listing source output.\n\nUnlike the `--documentation` option, these files are not included in navigation and if a file does not match a section title, it is not included at all.\n\nThis is very helpful when using `custom_categories` for grouping types and including relevant documentation in those sections.\n\nFor an example of a project using both `--documentation` and `--abstract` see: [https://reswift.github.io/ReSwift/](https://reswift.github.io/ReSwift/)\n\n### Controlling what is documented\n\nIn Swift mode, Jazzy by default documents only `public` and `open` declarations. To\ninclude declarations with a lower access level, set the `--min-acl` flag to `internal`,\n`fileprivate`, or `private`.\n\nBy default, Jazzy does not document declarations marked `@_spi` when `--min-acl` is\nset to `public` or `open`.  Set the `--include-spi-declarations` flag to include them.\n\nIn Objective-C mode, Jazzy documents all declarations found in the `--umbrella-header`\nheader file and any other header files included by it.\n\nYou can control exactly which declarations should be documented using `--exclude`,\n`--include`, or `:nodoc:`.\n\nThe `--include` and `--exclude` flags list source files that should be included/excluded\nrespectively in the documentation. Entries in the list can be absolute pathnames beginning\nwith `/` or relative pathnames. Relative pathnames are interpreted relative to the\ndirectory from where you run `jazzy` or, if the flags are set in the config file, relative\nto the directory containing the config file. Entries in the list can match multiple files\nusing `*` to match any number of characters including `/`.  For example:\n* `jazzy --include=/Users/fred/project/Sources/Secret.swift` -- include a specific file\n* `jazzy --exclude=/*/Internal*` -- exclude all files with names that begin with *Internal*\n  and any files under any directory with a name beginning *Internal*.\n* `jazzy --exclude=Impl1/*,Impl2/*` -- exclude all files under the directories *Impl1* and\n  *Impl2* found in the current directory.\n\nNote that the `--include` option is applied before the `--exclude` option. For example:\n\n* `jazzy --include=/*/Internal* --exclude=Impl1/*,Impl2/*` -- include all files with names\n  that begin with *Internal* and any files under any directory with a name beginning\n  *Internal*, **except** for those under the directories *Impl1* and *Impl2* found in the\n  current directory\n\nDeclarations with a documentation comment containing `:nodoc:` are excluded from the\ndocumentation.\n\nDeclarations with the `@_documentation(visibility:)` attribute are treated as though they\nare written with the given visibility.  You can use this as a replacement for `:nodoc:` as\npart of a transition to Apple's DocC but it is not compatible with Jazzy's symbolgraph mode.\n\n### Documentation structure\n\nJazzy arranges documentation into categories.  The default categories are things\nlike _Classes_ and _Structures_ corresponding to programming-language concepts,\nas well as _Guides_ if `--documentation` is set.\n\nYou can customize the categories and their contents using `custom_categories` in\nthe config file. `custom_categories` is an array of objects.  Each category must contain two properties:\n- `name`: A string with the name you want to give to this category\n- `children`: An array used to specify the root level declarations that you want to add to\nthis category. \n\nEach child, then, can be one of the following:\n- A string, containing either the exact name of one root level declaration you want to\nmatch, or the fully qualified name (`ModuleName.DeclarationName`)\n- An object, containing the property:\n  - `regex`: a string which will be used to match multiple root level declarations from\nall of the modules.\n\nSee the ReSwift [docs](https://reswift.github.io/ReSwift/) and\n[config file](https://github.com/ReSwift/ReSwift/blob/e94737282850fa038b625b4e351d1608a3d02cee/.jazzy.json)\nfor an example.\n\nWithin each category the items are ordered first alphabetically by source\nfilename, and then by declaration order within the file.  You can use\n`// MARK:` comments within the file to create subheadings on the page, for\nexample to split up properties and methods.  There’s no way to customize this\norder short of editing either the generated web page or the SourceKitten JSON.\n\nSwift extensions and Objective-C categories allow type members to be declared\nacross multiple source files.  In general, extensions follow the main type\ndeclaration: first extensions from the same source file, then extensions from\nother files ordered alphabetically by filename.  Swift conditional extensions\n(`extension A where …`) always appear beneath unconditional extensions.\n\nUse this pattern to add or customize the subheading before extension members:\n```swift\nextension MyType {\n  // MARK: Subheading for this group of methods\n  …\n}\n```\n\nWhen Jazzy is using `--swift-build-tool symgraph` the source file names and\nline numbers may not be available. In this case the ordering is approximately\nalphabetical by symbol name and USR; the order is stable for the same input.\n\nJazzy does not normally create separate web pages for declarations that do not\nhave any members -- instead they are entirely nested into their parent page.  Use\nthe `--separate-global-declarations` flag to change this and create pages for\nthese empty types.\n\n### Choosing the Swift language version\n\nJazzy normally uses the Swift compiler from the Xcode currently configured by\n`xcode-select`.  Use the `--swift-version` flag or the `DEVELOPER_DIR` environment\nvariable to compile with a different Xcode.\n\nThe value you pass to `--swift-version` must be the Swift language version given\nby `swift --version` in the Xcode you want to use. Jazzy uses\n[xcinvoke](https://github.com/segiddins/xcinvoke) to find a suitable Xcode\ninstallation on your system. This can be slow: if you know where Xcode is\ninstalled then it's faster to set `DEVELOPER_DIR` directly.\n\nFor example to use Xcode 14:\n```shell\njazzy --swift-version 5.7\n```\n...or:\n```shell\nDEVELOPER_DIR=/Applications/Xcode_14.app/Contents/Developer jazzy\n```\n\n### Dash Docset Support\n\nAs well as the browsable HTML documentation, Jazzy creates a _docset_ for use\nwith the [Dash][dash] app.\n\nBy default the docset is created at `docs/docsets/ModuleName.tgz`.  Use\n`--docset-path` to create it somewhere else; use `--docset-title` to change\nthe docset's title.\n\nUse `--docset-playground-url` and `--docset-icon` to further customize the\ndocset.\n\nIf you set both `--root-url` to be the (https://) URL where you plan to deploy\nyour documentation and `--version` to give your documentation a version number\nthen Jazzy also creates a docset feed XML file and includes an \"Install in Dash\"\nbutton on the site.  This lets users who are browsing your documentation on the\nweb install and start using the docs in Dash locally.\n\n## Linux\n\nJazzy uses [SourceKitten][sourcekitten] to communicate with the Swift build\nenvironment and compiler.  The `sourcekitten` binary included in the Jazzy gem\nis built for macOS and so does not run on other operating systems.\n\nTo use Jazzy on Linux you first need to install and build `sourcekitten`\nfollowing instructions from [SourceKitten's GitHub repository][sourcekitten].\n\nThen to generate documentation for a SwiftPM project, instead of running just\n`jazzy` do:\n```shell\nsourcekitten doc --spm > doc.json\njazzy --sourcekitten-sourcefile doc.json\n```\n\nWe hope to improve this process in the future.\n\n## Troubleshooting\n\n### Swift\n\n**Only extensions are listed in the documentation?**\n\nCheck the `--min-acl` setting -- see [above](#controlling-what-is-documented).\n\n**Unable to find an Xcode with swift version X**\n\n1. The value passed with `--swift-version` must exactly match the version\n   number from `swiftc --version`.  For example Xcode 10.1 needs\n   `--swift-version 4.2.1`.  See [the flag documentation](#choosing-the-swift-language-version).\n2. The Xcode you want to use must be in the Spotlight index.  You can check\n   this using `mdfind 'kMDItemCFBundleIdentifier == com.apple.dt.Xcode'`.\n   Some users have reported this issue being fixed by a reboot; `mdutil -E`\n   may also help.  If none of these work then you can set the `DEVELOPER_DIR`\n   environment variable to point to the Xcode you want before running Jazzy\n   without the `--swift-version` flag.\n\n### Objective-C\n\nSee [this document](ObjectiveC.md).\n\n### Miscellaneous\n\n**Missing docset**\n\nJazzy only builds a docset when you set the `--module` or `--modules` flag.\n\n**Unable to pass --build-tool-arguments containing commas**\n\nIf you want Jazzy to run something like `xcodebuild -scheme Scheme -destination 'a=x,b=y,c=z'`\nthen you must use the config file instead of the CLI flag because the CLI parser\nthat Jazzy uses cannot handle arguments that themselves contain commas.\n\nThe example config file here would be:\n```yaml\nbuild_tool_arguments:\n  - \"-scheme\"\n  - \"Scheme\"\n  - \"-destination\"\n  - \"a=x,b=y,c=z\"\n```\n\n**Errors running in an Xcode Run Script phase**\n\nRunning Jazzy from an Xcode build phase can go wrong in cryptic ways when Jazzy\nhas to run `xcodebuild`.\n\nUsers [have reported](https://github.com/realm/jazzy/issues/1012) that error\nmessages about symbols lacking USRs can be fixed by unsetting\n`LLVM_TARGET_TRIPLE_SUFFIX` as part of the run script.\n\n**Warnings about matches and leftovers when using globs and wildcards**\n\nSome flags such as `--include` and `--documentation` support '*' characters as\nwildcards.  If you are using the CLI then you must make sure that your shell\ndoes not itself try to interpret them, for example by quoting the token: use\n`jazzy --documentation '*.md'` instead of `jazzy --documentation *.md`.\n\n### Installation Problems\n\n**Can't find header files / clang**\n\nSome of the Ruby gems that Jazzy depends on have native C extensions.  This\nmeans you need the Xcode command-line developer tools installed to build\nthem: run `xcode-select --install` to install the tools.\n\n**/Applications/Xcode: No such file or directory**\n\nThe path of your active Xcode installation must not contain spaces.  So\n`/Applications/Xcode.app/` is fine, `/Applications/Xcode-10.2.app/` is fine,\nbut `/Applications/Xcode 10.2.app/` is not.  This restriction applies only\nwhen *installing* Jazzy, not running it.\n\n### MacOS Before 10.14.4\n\nStarting with Jazzy 0.10.0, if you see an error similar to `dyld: Symbol not found: _$s11SubSequenceSlTl` then you need to install the [Swift 5 Runtime Support for Command Line Tools](https://support.apple.com/kb/DL1998).\n\nAlternatively, you can:\n* Update to macOS 10.14.4 or later; or\n* Install Xcode 10.2 or later at `/Applications/Xcode.app`.\n\n## Development\n\nPlease review jazzy's [contributing guidelines](https://github.com/realm/jazzy/blob/master/CONTRIBUTING.md) when submitting pull requests.\n\njazzy is composed of two parts:\n\n1. The parser, [SourceKitten][SourceKitten] (written in Swift)\n2. The site generator (written in ruby)\n\nTo build and run jazzy from source:\n\n1. Install [bundler][bundler].\n2. Run `bundle install` from the root of this repo.\n3. Run jazzy from source by running `bin/jazzy`.\n\nInstructions to build SourceKitten from source can be found at\n[SourceKitten's GitHub repository][SourceKitten].\n\n## Design Goals\n\n- Generate source code docs matching Apple's official reference documentation\n- Support for standard Objective-C and Swift documentation comment syntax\n- Leverage modern HTML templating ([Mustache][mustache])\n- Leverage the power and accuracy of the [Clang AST][ast] and [SourceKit][sourcekit]\n- Support for Dash docsets\n- Support Swift and Objective-C\n\n## License\n\nThis project is released under the [MIT license](https://github.com/realm/jazzy/blob/master/LICENSE).\n\n## About\n\n<img src=\"images/realm.png\" width=\"184\" />\n\nJazzy is maintained and funded by Realm Inc. The names and logos for\nRealm are trademarks of Realm Inc.\n\nWe :heart: open source software!\nSee [our other open source projects](https://github.com/realm),\nread [our blog](https://realm.io/news) or say hi on twitter\n([@realm](https://twitter.com/realm)).\n\n[clang]: https://clang.llvm.org \"Clang\"\n[sourcekit]: https://www.jpsim.com/uncovering-sourcekit \"Uncovering SourceKit\"\n[ast]: https://clang.llvm.org/docs/IntroductionToTheClangAST.html \"Introduction To The Clang AST\"\n[xcode]: https://developer.apple.com/xcode \"Xcode\"\n[SourceKitten]: https://github.com/jpsim/SourceKitten \"SourceKitten\"\n[bundler]: https://rubygems.org/gems/bundler\n[mustache]: https://mustache.github.io \"Mustache\"\n[spm]: https://swift.org/package-manager/ \"Swift Package Manager\"\n[dash]: https://kapeli.com/dash/ \"Dash\"\n"
  },
  {
    "path": "Rakefile",
    "content": "# frozen_string_literal: true\n\n#-- Bootstrap --------------------------------------------------------------#\n\ndesc 'Initializes your working copy to run the specs'\ntask :bootstrap do\n  if system('which bundle')\n    title 'Installing gems'\n    sh 'bundle install'\n\n    title 'Updating submodules'\n    sh 'git submodule update --init --recursive'\n  else\n    warn \"\\033[0;31m\" \\\n      \"[!] Please install the bundler gem manually:\\n\" \\\n      '    $ [sudo] gem install bundler' \\\n      \"\\e[0m\"\n    exit 1\n  end\nend\n\nbegin\n  require 'bundler/gem_tasks'\n  require 'fileutils'\n\n  task default: :spec\n\n  #-- Specs ------------------------------------------------------------------#\n\n  desc 'Run specs'\n  task :spec do\n    title 'Running Tests'\n    Rake::Task['unit_spec'].invoke\n    Rake::Task['objc_spec'].invoke\n    Rake::Task['swift_spec'].invoke\n    Rake::Task['cocoapods_spec'].invoke\n    Rake::Task['rubocop'].invoke\n  end\n\n  desc 'Run unit specs'\n  task :unit_spec do\n    files = FileList['spec/*_spec.rb']\n      .exclude('spec/integration_spec.rb').shuffle.join(' ')\n    sh \"bundle exec bacon #{files}\"\n  end\n\n  desc 'Run objc integration specs'\n  task :objc_spec do\n    sh 'JAZZY_SPEC_SUBSET=objc bundle exec bacon spec/integration_spec.rb'\n  end\n\n  desc 'Run swift integration specs'\n  task :swift_spec do\n    sh 'JAZZY_SPEC_SUBSET=swift bundle exec bacon spec/integration_spec.rb'\n  end\n\n  desc 'Run cocoapods integration specs'\n  task :cocoapods_spec do\n    sh 'JAZZY_SPEC_SUBSET=cocoapods bundle exec bacon spec/integration_spec.rb'\n  end\n\n  desc 'Rebuilds integration fixtures'\n  task :rebuild_integration_fixtures do\n    title 'Running Integration tests'\n    sh 'rm -rf spec/integration_specs/tmp'\n    puts `bundle exec bacon spec/integration_spec.rb`\n\n    title 'Storing fixtures'\n    # Copy the files to the files produced by the specs to the after folders\n    FileList['tmp/*'].each do |source|\n      destination = \"spec/integration_specs/#{source.gsub('tmp/', '')}/after\"\n      if File.exist?(destination)\n        sh \"rm -rf #{destination}\"\n        sh \"mv #{source}/transformed #{destination}\"\n      end\n    end\n\n    # Remove files not used for the comparison\n    # To keep the git diff clean\n    specs_root = 'spec/integration_specs/*/after'\n    files_glob = \"#{specs_root}/{*,.*}\"\n    files_to_delete = FileList[files_glob]\n      .exclude('**/.', '**/..')\n      .exclude(\"#{specs_root}/*docs\",\n               \"#{specs_root}/execution_output.txt\")\n      .include(\"#{specs_root}/**/*.dsidx\")\n      .include(\"#{specs_root}/**/*.tgz\")\n    files_to_delete.each do |file_to_delete|\n      sh \"rm -rf '#{file_to_delete}'\"\n    end\n\n    puts\n    puts 'Integration fixtures updated, see `spec/integration_specs`'\n  end\n\n  #-- RuboCop ----------------------------------------------------------------#\n\n  desc 'Runs RuboCop linter on Ruby files'\n  task :rubocop do\n    sh 'bundle exec rubocop'\n  end\n\n  #-- SourceKitten -----------------------------------------------------------#\n\n  desc 'Vendors SourceKitten'\n  task :sourcekitten do\n    sk_dir = 'SourceKitten'\n    bin_path = Dir.chdir(sk_dir) do\n      build_cmd = 'swift build -c release --arch arm64 --arch x86_64'\n      `#{build_cmd}`\n      `#{build_cmd} --show-bin-path`.chomp\n    end\n    FileUtils.cp_r \"#{bin_path}/sourcekitten\", 'bin'\n  end\n\n  #-- Theme Dependencies -----------------------------------------------------#\n\n  THEME_FILES = {\n    'jquery/dist/jquery.min.js' => [\n      'themes/apple/assets/js',\n      'themes/fullwidth/assets/js',\n      'themes/jony/assets/js',\n    ],\n    'lunr/lunr.min.js' => [\n      'themes/apple/assets/js',\n      'themes/fullwidth/assets/js',\n    ],\n    'corejs-typeahead/dist/typeahead.jquery.js' => [\n      'themes/apple/assets/js',\n      'themes/fullwidth/assets/js',\n    ],\n    'katex/dist/katex.min.css' => ['extensions/katex/css'],\n    'katex/dist/fonts' => ['extensions/katex/css'],\n    'katex/dist/katex.min.js' => ['extensions/katex/js'],\n  }.freeze\n\n  desc 'Copies theme dependencies (`npm update/install` by hand first)'\n  task :theme_deps do\n    THEME_FILES.each_pair do |src, dsts|\n      dsts.each do |dst|\n        FileUtils.cp_r \"js/node_modules/#{src}\", \"lib/jazzy/#{dst}\"\n      end\n    end\n  end\nrescue LoadError, NameError => e\n  warn \"\\033[0;31m\" \\\n    '[!] Some Rake tasks haven been disabled because the environment' \\\n    ' couldn’t be loaded. Be sure to run `rake bootstrap` first.' \\\n    \"\\e[0m\"\n  warn e.message\n  warn e.backtrace\n  warn ''\nend\n\n#-- Helpers ------------------------------------------------------------------#\n\ndef title(title)\n  cyan_title = \"\\033[0;36m#{title}\\033[0m\"\n  puts\n  puts '-' * 80\n  puts cyan_title\n  puts '-' * 80\n  puts\nend\n"
  },
  {
    "path": "bin/jazzy",
    "content": "#!/usr/bin/env ruby\n# frozen_string_literal: true\n\nif $PROGRAM_NAME == __FILE__ && !ENV['JAZZY_NO_BUNDLER']\n  ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', __dir__)\n  require 'rubygems'\n  require 'bundler/setup'\n  $LOAD_PATH.unshift File.expand_path('../lib', __dir__)\nelsif ENV['JAZZY_NO_BUNDLER']\n  require 'rubygems'\n  gem 'jazzy'\nend\n\nrequire 'jazzy'\n\nJazzy::DocBuilder.build(Jazzy::Config.instance = Jazzy::Config.parse!)\n"
  },
  {
    "path": "jazzy.gemspec",
    "content": "# coding: utf-8\n# frozen_string_literal: true\n\nrequire File.expand_path('lib/jazzy/gem_version.rb', File.dirname(__FILE__))\n\nGem::Specification.new do |spec|\n  spec.name          = 'jazzy'\n  spec.version       = Jazzy::VERSION\n  spec.authors       = ['JP Simard', 'Tim Anglade', 'Samuel Giddins', 'John Fairhurst']\n  spec.email         = ['jp@jpsim.com']\n  spec.summary       = 'Soulful docs for Swift & Objective-C.'\n  spec.description   = 'Soulful docs for Swift & Objective-C. ' \\\n    \"Run in your SPM or Xcode project's root directory for \" \\\n    'instant HTML docs.'\n  spec.homepage      = 'https://github.com/realm/jazzy'\n  spec.license       = 'MIT'\n\n  spec.files         = `git ls-files`.split($/)\n  spec.executables << 'jazzy'\n\n  spec.add_dependency 'activesupport', '>= 5.0', '< 8'\n  spec.add_dependency 'cocoapods', '~> 1.5'\n  spec.add_dependency 'logger'\n  spec.add_dependency 'mustache', '~> 1.1'\n  spec.add_dependency 'open4', '~> 1.3'\n  spec.add_dependency 'redcarpet', '~> 3.4'\n  spec.add_dependency 'rexml', ['>= 3.2.7', '< 4.0']\n  spec.add_dependency 'rouge', ['>= 2.0.6', '< 5.0']\n  spec.add_dependency 'sassc', '~> 2.1'\n  spec.add_dependency 'sqlite3', '~> 1.3'\n  spec.add_dependency 'xcinvoke', '~> 0.3.0'\n\n  spec.add_development_dependency 'bundler', '~> 2.1'\n  spec.add_development_dependency 'rake', '~> 13.0'\n\n  spec.required_ruby_version = '>= 2.6.3'\n  spec.metadata['rubygems_mfa_required'] = 'true'\nend\n"
  },
  {
    "path": "js/package.json",
    "content": "{\n  \"name\": \"jazzy-js\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Jazzy theme dependencies\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"corejs-typeahead\": \"^1.3.1\",\n    \"jquery\": \"^3.7.1\",\n    \"katex\": \"^0.16.8\",\n    \"lunr\": \"^2.3.9\"\n  }\n}\n"
  },
  {
    "path": "lib/jazzy/config.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'optparse'\nrequire 'pathname'\nrequire 'uri'\n\nrequire 'jazzy/podspec_documenter'\nrequire 'jazzy/source_declaration/access_control_level'\n\nmodule Jazzy\n  # rubocop:disable Metrics/ClassLength\n  class Config\n    # rubocop:disable Naming/AccessorMethodName\n    class Attribute\n      attr_reader :name, :description, :command_line, :config_file_key,\n                  :default, :parse, :per_module\n\n      def initialize(name, description: nil, command_line: nil,\n                     default: nil, parse: ->(x) { x }, per_module: false)\n        @name = name.to_s\n        @description = Array(description)\n        @command_line = Array(command_line)\n        @default = default\n        @parse = parse\n        @config_file_key = full_command_line_name || @name\n        @per_module = per_module\n      end\n\n      def get(config)\n        config.method(name).call\n      end\n\n      def set_raw(config, val)\n        config.method(\"#{name}=\").call(val)\n      end\n\n      def set(config, val, mark_configured: true)\n        set_raw(config, config.instance_exec(val, &parse))\n        config.method(\"#{name}_configured=\").call(true) if mark_configured\n      end\n\n      def set_to_default(config)\n        set(config, default, mark_configured: false) if default\n      end\n\n      def set_if_unconfigured(config, val)\n        set(config, val) unless configured?(config)\n      end\n\n      def configured?(config)\n        config.method(\"#{name}_configured\").call\n      end\n\n      def attach_to_option_parser(config, opt)\n        return if command_line.empty?\n\n        opt.on(*command_line, *description) do |val|\n          set(config, val)\n        end\n      end\n\n      private\n\n      def full_command_line_name\n        long_option_names = command_line.map do |opt|\n          Regexp.last_match(1) if opt.to_s =~ %r{\n            ^--           # starts with double dash\n            (?:\\[no-\\])?  # optional prefix for booleans\n            ([^\\s]+)      # long option name\n          }x\n        end\n        if long_option_name = long_option_names.compact.first\n          long_option_name.tr('-', '_')\n        end\n      end\n    end\n    # rubocop:enable Naming/AccessorMethodName\n\n    def self.config_attr(name, **opts)\n      attr_accessor name\n      attr_accessor \"#{name}_configured\"\n\n      @all_config_attrs ||= []\n      @all_config_attrs << Attribute.new(name, **opts)\n    end\n\n    def self.alias_config_attr(name, forward, **opts)\n      alias_method name.to_s, forward.to_s\n      alias_method \"#{name}=\", \"#{forward}=\"\n      alias_method \"#{name}_configured\", \"#{forward}_configured\"\n      alias_method \"#{name}_configured=\", \"#{forward}_configured=\"\n      @all_config_attrs << Attribute.new(name, **opts)\n    end\n\n    class << self\n      attr_reader :all_config_attrs\n    end\n\n    attr_accessor :base_path\n\n    def expand_glob_path(path)\n      Pathname(path).expand_path(base_path) # nil means Pathname.pwd\n    end\n\n    def expand_path(path)\n      abs_path = expand_glob_path(path)\n      Pathname(Dir[abs_path][0] || abs_path) # Use existing filesystem spelling\n    end\n\n    def hide_swift?\n      hide_declarations == 'swift'\n    end\n\n    def hide_objc?\n      hide_declarations == 'objc'\n    end\n\n    # ──────── Build ────────\n\n    # rubocop:disable Layout/ArgumentAlignment\n\n    config_attr :output,\n      description: 'Folder to output the HTML docs to',\n      command_line: ['-o', '--output FOLDER'],\n      default: 'docs',\n      parse: ->(o) { expand_path(o) }\n\n    config_attr :clean,\n      command_line: ['-c', '--[no-]clean'],\n      description: ['Delete contents of output directory before running. ',\n                    'WARNING: If --output is set to ~/Desktop, this will ' \\\n                      'delete the ~/Desktop directory.'],\n      default: false\n\n    config_attr :objc_mode,\n      command_line: '--[no-]objc',\n      description: 'Generate docs for Objective-C.',\n      default: false,\n      per_module: true\n\n    config_attr :umbrella_header,\n      command_line: '--umbrella-header PATH',\n      description: 'Umbrella header for your Objective-C framework.',\n      parse: ->(uh) { expand_path(uh) },\n      per_module: true\n\n    config_attr :framework_root,\n      command_line: '--framework-root PATH',\n      description: 'The root path to your Objective-C framework.',\n      parse: ->(fr) { expand_path(fr) },\n      per_module: true\n\n    config_attr :sdk,\n      command_line: '--sdk [iphone|watch|appletv][os|simulator]|macosx',\n      description: 'The SDK for which your code should be built.',\n      default: 'macosx',\n      per_module: true\n\n    config_attr :hide_declarations,\n      command_line: '--hide-declarations [objc|swift] ',\n      description: 'Hide declarations in the specified language. Given that ' \\\n        'generating Swift docs only generates Swift declarations, ' \\\n        'this is useful for hiding a specific interface for ' \\\n        'either Objective-C or mixed Objective-C and Swift ' \\\n        'projects.',\n      default: ''\n\n    config_attr :keep_property_attributes,\n      command_line: '--[no-]keep-property-attributes',\n      description: 'Include the default Objective-C property attributes.',\n      default: false\n\n    config_attr :config_file,\n      command_line: '--config PATH',\n      description: ['Configuration file (.yaml or .json)',\n                    'Default: .jazzy.yaml in source directory or ancestor'],\n      parse: ->(cf) { expand_path(cf) }\n\n    config_attr :build_tool_arguments,\n      command_line: ['-b', '--build-tool-arguments arg1,arg2,…argN', Array],\n      description: 'Arguments to forward to xcodebuild, swift build, or ' \\\n        'sourcekitten.',\n      default: [],\n      per_module: true\n\n    config_attr :modules,\n      command_line: ['--modules Mod1,Mod2,…ModN', Array],\n      description: 'List of modules to document.  Use the config file to set per-module ' \\\n        \"build flags, see 'Documenting multiple modules' in the README.\",\n      default: []\n\n    alias_config_attr :xcodebuild_arguments, :build_tool_arguments,\n      command_line: ['-x', '--xcodebuild-arguments arg1,arg2,…argN', Array],\n      description: 'Back-compatibility alias for build_tool_arguments.'\n\n    config_attr :sourcekitten_sourcefile,\n      command_line: ['-s', '--sourcekitten-sourcefile filepath1,…filepathN',\n                     Array],\n      description: 'File(s) generated from sourcekitten output to parse',\n      parse: ->(paths) { [paths].flatten.map { |path| expand_path(path) } },\n      default: [],\n      per_module: true\n\n    config_attr :source_directory,\n      command_line: '--source-directory DIRPATH',\n      description: 'The directory that contains the source to be documented',\n      default: Pathname.pwd,\n      parse: ->(sd) { expand_path(sd) },\n      per_module: true\n\n    config_attr :symbolgraph_directory,\n      command_line: '--symbolgraph-directory DIRPATH',\n      description: 'A directory containing a set of Swift Symbolgraph files ' \\\n        'representing the module to be documented',\n      parse: ->(sd) { expand_path(sd) },\n      per_module: true\n\n    config_attr :excluded_files,\n      command_line: ['-e', '--exclude filepath1,filepath2,…filepathN', Array],\n      description: 'Source file pathnames to be excluded from documentation. ' \\\n        'Supports wildcards.',\n      default: [],\n      parse: ->(files) do\n        Array(files).map { |f| expand_glob_path(f).to_s }\n      end\n\n    config_attr :included_files,\n      command_line: ['-i', '--include filepath1,filepath2,…filepathN', Array],\n      description: 'Source file pathnames to be included in documentation. ' \\\n        'Supports wildcards.',\n      default: [],\n      parse: ->(files) do\n        Array(files).map { |f| expand_glob_path(f).to_s }\n      end\n\n    config_attr :swift_version,\n      command_line: '--swift-version VERSION',\n      default: nil,\n      parse: ->(v) do\n        if v.to_s.empty?\n          nil\n        elsif v.to_f < 2\n          raise 'jazzy only supports Swift 2.0 or later.'\n        else\n          v\n        end\n      end\n\n    SWIFT_BUILD_TOOLS = %w[spm xcodebuild symbolgraph].freeze\n\n    config_attr :swift_build_tool,\n      command_line: \"--swift-build-tool #{SWIFT_BUILD_TOOLS.join(' | ')}\",\n      description: 'Control whether Jazzy uses Swift Package Manager, ' \\\n        'xcodebuild, or swift-symbolgraph to build the module ' \\\n        'to be documented.  By default it uses xcodebuild if ' \\\n        'there is a .xcodeproj file in the source directory.',\n      parse: ->(tool) do\n        return tool.to_sym if SWIFT_BUILD_TOOLS.include?(tool)\n\n        raise \"Unsupported swift_build_tool #{tool}, \" \\\n          \"supported values: #{SWIFT_BUILD_TOOLS.join(', ')}\"\n      end\n\n    # ──────── Metadata ────────\n\n    config_attr :author_name,\n      command_line: ['-a', '--author AUTHOR_NAME'],\n      description: 'Name of author to attribute in docs (e.g. Realm)',\n      default: ''\n\n    config_attr :author_url,\n      command_line: ['-u', '--author_url URL'],\n      description: 'Author URL of this project (e.g. https://realm.io)',\n      default: '',\n      parse: ->(u) { URI(u) }\n\n    config_attr :module_name,\n      command_line: ['-m', '--module MODULE_NAME'],\n      description: 'Name of module being documented. (e.g. RealmSwift)',\n      default: '',\n      per_module: true\n\n    config_attr :version,\n      command_line: '--module-version VERSION',\n      description: 'Version string to use as part of the default docs ' \\\n        'title and inside the docset.',\n      default: '1.0'\n\n    config_attr :title,\n      command_line: '--title TITLE',\n      description: 'Title to display at the top of each page, overriding the ' \\\n        'default generated from module name and version.',\n      default: ''\n\n    config_attr :copyright,\n      command_line: '--copyright COPYRIGHT_MARKDOWN',\n      description: 'copyright markdown rendered at the bottom of the docs pages'\n\n    config_attr :readme_path,\n      command_line: '--readme FILEPATH',\n      description: 'The path to a markdown README file',\n      parse: ->(rp) { expand_path(rp) }\n\n    config_attr :readme_title,\n      command_line: '--readme-title TITLE',\n      description: 'The title for the README in the generated documentation'\n\n    config_attr :documentation_glob,\n      command_line: '--documentation GLOB',\n      description: 'Glob that matches available documentation',\n      parse: ->(dg) { Pathname.glob(dg) }\n\n    config_attr :abstract_glob,\n      command_line: '--abstract GLOB',\n      description: 'Glob that matches available abstracts for categories',\n      parse: ->(ag) { Pathname.glob(ag) }\n\n    config_attr :podspec,\n      command_line: '--podspec FILEPATH',\n      description: 'A CocoaPods Podspec that describes the Swift library to ' \\\n        'document',\n      parse: ->(ps) { PodspecDocumenter.create_podspec(Pathname(ps)) if ps },\n      default: Dir['*.podspec{,.json}'].first\n\n    config_attr :pod_sources,\n      command_line: ['--pod-sources url1,url2,…urlN', Array],\n      description: 'A list of sources to find pod dependencies. Used only ' \\\n        'with --podspec when the podspec contains references to ' \\\n        'privately hosted pods. You must include the default pod ' \\\n        'source if public pods are also used.',\n      default: []\n\n    config_attr :docset_icon,\n      command_line: '--docset-icon FILEPATH',\n      parse: ->(di) { expand_path(di) }\n\n    config_attr :docset_path,\n      command_line: '--docset-path DIRPATH',\n      description: 'The relative path for the generated docset'\n\n    config_attr :docset_title,\n      command_line: '--docset-title TITLE',\n      description: 'The title of the generated docset.  A simplified version ' \\\n        'is used for the filenames associated with the docset.  If the ' \\\n        'option is not set then the name of the module being documented is ' \\\n        'used as the docset title.'\n\n    # ──────── URLs ────────\n\n    config_attr :root_url,\n      command_line: ['-r', '--root-url URL'],\n      description: 'Absolute URL root where these docs will be stored',\n      # ensure trailing slash for correct URI.join()\n      parse: ->(r) { URI(r.sub(%r{/?$}, '/')) }\n\n    config_attr :dash_url,\n      command_line: ['-d', '--dash_url URL'],\n      description: 'Location of the dash XML feed ' \\\n        'e.g. https://realm.io/docsets/realm.xml)',\n      parse: ->(d) { URI(d) }\n\n    SOURCE_HOSTS = %w[github gitlab bitbucket].freeze\n\n    config_attr :source_host,\n      command_line: \"--source-host #{SOURCE_HOSTS.join(' | ')}\",\n      description: ['The source-code hosting site to be linked from documentation.',\n                    'This setting affects the logo image and link format.',\n                    \"Default: 'github'\"],\n      default: 'github',\n      parse: ->(host) do\n        return host.to_sym if SOURCE_HOSTS.include?(host)\n\n        raise \"Unsupported source_host '#{host}', \" \\\n          \"supported values: #{SOURCE_HOSTS.join(', ')}\"\n      end\n\n    config_attr :source_host_url,\n      command_line: ['--source-host-url URL'],\n      description: [\"URL to link from the source host's logo.\",\n                    'For example https://github.com/realm/realm-cocoa'],\n      parse: ->(g) { URI(g) }\n\n    alias_config_attr :github_url, :source_host_url,\n      command_line: ['-g', '--github_url URL'],\n      description: 'Back-compatibility alias for source_host_url.'\n\n    config_attr :source_host_files_url,\n      command_line: '--source-host-files-url PREFIX',\n      description: [\n        \"The base URL on the source host of the project's files, to link \" \\\n          'from individual declarations.',\n        'For example https://github.com/realm/realm-cocoa/tree/v0.87.1',\n      ]\n\n    alias_config_attr :github_file_prefix, :source_host_files_url,\n      command_line: '--github-file-prefix PREFIX',\n      description: 'Back-compatibility alias for source_host_files_url'\n\n    config_attr :docset_playground_url,\n      command_line: '--docset-playground-url URL',\n      description: 'URL of an interactive playground to demonstrate the ' \\\n        'framework, linked to from the docset.'\n\n    # ──────── Doc generation options ────────\n    config_attr :disable_search,\n      command_line: '--disable-search',\n      description: 'Avoid generating a search index. ' \\\n        'Search is available in some themes.',\n      default: false\n\n    config_attr :skip_documentation,\n      command_line: '--skip-documentation',\n      description: 'Will skip the documentation generation phase.',\n      default: false\n\n    config_attr :min_acl,\n      command_line:\n         '--min-acl [private | fileprivate | internal | package | public | open]',\n      description: 'minimum access control level to document',\n      default: 'public',\n      parse: ->(acl) do\n        SourceDeclaration::AccessControlLevel.from_human_string(acl)\n      end\n\n    config_attr :skip_undocumented,\n      command_line: '--[no-]skip-undocumented',\n      description: \"Don't document declarations that have no documentation \" \\\n        'comments.',\n      default: false\n\n    config_attr :hide_documentation_coverage,\n      command_line: '--[no-]hide-documentation-coverage',\n      description: 'Hide \"(X% documented)\" from the generated documents',\n      default: false\n\n    config_attr :custom_categories,\n      description: 'Custom navigation categories to replace the standard ' \\\n        \"'Classes', 'Protocols', etc. Types not explicitly named \" \\\n        'in a custom category appear in generic groups at the ' \\\n        'end.  Example: https://git.io/v4Bcp',\n      default: []\n\n    config_attr :custom_categories_unlisted_prefix,\n      description: \"Prefix for navigation section names that aren't \" \\\n        'explicitly listed in `custom_categories`.',\n      default: 'Other '\n\n    config_attr :hide_unlisted_documentation,\n      command_line: '--[no-]hide-unlisted-documentation',\n      description: \"Don't include documentation in the sidebar from the \" \\\n        \"`documentation` config value that aren't explicitly \" \\\n        'listed in `custom_categories`.',\n      default: false\n\n    config_attr :custom_head,\n      command_line: '--head HTML',\n      description: 'Custom HTML to inject into <head></head>.',\n      default: ''\n\n    BUILTIN_THEME_DIR = Pathname(__dir__) + 'themes'\n    BUILTIN_THEMES = BUILTIN_THEME_DIR.children(false).map(&:to_s)\n\n    config_attr :theme_directory,\n      command_line: \"--theme [#{BUILTIN_THEMES.join(' | ')} | DIRPATH]\",\n      description: \"Which theme to use. Specify either 'apple' (default), \" \\\n        'one of the other built-in theme names, or the path to ' \\\n        'your mustache templates and other assets for a custom ' \\\n        'theme.',\n      default: 'apple',\n      parse: ->(t) do\n        if BUILTIN_THEMES.include?(t)\n          BUILTIN_THEME_DIR + t\n        else\n          expand_path(t)\n        end\n      end\n\n    config_attr :use_safe_filenames,\n      command_line: '--use-safe-filenames',\n      description: 'Replace unsafe characters in filenames with an encoded ' \\\n        'representation. This will reduce human readability of ' \\\n        'some URLs, but may be necessary for projects that ' \\\n        'expose filename-unfriendly functions such as /(_:_:)',\n      default: false\n\n    config_attr :template_directory,\n      command_line: ['-t', '--template-directory DIRPATH'],\n      description: 'DEPRECATED: Use --theme instead.',\n      parse: ->(_) do\n        raise '--template-directory (-t) is deprecated: use --theme instead.'\n      end\n\n    config_attr :assets_directory,\n      command_line: '--assets-directory DIRPATH',\n      description: 'DEPRECATED: Use --theme instead.',\n      parse: ->(_) do\n        raise '--assets-directory is deprecated: use --theme instead.'\n      end\n\n    config_attr :undocumented_text,\n      command_line: '--undocumented-text UNDOCUMENTED_TEXT',\n      description: 'Default text for undocumented symbols. The default ' \\\n        'is \"Undocumented\", put \"\" if no text is required',\n      default: 'Undocumented'\n\n    config_attr :separate_global_declarations,\n      command_line: '--[no-]separate-global-declarations',\n      description: 'Create separate pages for all global declarations ' \\\n        \"(classes, structures, enums etc.) even if they don't \" \\\n        'have children.',\n      default: false\n\n    config_attr :include_spi_declarations,\n      command_line: '--[no-]include-spi-declarations',\n      description: 'Include Swift declarations marked `@_spi` even if ' \\\n        '--min-acl is set to `public` or `open`.',\n      default: false\n\n    MERGE_MODULES = %w[all extensions none].freeze\n\n    config_attr :merge_modules,\n      command_line: \"--merge-modules #{MERGE_MODULES.join(' | ')}\",\n      description: 'Control how to display declarations from multiple ' \\\n        'modules.  `all`, the default, places all declarations of the ' \\\n        \"same kind together.  `none` keeps each module's declarations \" \\\n        'separate.  `extensions` is like `none` but merges ' \\\n        'cross-module extensions into their extended type.',\n      default: 'all',\n      parse: ->(merge) do\n        return merge.to_sym if MERGE_MODULES.include?(merge)\n\n        raise \"Unsupported merge_modules #{merge}, \" \\\n          \"supported values: #{MERGE_MODULES.join(', ')}\"\n      end\n\n    # rubocop:enable Layout/ArgumentAlignment\n\n    def initialize\n      self.class.all_config_attrs.each do |attr|\n        attr.set_to_default(self)\n      end\n    end\n\n    def theme_directory=(theme_directory)\n      @theme_directory = theme_directory\n      Doc.template_path = theme_directory + 'templates'\n    end\n\n    def self.parse!\n      config = new\n      config.parse_command_line\n      config.parse_config_file\n      PodspecDocumenter.apply_config_defaults(config.podspec, config)\n\n      config.set_module_configs\n\n      config.validate\n\n      config\n    end\n\n    def warning(message)\n      warn \"WARNING: #{message}\"\n    end\n\n    # rubocop:disable Metrics/MethodLength\n    def parse_command_line\n      OptionParser.new do |opt|\n        opt.banner = 'Usage: jazzy'\n        opt.separator ''\n        opt.separator 'Options'\n\n        self.class.all_config_attrs.each do |attr|\n          attr.attach_to_option_parser(self, opt)\n        end\n\n        opt.on('-v', '--version', 'Print version number') do\n          puts \"jazzy version: #{Jazzy::VERSION}\"\n          exit\n        end\n\n        opt.on('-h', '--help [TOPIC]', 'Available topics:',\n               '  usage   Command line options (this help message)',\n               '  config  Configuration file options',\n               '...or an option keyword, e.g. \"dash\"') do |topic|\n          case topic\n          when 'usage', nil\n            puts opt\n          when 'config'\n            print_config_file_help\n          else\n            print_option_help(topic)\n          end\n          exit\n        end\n      end.parse!\n\n      unless ARGV.empty?\n        warning \"Leftover unused command-line text: #{ARGV}\"\n      end\n    end\n\n    def parse_config_file\n      config_path = locate_config_file\n      return unless config_path\n\n      self.base_path = config_path.parent\n\n      puts \"Using config file #{config_path}\"\n      config_file = read_config_file(config_path)\n\n      attrs_by_conf_key, attrs_by_name = grouped_attributes\n\n      parse_config_hash(config_file, attrs_by_conf_key, attrs_by_name)\n    end\n\n    def parse_config_hash(hash, attrs_by_conf_key, attrs_by_name, override: false)\n      hash.each do |key, value|\n        unless attr = attrs_by_conf_key[key]\n          message = \"Unknown config file attribute #{key.inspect}\"\n          if matching_name = attrs_by_name[key]\n            message +=\n              \" (Did you mean #{matching_name.first.config_file_key.inspect}?)\"\n          end\n          warning message\n          next\n        end\n        setter = override ? :set : :set_if_unconfigured\n        attr.first.method(setter).call(self, value)\n      end\n    end\n\n    # Find keyed versions of the attributes, by config file key and then name-in-code\n    # Optional block allows filtering/overriding of attribute list.\n    def grouped_attributes\n      attrs = self.class.all_config_attrs\n      attrs = yield attrs if block_given?\n      %i[config_file_key name].map do |property|\n        attrs.group_by(&property)\n      end\n    end\n\n    def validate\n      if source_host_configured &&\n         source_host_url.nil? &&\n         source_host_files_url.nil?\n        warning 'Option `source_host` is set but has no effect without either ' \\\n          '`source_host_url` or `source_host_files_url`.'\n      end\n\n      if modules_configured && module_name_configured\n        raise 'Options `modules` and `module` are both set which is not supported. ' \\\n          'To document multiple modules, use just `modules`.'\n      end\n\n      if modules_configured && podspec_configured\n        raise 'Options `modules` and `podspec` are both set which is not supported.'\n      end\n\n      module_configs.each(&:validate_module)\n    end\n\n    def validate_module\n      if objc_mode &&\n         build_tool_arguments_configured &&\n         (framework_root_configured || umbrella_header_configured)\n        warning 'Option `build_tool_arguments` is set: values passed to ' \\\n          '`framework_root` or `umbrella_header` may be ignored.'\n      end\n    end\n\n    # rubocop:enable Metrics/MethodLength\n\n    # Module Configs\n    #\n    # The user can enter module information in three different ways.  This\n    # consolidates them into one view for the rest of the code.\n    #\n    # 1) Single module, back-compatible\n    #    --module Foo etc etc (or not given at all)\n    #\n    # 2) Multiple modules, simple, sharing build params\n    #    --modules Foo,Bar,Baz --source-directory Xyz\n    #\n    # 3) Multiple modules, custom, different build params but\n    #    inheriting others from the top level.\n    #    This is config-file only.\n    #    - modules\n    #      - module: Foo\n    #        source_directory: Xyz\n    #        build_tool_arguments: [a, b, c]\n    #\n    # After this we're left with `config.module_configs` that is an\n    # array of `Config` objects.\n\n    attr_reader :module_configs\n    attr_reader :module_names\n\n    def set_module_configs\n      @module_configs = parse_module_configs\n      @module_names = module_configs.map(&:module_name)\n      @module_names_set = Set.new(module_names)\n    end\n\n    def module_name?(name)\n      @module_names_set.include?(name)\n    end\n\n    def multiple_modules?\n      @module_names.count > 1\n    end\n\n    def parse_module_configs\n      return [self] unless modules_configured\n\n      raise 'Config file key `modules` must be an array' unless modules.is_a?(Array)\n\n      if modules.first.is_a?(String)\n        # Massage format (2) into (3)\n        self.modules = modules.map { |mod| { 'module' => mod } }\n      end\n\n      # Allow per-module overrides of only some config options\n      attrs_by_conf_key, attrs_by_name =\n        grouped_attributes { |attr| attr.select(&:per_module) }\n\n      modules.map do |module_hash|\n        mod_name = module_hash['module'] || ''\n        raise 'Missing `modules.module` config key' if mod_name.empty?\n\n        dup.tap do |module_config|\n          module_config.parse_config_hash(\n            module_hash, attrs_by_conf_key, attrs_by_name, override: true\n          )\n        end\n      end\n    end\n\n    # For podspec query\n    def module_name_known?\n      module_name_configured || modules_configured\n    end\n\n    def locate_config_file\n      return config_file if config_file\n\n      source_directory.ascend do |dir|\n        candidate = dir.join('.jazzy.yaml')\n        return candidate if candidate.exist?\n      end\n      nil\n    end\n\n    def read_config_file(file)\n      case File.extname(file)\n        when '.json'\n          JSON.parse(File.read(file))\n        when '.yaml', '.yml'\n          YAML.safe_load(File.read(file))\n        else raise \"Config file must be .yaml or .json, but got #{file.inspect}\"\n      end\n    end\n\n    def print_config_file_help\n      puts <<-_EOS_\n\n        By default, jazzy looks for a file named \".jazzy.yaml\" in the source\n        directory and its ancestors. You can override the config file location\n        with --config.\n\n        (The source directory is the current working directory by default.\n        You can override that with --source-directory.)\n\n        The config file can be in YAML or JSON format. Available options are:\n\n      _EOS_\n        .gsub(/^ +/, '')\n\n      print_option_help\n    end\n\n    def print_option_help(topic = '')\n      found = false\n      self.class.all_config_attrs.each do |attr|\n        match = ([attr.name] + attr.command_line).any? do |opt|\n          opt.to_s.include?(topic)\n        end\n        if match\n          found = true\n          puts\n          puts attr.name.to_s.tr('_', ' ').upcase\n          puts\n          puts \"  Config file:   #{attr.config_file_key}\"\n          cmd_line_forms = attr.command_line.select { |opt| opt.is_a?(String) }\n          if cmd_line_forms.any?\n            puts \"  Command line:  #{cmd_line_forms.join(', ')}\"\n          end\n          puts\n          print_attr_description(attr)\n        end\n      end\n      warn \"Unknown help topic #{topic.inspect}\" unless found\n    end\n\n    def print_attr_description(attr)\n      attr.description.each { |line| puts \"  #{line}\" }\n      if attr.default && attr.default != ''\n        puts \"  Default: #{attr.default}\"\n      end\n    end\n\n    #-------------------------------------------------------------------------#\n\n    # @!group Singleton\n\n    # @return [Config] the current config instance creating one if needed.\n    #\n    def self.instance\n      @instance ||= new\n    end\n\n    # Sets the current config instance. If set to nil the config will be\n    # recreated when needed.\n    #\n    # @param  [Config, Nil] the instance.\n    #\n    # @return [void]\n    #\n    class << self\n      attr_writer :instance\n    end\n\n    # Provides support for accessing the configuration instance in other\n    # scopes.\n    #\n    module Mixin\n      def config\n        Config.instance\n      end\n    end\n  end\n  # rubocop:enable Metrics/ClassLength\nend\n"
  },
  {
    "path": "lib/jazzy/doc.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'date'\nrequire 'pathname'\nrequire 'mustache'\n\nrequire 'jazzy/config'\nrequire 'jazzy/gem_version'\nrequire 'jazzy/jazzy_markdown'\n\nmodule Jazzy\n  class Doc < Mustache\n    include Config::Mixin\n\n    self.template_name = 'doc'\n\n    def copyright\n      copyright = config.copyright || (\n        # Fake date is used to keep integration tests consistent\n        date = ENV['JAZZY_FAKE_DATE'] || DateTime.now.strftime('%Y-%m-%d')\n        year = date[0..3]\n        \"&copy; #{year} [#{config.author_name}](#{config.author_url}). \" \\\n          \"All rights reserved. (Last updated: #{date})\"\n      )\n      Markdown.render_copyright(copyright).chomp\n    end\n\n    def jazzy_version\n      # Fake version is used to keep integration tests consistent\n      ENV['JAZZY_FAKE_VERSION'] || Jazzy::VERSION\n    end\n\n    def objc_first?\n      config.objc_mode && config.hide_declarations != 'objc'\n    end\n\n    def language_stub\n      objc_first? ? 'objc' : 'swift'\n    end\n\n    def module_version\n      config.version_configured ? config.version : nil\n    end\n\n    def docs_title\n      if config.title_configured\n        config.title\n      elsif config.version_configured\n        # Fake version for integration tests\n        version = ENV['JAZZY_FAKE_MODULE_VERSION'] || config.version\n        \"#{config.module_configs.first.module_name} #{version} Docs\"\n      else\n        \"#{config.module_configs.first.module_name} Docs\"\n      end\n    end\n\n    def enable_katex\n      Markdown.has_math\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/doc_builder.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'fileutils'\nrequire 'mustache'\nrequire 'pathname'\nrequire 'sassc'\n\nrequire 'jazzy/config'\nrequire 'jazzy/doc'\nrequire 'jazzy/docset_builder'\nrequire 'jazzy/documentation_generator'\nrequire 'jazzy/search_builder'\nrequire 'jazzy/jazzy_markdown'\nrequire 'jazzy/podspec_documenter'\nrequire 'jazzy/source_declaration'\nrequire 'jazzy/source_document'\nrequire 'jazzy/source_module'\nrequire 'jazzy/sourcekitten'\nrequire 'jazzy/symbol_graph'\n\nmodule Jazzy\n  # This module handles HTML generation, file writing, asset copying,\n  # and generally building docs given sourcekitten output\n  module DocBuilder\n    # mkdir -p output directory and clean if option is set\n    def self.prepare_output_dir(output_dir, clean)\n      FileUtils.rm_r output_dir if clean && output_dir.directory?\n      FileUtils.mkdir_p output_dir\n    end\n\n    # Generate doc structure to be used in sidebar navigation\n    # @return [Array] doc structure comprised of\n    #                     section names & child names & URLs\n    def self.doc_structure_for_docs(docs)\n      docs\n        .map do |doc|\n          children = children_for_doc(doc)\n          {\n            section: doc.name,\n            url: doc.url,\n            children: children,\n          }\n        end\n        .select do |structure|\n          if Config.instance.hide_unlisted_documentation\n            unlisted_prefix = Config.instance.custom_categories_unlisted_prefix\n            structure[:section] != \"#{unlisted_prefix}Guides\"\n          else\n            true\n          end\n        end\n    end\n\n    def self.children_for_doc(doc)\n      doc.children\n        .sort_by { |c| [c.nav_order, c.name, c.usr || ''] }\n        .flat_map do |child|\n        # FIXME: include arbitrarily nested extensible types\n        [{ name: child.name, url: child.url }] +\n          Array(child.children.select do |sub_child|\n            sub_child.type.swift_extensible? || sub_child.type.extension?\n          end).map do |sub_child|\n            { name: \"– #{sub_child.name}\", url: sub_child.url }\n          end\n      end\n    end\n\n    # Build documentation from the given options\n    # @param [Config] options\n    def self.build(options)\n      module_jsons = options.module_configs.map do |module_config|\n        if module_config.podspec_configured\n          # Config#validate guarantees not multi-module here\n          pod_documenter = PodspecDocumenter.new(options.podspec)\n          pod_documenter.sourcekitten_output(options)\n        elsif !module_config.sourcekitten_sourcefile.empty?\n          \"[#{module_config.sourcekitten_sourcefile.map(&:read).join(',')}]\"\n        elsif module_config.swift_build_tool == :symbolgraph\n          SymbolGraph.build(module_config)\n        else\n          Dir.chdir(module_config.source_directory) do\n            arguments = SourceKitten.arguments_from_options(module_config)\n            SourceKitten.run_sourcekitten(arguments)\n          end\n        end\n      end\n\n      build_docs_for_sourcekitten_output(module_jsons, options)\n    end\n\n    # Build & write HTML docs to disk from structured docs array\n    # @param [String] output_dir Root directory to write docs\n    # @param [SourceModule] source_module All info to generate docs\n    def self.build_docs(output_dir, source_module)\n      each_doc(output_dir, source_module.docs) do |doc, path|\n        prepare_output_dir(path.parent, false)\n        depth = path.relative_path_from(output_dir).each_filename.count - 1\n        path_to_root = '../' * depth\n        path.open('w') do |file|\n          file.write(document(source_module, doc, path_to_root))\n        end\n      end\n    end\n\n    def self.each_doc(output_dir, docs, &block)\n      docs.each do |doc|\n        next unless doc.render_as_page?\n\n        # Filepath is relative to documentation root:\n        path = output_dir + doc.filepath\n        block.call(doc, path)\n        each_doc(\n          output_dir,\n          doc.children,\n          &block\n        )\n      end\n    end\n\n    def self.build_site(docs, coverage, options)\n      warn 'building site'\n\n      structure = doc_structure_for_docs(docs)\n\n      docs << SourceDocument.make_index(options.readme_path)\n\n      output_dir = options.output\n\n      docset_builder = DocsetBuilder.new(output_dir)\n\n      source_module = SourceModule.new(docs, structure, coverage, docset_builder)\n\n      build_docs(output_dir, source_module)\n\n      unless options.disable_search\n        warn 'building search index'\n        SearchBuilder.build(source_module, output_dir)\n      end\n\n      copy_extensions(source_module, output_dir)\n      copy_theme_assets(output_dir)\n\n      docset_builder.build!(source_module.all_declarations)\n\n      generate_badge(source_module.doc_coverage, options)\n\n      friendly_path = relative_path_if_inside(output_dir, Pathname.pwd)\n      puts \"jam out ♪♫ to your fresh new docs in `#{friendly_path}`\"\n\n      source_module\n    end\n\n    # Build docs given sourcekitten output\n    # @param [Array<String>] sourcekitten_output Output of sourcekitten command for each module\n    # @param [Config] options Build options\n    def self.build_docs_for_sourcekitten_output(sourcekitten_output, options)\n      (docs, stats) = SourceKitten.parse(\n        sourcekitten_output,\n        options,\n        DocumentationGenerator.source_docs,\n      )\n\n      prepare_output_dir(options.output, options.clean)\n\n      stats.report\n\n      unless options.skip_documentation\n        build_site(docs, stats.doc_coverage, options)\n      end\n\n      write_lint_report(stats.undocumented_decls, options)\n    end\n\n    def self.relative_path_if_inside(path, base_path)\n      relative = path.relative_path_from(base_path)\n      if relative.to_path =~ %r{/^..(/|$)/}\n        path\n      else\n        relative\n      end\n    end\n\n    def self.undocumented_warnings(decls)\n      decls.map do |decl|\n        {\n          file: decl.file,\n          line: decl.start_line || decl.line,\n          symbol: decl.fully_qualified_name,\n          symbol_kind: decl.type.kind,\n          warning: 'undocumented',\n        }\n      end\n    end\n\n    def self.write_lint_report(undocumented, options)\n      (options.output + 'undocumented.json').open('w') do |f|\n        warnings = undocumented_warnings(undocumented)\n\n        lint_report = {\n          warnings: warnings.sort_by do |w|\n            [w[:file] || Pathname(''),\n             w[:line] || 0,\n             w[:symbol],\n             w[:symbol_kind]]\n          end,\n          source_directory: options.source_directory,\n        }\n        f.write(JSON.pretty_generate(lint_report))\n      end\n    end\n\n    def self.copy_theme_assets(destination)\n      assets_directory = Config.instance.theme_directory + 'assets'\n      FileUtils.cp_r(assets_directory.children, destination)\n      Pathname.glob(destination + 'css/**/*.scss').each do |scss|\n        css = SassC::Engine.new(scss.read).render\n        css_filename = scss.sub(/\\.scss$/, '')\n        css_filename.open('w') { |f| f.write(css) }\n        FileUtils.rm scss\n      end\n    end\n\n    def self.copy_extensions(source_module, destination)\n      if source_host = source_module.host&.extension\n        copy_extension(source_host, destination)\n      end\n      copy_extension('katex', destination) if Markdown.has_math\n    end\n\n    def self.copy_extension(name, destination)\n      ext_directory = Pathname(__dir__) / 'extensions' / name\n      FileUtils.cp_r(ext_directory.children, destination)\n    end\n\n    def self.render(doc_model, markdown)\n      html = Markdown.render(markdown)\n      SourceKitten.autolink_document(html, doc_model)\n    end\n\n    def self.render_inline(doc_model, markdown)\n      html = Markdown.render_inline(markdown)\n      SourceKitten.autolink_document(html, doc_model)\n    end\n\n    # Build Mustache document - common fields between page types\n    def self.new_document(source_module, doc_model)\n      Doc.new.tap do |doc|\n        doc[:custom_head] = Config.instance.custom_head\n        doc[:disable_search] = Config.instance.disable_search\n        doc[:doc_coverage] = source_module.doc_coverage unless\n          Config.instance.hide_documentation_coverage\n        doc[:structure] = source_module.doc_structure\n        doc[:readme_title] = source_module.readme_title\n        doc[:module_name] = doc[:readme_title]\n        doc[:author_name] = source_module.author_name\n        if source_host = source_module.host\n          doc[:source_host_name] = source_host.name\n          doc[:source_host_url] = source_host.url\n          doc[:source_host_image] = source_host.image\n          doc[:source_host_item_url] = source_host.item_url(doc_model)\n          doc[:github_url] = doc[:source_host_url]\n          doc[:github_token_url] = doc[:source_host_item_url]\n        end\n        doc[:dash_url] = source_module.dash_feed_url\n        doc[:breadcrumbs] = make_breadcrumbs(doc_model)\n      end\n    end\n\n    # Build Mustache document from a markdown source file\n    # @param [SourceModule] module-wide settings\n    # @param [Hash] doc_model Parsed doc. @see SourceKitten.parse\n    # @param [String] path_to_root\n    def self.document_markdown(source_module, doc_model, path_to_root)\n      doc = new_document(source_module, doc_model)\n      name = doc_model.readme? ? source_module.readme_title : doc_model.name\n      doc[:name] = name\n      doc[:overview] = render(doc_model, doc_model.content(source_module))\n      doc[:path_to_root] = path_to_root\n      doc[:hide_name] = true\n      doc.render.gsub(ELIDED_AUTOLINK_TOKEN, path_to_root)\n    end\n\n    # Returns the appropriate color for the provided percentage,\n    # used for generating a badge on shields.io\n    # @param [Number] coverage The documentation coverage percentage\n    def self.color_for_coverage(coverage)\n      if coverage < 10\n        'e05d44' # red\n      elsif coverage < 30\n        'fe7d37' # orange\n      elsif coverage < 60\n        'dfb317' # yellow\n      elsif coverage < 85\n        'a4a61d' # yellowgreen\n      elsif coverage < 90\n        '97CA00' # green\n      else\n        '4c1' # brightgreen\n      end\n    end\n\n    # rubocop:disable Metrics/MethodLength\n\n    # Generates an SVG similar to those from shields.io displaying the\n    # documentation percentage\n    # @param [Number] coverage The documentation coverage percentage\n    # @param [Config] options Build options\n    def self.generate_badge(coverage, options)\n      return if options.hide_documentation_coverage\n\n      coverage_length = coverage.to_s.size.succ\n      percent_string_length = coverage_length * 80 + 10\n      percent_string_offset = coverage_length * 40 + 975\n      width = coverage_length * 8 + 104\n      svg = <<-SVG.gsub(/^ {8}/, '')\n        <svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"#{width}\" height=\"20\">\n          <linearGradient id=\"b\" x2=\"0\" y2=\"100%\">\n            <stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/>\n            <stop offset=\"1\" stop-opacity=\".1\"/>\n          </linearGradient>\n          <clipPath id=\"a\">\n            <rect width=\"#{width}\" height=\"20\" rx=\"3\" fill=\"#fff\"/>\n          </clipPath>\n          <g clip-path=\"url(#a)\">\n            <path fill=\"#555\" d=\"M0 0h93v20H0z\"/>\n            <path fill=\"##{color_for_coverage(coverage)}\" d=\"M93 0h#{percent_string_length / 10 + 10}v20H93z\"/>\n            <path fill=\"url(#b)\" d=\"M0 0h#{width}v20H0z\"/>\n          </g>\n          <g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"110\">\n            <text x=\"475\" y=\"150\" fill=\"#010101\" fill-opacity=\".3\" transform=\"scale(.1)\" textLength=\"830\">\n              documentation\n            </text>\n            <text x=\"475\" y=\"140\" transform=\"scale(.1)\" textLength=\"830\">\n              documentation\n            </text>\n            <text x=\"#{percent_string_offset}\" y=\"150\" fill=\"#010101\" fill-opacity=\".3\" transform=\"scale(.1)\" textLength=\"#{percent_string_length}\">\n              #{coverage}%\n            </text>\n            <text x=\"#{percent_string_offset}\" y=\"140\" transform=\"scale(.1)\" textLength=\"#{percent_string_length}\">\n              #{coverage}%\n            </text>\n          </g>\n        </svg>\n      SVG\n\n      badge_output = options.output + 'badge.svg'\n      File.open(badge_output, 'w') { |f| f << svg }\n    end\n    # rubocop:enable Metrics/MethodLength\n\n    # Build mustache item for a top-level doc\n    # @param [Hash] item Parsed doc child item\n    # @param [Config] options Build options\n    # rubocop:disable Metrics/MethodLength\n    def self.render_item(item, source_module)\n      # Combine abstract and discussion into abstract\n      abstract = (item.abstract || '') + (item.discussion || '')\n      source_host_item_url = source_module.host&.item_url(item)\n      {\n        name: item.name,\n        name_html: item.name.gsub(':', ':<wbr>'),\n        abstract: abstract,\n        declaration: item.display_declaration,\n        language: item.display_language,\n        other_language_declaration: item.display_other_language_declaration,\n        usr: item.usr,\n        dash_type: item.type.dash_type,\n        source_host_item_url: source_host_item_url,\n        github_token_url: source_host_item_url,\n        default_impl_abstract: item.default_impl_abstract,\n        from_protocol_extension: item.from_protocol_extension,\n        return: item.return,\n        parameters: (item.parameters if item.parameters.any?),\n        url: (item.url if item.render_as_page?),\n        start_line: item.start_line,\n        end_line: item.end_line,\n        direct_link: item.omit_content_from_parent?,\n        deprecation_message: item.deprecation_message,\n        unavailable_message: item.unavailable_message,\n        usage_discouraged: item.usage_discouraged?,\n        async: item.async,\n        declaration_note: item.declaration_note,\n      }\n    end\n    # rubocop:enable Metrics/MethodLength\n\n    def self.make_task(mark, uid, items, doc_model)\n      {\n        name: mark.name,\n        name_html: (render_inline(doc_model, mark.name) if mark.name),\n        uid: ERB::Util.url_encode(uid),\n        items: items,\n        pre_separator: mark.has_start_dash,\n        post_separator: mark.has_end_dash,\n      }\n    end\n\n    # Render tasks for Mustache document\n    # @param [Config] options Build options\n    # @param [Hash] doc_model Parsed doc. @see SourceKitten.parse\n    def self.render_tasks(source_module, children)\n      marks = children.map(&:mark).uniq.compact\n      mark_names_counts = {}\n      marks.map do |mark|\n        mark_children = children.select { |child| child.mark == mark }\n        items = mark_children.map { |child| render_item(child, source_module) }\n        uid = (mark.name || 'Unnamed').to_s\n        if mark_names_counts.key?(uid)\n          mark_names_counts[uid] += 1\n          uid += mark_names_counts[uid].to_s\n        else\n          mark_names_counts[uid] = 1\n        end\n        make_task(mark, uid, items, mark_children.first)\n      end\n    end\n\n    # rubocop:disable Metrics/MethodLength\n    # Build Mustache document from single parsed decl\n    # @param [SourceModule] module-wide settings\n    # @param [Hash] doc_model Parsed doc. @see SourceKitten.parse\n    # @param [String] path_to_root\n    def self.document(source_module, doc_model, path_to_root)\n      if doc_model.type.markdown?\n        return document_markdown(source_module, doc_model, path_to_root)\n      end\n\n      overview = (doc_model.abstract || '') + (doc_model.discussion || '')\n      alternative_abstract = doc_model.alternative_abstract\n      if alternative_abstract\n        overview = render(doc_model, alternative_abstract) + overview\n      end\n\n      doc = new_document(source_module, doc_model)\n      doc[:name] = doc_model.name\n      doc[:kind] = doc_model.type.name\n      doc[:dash_type] = doc_model.type.dash_type\n      doc[:declaration] = doc_model.display_declaration\n      doc[:language] = doc_model.display_language\n      doc[:other_language_declaration] =\n        doc_model.display_other_language_declaration\n      doc[:overview] = overview\n      doc[:parameters] = doc_model.parameters\n      doc[:return] = doc_model.return\n      doc[:tasks] = render_tasks(source_module, doc_model.children)\n      doc[:path_to_root] = path_to_root\n      doc[:deprecation_message] = doc_model.deprecation_message\n      doc[:unavailable_message] = doc_model.unavailable_message\n      doc[:usage_discouraged] = doc_model.usage_discouraged?\n      doc.render.gsub(ELIDED_AUTOLINK_TOKEN, path_to_root)\n    end\n    # rubocop:enable Metrics/MethodLength\n\n    # Breadcrumbs for a page - doesn't include the top 'readme' crumb\n    def self.make_breadcrumbs(doc_model)\n      return [] if doc_model.readme?\n\n      docs_path = doc_model.docs_path\n      breadcrumbs = docs_path.map do |doc|\n        {\n          name: doc.name,\n          url: doc.url,\n          last: doc == doc_model,\n        }\n      end\n\n      return breadcrumbs if breadcrumbs.one?\n\n      # Add the module name to the outer type if not clear from context\n      if docs_path[1].ambiguous_module_name?(docs_path[0].name)\n        breadcrumbs[1][:name] = docs_path[1].fully_qualified_module_name\n      end\n\n      breadcrumbs\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/doc_index.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  # This class stores an index of symbol names for doing name lookup\n  # when resolving custom categories and autolinks.\n  class DocIndex\n    # A node in the index tree.  The root has no decl; its children are\n    # per-module indexed by module names.  The second level, where each\n    # scope is a module, also has no decl; its children are scopes, one\n    # for each top-level decl in the module.  From the third level onwards\n    # the decl is valid.\n    class Scope\n      attr_reader :decl # SourceDeclaration\n      attr_reader :children # String:Scope\n\n      def initialize(decl, children)\n        @decl = decl\n        @children = children\n      end\n\n      def self.new_root(module_decls)\n        new(nil,\n            module_decls.transform_values do |decls|\n              Scope.new_decl(nil, decls)\n            end)\n      end\n\n      # Decl names in a scope are usually unique.  The exceptions\n      # are (1) methods and (2) typealias+extension, which historically\n      # jazzy does not merge.  The logic here and in `merge()` below\n      # preserves the historical ambiguity-resolution of (1) and tries\n      # to do the best for (2).\n      def self.new_decl(decl, child_decls)\n        child_scopes = {}\n        child_decls.flat_map do |child_decl|\n          child_scope = Scope.new_decl(child_decl, child_decl.children)\n          child_decl.index_names.map do |name|\n            if curr = child_scopes[name]\n              curr.merge(child_scope)\n            else\n              child_scopes[name] = child_scope\n            end\n          end\n        end\n        new(decl, child_scopes)\n      end\n\n      def merge(new_scope)\n        return unless type = decl&.type\n        return unless new_type = new_scope.decl&.type\n\n        if type.swift_typealias? && new_type.swift_extension?\n          @children = new_scope.children\n        elsif type.swift_extension? && new_type.swift_typealias?\n          @decl = new_scope.decl\n        end\n      end\n\n      # Lookup of a name like `Mod.Type.method(arg:)` requires passing\n      # an array of name 'parts' eg. ['Mod', 'Type', 'method(arg:)'].\n      def lookup(parts)\n        return decl if parts.empty?\n\n        children[parts.first]&.lookup(parts[1...])\n      end\n\n      # Look up of a regex matching all children for current level only.\n      def lookup_regex(regex)\n        children.select { |name, _| name.match(regex) }\n          .map { |_, scope| scope.decl }.compact\n      end\n\n      # Get an array of scopes matching the name parts.\n      def lookup_path(parts)\n        [self] +\n          (children[parts.first]&.lookup_path(parts[1...]) || [])\n      end\n    end\n\n    attr_reader :root_scope\n\n    def initialize(all_decls)\n      @root_scope = Scope.new_root(all_decls.group_by(&:module_name))\n    end\n\n    # Look up a name and return the matching SourceDeclaration or nil.\n    #\n    # `context` is an optional SourceDeclaration indicating where the text\n    # was found, affects name resolution - see `lookup_context()` below.\n    def lookup(name, context = nil)\n      lookup_name = LookupName.new(name)\n\n      return lookup_fully_qualified(lookup_name) if lookup_name.fully_qualified?\n      return lookup_guess(lookup_name) if context.nil?\n\n      lookup_context(lookup_name, context)\n    end\n\n    # Look up a regex and return all matching top level SourceDeclaration.\n    def lookup_regex(regex)\n      root_scope.children.map { |_, scope| scope.lookup_regex(regex) }.flatten\n    end\n\n    private\n\n    # Look up a fully-qualified name, ie. it starts with the module name.\n    def lookup_fully_qualified(lookup_name)\n      root_scope.lookup(lookup_name.parts)\n    end\n\n    # Look up a top-level name best-effort, searching for a module that\n    # has it before trying the first name-part as a module name.\n    def lookup_guess(lookup_name)\n      root_scope.children.each_value do |module_scope|\n        if result = module_scope.lookup(lookup_name.parts)\n          return result\n        end\n      end\n\n      lookup_fully_qualified(lookup_name)\n    end\n\n    # Look up a name from a declaration context, approximately how\n    # Swift resolves names.\n    #\n    # 1 - try and resolve with a common prefix, eg. 'B' from 'T.A'\n    #     can match 'T.B', or 'R' from 'S.T.A' can match 'S.R'.\n    # 2 - try and resolve as a top-level symbol from a different module\n    # 3 - (affordance for docs writers) resolve as a child of the context,\n    #     eg. 'B' from 'T.A' can match 'T.A.B' *only if* (1,2) fail.\n    #     Currently disabled for Swift for back-compatibility.\n    def lookup_context(lookup_name, context)\n      context_scope_path =\n        root_scope.lookup_path(context.fully_qualified_module_name_parts)\n\n      context_scope = context_scope_path.pop\n      context_scope_path.reverse.each do |scope|\n        if decl = scope.lookup(lookup_name.parts)\n          return decl\n        end\n      end\n\n      lookup_guess(lookup_name) ||\n        (lookup_name.objc? && context_scope.lookup(lookup_name.parts))\n    end\n\n    # Helper for name lookup, really a cache for information as we\n    # try various strategies.\n    class LookupName\n      attr_reader :name\n\n      def initialize(name)\n        @name = name\n      end\n\n      def fully_qualified?\n        name.start_with?('/')\n      end\n\n      def objc?\n        name.start_with?('-', '+')\n      end\n\n      def parts\n        @parts ||= find_parts\n      end\n\n      private\n\n      # Turn a name as written into a list of components to\n      # be matched.\n      # Swift: Strip out odd characters and split\n      # ObjC: Compound names look like '+[Class(Category) method:]'\n      #       and need to become ['Class(Category)', '+method:']\n      def find_parts\n        if name =~ /([+-])\\[(\\w+(?: ?\\(\\w+\\))?) ([\\w:]+)\\]/\n          [Regexp.last_match[2],\n           Regexp.last_match[1] + Regexp.last_match[3]]\n        else\n          name\n            .sub(%r{^[@/]}, '') # ignore custom attribute reference, fully-qualified\n            .gsub(/<.*?>/, '') # remove generic parameters\n            .split(%r{(?<!\\.)[/.](?!\\.)}) # dot or slash, but not '...'\n            .reject(&:empty?)\n        end\n      end\n    end\n  end\n\n  class SourceDeclaration\n    # Names for a symbol.  Permits function parameters to be omitted.\n    def index_names\n      [name, name.sub(/\\(.*\\)/, '(...)')].uniq\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/docset_builder/info_plist.mustache",
    "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    <key>CFBundleIdentifier</key>\n      <string>com.jazzy.{{lowercase_safe_name}}</string>\n    <key>CFBundleName</key>\n      <string>{{name}}</string>\n    <key>DocSetPlatformFamily</key>\n      <string>{{lowercase_name}}</string>\n    <key>isDashDocset</key>\n      <true/>\n    <key>dashIndexFilePath</key>\n      <string>index.html</string>\n    <key>isJavaScriptEnabled</key>\n      <true/>\n    <key>DashDocSetFamily</key>\n      <string>dashtoc</string>\n    {{#root_url}}\n    <key>DashDocSetFallbackURL</key>\n      <string>{{{.}}}</string>\n    {{/root_url}}\n    {{#playground_url}}\n    <key>DashDocSetPlayURL</key>\n      <string>{{{.}}}</string>\n    {{/playground_url}}\n  </dict>\n</plist>\n"
  },
  {
    "path": "lib/jazzy/docset_builder.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'mustache'\nrequire 'sqlite3'\n\nmodule Jazzy\n  module DocBuilder\n    # Follows the instructions found at https://kapeli.com/docsets#dashDocset.\n    class DocsetBuilder\n      include Config::Mixin\n\n      attr_reader :output_dir\n      attr_reader :generated_docs_dir\n      attr_reader :source_module\n      attr_reader :docset_dir\n      attr_reader :documents_dir\n      attr_reader :name\n\n      def initialize(generated_docs_dir)\n        @name = config.docset_title || config.module_names.first\n        docset_path = config.docset_path ||\n                      \"docsets/#{safe_name}.docset\"\n        @docset_dir = generated_docs_dir + docset_path\n        @generated_docs_dir = generated_docs_dir\n        @output_dir = docset_dir.parent\n        @documents_dir = docset_dir + 'Contents/Resources/Documents/'\n      end\n\n      def build!(all_declarations)\n        docset_dir.rmtree if docset_dir.exist?\n        copy_docs\n        copy_icon if config.docset_icon\n        write_plist\n        create_index(all_declarations)\n        create_archive\n        create_xml if config.version && config.root_url\n      end\n\n      private\n\n      def safe_name\n        name.gsub(/[^a-z0-9_-]+/i, '_')\n      end\n\n      def write_plist\n        info_plist_path = docset_dir + 'Contents/Info.plist'\n        info_plist_path.open('w') do |plist|\n          template = Pathname(__dir__) + 'docset_builder/info_plist.mustache'\n          plist << Mustache.render(\n            template.read,\n            lowercase_name: name.downcase,\n            lowercase_safe_name: safe_name.downcase,\n            name: name,\n            root_url: config.root_url,\n            playground_url: config.docset_playground_url,\n          )\n        end\n      end\n\n      def create_archive\n        target  = \"#{safe_name}.tgz\"\n        source  = docset_dir.basename.to_s\n        options = {\n          chdir: output_dir.to_s,\n          [1, 2] => '/dev/null', # silence all output from `tar`\n        }\n        system('tar', \"--exclude='.DS_Store'\", '-cvzf', target, source, options)\n      end\n\n      def copy_docs\n        files_to_copy = Pathname.glob(generated_docs_dir + '*') -\n                        [docset_dir, output_dir]\n\n        FileUtils.mkdir_p documents_dir\n        FileUtils.cp_r files_to_copy, documents_dir\n      end\n\n      def copy_icon\n        FileUtils.cp config.docset_icon, docset_dir + 'icon.png'\n      end\n\n      def create_index(all_declarations)\n        search_index_path = docset_dir + 'Contents/Resources/docSet.dsidx'\n        SQLite3::Database.new(search_index_path.to_s) do |db|\n          db.execute('CREATE TABLE searchIndex(' \\\n            'id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT);')\n          db.execute('CREATE UNIQUE INDEX anchor ON ' \\\n            'searchIndex (name, type, path);')\n          all_declarations.select(&:type).each do |doc|\n            db.execute('INSERT OR IGNORE INTO searchIndex(name, type, path) ' \\\n              'VALUES (?, ?, ?);', [doc.name, doc.type.dash_type, doc.filepath])\n          end\n        end\n      end\n\n      def create_xml\n        (output_dir + \"#{safe_name}.xml\").open('w') do |xml|\n          url = URI.join(config.root_url, \"docsets/#{safe_name}.tgz\")\n          xml << \"<entry><version>#{config.version}</version><url>#{url}\" \\\n            \"</url></entry>\\n\"\n        end\n      end\n\n      # The web URL where the user intends to place the docset XML file.\n      def dash_url\n        return nil unless config.dash_url || config.root_url\n\n        config.dash_url ||\n          URI.join(\n            config.root_url,\n            \"docsets/#{safe_name}.xml\",\n          )\n      end\n\n      public\n\n      # The dash-feed:// URL that links from the Dash icon in generated\n      # docs.  This is passed to the Dash app and encodes the actual web\n      # `dash_url` where the user has placed the XML file.\n      #\n      # Unfortunately for historical reasons this is *also* called the\n      # 'dash_url' where it appears in mustache templates and so on.\n      def dash_feed_url\n        dash_url&.then do |url|\n          \"dash-feed://#{ERB::Util.url_encode(url.to_s)}\"\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/documentation_generator.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'pathname'\n\nrequire 'jazzy/jazzy_markdown'\nrequire 'jazzy/source_document'\n\nmodule Jazzy\n  module DocumentationGenerator\n    extend Config::Mixin\n\n    def self.source_docs\n      documentation_entries.map do |file_path|\n        SourceDocument.new.tap do |sd|\n          sd.name = File.basename(file_path, '.md')\n          sd.overview = overview Pathname(file_path)\n          sd.usr = \"documentation.#{sd.name}\"\n        end\n      end\n    end\n\n    def self.overview(file_path)\n      return '' unless file_path&.exist?\n\n      file_path.read\n    end\n\n    def self.documentation_entries\n      return [] unless\n        config.documentation_glob_configured && config.documentation_glob\n\n      config.documentation_glob.select { |e| File.file? e }\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/executable.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  module Executable\n    class IO < Array\n      def initialize(io = nil)\n        super()\n        @io = io\n      end\n\n      def <<(value)\n        super\n      ensure\n        @io << value.to_s if @io\n      end\n\n      def to_s\n        join(\"\\n\")\n      end\n    end\n\n    class << self\n      def execute_command(executable, args, raise_on_failure, env: {})\n        require 'shellwords'\n        bin = `which #{executable.to_s.shellescape}`.strip\n        raise \"Unable to locate the executable `#{executable}`\" if bin.empty?\n\n        require 'open4'\n\n        stdout = IO.new\n        stderr = IO.new($stderr)\n\n        options = { stdout: stdout, stderr: stderr, status: true }\n        status  = Open4.spawn(env, bin, *args, options)\n        unless status.success?\n          full_command = \"#{bin.shellescape} #{args.map(&:shellescape)}\"\n          output = stdout.to_s << stderr.to_s\n          if raise_on_failure\n            raise \"#{full_command}\\n\\n#{output}\"\n          else\n            warn(\"[!] Failed: #{full_command}\")\n          end\n        end\n        [stdout.to_s, status]\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/gem_version.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  VERSION = '0.15.4' unless defined? Jazzy::VERSION\nend\n"
  },
  {
    "path": "lib/jazzy/grouper.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  # This module deals with arranging top-level declarations and guides into\n  # groups automatically and/or using a custom list.\n  module Grouper\n    extend Config::Mixin\n\n    # Group root-level docs by custom categories (if any) and type or module\n    def self.group_docs(docs, doc_index)\n      custom_categories, docs = group_custom_categories(docs, doc_index)\n      unlisted_prefix = config.custom_categories_unlisted_prefix\n      type_category_prefix = custom_categories.any? ? unlisted_prefix : ''\n      all_categories =\n        custom_categories +\n        if config.merge_modules == :all\n          group_docs_by_type(docs, type_category_prefix)\n        else\n          group_docs_by_module(docs, type_category_prefix)\n        end\n      merge_consecutive_marks(all_categories)\n    end\n\n    # Group root-level docs by type\n    def self.group_docs_by_type(docs, type_category_prefix)\n      type_groups = SourceDeclaration::Type.all.map do |type|\n        children, docs = docs.partition { |doc| doc.type == type }\n        make_type_group(children, type, type_category_prefix)\n      end\n      merge_categories(type_groups.compact) + docs\n    end\n\n    # Group root-level docs by module name\n    def self.group_docs_by_module(docs, type_category_prefix)\n      guide_categories, docs = group_guides(docs, type_category_prefix)\n\n      module_categories = docs\n        .group_by(&:doc_module_name)\n        .map do |name, module_docs|\n          make_group(\n            module_docs,\n            name,\n            \"The following declarations are provided by module #{name}.\",\n          )\n        end\n\n      guide_categories + module_categories\n    end\n\n    def self.group_custom_categories(docs, doc_index)\n      group = config.custom_categories.map do |category|\n        children = category['children'].map do |selector|\n          selected = select_docs(doc_index, selector)\n          selected.map do |doc|\n            unless doc.parent_in_code.nil?\n              warn \"WARNING: Declaration \\\"#{doc.fully_qualified_module_name}\\\" \" \\\n                'specified in categories file exists but is not top-level and ' \\\n                'cannot be included here'\n              next nil\n            end\n            docs.delete(doc)\n          end\n        end.flatten.compact\n        # Category config overrides alphabetization\n        children.each.with_index { |child, i| child.nav_order = i }\n        make_group(children, category['name'], '')\n      end\n      [group.compact, docs]\n    end\n\n    def self.select_docs(doc_index, selector)\n      if selector.is_a?(String)\n        unless single_doc = doc_index.lookup(selector)\n          warn 'WARNING: No documented top-level declarations match ' \\\n            \"name \\\"#{selector}\\\" specified in categories file\"\n          return []\n        end\n        [single_doc]\n      else\n        doc_index.lookup_regex(selector['regex'])\n          .sort_by(&:name)\n      end\n    end\n\n    def self.group_guides(docs, prefix)\n      guides, others = docs.partition { |doc| doc.type.markdown? }\n      return [[], others] unless guides.any?\n\n      [[make_type_group(guides, guides.first.type, prefix)], others]\n    end\n\n    def self.make_type_group(docs, type, type_category_prefix)\n      make_group(\n        docs,\n        type_category_prefix + type.plural_name,\n        \"The following #{type.plural_name.downcase} are available globally.\",\n        type_category_prefix + type.plural_url_name,\n      )\n    end\n\n    # Join categories with the same name (eg. ObjC and Swift classes)\n    def self.merge_categories(categories)\n      merged = []\n      categories.each do |new_category|\n        if existing = merged.find { |cat| cat.name == new_category.name }\n          existing.children += new_category.children\n        else\n          merged.append(new_category)\n        end\n      end\n      merged\n    end\n\n    def self.make_group(group, name, abstract, url_name = nil)\n      group.reject! { |decl| decl.name.empty? }\n      unless group.empty?\n        SourceDeclaration.new.tap do |sd|\n          sd.type     = SourceDeclaration::Type.overview\n          sd.name     = name\n          sd.url_name = url_name\n          sd.abstract = Markdown.render(abstract)\n          sd.children = group\n        end\n      end\n    end\n\n    # Merge consecutive sections with the same mark into one section\n    # Needed because of pulling various decls into groups\n    def self.merge_consecutive_marks(docs)\n      prev_mark = nil\n      docs.each do |doc|\n        if prev_mark&.can_merge?(doc.mark)\n          doc.mark = prev_mark\n        end\n        prev_mark = doc.mark\n        merge_consecutive_marks(doc.children)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/highlighter.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rouge'\n\nmodule Jazzy\n  # This module helps highlight code\n  module Highlighter\n    SWIFT = 'swift'\n    OBJC = 'objective_c'\n\n    class Formatter < Rouge::Formatters::HTML\n      def initialize(language)\n        @language = language\n        super()\n      end\n\n      def stream(tokens, &block)\n        yield \"<pre class=\\\"highlight #{@language}\\\"><code>\"\n        super\n        yield \"</code></pre>\\n\"\n      end\n    end\n\n    def self.highlight_swift(source)\n      highlight(source, SWIFT)\n    end\n\n    def self.highlight_objc(source)\n      highlight(source, OBJC)\n    end\n\n    def self.highlight(source, language)\n      source && Rouge.highlight(source, language, Formatter.new(language))\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/jazzy_markdown.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'redcarpet'\nrequire 'rouge'\nrequire 'rouge/plugins/redcarpet'\n\nmodule Jazzy\n  module Markdown\n    # Publish if generated HTML needs math support\n    class << self; attr_accessor :has_math; end\n\n    module Footnotes\n      # Global unique footnote ID\n      def self.next_footnote\n        @next_footnote ||= 0\n        @next_footnote += 1\n      end\n\n      # Per-render map from user to global ID\n      attr_accessor :footnotes_hash\n\n      def reset\n        @footnotes_hash = {}\n      end\n\n      def map_footnote(user_num)\n        footnotes_hash.fetch(user_num) do\n          footnotes_hash[user_num] = Footnotes.next_footnote\n        end\n      end\n\n      def footnote_ref(num)\n        mapped = map_footnote(num)\n        \"<span class='footnote-ref' id=\\\"fnref#{mapped}\\\">\" \\\n          \"<sup><a href=\\\"#fn#{mapped}\\\">#{num}</a></sup></span>\"\n      end\n\n      # follow native redcarpet: backlink goes before the first </p> tag\n      def footnote_def(text, num)\n        mapped = map_footnote(num)\n        \"\\n<li><div class='footnote-def' id=\\\"fn#{mapped}\\\">\" +\n          text.sub(%r{(?=</p>)},\n                   \"&nbsp;<a href=\\\"#fnref#{mapped}\\\">&#8617;</a>\") +\n          '</div></li>'\n      end\n    end\n\n    # rubocop:disable Metrics/ClassLength\n    class JazzyHTML < Redcarpet::Render::HTML\n      include Redcarpet::Render::SmartyPants\n      include Rouge::Plugins::Redcarpet\n      include Footnotes\n\n      attr_accessor :default_language\n\n      def header(text, header_level)\n        text_slug = text.gsub(/[^[[:word:]]]+/, '-')\n          .downcase\n          .sub(/^-/, '')\n          .sub(/-$/, '')\n\n        \"<h#{header_level} id='#{text_slug}' class='heading'>\" \\\n          \"#{text}\" \\\n          \"</h#{header_level}>\\n\"\n      end\n\n      def codespan(text)\n        case text\n        when /^\\$\\$(.*)\\$\\$$/m\n          o = [\"</p><div class='math m-block'>\",\n               Regexp.last_match[1],\n               '</div><p>']\n          Markdown.has_math = true\n        when /^\\$(.*)\\$$/m\n          o = [\"<span class='math m-inline'>\", Regexp.last_match[1], '</span>']\n          Markdown.has_math = true\n        else\n          o = ['<code>', text.to_s, '</code>']\n        end\n\n        o[0] + CGI.escapeHTML(o[1]) + o[2]\n      end\n\n      # List from\n      # https://github.com/apple/swift/blob/master/include/swift/Markup/SimpleFields.def\n      UNIQUELY_HANDLED_CALLOUTS = %w[parameters\n                                     parameter\n                                     returns].freeze\n      GENERAL_CALLOUTS = %w[attention\n                            author\n                            authors\n                            bug\n                            complexity\n                            copyright\n                            date\n                            experiment\n                            important\n                            invariant\n                            keyword\n                            mutatingvariant\n                            nonmutatingvariant\n                            note\n                            postcondition\n                            precondition\n                            recommended\n                            recommendedover\n                            remark\n                            remarks\n                            requires\n                            see\n                            seealso\n                            since\n                            todo\n                            throws\n                            version\n                            warning].freeze\n      SPECIAL_LIST_TYPES = (UNIQUELY_HANDLED_CALLOUTS + GENERAL_CALLOUTS).freeze\n\n      SPECIAL_LIST_TYPE_REGEX = %r{\n        \\A\\s* # optional leading spaces\n        (<p>\\s*)? # optional opening p tag\n        # any one of our special list types\n        (#{SPECIAL_LIST_TYPES.map(&Regexp.method(:escape)).join('|')})\n        [\\s:] # followed by either a space or a colon\n        }ix.freeze\n\n      ELIDED_LI_TOKEN =\n        '7wNVzLB0OYPL2eGlPKu8q4vITltqh0Y6DPZf659TPMAeYh49o'\n\n      def list_item(text, _list_type)\n        if text =~ SPECIAL_LIST_TYPE_REGEX\n          type = Regexp.last_match(2)\n          if UNIQUELY_HANDLED_CALLOUTS.include? type.downcase\n            return ELIDED_LI_TOKEN\n          end\n\n          return render_list_aside(type,\n                                   text.sub(/#{Regexp.escape(type)}:\\s+/, ''))\n        end\n        \"<li>#{text.strip}</li>\\n\"\n      end\n\n      def render_list_aside(type, text)\n        \"</ul>#{render_aside(type, text).chomp}<ul>\\n\"\n      end\n\n      def render_aside(type, text)\n        <<-HTML\n<div class=\"aside aside-#{type.underscore.tr('_', '-')}\">\n    <p class=\"aside-title\">#{type.underscore.humanize}</p>\n    #{text}\n</div>\n        HTML\n      end\n\n      def list(text, list_type)\n        elided = text.gsub!(ELIDED_LI_TOKEN, '')\n        return if text =~ /\\A\\s*\\Z/ && elided\n\n        tag = list_type == :ordered ? 'ol' : 'ul'\n        \"\\n<#{tag}>\\n#{text}</#{tag}>\\n\"\n          .gsub(%r{\\n?<ul>\\n?</ul>}, '')\n      end\n\n      # List from\n      # https://developer.apple.com/documentation/xcode/formatting-your-documentation-content#Add-Notes-and-Other-Asides\n      DOCC_CALLOUTS = %w[note\n                         important\n                         warning\n                         tip\n                         experiment].freeze\n\n      DOCC_CALLOUT_REGEX = %r{\n        \\A\\s* # optional leading spaces\n        (?:<p>\\s*)? # optional opening p tag\n        # any one of the callout names\n        (#{DOCC_CALLOUTS.map(&Regexp.method(:escape)).join('|')})\n        : # followed directly by a colon\n      }ix.freeze\n\n      def block_quote(html)\n        if html =~ DOCC_CALLOUT_REGEX\n          type = Regexp.last_match[1]\n          render_aside(type, html.sub(/#{Regexp.escape(type)}:\\s*/, ''))\n        else\n          \"\\n<blockquote>\\n#{html}</blockquote>\\n\"\n        end\n      end\n\n      def block_code(code, language)\n        super(code, language || default_language)\n      end\n\n      def rouge_formatter(lexer)\n        Highlighter::Formatter.new(lexer.tag)\n      end\n    end\n    # rubocop:enable Metrics/ClassLength\n\n    REDCARPET_OPTIONS = {\n      autolink: true,\n      fenced_code_blocks: true,\n      no_intra_emphasis: true,\n      strikethrough: true,\n      space_after_headers: false,\n      tables: true,\n      lax_spacing: true,\n      footnotes: true,\n    }.freeze\n\n    # Spot and capture returns & param HTML for separate display.\n    class JazzyDeclarationHTML < JazzyHTML\n      attr_reader :returns, :parameters\n\n      def reset\n        @returns = nil\n        @parameters = {}\n        super\n      end\n\n      INTRO_PAT = '\\A(?<intro>\\s*(<p>\\s*)?)'\n      OUTRO_PAT = '(?<outro>.*)\\z'\n\n      RETURNS_REGEX = /#{INTRO_PAT}returns:#{OUTRO_PAT}/im.freeze\n\n      IDENT_PAT = '(?<param>\\S+)'\n\n      # Param formats: normal swift, objc via sourcekitten, and\n      # possibly inside 'Parameters:'\n      PARAM_PAT1 = \"(parameter +#{IDENT_PAT}\\\\s*:)\"\n      PARAM_PAT2 = \"(parameter:\\\\s*#{IDENT_PAT}\\\\s+)\"\n      PARAM_PAT3 = \"(#{IDENT_PAT}\\\\s*:)\"\n\n      PARAM_PAT = \"(?:#{PARAM_PAT1}|#{PARAM_PAT2}|#{PARAM_PAT3})\"\n\n      PARAM_REGEX = /#{INTRO_PAT}#{PARAM_PAT}#{OUTRO_PAT}/im.freeze\n\n      def list_item(text, _list_type)\n        if text =~ RETURNS_REGEX\n          @returns = render_param_returns(Regexp.last_match)\n        elsif text =~ PARAM_REGEX\n          @parameters[Regexp.last_match(:param)] =\n            render_param_returns(Regexp.last_match)\n        end\n        super\n      end\n\n      def render_param_returns(matches)\n        body = matches[:intro].strip + matches[:outro].strip\n        body = \"<p>#{body}</p>\" unless body.start_with?('<p>')\n        # call smartypants for pretty quotes etc.\n        postprocess(body)\n      end\n    end\n\n    def self.renderer\n      @renderer ||= JazzyDeclarationHTML.new\n    end\n\n    def self.markdown\n      @markdown ||= Redcarpet::Markdown.new(renderer, REDCARPET_OPTIONS)\n    end\n\n    # Produces <p>-delimited block content\n    def self.render(markdown_text, default_language = nil)\n      renderer.reset\n      renderer.default_language = default_language\n      markdown.render(markdown_text)\n    end\n\n    # Produces <span>-delimited inline content\n    def self.render_inline(markdown_text, default_language = nil)\n      render(markdown_text, default_language)\n        .sub(%r{^<p>(.*)</p>$}, '<span>\\1</span>')\n    end\n\n    def self.rendered_returns\n      renderer.returns\n    end\n\n    def self.rendered_parameters\n      renderer.parameters\n    end\n\n    class JazzyCopyright < Redcarpet::Render::HTML\n      def link(link, _title, content)\n        %(<a class=\"link\" href=\"#{link}\" target=\"_blank\" \\\nrel=\"external noopener\">#{content}</a>)\n      end\n    end\n\n    def self.copyright_markdown\n      @copyright_markdown ||= Redcarpet::Markdown.new(\n        JazzyCopyright,\n        REDCARPET_OPTIONS,\n      )\n    end\n\n    def self.render_copyright(markdown_text)\n      copyright_markdown.render(markdown_text)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/podspec_documenter.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'tmpdir'\nrequire 'json'\n\nmodule Jazzy\n  # rubocop:disable Metrics/ClassLength\n  class PodspecDocumenter\n    attr_reader :podspec\n\n    def initialize(podspec)\n      @podspec = podspec\n    end\n\n    # Build documentation from the given options\n    # @param [Config] options\n    def sourcekitten_output(config)\n      installation_root = Pathname(Dir.mktmpdir(['jazzy', podspec.name]))\n      installation_root.rmtree if installation_root.exist?\n      Pod::Config.instance.with_changes(installation_root: installation_root,\n                                        verbose: false) do\n        sandbox = Pod::Sandbox.new(Pod::Config.instance.sandbox_root)\n        installer = Pod::Installer.new(sandbox, podfile(config))\n        installer.install!\n        stdout = Dir.chdir(sandbox.root) do\n          targets = installer.pod_targets\n            .select { |pt| pt.pod_name == podspec.root.name }\n            .map(&:label)\n\n          targets.map do |t|\n            args = %W[doc --module-name #{podspec.module_name} -- -target #{t}]\n            SourceKitten.run_sourcekitten(args)\n          end\n        end\n        stdout.reduce([]) { |a, s| a + JSON.parse(s) }.to_json\n      end\n    end\n\n    def self.create_podspec(podspec_path)\n      case podspec_path\n      when Pathname, String\n        require 'cocoapods'\n        Pod::Specification.from_file(podspec_path)\n      end\n    end\n\n    # rubocop:disable Metrics/MethodLength\n    def self.apply_config_defaults(podspec, config)\n      return unless podspec\n\n      unless config.author_name_configured\n        config.author_name = author_name(podspec)\n        config.author_name_configured = true\n      end\n      unless config.module_name_known?\n        config.module_name = podspec.module_name\n        config.module_name_configured = true\n      end\n      unless config.author_url_configured\n        config.author_url = podspec.homepage || github_file_prefix(podspec)\n        config.author_url_configured = true\n      end\n      unless config.version_configured\n        config.version = podspec.version.to_s\n        config.version_configured = true\n      end\n      unless config.source_host_files_url_configured\n        config.source_host_files_url = github_file_prefix(podspec)\n        config.source_host_files_url_configured = true\n      end\n      unless config.swift_version_configured\n        trunk_swift_build = podspec.attributes_hash['pushed_with_swift_version']\n        config.swift_version = trunk_swift_build if trunk_swift_build\n        config.swift_version_configured = true\n      end\n    end\n    # rubocop:enable Metrics/MethodLength\n\n    private\n\n    # @!group Config helper methods\n\n    def self.author_name(podspec)\n      if podspec.authors.respond_to? :to_hash\n        podspec.authors.keys.to_sentence || ''\n      elsif podspec.authors.respond_to? :to_ary\n        podspec.authors.to_sentence\n      end || podspec.authors || ''\n    end\n\n    private_class_method :author_name\n\n    def self.github_file_prefix(podspec)\n      return unless podspec.source[:url] =~ %r{github.com[:/]+(.+)/(.+)}\n\n      org, repo = Regexp.last_match\n      return unless rev = podspec.source[:tag] || podspec.source[:commit]\n\n      \"https://github.com/#{org}/#{repo.sub(/\\.git$/, '')}/blob/#{rev}\"\n    end\n\n    private_class_method :github_file_prefix\n\n    # Latest valid value for SWIFT_VERSION.\n    LATEST_SWIFT_VERSION = '6'\n    private_constant :LATEST_SWIFT_VERSION\n\n    # All valid values for SWIFT_VERSION that are longer\n    # than a major version number.  Ordered ascending.\n    LONG_SWIFT_VERSIONS = ['4.2'].freeze\n    private_constant :LONG_SWIFT_VERSIONS\n\n    # Go from a full Swift version like 4.2.1 to\n    # something valid for SWIFT_VERSION.\n    def compiler_swift_version(user_version)\n      unless user_version\n        return podspec_swift_version || LATEST_SWIFT_VERSION\n      end\n\n      LONG_SWIFT_VERSIONS.select do |version|\n        user_version.start_with?(version)\n      end.last || \"#{user_version[0]}.0\"\n    end\n\n    def podspec_swift_version\n      # `swift_versions` exists from CocoaPods 1.7\n      if podspec.respond_to?('swift_versions')\n        podspec.swift_versions.max\n      else\n        podspec.swift_version\n      end\n    end\n\n    # @!group SourceKitten output helper methods\n\n    def pod_path\n      if podspec.defined_in_file\n        podspec.defined_in_file.parent\n      else\n        config.source_directory\n      end\n    end\n\n    # rubocop:disable Metrics/MethodLength\n    def podfile(config)\n      swift_version = compiler_swift_version(config.swift_version)\n      podspec = @podspec\n      path = pod_path\n      @podfile ||= Pod::Podfile.new do\n        config.pod_sources.each do |src|\n          source src\n        end\n\n        install! 'cocoapods',\n                 integrate_targets: false,\n                 deterministic_uuids: false\n\n        [podspec, *podspec.recursive_subspecs].each do |ss|\n          next if ss.test_specification\n\n          ss.available_platforms.each do |p|\n            # Travis builds take too long when building docs for all available\n            # platforms for the Moya integration spec, so we just document OSX.\n            # TODO: remove once jazzy is fast enough.\n            next if ENV['JAZZY_INTEGRATION_SPECS'] && p.name != :osx\n\n            target(\"Jazzy-#{ss.name.gsub('/', '__')}-#{p.name}\") do\n              use_frameworks!\n              platform p.name, p.deployment_target\n              pod ss.name, path: path.realpath.to_s\n              current_target_definition.swift_version = swift_version\n            end\n          end\n        end\n      end\n    end\n    # rubocop:enable Metrics/MethodLength\n  end\n  # rubocop:enable Metrics/ClassLength\nend\n"
  },
  {
    "path": "lib/jazzy/search_builder.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  module SearchBuilder\n    def self.build(source_module, output_dir)\n      decls = source_module.all_declarations.select do |d|\n        d.type && d.name && !d.name.empty?\n      end\n      index = decls.to_h do |d|\n        [d.url,\n         {\n           name: d.name,\n           abstract: d.abstract && d.abstract.split(\"\\n\").map(&:strip).first,\n           parent_name: d.parent_in_code&.name,\n         }.reject { |_, v| v.nil? || v.empty? }]\n      end\n      File.write(File.join(output_dir, 'search.json'), index.to_json)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/source_declaration/access_control_level.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  class SourceDeclaration\n    class AccessControlLevel\n      include Comparable\n\n      # Order matters\n      LEVELS = %i[private fileprivate internal package public open].freeze\n\n      LEVELS_INDEX = LEVELS.to_h { |i| [i, LEVELS.index(i)] }.freeze\n\n      attr_reader :level\n\n      def initialize(level)\n        @level = level\n      end\n\n      # From a SourceKit accessibility string\n      def self.from_accessibility(accessibility)\n        return nil if accessibility.nil?\n\n        if accessibility =~ /^source\\.lang\\.swift\\.accessibility\\.(.*)$/ &&\n           (matched = Regexp.last_match(1).to_sym) &&\n           !LEVELS_INDEX[matched].nil?\n          return new(matched)\n        end\n\n        raise \"cannot initialize AccessControlLevel with '#{accessibility}'\"\n      end\n\n      # From a SourceKit declaration hash\n      def self.from_doc(doc)\n        return AccessControlLevel.internal if implicit_deinit?(doc)\n\n        from_documentation_attribute(doc) ||\n          from_accessibility(doc['key.accessibility']) ||\n          from_doc_explicit_declaration(doc) ||\n          AccessControlLevel.internal # fallback on internal ACL\n      end\n\n      # Workaround `deinit` being always technically public\n      def self.implicit_deinit?(doc)\n        doc['key.name'] == 'deinit' &&\n          from_doc_explicit_declaration(doc).nil?\n      end\n\n      # From a Swift declaration\n      def self.from_doc_explicit_declaration(doc)\n        declaration = doc['key.parsed_declaration']\n        LEVELS.each do |level|\n          if declaration =~ /\\b#{level}\\b/\n            return send(level)\n          end\n        end\n        nil\n      end\n\n      # From a config instruction\n      def self.from_human_string(string)\n        normalized = string.to_s.downcase.to_sym\n        if LEVELS_INDEX[normalized].nil?\n          raise \"cannot initialize AccessControlLevel with '#{string}'\"\n        end\n\n        send(normalized)\n      end\n\n      # From a @_documentation(visibility:) attribute\n      def self.from_documentation_attribute(doc)\n        if doc['key.annotated_decl'] =~ /@_documentation\\(\\s*visibility\\s*:\\s*(\\w+)/\n          from_human_string(Regexp.last_match[1])\n        end\n      end\n\n      # Define `AccessControlLevel.public` etc.\n\n      LEVELS.each do |level|\n        define_singleton_method(level) do\n          new(level)\n        end\n      end\n\n      # Comparing access levels\n\n      def <=>(other)\n        LEVELS_INDEX[level] <=> LEVELS_INDEX[other.level]\n      end\n\n      def included_levels\n        LEVELS_INDEX.select { |_, v| v >= LEVELS_INDEX[level] }.keys\n      end\n\n      def excluded_levels\n        LEVELS_INDEX.select { |_, v| v < LEVELS_INDEX[level] }.keys\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/source_declaration/type.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'logger'\nrequire 'active_support'\nrequire 'active_support/inflector'\n\nmodule Jazzy\n  class SourceDeclaration\n    # rubocop:disable Metrics/ClassLength\n    class Type\n      def self.all\n        TYPES.keys.map { |k| new(k) }.reject { |t| t.name.nil? }\n      end\n\n      attr_reader :kind\n\n      def initialize(kind, declaration = nil)\n        kind = fixup_kind(kind, declaration) if declaration\n        @kind = kind\n        @type = TYPES[kind]\n      end\n\n      # Improve kind from full declaration\n      def fixup_kind(kind, declaration)\n        if kind == 'source.lang.swift.decl.class' &&\n           declaration.include?(\n             '<syntaxtype.keyword>actor</syntaxtype.keyword>',\n           )\n          'source.lang.swift.decl.actor'\n        else\n          kind\n        end\n      end\n\n      def dash_type\n        @type && @type[:dash]\n      end\n\n      def name\n        @type && @type[:jazzy]\n      end\n\n      # kinds that are 'global' and should get their own pages\n      # with --separate-global-declarations\n      def global?\n        @type && @type[:global]\n      end\n\n      # name to use for type subdirectory in URLs for back-compatibility\n      def url_name\n        @type && (@type[:url] || @type[:jazzy])\n      end\n\n      def name_controlled_manually?\n        !kind.start_with?('source')\n        # \"'source'.lang...\" for Swift\n        # or \"'source'kitten.source...\" for Objective-C\n        # but not \"Overview\" for navigation groups.\n      end\n\n      def plural_name\n        name.pluralize\n      end\n\n      def plural_url_name\n        url_name.pluralize\n      end\n\n      def objc_mark?\n        kind == 'sourcekitten.source.lang.objc.mark'\n      end\n\n      # covers MARK: TODO: FIXME: comments\n      def swift_mark?\n        kind == 'source.lang.swift.syntaxtype.comment.mark'\n      end\n\n      def mark?\n        objc_mark? || swift_mark?\n      end\n\n      # mark that should start a new task section\n      def task_mark?(name)\n        objc_mark? || (swift_mark? && name.start_with?('MARK: '))\n      end\n\n      def objc_enum?\n        kind == 'sourcekitten.source.lang.objc.decl.enum'\n      end\n\n      def objc_typedef?\n        kind == 'sourcekitten.source.lang.objc.decl.typedef'\n      end\n\n      def objc_category?\n        kind == 'sourcekitten.source.lang.objc.decl.category'\n      end\n\n      def objc_class?\n        kind == 'sourcekitten.source.lang.objc.decl.class'\n      end\n\n      def swift_type?\n        kind.include? 'swift'\n      end\n\n      def swift_enum_case?\n        kind == 'source.lang.swift.decl.enumcase'\n      end\n\n      def swift_enum_element?\n        kind == 'source.lang.swift.decl.enumelement'\n      end\n\n      def should_document?\n        declaration? && !param? && !generic_type_param?\n      end\n\n      def declaration?\n        kind.start_with?('source.lang.swift.decl',\n                         'sourcekitten.source.lang.objc.decl')\n      end\n\n      def extension?\n        swift_extension? || objc_category?\n      end\n\n      def swift_extension?\n        kind =~ /^source\\.lang\\.swift\\.decl\\.extension.*/\n      end\n\n      def swift_extensible?\n        kind =~\n          /^source\\.lang\\.swift\\.decl\\.(class|struct|protocol|enum|actor)$/\n      end\n\n      def swift_protocol?\n        kind == 'source.lang.swift.decl.protocol'\n      end\n\n      def swift_typealias?\n        kind == 'source.lang.swift.decl.typealias'\n      end\n\n      def swift_global_function?\n        kind == 'source.lang.swift.decl.function.free'\n      end\n\n      def param?\n        # SourceKit strangely categorizes initializer parameters as local\n        # variables, so both kinds represent a parameter in jazzy.\n        ['source.lang.swift.decl.var.parameter',\n         'source.lang.swift.decl.var.local'].include?(kind)\n      end\n\n      def generic_type_param?\n        kind == 'source.lang.swift.decl.generic_type_param'\n      end\n\n      def swift_variable?\n        kind.start_with?('source.lang.swift.decl.var')\n      end\n\n      def objc_unexposed?\n        kind == 'sourcekitten.source.lang.objc.decl.unexposed'\n      end\n\n      OVERVIEW_KIND = 'Overview'\n\n      def self.overview\n        Type.new(OVERVIEW_KIND)\n      end\n\n      def overview?\n        kind == OVERVIEW_KIND\n      end\n\n      MARKDOWN_KIND = 'document.markdown'\n\n      def self.markdown\n        Type.new(MARKDOWN_KIND)\n      end\n\n      def markdown?\n        kind == MARKDOWN_KIND\n      end\n\n      def hash\n        kind.hash\n      end\n\n      alias equals ==\n      def ==(other)\n        other && kind == other.kind\n      end\n\n      TYPES = {\n        # Markdown\n        MARKDOWN_KIND => {\n          jazzy: 'Guide',\n          dash: 'Guide',\n        }.freeze,\n\n        # Group/Overview\n        OVERVIEW_KIND => {\n          jazzy: nil,\n          dash: 'Section',\n        }.freeze,\n\n        # Objective-C\n        'sourcekitten.source.lang.objc.decl.unexposed' => {\n          jazzy: 'Unexposed',\n          dash: 'Unexposed',\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.category' => {\n          jazzy: 'Category',\n          dash: 'Extension',\n          global: true,\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.class' => {\n          jazzy: 'Class',\n          dash: 'Class',\n          global: true,\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.constant' => {\n          jazzy: 'Constant',\n          dash: 'Constant',\n          global: true,\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.enum' => {\n          jazzy: 'Enumeration',\n          url: 'Enum',\n          dash: 'Enum',\n          global: true,\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.enumcase' => {\n          jazzy: 'Enumeration Case',\n          dash: 'Case',\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.initializer' => {\n          jazzy: 'Initializer',\n          dash: 'Initializer',\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.method.class' => {\n          jazzy: 'Class Method',\n          dash: 'Method',\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.method.instance' => {\n          jazzy: 'Instance Method',\n          dash: 'Method',\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.property' => {\n          jazzy: 'Property',\n          dash: 'Property',\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.protocol' => {\n          jazzy: 'Protocol',\n          dash: 'Protocol',\n          global: true,\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.typedef' => {\n          jazzy: 'Type Definition',\n          dash: 'Type',\n          global: true,\n        }.freeze,\n        'sourcekitten.source.lang.objc.mark' => {\n          jazzy: 'Mark',\n          dash: 'Mark',\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.function' => {\n          jazzy: 'Function',\n          dash: 'Function',\n          global: true,\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.struct' => {\n          jazzy: 'Structure',\n          url: 'Struct',\n          dash: 'Struct',\n          global: true,\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.union' => {\n          jazzy: 'Union',\n          dash: 'Union',\n          global: true,\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.field' => {\n          jazzy: 'Field',\n          dash: 'Field',\n        }.freeze,\n        'sourcekitten.source.lang.objc.decl.ivar' => {\n          jazzy: 'Instance Variable',\n          dash: 'Ivar',\n        }.freeze,\n        'sourcekitten.source.lang.objc.module.import' => {\n          jazzy: 'Module',\n          dash: 'Module',\n        }.freeze,\n\n        # Swift\n        'source.lang.swift.decl.actor' => {\n          jazzy: 'Actor',\n          dash: 'Actor',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.function.accessor.address' => {\n          jazzy: 'Addressor',\n          dash: 'Function',\n        }.freeze,\n        'source.lang.swift.decl.function.accessor.didset' => {\n          jazzy: 'didSet Observer',\n          dash: 'Function',\n        }.freeze,\n        'source.lang.swift.decl.function.accessor.getter' => {\n          jazzy: 'Getter',\n          dash: 'Function',\n        }.freeze,\n        'source.lang.swift.decl.function.accessor.mutableaddress' => {\n          jazzy: 'Mutable Addressor',\n          dash: 'Function',\n        }.freeze,\n        'source.lang.swift.decl.function.accessor.setter' => {\n          jazzy: 'Setter',\n          dash: 'Function',\n        }.freeze,\n        'source.lang.swift.decl.function.accessor.willset' => {\n          jazzy: 'willSet Observer',\n          dash: 'Function',\n        }.freeze,\n        'source.lang.swift.decl.function.operator' => {\n          jazzy: 'Operator',\n          dash: 'Function',\n        }.freeze,\n        'source.lang.swift.decl.function.operator.infix' => {\n          jazzy: 'Infix Operator',\n          dash: 'Function',\n        }.freeze,\n        'source.lang.swift.decl.function.operator.postfix' => {\n          jazzy: 'Postfix Operator',\n          dash: 'Function',\n        }.freeze,\n        'source.lang.swift.decl.function.operator.prefix' => {\n          jazzy: 'Prefix Operator',\n          dash: 'Function',\n        }.freeze,\n        'source.lang.swift.decl.function.method.class' => {\n          jazzy: 'Class Method',\n          dash: 'Method',\n        }.freeze,\n        'source.lang.swift.decl.var.class' => {\n          jazzy: 'Class Variable',\n          dash: 'Variable',\n        }.freeze,\n        'source.lang.swift.decl.class' => {\n          jazzy: 'Class',\n          dash: 'Class',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.function.constructor' => {\n          jazzy: 'Initializer',\n          dash: 'Constructor',\n        }.freeze,\n        'source.lang.swift.decl.function.destructor' => {\n          jazzy: 'Deinitializer',\n          dash: 'Method',\n        }.freeze,\n        'source.lang.swift.decl.var.global' => {\n          jazzy: 'Global Variable',\n          dash: 'Global',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.enumcase' => {\n          jazzy: 'Enumeration Case',\n          dash: 'Case',\n        }.freeze,\n        'source.lang.swift.decl.enumelement' => {\n          jazzy: 'Enumeration Element',\n          dash: 'Element',\n        }.freeze,\n        'source.lang.swift.decl.enum' => {\n          jazzy: 'Enumeration',\n          url: 'Enum',\n          dash: 'Enum',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.extension' => {\n          jazzy: 'Extension',\n          dash: 'Extension',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.extension.class' => {\n          jazzy: 'Class Extension',\n          dash: 'Extension',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.extension.enum' => {\n          jazzy: 'Enumeration Extension',\n          dash: 'Extension',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.extension.protocol' => {\n          jazzy: 'Protocol Extension',\n          dash: 'Extension',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.extension.struct' => {\n          jazzy: 'Structure Extension',\n          dash: 'Extension',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.function.free' => {\n          jazzy: 'Function',\n          dash: 'Function',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.function.method.instance' => {\n          jazzy: 'Instance Method',\n          dash: 'Method',\n        }.freeze,\n        'source.lang.swift.decl.var.instance' => {\n          jazzy: 'Instance Variable',\n          dash: 'Property',\n        }.freeze,\n        'source.lang.swift.decl.var.local' => {\n          jazzy: 'Local Variable',\n          dash: 'Variable',\n        }.freeze,\n        'source.lang.swift.decl.var.parameter' => {\n          jazzy: 'Parameter',\n          dash: 'Parameter',\n        }.freeze,\n        'source.lang.swift.decl.protocol' => {\n          jazzy: 'Protocol',\n          dash: 'Protocol',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.function.method.static' => {\n          jazzy: 'Static Method',\n          dash: 'Method',\n        }.freeze,\n        'source.lang.swift.decl.var.static' => {\n          jazzy: 'Static Variable',\n          dash: 'Variable',\n        }.freeze,\n        'source.lang.swift.decl.struct' => {\n          jazzy: 'Structure',\n          url: 'Struct',\n          dash: 'Struct',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.function.subscript' => {\n          jazzy: 'Subscript',\n          dash: 'Method',\n        }.freeze,\n        'source.lang.swift.decl.typealias' => {\n          jazzy: 'Type Alias',\n          url: 'Typealias',\n          dash: 'Alias',\n          global: true,\n        }.freeze,\n        'source.lang.swift.decl.generic_type_param' => {\n          jazzy: 'Generic Type Parameter',\n          dash: 'Parameter',\n        }.freeze,\n        'source.lang.swift.decl.associatedtype' => {\n          jazzy: 'Associated Type',\n          dash: 'Alias',\n        }.freeze,\n        'source.lang.swift.decl.macro' => {\n          jazzy: 'Macro',\n          dash: 'Macro',\n        }.freeze,\n      }.freeze\n    end\n    # rubocop:enable Metrics/ClassLength\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/source_declaration.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'jazzy/source_declaration/access_control_level'\nrequire 'jazzy/source_declaration/type'\n\nmodule Jazzy\n  # rubocop:disable Metrics/ClassLength\n  class SourceDeclaration\n    # kind of declaration (e.g. class, variable, function)\n    attr_accessor :type\n    # static type of declared element (e.g. String.Type -> ())\n    attr_accessor :typename\n\n    # Give the item its own page or just inline into parent?\n    def render_as_page?\n      children.any? ||\n        (Config.instance.separate_global_declarations &&\n         type.global?)\n    end\n\n    def swift?\n      type.swift_type?\n    end\n\n    def highlight_language\n      swift? ? Highlighter::SWIFT : Highlighter::OBJC\n    end\n\n    # When referencing this item from its parent category,\n    # include the content or just link to it directly?\n    def omit_content_from_parent?\n      Config.instance.separate_global_declarations &&\n        render_as_page?\n    end\n\n    # Element containing this declaration in the code\n    attr_accessor :parent_in_code\n\n    # Logical parent in the documentation. May differ from parent_in_code\n    # because of top-level categories and merged extensions.\n    attr_accessor :parent_in_docs\n\n    # counterpart of parent_in_docs\n    attr_reader :children\n\n    def children=(new_children)\n      # Freeze to ensure that parent_in_docs stays in sync\n      @children = new_children.freeze\n      @children.each { |c| c.parent_in_docs = self }\n    end\n\n    # Chain of parent_in_code from top level to self. (Includes self.)\n    def namespace_path\n      namespace_ancestors + [self]\n    end\n\n    def namespace_ancestors\n      if parent_in_code\n        parent_in_code.namespace_path\n      else\n        []\n      end\n    end\n\n    # 'OuterType.NestedType.method(arg:)'\n    def fully_qualified_name\n      namespace_path.map(&:name).join('.')\n    end\n\n    # :name doesn't include any generic type params.\n    # This regexp matches any generic type params in parent names.\n    def fully_qualified_name_regexp\n      Regexp.new(namespace_path.map(&:name)\n                               .map { |n| Regexp.escape(n) }\n                               .join('(?:<.*?>)?\\.'))\n    end\n\n    def fully_qualified_module_name_parts\n      path = namespace_path\n      path.map(&:name).prepend(path.first.module_name).compact\n    end\n\n    # 'MyModule.OuterType.NestedType.method(arg:)'\n    def fully_qualified_module_name\n      fully_qualified_module_name_parts.join('.')\n    end\n\n    # List of doc_parent decls, .last is self\n    def docs_path\n      (parent_in_docs&.docs_path || []) + [self]\n    end\n\n    # If this declaration is an objc category, returns an array with the name\n    # of the extended objc class and the category name itself, i.e.\n    # [\"NSString\", \"MyMethods\"], nil otherwise.\n    def objc_category_name\n      name.split(/[()]/) if type.objc_category?\n    end\n\n    def swift_objc_extension?\n      type.swift_extension? && usr&.start_with?('c:objc')\n    end\n\n    def swift_extension_objc_name\n      return unless type.swift_extension? && usr\n\n      usr.split('(cs)').last\n    end\n\n    # The language in the templates for display\n    def display_language\n      return 'Swift' if swift?\n\n      Config.instance.hide_objc? ? 'Swift' : 'Objective-C'\n    end\n\n    def display_declaration\n      return declaration if swift?\n\n      Config.instance.hide_objc? ? other_language_declaration : declaration\n    end\n\n    def display_other_language_declaration\n      other_language_declaration unless\n        Config.instance.hide_objc? || Config.instance.hide_swift?\n    end\n\n    attr_accessor :file\n    attr_accessor :line\n    attr_accessor :column\n    attr_accessor :usr\n    attr_accessor :type_usr\n    attr_accessor :module_name\n    attr_accessor :name\n    attr_accessor :objc_name\n    attr_accessor :declaration\n    attr_accessor :other_language_declaration\n    attr_accessor :abstract\n    attr_accessor :default_impl_abstract\n    attr_accessor :from_protocol_extension\n    attr_accessor :discussion\n    attr_accessor :return\n    attr_accessor :parameters\n    attr_accessor :url\n    attr_accessor :mark\n    attr_accessor :access_control_level\n    attr_accessor :start_line\n    attr_accessor :end_line\n    attr_accessor :nav_order\n    attr_accessor :url_name\n    attr_accessor :deprecated\n    attr_accessor :deprecation_message\n    attr_accessor :unavailable\n    attr_accessor :unavailable_message\n    attr_accessor :generic_requirements\n    attr_accessor :inherited_types\n    attr_accessor :async\n\n    # The name of the module being documented that contains this\n    # declaration.  Only different from module_name when this is\n    # an extension of a type from another module.  Nil for guides.\n    attr_accessor :doc_module_name\n\n    def usage_discouraged?\n      unavailable || deprecated\n    end\n\n    def filepath\n      CGI.unescape(url)\n    end\n\n    # Base filename (no extension) for the item\n    def docs_filename\n      result = url_name || name\n      # Workaround functions sharing names with\n      # different argument types (f(a:Int) vs. f(a:String))\n      return result unless type.swift_global_function?\n\n      result + \"_#{type_usr}\"\n    end\n\n    def constrained_extension?\n      type.swift_extension? &&\n        generic_requirements\n    end\n\n    def mark_for_children\n      if constrained_extension?\n        SourceMark.new_generic_requirements(generic_requirements)\n      else\n        SourceMark.new\n      end\n    end\n\n    def inherited_types?\n      inherited_types &&\n        !inherited_types.empty?\n    end\n\n    # Is there at least one inherited type that is not in the given list?\n    def other_inherited_types?(unwanted)\n      return false unless inherited_types?\n\n      inherited_types.any? { |t| !unwanted.include?(t) }\n    end\n\n    # Pre-Swift 5.6: SourceKit only sets module_name for imported modules\n    # Swift 5.6+: module_name is always set\n    def type_from_doc_module?\n      !type.extension? ||\n        (swift? && usr &&\n          (module_name.nil? || module_name == doc_module_name))\n    end\n\n    # Don't ask the user to write documentation for types being extended\n    # from other modules.  Compile errors leave no docs and a `nil` USR.\n    def mark_undocumented?\n      !swift? || (usr && !extension_of_external_type?)\n    end\n\n    def extension_of_external_type?\n      !module_name.nil? &&\n        !Config.instance.module_name?(module_name)\n    end\n\n    # Is it unclear from context what module the (top-level) decl is from?\n    def ambiguous_module_name?(group_name)\n      extension_of_external_type? ||\n        (Config.instance.multiple_modules? &&\n          !module_name.nil? &&\n          group_name != module_name)\n    end\n\n    # Does the user need help understanding how to get this declaration?\n    def need_doc_module_note?\n      return false unless Config.instance.multiple_modules?\n      return false if docs_path.first.name == doc_module_name\n\n      if parent_in_code.nil?\n        # Top-level decls with no page of their own\n        !render_as_page?\n      else\n        # Members added by extension\n        parent_in_code.module_name != doc_module_name\n      end\n    end\n\n    # Info text for contents page by collapsed item name\n    def declaration_note\n      notes = [\n        default_impl_abstract ? 'default implementation' : nil,\n        from_protocol_extension ? 'extension method' : nil,\n        async ? 'asynchronous' : nil,\n        need_doc_module_note? ? \"from #{doc_module_name}\" : nil,\n      ].compact\n      notes.join(', ').upcase_first unless notes.empty?\n    end\n\n    # For matching where `Self` is equivalent without considering\n    # constraints\n    def simplified_typename\n      typename&.gsub(/<Self .*?>/, '<Self>')\n    end\n\n    # Is the candidate `SourceDeclaration` probably a default\n    # implementation of this declaration?\n    def default_implementation?(candidate)\n      name == candidate.name &&\n        type == candidate.type &&\n        simplified_typename == candidate.simplified_typename &&\n        async == candidate.async\n    end\n\n    def readme?\n      false\n    end\n\n    def alternative_abstract\n      if file = alternative_abstract_file\n        Pathname(file).read\n      end\n    end\n\n    def alternative_abstract_file\n      abstract_glob.select do |f|\n        # allow Structs.md or Structures.md\n        [name, url_name].include?(File.basename(f).split('.').first)\n      end.first\n    end\n\n    def abstract_glob\n      return [] unless\n        Config.instance.abstract_glob_configured &&\n        Config.instance.abstract_glob\n\n      Config.instance.abstract_glob.select { |e| File.file? e }\n    end\n  end\n  # rubocop:enable Metrics/ClassLength\nend\n"
  },
  {
    "path": "lib/jazzy/source_document.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'pathname'\n\nrequire 'jazzy/jazzy_markdown'\n\nmodule Jazzy\n  # Standalone markdown docs including index.html\n  class SourceDocument < SourceDeclaration\n    attr_accessor :overview\n    attr_accessor :readme_path\n\n    def initialize\n      super\n      self.children = []\n      self.parameters = []\n      self.abstract = ''\n      self.type = SourceDeclaration::Type.markdown\n      self.mark = SourceMark.new\n    end\n\n    def self.make_index(readme_path)\n      SourceDocument.new.tap do |sd|\n        sd.name = 'index'\n        sd.url = sd.name + '.html'\n        sd.readme_path = readme_path\n      end\n    end\n\n    def readme?\n      url == 'index.html'\n    end\n\n    def render_as_page?\n      true\n    end\n\n    def omit_content_from_parent?\n      true\n    end\n\n    def config\n      Config.instance\n    end\n\n    def url_name\n      name.downcase.strip.tr(' ', '-').gsub(/[^[[:word:]]-]/, '')\n    end\n\n    def content(source_module)\n      return readme_content(source_module) if name == 'index'\n\n      overview\n    end\n\n    def readme_content(source_module)\n      config_readme || fallback_readme || generated_readme(source_module)\n    end\n\n    def config_readme\n      readme_path.read if readme_path&.exist?\n    end\n\n    def fallback_readme\n      %w[README.md README.markdown README.mdown README].each do |potential_name|\n        file = config.source_directory + potential_name\n        return file.read if file.exist?\n      end\n      false\n    end\n\n    def generated_readme(source_module)\n      if podspec = config.podspec\n        ### License\n\n        # <a href=\"#{license[:url]}\">#{license[:license]}</a>\n        <<-README\n# #{podspec.name}\n\n### #{podspec.summary}\n\n#{podspec.description}\n\n### Installation\n\n```ruby\npod '#{podspec.name}'\n```\n\n### Authors\n\n#{source_module.author_name}\n        README\n      else\n        <<-README\n# #{source_module.readme_title}\n\n### Authors\n\n#{source_module.author_name}\n        README\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/source_host.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  # Deal with different source code repositories\n  module SourceHost\n    # Factory to create the right source host\n    def self.create(options)\n      return unless options.source_host_url || options.source_host_files_url\n\n      case options.source_host\n      when :github then GitHub.new\n      when :gitlab then GitLab.new\n      when :bitbucket then BitBucket.new\n      end\n    end\n\n    # Use GitHub as the default behaviour.\n    class GitHub\n      include Config::Mixin\n\n      # Human readable name, appears in UI\n      def name\n        'GitHub'\n      end\n\n      # Jazzy extension with logo\n      def extension\n        name.downcase\n      end\n\n      # Logo image filename within extension\n      def image\n        'gh.png'\n      end\n\n      # URL to link to from logo\n      def url\n        config.source_host_url\n      end\n\n      # URL to link to from a SourceDeclaration.\n      # Compare using `realpath` because `item.file` comes out of\n      # SourceKit/etc.\n      def item_url(item)\n        return unless files_url && item.file\n\n        realpath = item.file.realpath\n        return unless realpath.to_path.start_with?(local_root_realpath)\n\n        path = realpath.relative_path_from(local_root_realpath)\n        fragment =\n          if item.start_line && (item.start_line != item.end_line)\n            item_url_multiline_fragment(item.start_line, item.end_line)\n          else\n            item_url_line_fragment(item.line)\n          end\n\n        \"#{files_url}/#{path}##{fragment}\"\n      end\n\n      private\n\n      def files_url\n        config.source_host_files_url\n      end\n\n      def local_root_realpath\n        @local_root_realpath ||= config.source_directory.realpath.to_path\n      end\n\n      # Source host's line numbering link scheme\n      def item_url_line_fragment(line)\n        \"L#{line}\"\n      end\n\n      def item_url_multiline_fragment(start_line, end_line)\n        \"L#{start_line}-L#{end_line}\"\n      end\n    end\n\n    # GitLab very similar to GitHub\n    class GitLab < GitHub\n      def name\n        'GitLab'\n      end\n\n      def image\n        'gitlab.svg'\n      end\n    end\n\n    # BitBucket has its own line number system\n    class BitBucket < GitHub\n      def name\n        'Bitbucket'\n      end\n\n      def image\n        'bitbucket.svg'\n      end\n\n      def item_url_line_fragment(line)\n        \"lines-#{line}\"\n      end\n\n      def item_url_multiline_fragment(start_line, end_line)\n        \"lines-#{start_line}:#{end_line}\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/source_mark.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  class SourceMark\n    attr_accessor :name\n    attr_accessor :has_start_dash\n    attr_accessor :has_end_dash\n\n    def initialize(mark_string = nil)\n      return unless mark_string\n\n      # Format: 'MARK: - NAME -' with dashes optional\n      mark_content = mark_string.sub(/^MARK: /, '')\n\n      if mark_content.empty?\n        # Empty\n        return\n      elsif mark_content == '-'\n        # Separator\n        self.has_start_dash = true\n        return\n      end\n\n      self.has_start_dash = mark_content.start_with?('- ')\n      self.has_end_dash = mark_content.end_with?(' -')\n\n      start_index = has_start_dash ? 2 : 0\n      end_index = has_end_dash ? -3 : -1\n\n      self.name = mark_content[start_index..end_index]\n    end\n\n    def self.new_generic_requirements(requirements)\n      marked_up = requirements.gsub(/\\b([^=:]\\S*)\\b/, '`\\1`')\n      text = \"Available where #{marked_up}\"\n      new(text)\n    end\n\n    def empty?\n      !name && !has_start_dash && !has_end_dash\n    end\n\n    def copy(other)\n      self.name = other.name\n      self.has_start_dash = other.has_start_dash\n      self.has_end_dash = other.has_end_dash\n    end\n\n    # Can we merge the contents of another mark into our own?\n    def can_merge?(other)\n      other.empty? || other.name == name\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/source_module.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'uri'\n\nrequire 'jazzy/config'\nrequire 'jazzy/source_declaration'\nrequire 'jazzy/source_host'\n\nmodule Jazzy\n  # A cache of info that is common across all page templating, gathered\n  # from other parts of the program.\n  class SourceModule\n    include Config::Mixin\n\n    attr_accessor :readme_title\n    attr_accessor :docs\n    attr_accessor :doc_coverage\n    attr_accessor :doc_structure\n    attr_accessor :author_name\n    attr_accessor :author_url\n    attr_accessor :dash_feed_url\n    attr_accessor :host\n\n    def initialize(docs, doc_structure, doc_coverage, docset_builder)\n      self.docs = docs\n      self.doc_structure = doc_structure\n      self.doc_coverage = doc_coverage\n      title = config.readme_title || config.module_names.first\n      self.readme_title = title.empty? ? 'Index' : title\n      self.author_name = config.author_name\n      self.author_url = config.author_url\n      self.host = SourceHost.create(config)\n      self.dash_feed_url = docset_builder.dash_feed_url\n    end\n\n    def all_declarations\n      all_declarations = []\n      visitor = lambda do |d|\n        all_declarations.unshift(*d)\n        d.map(&:children).each { |c| visitor[c] }\n      end\n      visitor[docs]\n      all_declarations.reject { |doc| doc.name == 'index' }\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/sourcekitten.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'json'\nrequire 'pathname'\nrequire 'shellwords'\nrequire 'xcinvoke'\nrequire 'cgi'\nrequire 'rexml/document'\n\nrequire 'jazzy/config'\nrequire 'jazzy/executable'\nrequire 'jazzy/highlighter'\nrequire 'jazzy/source_declaration'\nrequire 'jazzy/source_mark'\nrequire 'jazzy/stats'\nrequire 'jazzy/grouper'\nrequire 'jazzy/doc_index'\n\nELIDED_AUTOLINK_TOKEN = '36f8f5912051ae747ef441d6511ca4cb'\n\ndef autolink_regex(middle_regex, after_highlight)\n  start_tag_re, end_tag_re =\n    if after_highlight\n      [/<span class=\"(?:n|kt|kd|nc)\">/, '</span>']\n    else\n      ['<code>', '</code>']\n    end\n  /(#{start_tag_re})[ \\t]*(#{middle_regex})[ \\t]*(#{end_tag_re})/\nend\n\nclass String\n  def autolink_block(doc_url, middle_regex, after_highlight)\n    gsub(autolink_regex(middle_regex, after_highlight)) do\n      original = Regexp.last_match(0)\n      start_tag, raw_name, end_tag = Regexp.last_match.captures\n      link_target, display_name = yield(CGI.unescape_html(raw_name))\n\n      if link_target &&\n         !link_target.type.extension? &&\n         link_target.url &&\n         link_target.url != doc_url.split('#').first && # Don't link to parent\n         link_target.url != doc_url # Don't link to self\n        \"#{start_tag}<a href=\\\"#{ELIDED_AUTOLINK_TOKEN}#{link_target.url}\\\">\" \\\n          \"#{CGI.escape_html(display_name)}</a>#{end_tag}\"\n      else\n        original\n      end\n    end\n  end\n\n  def unindent(count)\n    gsub(/^#{' ' * count}/, '')\n  end\nend\n\nmodule Jazzy\n  # This module interacts with the sourcekitten command-line executable\n  module SourceKitten\n    def self.undocumented_abstract\n      @undocumented_abstract ||= Markdown.render(\n        Config.instance.undocumented_text,\n      ).freeze\n    end\n\n    #\n    # URL assignment\n    #\n\n    def self.sanitize_filename(doc)\n      unsafe_filename = doc.docs_filename\n      sanitzation_enabled = Config.instance.use_safe_filenames\n      if sanitzation_enabled && !doc.type.name_controlled_manually?\n        CGI.escape(unsafe_filename).gsub('_', '%5F').tr('%', '_')\n      else\n        unsafe_filename\n      end\n    end\n\n    # rubocop:disable Metrics/MethodLength\n    # Generate doc URL by prepending its parents' URLs\n    # @return [Hash] input docs with URLs\n    def self.make_doc_urls(docs)\n      docs.each do |doc|\n        if doc.render_as_page?\n          doc.url = (\n            subdir_for_doc(doc) +\n            [sanitize_filename(doc) + '.html']\n          ).map { |path| ERB::Util.url_encode(path) }.join('/')\n          doc.children = make_doc_urls(doc.children)\n        else\n          # Don't create HTML page for this doc if it doesn't have children\n          # Instead, make its link a hash-link on its parent's page\n          if doc.typename == '<<error type>>'\n            warn \"A compile error prevented #{doc.fully_qualified_name} \" \\\n              'from receiving a unique USR. Documentation may be ' \\\n              'incomplete. Please check for compile errors by running ' \\\n              '`xcodebuild` or `swift build` with arguments ' \\\n              \"`#{Config.instance.build_tool_arguments.shelljoin}`.\"\n          end\n          id = doc.usr\n          unless id\n            id = doc.name || 'unknown'\n            warn \"`#{id}` has no USR. First make sure all modules used in \" \\\n              'your project have been imported. If all used modules are ' \\\n              'imported, please report this problem by filing an issue at ' \\\n              'https://github.com/realm/jazzy/issues along with your ' \\\n              'Xcode project. If this token is declared in an `#if` block, ' \\\n              'please ignore this message.'\n          end\n          doc.url = \"#{doc.parent_in_docs.url}#/#{id}\"\n        end\n      end\n    end\n    # rubocop:enable Metrics/MethodLength\n\n    # Determine the subdirectory in which a doc should be placed.\n    # Guides in the root for back-compatibility.\n    # Declarations under outer namespace type (Structures, Classes, etc.)\n    def self.subdir_for_doc(doc)\n      if Config.instance.multiple_modules?\n        subdir_for_doc_multi_module(doc)\n      else\n        # Back-compatibility layout version\n        subdir_for_doc_single_module(doc)\n      end\n    end\n\n    # Pre-multi-module site layout, does not allow for\n    # types with the same name.\n    def self.subdir_for_doc_single_module(doc)\n      # Guides + Groups in the root\n      return [] if doc.type.markdown? || doc.type.overview?\n\n      [doc.namespace_path.first.type.plural_url_name] +\n        doc.namespace_ancestors.map(&:name)\n    end\n\n    # Multi-module site layout, separate each module that\n    # is being documented.\n    def self.subdir_for_doc_multi_module(doc)\n      # Guides + Groups in the root\n      return [] if doc.type.markdown? || doc.type.overview?\n\n      root_decl = doc.namespace_path.first\n\n      # Extensions need an extra dir to allow for extending\n      # ExternalModule1.TypeName and ExternalModule2.TypeName\n      namespace_subdir =\n        if root_decl.type.swift_extension?\n          ['Extensions', root_decl.module_name]\n        else\n          [doc.namespace_path.first.type.plural_url_name]\n        end\n\n      [root_decl.doc_module_name] +\n        namespace_subdir +\n        doc.namespace_ancestors.map(&:name)\n    end\n\n    #\n    # CLI argument calculation\n    #\n\n    # returns all subdirectories of specified path\n    def self.rec_path(path)\n      path.children.collect do |child|\n        if child.directory?\n          rec_path(child) + [child]\n        end\n      end.select { |x| x }.flatten(1)\n    end\n\n    def self.use_spm?(module_config)\n      module_config.swift_build_tool == :spm ||\n        (!module_config.swift_build_tool_configured &&\n         Dir['*.xcodeproj', '*.xcworkspace'].empty? &&\n         !module_config.build_tool_arguments.include?('-project') &&\n         !module_config.build_tool_arguments.include?('-workspace'))\n    end\n\n    # Builds SourceKitten arguments based on Jazzy options\n    def self.arguments_from_options(module_config)\n      arguments = ['doc']\n      if module_config.objc_mode\n        arguments += objc_arguments_from_options(module_config)\n      else\n        arguments += ['--spm'] if use_spm?(module_config)\n        unless module_config.module_name.empty?\n          arguments += ['--module-name', module_config.module_name]\n        end\n        arguments += ['--']\n      end\n\n      arguments + module_config.build_tool_arguments\n    end\n\n    def self.objc_arguments_from_options(module_config)\n      arguments = []\n      if module_config.build_tool_arguments.empty?\n        arguments += ['--objc', module_config.umbrella_header.to_s, '--', '-x',\n                      'objective-c', '-isysroot',\n                      `xcrun --show-sdk-path --sdk #{module_config.sdk}`.chomp,\n                      '-I', module_config.framework_root.to_s,\n                      '-fmodules']\n      end\n      # add additional -I arguments for each subdirectory of framework_root\n      unless module_config.framework_root.nil?\n        rec_path(Pathname.new(module_config.framework_root.to_s)).collect do |child|\n          if child.directory?\n            arguments += ['-I', child.to_s]\n          end\n        end\n      end\n      arguments\n    end\n\n    # Run sourcekitten with given arguments and return STDOUT\n    def self.run_sourcekitten(arguments)\n      if swift_version = Config.instance.swift_version\n        unless xcode = XCInvoke::Xcode.find_swift_version(swift_version)\n          raise \"Unable to find an Xcode with swift version #{swift_version}.\"\n        end\n\n        env = xcode.as_env\n      else\n        env = ENV\n      end\n      bin_path = Pathname(__FILE__) + '../../../bin/sourcekitten'\n      output, = Executable.execute_command(bin_path, arguments, true, env: env)\n      output\n    end\n\n    #\n    # SourceDeclaration generation\n    #\n\n    def self.make_default_doc_info(declaration)\n      # @todo: Fix these\n      declaration.abstract = ''\n      declaration.parameters = []\n      declaration.children = []\n    end\n\n    def self.attribute?(doc, attr_name)\n      doc['key.attributes']&.find do |attribute|\n        attribute['key.attribute'] == \"source.decl.attribute.#{attr_name}\"\n      end\n    end\n\n    def self.availability_attribute?(doc)\n      attribute?(doc, 'available')\n    end\n\n    def self.spi_attribute?(doc)\n      attribute?(doc, '_spi')\n    end\n\n    def self.should_document?(doc)\n      return false if doc['key.doc.comment'].to_s.include?(':nodoc:')\n\n      type = SourceDeclaration::Type.new(doc['key.kind'])\n\n      # Always document Objective-C declarations.\n      return true unless type.swift_type?\n\n      # Don't document Swift types if we are hiding Swift\n      return false if Config.instance.hide_swift?\n\n      # Don't document @available declarations with no USR, since it means\n      # they're unavailable.\n      if availability_attribute?(doc) && !doc['key.usr']\n        return false\n      end\n\n      # Only document @_spi declarations in some scenarios\n      return false unless should_document_spi?(doc)\n\n      # Don't document declarations excluded by the min_acl setting\n      if type.swift_extension?\n        should_document_swift_extension?(doc)\n      else\n        should_document_acl?(type, doc)\n      end\n    end\n\n    # Check visibility: SPI\n    def self.should_document_spi?(doc)\n      spi_ok = @min_acl < SourceDeclaration::AccessControlLevel.public ||\n               Config.instance.include_spi_declarations ||\n               (!spi_attribute?(doc) && !doc['key.symgraph_spi'])\n\n      @stats.add_spi_skipped unless spi_ok\n      spi_ok\n    end\n\n    # Check visibility: access control\n    def self.should_document_acl?(type, doc)\n      # Include all enum elements for now, can't tell their ACL.\n      return true if type.swift_enum_element?\n\n      acl_ok = SourceDeclaration::AccessControlLevel.from_doc(doc) >= @min_acl\n      unless acl_ok\n        @stats.add_acl_skipped\n        @inaccessible_protocols.append(doc['key.name']) if type.swift_protocol?\n      end\n      acl_ok\n    end\n\n    # Document extensions if they add protocol conformances, or have any\n    # member that needs to be documented.\n    def self.should_document_swift_extension?(doc)\n      doc['key.inheritedtypes'] ||\n        Array(doc['key.substructure']).any? do |subdoc|\n          subtype = SourceDeclaration::Type.new(subdoc['key.kind'])\n          !subtype.mark? && should_document?(subdoc)\n        end\n    end\n\n    def self.process_undocumented_token(doc, declaration)\n      make_default_doc_info(declaration)\n\n      if declaration.mark_undocumented?\n        @stats.add_undocumented(declaration)\n        return nil if @skip_undocumented\n\n        declaration.abstract = undocumented_abstract\n      else\n        declaration.abstract = Markdown.render(doc['key.doc.comment'] || '',\n                                               declaration.highlight_language)\n      end\n\n      declaration\n    end\n\n    def self.parameters(doc, discovered)\n      (doc['key.doc.parameters'] || []).map do |p|\n        name = p['name']\n        {\n          name: name,\n          discussion: discovered[name],\n        }\n      end.reject { |param| param[:discussion].nil? }\n    end\n\n    def self.make_doc_info(doc, declaration)\n      return unless should_document?(doc)\n\n      highlight_declaration(doc, declaration)\n      make_deprecation_info(doc, declaration)\n\n      unless doc['key.doc.full_as_xml']\n        return process_undocumented_token(doc, declaration)\n      end\n\n      declaration.abstract = Markdown.render(doc['key.doc.comment'] || '',\n                                             declaration.highlight_language)\n      declaration.discussion = ''\n      declaration.return = Markdown.rendered_returns\n      declaration.parameters = parameters(doc, Markdown.rendered_parameters)\n\n      @stats.add_documented\n    end\n\n    def self.highlight_declaration(doc, declaration)\n      if declaration.swift?\n        declaration.declaration =\n          Highlighter.highlight_swift(make_swift_declaration(doc, declaration))\n      else\n        declaration.declaration =\n          Highlighter.highlight_objc(\n            make_objc_declaration(doc['key.parsed_declaration']),\n          )\n        declaration.other_language_declaration =\n          Highlighter.highlight_swift(doc['key.swift_declaration'])\n      end\n    end\n\n    def self.make_deprecation_info(doc, declaration)\n      if declaration.deprecated\n        declaration.deprecation_message =\n          Markdown.render(doc['key.deprecation_message'] || '')\n      end\n      if declaration.unavailable\n        declaration.unavailable_message =\n          Markdown.render(doc['key.unavailable_message'] || '')\n      end\n    end\n\n    # Strip tags and convert entities\n    def self.xml_to_text(xml)\n      document = REXML::Document.new(xml)\n      REXML::XPath.match(document.root, '//text()').map(&:value).join\n    rescue StandardError\n      ''\n    end\n\n    # Regexp to match an @attribute.  Complex to handle @available().\n    def self.attribute_regexp(name)\n      qstring = /\"(?:[^\"\\\\]*|\\\\.)*\"/\n      %r{@#{name}      # @attr name\n        (?:\\s*\\(       # optionally followed by spaces + parens,\n          (?:          # containing any number of either..\n            [^\")]*|    # normal characters or...\n            #{qstring} # quoted strings.\n          )*           # (end parens content)\n        \\))?           # (end optional parens)\n      }x\n    end\n\n    # Get all attributes of some name\n    def self.extract_attributes(declaration, name = '\\w+')\n      attrs = declaration.scan(attribute_regexp(name))\n      # Rouge #806 workaround, use unicode lookalike for ')' inside attributes.\n      attrs.map { |str| str.gsub(/\\)(?!\\s*$)/, \"\\ufe5a\") }\n    end\n\n    # Keep everything except instructions to us\n    def self.extract_documented_attributes(declaration)\n      extract_attributes(declaration).reject do |attr|\n        attr.start_with?('@_documentation')\n      end\n    end\n\n    def self.extract_availability(declaration)\n      extract_attributes(declaration, 'available')\n    end\n\n    # Split leading attributes from a decl, returning both parts.\n    def self.split_decl_attributes(declaration)\n      declaration =~ /^((?:#{attribute_regexp('\\w+')}\\s*)*)(.*)$/m\n      Regexp.last_match.captures\n    end\n\n    def self.prefer_parsed_decl?(parsed, annotated, type)\n      return true if annotated.empty?\n      return false unless parsed\n      return false if type.swift_variable? # prefer { get }-style\n\n      annotated.include?(' = default') || # SR-2608\n        (parsed.scan(/@autoclosure|@escaping/).count >\n         annotated.scan(/@autoclosure|@escaping/).count) || # SR-6321\n        parsed.include?(\"\\n\") # user formatting\n    end\n\n    # Apply fixes to improve the compiler's declaration\n    def self.fix_up_compiler_decl(annotated_decl, declaration)\n      annotated_decl.\n        # Replace the fully qualified name of a type with its base name\n        gsub(declaration.fully_qualified_name_regexp,\n             declaration.name).\n        # Workaround for SR-9816\n        gsub(\" {\\n  get\\n  }\", '').\n        # Workaround for SR-12139\n        gsub(/mutating\\s+mutating/, 'mutating')\n    end\n\n    # Find the best Swift declaration\n    def self.make_swift_declaration(doc, declaration)\n      # From compiler 'quick help' style\n      annotated_decl_xml = doc['key.annotated_decl']\n\n      return nil unless annotated_decl_xml\n\n      annotated_decl_attrs, annotated_decl_body =\n        split_decl_attributes(xml_to_text(annotated_decl_xml))\n\n      # From source code\n      parsed_decl = doc['key.parsed_declaration']\n\n      # Don't present type attributes on extensions\n      return parsed_decl if declaration.type.extension?\n\n      decl =\n        if prefer_parsed_decl?(parsed_decl,\n                               annotated_decl_body,\n                               declaration.type)\n          # Strip any attrs captured by parsed version\n          inline_attrs, parsed_decl_body = split_decl_attributes(parsed_decl)\n          parsed_decl_body.unindent(inline_attrs.length)\n        else\n          # Improve the compiler declaration\n          fix_up_compiler_decl(annotated_decl_body, declaration)\n        end\n\n      # @available attrs only in compiler 'interface' style\n      extract_availability(doc['key.doc.declaration'] || '')\n        .concat(extract_documented_attributes(annotated_decl_attrs))\n        .concat(fabricate_spi_attributes(doc, annotated_decl_attrs))\n        .push(decl)\n        .join(\"\\n\")\n    end\n\n    # Swift 6 workaround: @_spi attribute & SPI group missing\n    def self.fabricate_spi_attributes(doc, attrs)\n      return [] unless spi_attribute?(doc)\n      return [] if attrs =~ /@_spi/\n\n      ['@_spi(<<unknown>>)']\n    end\n\n    # Exclude non-async routines that accept async closures\n    def self.swift_async?(fully_annotated_decl)\n      document = REXML::Document.new(fully_annotated_decl)\n      !document.elements['/*/syntaxtype.keyword[text()=\"async\"]'].nil?\n    rescue StandardError\n      nil\n    end\n\n    # Strip default property attributes because libclang\n    # adds them all, even if absent in the original source code.\n    DEFAULT_ATTRIBUTES = %w[atomic readwrite assign unsafe_unretained].freeze\n\n    def self.make_objc_declaration(declaration)\n      return declaration if Config.instance.keep_property_attributes\n\n      declaration =~ /\\A@property\\s+\\((.*?)\\)/\n      return declaration unless Regexp.last_match\n\n      attrs = Regexp.last_match[1].split(',').map(&:strip) - DEFAULT_ATTRIBUTES\n      attrs_text = attrs.empty? ? '' : \" (#{attrs.join(', ')})\"\n\n      declaration\n        .sub(/(?<=@property)\\s+\\(.*?\\)/, attrs_text)\n        .gsub(/\\s+/, ' ')\n    end\n\n    def self.make_substructure(doc, declaration)\n      return [] unless subdocs = doc['key.substructure']\n\n      make_source_declarations(subdocs,\n                               declaration,\n                               declaration.mark_for_children)\n    end\n\n    # rubocop:disable Metrics/MethodLength\n    # rubocop:disable Metrics/CyclomaticComplexity\n    # rubocop:disable Metrics/PerceivedComplexity\n    def self.make_source_declarations(docs, parent = nil, mark = SourceMark.new)\n      declarations = []\n      current_mark = mark\n      Array(docs).each do |doc|\n        if doc.key?('key.diagnostic_stage')\n          declarations += make_source_declarations(\n            doc['key.substructure'], parent\n          )\n          next\n        end\n        declaration = SourceDeclaration.new\n        declaration.parent_in_code = parent\n        declaration.type =\n          SourceDeclaration::Type.new(doc['key.kind'],\n                                      doc['key.fully_annotated_decl'])\n        declaration.typename = doc['key.typename']\n        declaration.objc_name = doc['key.name']\n        documented_name = if Config.instance.hide_objc? && doc['key.swift_name']\n                            doc['key.swift_name']\n                          else\n                            declaration.objc_name\n                          end\n        if declaration.type.task_mark?(documented_name)\n          current_mark = SourceMark.new(documented_name)\n        end\n        if declaration.type.swift_enum_case?\n          # Enum \"cases\" are thin wrappers around enum \"elements\".\n          declarations += make_source_declarations(\n            doc['key.substructure'], parent, current_mark\n          )\n          next\n        end\n        next unless declaration.type.should_document?\n\n        unless declaration.type.name\n          raise 'Please file an issue at ' \\\n            'https://github.com/realm/jazzy/issues about adding support ' \\\n            \"for `#{declaration.type.kind}`.\"\n        end\n\n        unless documented_name\n          warn 'Found a declaration without `key.name` that will be ' \\\n            'ignored.  Documentation may be incomplete.  This is probably ' \\\n            'caused by unresolved compiler errors: check the sourcekitten ' \\\n            'output for error messages.'\n          next\n        end\n\n        declaration.file = Pathname(doc['key.filepath']) if doc['key.filepath']\n        declaration.usr = doc['key.usr']\n        declaration.type_usr = doc['key.typeusr']\n        declaration.module_name =\n          if declaration.swift?\n            # Filter out Apple sub-framework implementation names\n            doc['key.modulename']&.sub(/\\..*$/, '')\n          else\n            # ObjC best effort, category original module is unavailable\n            @current_module_name\n          end\n        declaration.doc_module_name = @current_module_name\n        declaration.name = documented_name\n        declaration.mark = current_mark\n        declaration.access_control_level =\n          SourceDeclaration::AccessControlLevel.from_doc(doc)\n        declaration.line = doc['key.doc.line'] || doc['key.line']\n        declaration.column = doc['key.doc.column'] || doc['key.column']\n        declaration.start_line = doc['key.parsed_scope.start']\n        declaration.end_line = doc['key.parsed_scope.end']\n        declaration.deprecated = doc['key.always_deprecated']\n        declaration.unavailable = doc['key.always_unavailable']\n        declaration.generic_requirements =\n          find_generic_requirements(doc['key.parsed_declaration'])\n        inherited_types = doc['key.inheritedtypes'] || []\n        declaration.inherited_types =\n          inherited_types.map { |type| type['key.name'] }.compact\n        declaration.async =\n          doc['key.symgraph_async'] ||\n          if xml_declaration = doc['key.fully_annotated_decl']\n            swift_async?(xml_declaration)\n          end\n\n        next unless make_doc_info(doc, declaration)\n\n        declaration.children = make_substructure(doc, declaration)\n        next if declaration.type.extension? &&\n                declaration.children.empty? &&\n                !declaration.inherited_types?\n\n        declarations << declaration\n      end\n      declarations\n    end\n    # rubocop:enable Metrics/PerceivedComplexity\n    # rubocop:enable Metrics/CyclomaticComplexity\n    # rubocop:enable Metrics/MethodLength\n\n    def self.find_generic_requirements(parsed_declaration)\n      parsed_declaration =~ /\\bwhere\\s+(.*)$/m\n      return nil unless Regexp.last_match\n\n      Regexp.last_match[1].gsub(/\\s+/, ' ')\n    end\n\n    #\n    # SourceDeclaration generation - extension management\n    #\n\n    # Expands extensions of nested types declared at the top level into\n    # a tree so they can be deduplicated properly\n    def self.expand_extensions(decls)\n      decls.map do |decl|\n        next decl unless decl.type.extension? && decl.name.include?('.')\n\n        # Don't expand the Swift namespace if we're in ObjC mode.\n        # ex: NS_SWIFT_NAME(Foo.Bar) should not create top-level Foo\n        next decl if decl.swift_objc_extension? && !Config.instance.hide_objc?\n\n        name_parts = decl.name.split('.')\n        decl.name = name_parts.pop\n        expand_extension(decl, name_parts, decls)\n      end\n    end\n\n    def self.expand_extension(extension, name_parts, decls)\n      return extension if name_parts.empty?\n\n      name = name_parts.shift\n      candidates = decls.select { |decl| decl.name == name }\n      SourceDeclaration.new.tap do |decl|\n        make_default_doc_info(decl)\n        decl.name = name\n        decl.module_name = extension.module_name\n        decl.doc_module_name = extension.doc_module_name\n        decl.type = extension.type\n        decl.mark = extension.mark\n        decl.usr = candidates.first.usr unless candidates.empty?\n        child = expand_extension(extension,\n                                 name_parts,\n                                 candidates.flat_map(&:children).uniq)\n        child.parent_in_code = decl\n        decl.children = [child]\n      end\n    end\n\n    # Merges multiple extensions of the same entity into a single document.\n    #\n    # Merges extensions into the protocol/class/struct/enum they extend, if it\n    # occurs in the same project.\n    #\n    # Merges redundant declarations when documenting podspecs.\n    def self.deduplicate_declarations(declarations)\n      duplicate_groups = declarations\n        .group_by { |d| deduplication_key(d, declarations) }\n        .values\n\n      duplicate_groups.flat_map do |group|\n        # Put extended type (if present) before extensions\n        merge_declarations(group)\n      end.compact\n    end\n\n    # Returns true if an Objective-C declaration is mergeable.\n    def self.mergeable_objc?(decl, root_decls)\n      decl.type.objc_class? ||\n        (decl.type.objc_category? &&\n          (category_classname = decl.objc_category_name[0]) &&\n          root_decls.any? { |d| d.name == category_classname })\n    end\n\n    # Returns if a Swift declaration is mergeable.\n    # Start off merging in typealiases to help understand extensions.\n    def self.mergeable_swift?(decl)\n      decl.type.swift_extensible? ||\n        decl.type.swift_extension? ||\n        decl.type.swift_typealias?\n    end\n\n    # Normally merge all extensions into their types and each other.\n    #\n    # :none means only merge within a module -- so two extensions to\n    #     some type get merged, but an extension to a type from\n    #     another documented module does not get merged into that type\n    # :extensions means extensions of documented modules get merged,\n    #     but if we're documenting ModA and ModB, and they both provide\n    #     extensions to Swift.String, then those two extensions still\n    #     appear separately.\n    #\n    # (The USR part of the dedup key means ModA.Foo and ModB.Foo do not\n    # get merged.)\n    def self.module_deduplication_key(decl)\n      if (Config.instance.merge_modules == :none) ||\n         (Config.instance.merge_modules == :extensions &&\n          decl.extension_of_external_type?)\n        decl.doc_module_name\n      else\n        ''\n      end\n    end\n\n    # Two declarations get merged if they have the same deduplication key.\n    def self.deduplication_key(decl, root_decls)\n      mod_key = module_deduplication_key(decl)\n      # Swift extension of objc class\n      if decl.swift_objc_extension?\n        [decl.swift_extension_objc_name, nil, :objc_class_and_categories, mod_key]\n      # Swift type or Swift extension of Swift type\n      elsif mergeable_swift?(decl)\n        [decl.usr, nil, decl.name, mod_key]\n      # Objc categories and classes\n      elsif mergeable_objc?(decl, root_decls)\n        # Using the ObjC name to match swift_objc_extension.\n        name, _ = decl.objc_category_name || decl.objc_name\n        [name, nil, :objc_class_and_categories, mod_key]\n      # Non-mergable declarations (funcs, typedefs etc...)\n      else\n        # The typename part works around a Swift bug, jazzy#1396\n        [decl.usr, decl.typename, decl.name, decl.type.kind, '']\n      end\n    end\n\n    # rubocop:disable Metrics/MethodLength\n    # rubocop:disable Metrics/PerceivedComplexity\n    # Merges all of the given types and extensions into a single document.\n    def self.merge_declarations(decls)\n      extensions, typedecls = decls.partition { |d| d.type.extension? }\n\n      if typedecls.size > 1\n        info = typedecls\n          .map { |t| \"#{t.type.name.downcase} #{t.name}\" }\n          .join(', ')\n        warn 'Found conflicting type declarations with the same name, which ' \\\n          \"may indicate a build issue or a bug in Jazzy: #{info}\"\n      end\n      typedecl = typedecls.first\n\n      extensions = reject_inaccessible_extensions(typedecl, extensions)\n\n      if typedecl\n        if typedecl.type.swift_protocol?\n          mark_and_merge_protocol_extensions(typedecl, extensions)\n          extensions.reject! { |ext| ext.children.empty? }\n        end\n\n        merge_objc_declaration_marks(typedecl, extensions)\n      end\n\n      # Keep type-aliases separate from any extensions\n      if typedecl&.type&.swift_typealias?\n        [merge_type_and_extensions(typedecls, []),\n         merge_type_and_extensions([], extensions)]\n      else\n        merge_type_and_extensions(typedecls, extensions)\n      end\n    end\n    # rubocop:enable Metrics/PerceivedComplexity\n    # rubocop:enable Metrics/MethodLength\n\n    def self.merge_type_and_extensions(typedecls, extensions)\n      # Constrained extensions at the end\n      constrained, regular_exts = extensions.partition(&:constrained_extension?)\n      decls = typedecls + regular_exts + constrained\n      return nil if decls.empty?\n\n      move_merged_extension_marks(decls)\n      merge_code_declaration(decls)\n\n      decls.first.tap do |merged|\n        merged.children = deduplicate_declarations(\n          decls.flat_map(&:children).uniq,\n        )\n        merged.children.each do |child|\n          child.parent_in_code = merged\n        end\n      end\n    end\n\n    # Now we know all the public types and all the private protocols,\n    # reject extensions that add public protocols to private types\n    # or add private protocols to public types.\n    def self.reject_inaccessible_extensions(typedecl, extensions)\n      swift_exts, objc_exts = extensions.partition(&:swift?)\n\n      # Reject extensions that are just conformances to private protocols\n      unwanted_exts, wanted_exts = swift_exts.partition do |ext|\n        ext.children.empty? &&\n          !ext.other_inherited_types?(@inaccessible_protocols)\n      end\n\n      # Given extensions of a type from this module, without the\n      # type itself, the type must be private and the extensions\n      # should be rejected.\n      if !typedecl &&\n         wanted_exts.first&.type_from_doc_module?\n        unwanted_exts += wanted_exts\n        wanted_exts = []\n      end\n\n      # Don't tell the user to document them or their contents\n      remover = lambda do |decls|\n        decls.each { |d| @stats.remove_undocumented(d) }\n        decls.map(&:children).each { |c| remover[c] }\n      end\n      remover[unwanted_exts]\n\n      objc_exts + wanted_exts\n    end\n\n    # Protocol extensions.\n    #\n    # If any of the extensions provide default implementations for methods in\n    # the given protocol, merge those members into the protocol doc instead of\n    # keeping them on the extension. These get a “Default implementation”\n    # annotation in the generated docs.  Default implementations added by\n    # conditional extensions are annotated but listed separately.\n    #\n    # Protocol methods provided only in an extension and not in the protocol\n    # itself are a special beast: they do not use dynamic dispatch. These get an\n    # “Extension method” annotation in the generated docs.\n    def self.mark_and_merge_protocol_extensions(protocol, extensions)\n      extensions.each do |ext|\n        ext.children = ext.children.select do |ext_member|\n          proto_member = protocol.children.find do |p|\n            p.default_implementation?(ext_member)\n          end\n\n          # Extension-only method, keep.\n          unless proto_member\n            ext_member.from_protocol_extension = true\n            next true\n          end\n\n          # Default impl but constrained, mark and keep.\n          if ext.constrained_extension?\n            ext_member.default_impl_abstract = ext_member.abstract\n            ext_member.abstract = nil\n            next true\n          end\n\n          # Default impl for all users, merge.\n          proto_member.default_impl_abstract = ext_member.abstract\n          next false\n        end\n      end\n    end\n\n    # Mark children merged from categories with the name of category\n    # (unless they already have a mark)\n    def self.merge_objc_declaration_marks(typedecl, extensions)\n      return unless typedecl.type.objc_class?\n\n      extensions.each do |ext|\n        _, category_name = ext.objc_category_name\n        ext.children.each { |c| c.mark.name ||= category_name }\n      end\n    end\n\n    # For each extension to be merged, move any MARK from the extension\n    # declaration down to the extension contents so it still shows up.\n    def self.move_merged_extension_marks(decls)\n      return unless to_be_merged = decls[1..]\n\n      to_be_merged.each do |ext|\n        child = ext.children.first\n        if child && child.mark.empty?\n          child.mark.copy(ext.mark)\n        end\n      end\n    end\n\n    # Merge useful information added by extensions into the main\n    # declaration: public protocol conformances and, for top-level extensions,\n    # further conditional extensions of the same type.\n    def self.merge_code_declaration(decls)\n      declarations = decls[1..].select do |decl|\n        decl.type.swift_extension? &&\n          (decl.other_inherited_types?(@inaccessible_protocols) ||\n            (decls.first.type.swift_extension? && decl.constrained_extension?))\n      end.prepend(decls.first)\n\n      html_declaration = ''\n      until declarations.empty?\n        module_decls, declarations = next_doc_module_group(declarations)\n        first = module_decls.first\n        if need_doc_module_note?(first, html_declaration)\n          html_declaration += \"<span class='declaration-note'>From #{first.doc_module_name}:</span>\"\n        end\n        html_declaration += module_decls.map(&:declaration).uniq.join\n      end\n\n      # Must preserve `nil` for edge cases\n      decls.first.declaration = html_declaration unless html_declaration.empty?\n    end\n\n    # Grab all the extensions from the same doc module\n    def self.next_doc_module_group(decls)\n      decls.partition do |decl|\n        decl.doc_module_name == decls.first.doc_module_name\n      end\n    end\n\n    # Does this extension/type need a note explaining which doc module it is from?\n    # Only for extensions, if there actually are multiple modules.\n    # Last condition avoids it for simple 'extension Array'.\n    def self.need_doc_module_note?(decl, html_declaration)\n      Config.instance.multiple_modules? &&\n        decl.type.swift_extension? &&\n        !(html_declaration.empty? &&\n          !decl.constrained_extension? &&\n          !decl.inherited_types?)\n    end\n\n    #\n    # Autolinking\n    #\n\n    # Links recognized top-level declarations within\n    # - inlined code within docs\n    # - method signatures after they've been processed by the highlighter\n    #\n    # The `after_highlight` flag is used to differentiate between the two modes.\n    #\n    # DocC link format - follow Xcode and don't display slash-separated parts.\n    def self.autolink_text(text, doc, after_highlight: false)\n      text.autolink_block(doc.url, '[^\\s]+', after_highlight) do |raw_name|\n        sym_name =\n          (raw_name[/^<doc:(.*)>$/, 1] || raw_name).sub(/(?<!^)-.+$/, '')\n\n        [@doc_index.lookup(sym_name, doc), sym_name.sub(%r{^.*/}, '')]\n      end.autolink_block(doc.url, '[+-]\\[\\w+(?: ?\\(\\w+\\))? [\\w:]+\\]',\n                         after_highlight) do |raw_name|\n        [@doc_index.lookup(raw_name, doc), raw_name]\n      end.autolink_block(doc.url, '[+-]\\w[\\w:]*', after_highlight) do |raw_name|\n        [@doc_index.lookup(raw_name, doc), raw_name]\n      end\n    end\n\n    AUTOLINK_TEXT_FIELDS = %w[return\n                              abstract\n                              unavailable_message\n                              deprecation_message].freeze\n\n    def self.autolink_text_fields(doc)\n      AUTOLINK_TEXT_FIELDS.each do |field|\n        if text = doc.send(field)\n          doc.send(field + '=', autolink_text(text, doc))\n        end\n      end\n\n      (doc.parameters || []).each do |param|\n        param[:discussion] =\n          autolink_text(param[:discussion], doc)\n      end\n    end\n\n    AUTOLINK_HIGHLIGHT_FIELDS = %w[declaration\n                                   other_language_declaration].freeze\n\n    def self.autolink_highlight_fields(doc)\n      AUTOLINK_HIGHLIGHT_FIELDS.each do |field|\n        if text = doc.send(field)\n          doc.send(field + '=',\n                   autolink_text(text, doc, after_highlight: true))\n        end\n      end\n    end\n\n    def self.autolink(docs)\n      docs.each do |doc|\n        doc.children = autolink(doc.children)\n        autolink_text_fields(doc)\n        autolink_highlight_fields(doc)\n      end\n    end\n\n    # For autolinking external markdown documents\n    def self.autolink_document(html, doc)\n      autolink_text(html, doc)\n    end\n\n    #\n    # Entrypoint and misc filtering\n    #\n\n    # Apply filtering based on the \"included\" and \"excluded\" flags.\n    def self.filter_files(json)\n      json = filter_included_files(json) if Config.instance.included_files.any?\n      json = filter_excluded_files(json) if Config.instance.excluded_files.any?\n      json.map do |doc|\n        key = doc.keys.first\n        doc[key]\n      end.compact\n    end\n\n    # Filter based on the \"included\" flag.\n    def self.filter_included_files(json)\n      included_files = Config.instance.included_files\n      json.map do |doc|\n        key = doc.keys.first\n        doc if included_files.detect do |include|\n          File.fnmatch?(include, key)\n        end\n      end.compact\n    end\n\n    # Filter based on the \"excluded\" flag.\n    def self.filter_excluded_files(json)\n      excluded_files = Config.instance.excluded_files\n      json.map do |doc|\n        key = doc.keys.first\n        doc unless excluded_files.detect do |exclude|\n          File.fnmatch?(exclude, key)\n        end\n      end.compact\n    end\n\n    def self.reject_objc_types(docs)\n      enums = docs.map do |doc|\n        [doc, doc.children]\n      end.flatten.select { |child| child.type.objc_enum? }.map(&:objc_name)\n      docs.map do |doc|\n        doc.children = doc.children.reject do |child|\n          child.type.objc_typedef? && enums.include?(child.name)\n        end\n        doc\n      end.reject do |doc|\n        doc.type.objc_unexposed? ||\n          (doc.type.objc_typedef? && enums.include?(doc.name))\n      end\n    end\n\n    # Remove top-level enum cases because it means they have an ACL lower\n    # than min_acl\n    def self.reject_swift_types(docs)\n      docs.reject { |doc| doc.type.swift_enum_element? }\n    end\n\n    # Spot and mark any categories on classes not declared in these docs\n    def self.mark_objc_external_categories(docs)\n      class_names = docs.select { |doc| doc.type.objc_class? }.to_set(&:name)\n\n      docs.map do |doc|\n        if (names = doc.objc_category_name) && !class_names.include?(names.first)\n          doc.module_name = '(Imported)'\n        end\n        doc\n      end\n    end\n\n    # Parse sourcekitten STDOUT output as JSON\n    # @return [Hash] structured docs\n    def self.parse(sourcekitten_output, options, inject_docs)\n      @min_acl = options.min_acl\n      @skip_undocumented = options.skip_undocumented\n      @stats = Stats.new\n      @inaccessible_protocols = []\n\n      # Process each module separately to inject the source module name\n      docs = sourcekitten_output.zip(options.module_names).map do |json, name|\n        @current_module_name = name\n        sourcekitten_dicts = filter_files(JSON.parse(json).flatten)\n        make_source_declarations(sourcekitten_dicts)\n      end.flatten + inject_docs\n\n      docs = expand_extensions(docs)\n      docs = deduplicate_declarations(docs)\n      docs = reject_objc_types(docs)\n      docs = reject_swift_types(docs)\n      docs = mark_objc_external_categories(docs)\n\n      @doc_index = DocIndex.new(docs)\n\n      docs = Grouper.group_docs(docs, @doc_index)\n\n      make_doc_urls(docs)\n      autolink(docs)\n      [docs, @stats]\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/stats.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  # Collect + report metadata about a processed module\n  class Stats\n    include Config::Mixin\n\n    attr_reader :documented, :acl_skipped, :spi_skipped, :undocumented_decls\n\n    def add_documented\n      @documented += 1\n    end\n\n    def add_acl_skipped\n      @acl_skipped += 1\n    end\n\n    def add_spi_skipped\n      @spi_skipped += 1\n    end\n\n    def add_undocumented(decl)\n      @undocumented_decls << decl\n    end\n\n    def remove_undocumented(decl)\n      @undocumented_decls.delete(decl)\n    end\n\n    def acl_included\n      documented + undocumented\n    end\n\n    def undocumented\n      undocumented_decls.count\n    end\n\n    def initialize\n      @documented = @acl_skipped = @spi_skipped = 0\n      @undocumented_decls = []\n    end\n\n    def report\n      puts \"#{doc_coverage}% documentation coverage \" \\\n        \"with #{undocumented} undocumented \" \\\n        \"#{symbol_or_symbols(undocumented)}\"\n\n      if acl_included > 0\n        swift_acls = comma_list(config.min_acl.included_levels)\n        puts \"included #{acl_included} \" +\n             (config.objc_mode ? '' : \"#{swift_acls} \") +\n             symbol_or_symbols(acl_included)\n      end\n\n      if !config.objc_mode && acl_skipped > 0\n        puts \"skipped #{acl_skipped} \" \\\n          \"#{comma_list(config.min_acl.excluded_levels)} \" \\\n          \"#{symbol_or_symbols(acl_skipped)} \" \\\n          '(use `--min-acl` to specify a different minimum ACL)'\n      end\n\n      if spi_skipped > 0\n        puts \"skipped #{spi_skipped} SPI #{symbol_or_symbols(spi_skipped)} \" \\\n          '(use `--include-spi-declarations` to include these)'\n      end\n    end\n\n    def doc_coverage\n      return 0 if acl_included == 0\n\n      (100 * documented) / acl_included\n    end\n\n    private\n\n    def comma_list(items)\n      case items.count\n      when 0 then ''\n      when 1 then items[0]\n      when 2 then \"#{items[0]} or #{items[1]}\"\n      else \"#{items[0..-2].join(', ')}, or #{items[-1]}\"\n      end\n    end\n\n    def symbol_or_symbols(count)\n      count == 1 ? 'symbol' : 'symbols'\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/symbol_graph/constraint.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  module SymbolGraph\n    # Constraint is a tidied-up JSON object, used by both Symbol and\n    # Relationship, and key to reconstructing extensions.\n    class Constraint\n      attr_accessor :kind\n      attr_accessor :lhs\n      attr_accessor :rhs\n\n      private\n\n      def initialize(kind, lhs, rhs)\n        self.kind = kind # \"==\" or \":\"\n        self.lhs = lhs\n        self.rhs = rhs\n      end\n\n      KIND_MAP = {\n        'conformance' => ':',\n        'superclass' => ':',\n        'sameType' => '==',\n      }.freeze\n      private_constant :KIND_MAP\n\n      public\n\n      # Init from a JSON hash\n      def self.new_hash(hash)\n        kind = KIND_MAP[hash[:kind]]\n        raise \"Unknown constraint kind '#{kind}'\" unless kind\n\n        lhs = hash[:lhs].sub(/^Self\\./, '')\n        rhs = hash[:rhs].sub(/^Self\\./, '')\n        new(kind, lhs, rhs)\n      end\n\n      # Init from a Swift declaration fragment eg. 'A : B'\n      def self.new_declaration(decl)\n        decl =~ /^(.*?)\\s*([:<=]+)\\s*(.*)$/\n        new(Regexp.last_match[2],\n            Regexp.last_match[1],\n            Regexp.last_match[3])\n      end\n\n      def to_swift\n        \"#{lhs} #{kind} #{rhs}\"\n      end\n\n      # The first component of types in the constraint\n      def type_names\n        Set.new([lhs, rhs].map { |n| n.sub(/\\..*$/, '') })\n      end\n\n      def self.new_list(hash_list)\n        hash_list.map { |h| Constraint.new_hash(h) }.sort.uniq\n      end\n\n      # Swift protocols and reqs have an implementation/hidden conformance\n      # to their own protocol: we don't want to think about this in docs.\n      def self.new_list_for_symbol(hash_list, path_components)\n        hash_list.map do |hash|\n          if hash[:lhs] == 'Self' &&\n             hash[:kind] == 'conformance' &&\n             path_components.include?(hash[:rhs])\n            next nil\n          end\n\n          Constraint.new_hash(hash)\n        end.compact\n      end\n\n      # Workaround Swift 5.3 bug with missing constraint rels, eg.\n      # extension P {\n      #   func f<C>(a: C) where C: P {}\n      # }\n      def self.new_list_from_declaration(decl)\n        return [] if decl.include?('(')\n\n        decl.split(/\\s*,\\s*/).map { |cons| Constraint.new_declaration(cons) }\n      end\n\n      # Sort order - by Swift text\n      include Comparable\n\n      def <=>(other)\n        to_swift <=> other.to_swift\n      end\n\n      alias eql? ==\n\n      def hash\n        to_swift.hash\n      end\n    end\n  end\nend\n\nclass Array\n  def to_where_clause\n    empty? ? '' : \" where #{map(&:to_swift).join(', ')}\"\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/symbol_graph/ext_key.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  module SymbolGraph\n    # An ExtKey identifies an extension of a type, made up of the USR of\n    # the type and the constraints of the extension.  With Swift 5.9 extension\n    # symbols, the USR is the 'fake' USR invented by symbolgraph to solve the\n    # same problem as this type, which means less merging takes place.\n    class ExtKey\n      attr_accessor :usr\n      attr_accessor :constraints_text\n\n      def initialize(usr, constraints)\n        self.usr = usr\n        self.constraints_text = constraints.map(&:to_swift).join\n      end\n\n      def hash_key\n        usr + constraints_text\n      end\n\n      def eql?(other)\n        hash_key == other.hash_key\n      end\n\n      def hash\n        hash_key.hash\n      end\n    end\n\n    class ExtSymNode\n      def ext_key\n        ExtKey.new(usr, all_constraints.ext)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/symbol_graph/ext_node.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'set'\n\nmodule Jazzy\n  module SymbolGraph\n    # For extensions we need to track constraints of the extended type\n    # and the constraints introduced by the extension.\n    class ExtConstraints\n      attr_accessor :type # array\n      attr_accessor :ext # array\n\n      # all constraints inherited by members of the extension\n      def merged\n        (type + ext).sort\n      end\n\n      def initialize(type_constraints, ext_constraints)\n        self.type = type_constraints || []\n        self.ext = ext_constraints || []\n      end\n    end\n\n    # An ExtNode is a node of the reconstructed syntax tree representing\n    # an extension that we fabricate to resolve certain relationships.\n    class ExtNode < BaseNode\n      attr_accessor :usr\n      attr_accessor :real_usr\n      attr_accessor :name\n      attr_accessor :all_constraints # ExtConstraints\n      attr_accessor :conformances # set, can be empty\n\n      # Deduce an extension from a member of an unknown type or\n      # of known type with additional constraints\n      def self.new_for_member(type_usr,\n                              member,\n                              constraints)\n        new(type_usr,\n            member.parent_qualified_name,\n            constraints).tap { |o| o.add_child(member) }\n      end\n\n      # Deduce an extension from a protocol conformance for some type\n      def self.new_for_conformance(type_usr,\n                                   type_name,\n                                   protocol,\n                                   constraints)\n        new(type_usr, type_name, constraints).tap do |o|\n          o.add_conformance(protocol)\n        end\n      end\n\n      private\n\n      def initialize(usr, name, constraints)\n        self.usr = usr\n        self.name = name\n        self.all_constraints = constraints\n        self.conformances = Set.new\n        super()\n      end\n\n      public\n\n      def constraints\n        all_constraints.merged\n      end\n\n      def add_conformance(protocol)\n        conformances.add(protocol)\n      end\n\n      def full_declaration\n        decl = \"extension #{name}\"\n        unless conformances.empty?\n          decl += \" : #{conformances.sort.join(', ')}\"\n        end\n        decl + all_constraints.ext.to_where_clause\n      end\n\n      def to_sourcekit(module_name, ext_module_name)\n        declaration = full_declaration\n        xml_declaration = \"<swift>#{CGI.escapeHTML(declaration)}</swift>\"\n\n        hash = {\n          'key.kind' => 'source.lang.swift.decl.extension',\n          'key.usr' => real_usr || usr,\n          'key.name' => name,\n          'key.modulename' => ext_module_name,\n          'key.parsed_declaration' => declaration,\n          'key.annotated_decl' => xml_declaration,\n        }\n\n        unless conformances.empty?\n          hash['key.inheritedtypes'] = conformances.sort.map do |conformance|\n            { 'key.name' => conformance }\n          end\n        end\n\n        add_children_to_sourcekit(hash, module_name)\n\n        hash\n      end\n\n      # Sort order - by type name then constraint then conformances\n      # Conformance check needed for stable order with Swift 5.9\n      # extension symbols that can't merge as well as previously.\n      include Comparable\n\n      def sort_key\n        name + constraints.map(&:to_swift).join + conformances.sort.join\n      end\n\n      def <=>(other)\n        sort_key <=> other.sort_key\n      end\n    end\n\n    # An ExtSymNode is an extension generated from a Swift 5.9 extension\n    # symbol, for extensions of types from other modules only.\n    class ExtSymNode < ExtNode\n      attr_accessor :symbol\n\n      def initialize(symbol)\n        self.symbol = symbol\n        super(symbol.usr, symbol.full_name,\n              # sadly can't tell what constraints are inherited vs added\n              ExtConstraints.new([], symbol.constraints))\n      end\n\n      def to_sourcekit(module_name, ext_module_name)\n        hash = super\n        symbol.add_to_sourcekit(hash)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/symbol_graph/graph.rb",
    "content": "# frozen_string_literal: true\n\n# rubocop:disable Metrics/ClassLength\nmodule Jazzy\n  module SymbolGraph\n    # A Graph is the coordinator to import a symbolgraph json file.\n    # Deserialize it to Symbols and Relationships, then rebuild\n    # the AST shape using SymNodes and ExtNodes and extract SourceKit json.\n    class Graph\n      attr_accessor :module_name # Our module\n      attr_accessor :ext_module_name # Module being extended\n      attr_accessor :symbol_nodes # usr -> SymNode\n      attr_accessor :relationships # [Relationship]\n      attr_accessor :ext_nodes # (usr, constraints) -> ExtNode\n\n      # Parse the JSON into flat tables of data\n      def initialize(json, module_name, ext_module_name)\n        self.module_name = module_name\n        self.ext_module_name = ext_module_name\n        graph = JSON.parse(json, symbolize_names: true)\n\n        self.symbol_nodes = {}\n        self.ext_nodes = {}\n\n        graph[:symbols].each do |hash|\n          symbol = Symbol.new(hash)\n          if symbol.extension?\n            node = ExtSymNode.new(symbol)\n            ext_nodes[node.ext_key] = node\n          else\n            symbol_nodes[symbol.usr] = SymNode.new(symbol)\n          end\n        end\n\n        self.relationships =\n          graph[:relationships].map { |hash| Relationship.new(hash) }\n      end\n\n      # ExtNode index.  ExtKey (type USR, extension constraints) -> ExtNode.\n      # This minimizes the number of extensions\n\n      def add_ext_member(type_usr, member_node, constraints)\n        key = ExtKey.new(type_usr, constraints.ext)\n        if ext_node = ext_nodes[key]\n          ext_node.add_child(member_node)\n        else\n          ext_nodes[key] =\n            ExtNode.new_for_member(type_usr, member_node, constraints)\n        end\n      end\n\n      def add_ext_conformance(type_usr,\n                              type_name,\n                              protocol,\n                              constraints)\n        key = ExtKey.new(type_usr, constraints.ext)\n        if ext_node = ext_nodes[key]\n          ext_node.add_conformance(protocol)\n        else\n          ext_nodes[key] =\n            ExtNode.new_for_conformance(type_usr,\n                                        type_name,\n                                        protocol,\n                                        constraints)\n        end\n      end\n\n      # Increasingly desparate ways to find the name of the symbol\n      # at the target end of a relationship\n      def rel_target_name(rel, target_node)\n        target_node&.symbol&.name ||\n          rel.target_fallback ||\n          Jazzy::SymbolGraph.demangle(rel.target_usr)\n      end\n\n      # Same for the source end.  Less help from the tool here\n      def rel_source_name(rel, source_node)\n        source_node&.qualified_name ||\n          Jazzy::SymbolGraph.demangle(rel.source_usr)\n      end\n\n      # Protocol conformance is redundant if it's unconditional\n      # and already expressed in the type's declaration.\n      #\n      # Skip implementation-detail conformances.\n      def redundant_conformance?(rel, type, protocol)\n        return false unless type\n\n        (rel.constraints.empty? && type.conformance?(protocol)) ||\n          (type.actor? && rel.actor_protocol?)\n      end\n\n      # source is a member/protocol requirement of target\n      def rebuild_member(rel, source, target)\n        return unless source\n\n        source.protocol_requirement = rel.protocol_requirement?\n        constraints =\n          ExtConstraints.new(target&.constraints,\n                             source.unique_context_constraints(target))\n\n        # Add to its parent or invent an extension\n        unless target&.add_child?(source, constraints.ext)\n          add_ext_member(rel.target_usr, source, constraints)\n        end\n      end\n\n      # \"source : target\" either from type decl or ext decl\n      def rebuild_conformance(rel, source, target)\n        protocol_name = rel_target_name(rel, target)\n\n        return if redundant_conformance?(rel, source, protocol_name)\n\n        type_constraints = source&.constraints || []\n        constraints =\n          ExtConstraints.new(type_constraints,\n                             rel.constraints - type_constraints)\n\n        # Create an extension or enhance an existing one\n        add_ext_conformance(rel.source_usr,\n                            rel_source_name(rel, source),\n                            protocol_name,\n                            constraints)\n      end\n\n      # \"source is a default implementation of protocol requirement target\"\n      def rebuild_default_implementation(_rel, source, target)\n        return unless source\n\n        unless target &&\n               (target_parent = target.parent) &&\n               target_parent.is_a?(SymNode)\n          # Could probably figure this out with demangle, but...\n          warn \"Can't resolve membership of default implementation \" \\\n            \"#{source.symbol.usr}.\"\n          source.unlisted = true\n          return\n        end\n        constraints =\n          ExtConstraints.new(target_parent.constraints,\n                             source.unique_context_constraints(target_parent))\n\n        add_ext_member(target_parent.symbol.usr,\n                       source,\n                       constraints)\n      end\n\n      # \"source is a class that inherits from target\"\n      def rebuild_inherits(_rel, source, target)\n        if source && target\n          source.superclass_name = target.symbol.name\n        end\n      end\n\n      # \"References to fake_usr should be real_usr\"\n      def unalias_extensions(fake_usr, real_usr)\n        ext_nodes.each_pair do |key, ext|\n          if key.usr == fake_usr\n            ext.real_usr = real_usr\n          end\n        end\n      end\n\n      # Process a structural relationship to link nodes\n      def rebuild_rel(rel)\n        source = symbol_nodes[rel.source_usr]\n        target = symbol_nodes[rel.target_usr]\n\n        case rel.kind\n        when :memberOf, :optionalRequirementOf, :requirementOf\n          rebuild_member(rel, source, target)\n\n        when :conformsTo\n          rebuild_conformance(rel, source, target)\n\n        when :defaultImplementationOf\n          rebuild_default_implementation(rel, source, target)\n\n        when :inheritsFrom\n          rebuild_inherits(rel, source, target)\n\n        when :extensionTo\n          unalias_extensions(rel.source_usr, rel.target_usr)\n        end\n\n        # don't seem to care about:\n        # - overrides: not bothered, also unimplemented for protocols\n      end\n\n      # Rebuild the AST structure  and convert to SourceKit\n      def to_sourcekit\n        relationships.sort.each { |r| rebuild_rel(r) }\n\n        root_symbol_nodes =\n          symbol_nodes.values\n            .select(&:top_level_decl?)\n            .sort\n            .map { |n| n.to_sourcekit(module_name) }\n\n        root_ext_nodes =\n          ext_nodes.values\n            .sort\n            .map { |n| n.to_sourcekit(module_name, ext_module_name) }\n        {\n          'key.diagnostic_stage' => 'parse',\n          'key.substructure' => root_symbol_nodes + root_ext_nodes,\n        }\n      end\n    end\n  end\nend\n# rubocop:enable Metrics/ClassLength\n"
  },
  {
    "path": "lib/jazzy/symbol_graph/relationship.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  module SymbolGraph\n    # A Relationship is a tidied-up SymbolGraph JSON object\n    class Relationship\n      attr_accessor :kind\n      attr_accessor :source_usr\n      attr_accessor :target_usr\n      attr_accessor :target_fallback # can be nil\n      attr_accessor :constraints # array, can be empty\n\n      # Order matters: defaultImplementationOf after the protocols\n      # have been defined; extensionTo after all the extensions have\n      # been discovered.\n      KINDS = %w[memberOf conformsTo overrides inheritsFrom\n                 requirementOf optionalRequirementOf\n                 defaultImplementationOf extensionTo].freeze\n\n      KINDS_INDEX = KINDS.to_h { |i| [i.to_sym, KINDS.index(i)] }.freeze\n\n      def protocol_requirement?\n        %i[requirementOf optionalRequirementOf].include? kind\n      end\n\n      def default_implementation?\n        kind == :defaultImplementationOf\n      end\n\n      def extension_to?\n        kind == :extensionTo\n      end\n\n      # Protocol conformances added by compiler to actor decls that\n      # users aren't interested in.\n      def actor_protocol?\n        %w[Actor AnyActor Sendable].include?(target_fallback)\n      end\n\n      def initialize(hash)\n        kind = hash[:kind]\n        unless KINDS.include?(kind)\n          raise \"Unknown relationship kind '#{kind}'\"\n        end\n\n        self.kind = kind.to_sym\n        self.source_usr = hash[:source]\n        self.target_usr = hash[:target]\n        if fallback = hash[:targetFallback]\n          # Strip the leading module name\n          self.target_fallback = fallback.sub(/^.*?\\./, '')\n        end\n        self.constraints = Constraint.new_list(hash[:swiftConstraints] || [])\n      end\n\n      # Sort order\n      include Comparable\n\n      def <=>(other)\n        return 0 if kind == other.kind\n\n        KINDS_INDEX[kind] <=> KINDS_INDEX[other.kind]\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/symbol_graph/sym_node.rb",
    "content": "# frozen_string_literal: true\n\nmodule Jazzy\n  module SymbolGraph\n    # The rebuilt syntax tree is made of nodes that either match\n    # symbols or that we fabricate for extensions.  This is the common\n    # treeishness.\n    class BaseNode\n      attr_accessor :children # array, can be empty\n      attr_accessor :parent # can be nil\n\n      def initialize\n        self.children = []\n      end\n\n      def add_child(child)\n        child.parent = self\n        children.append(child)\n      end\n\n      def add_children_to_sourcekit(hash, module_name)\n        unless children.empty?\n          hash['key.substructure'] =\n            children.sort.map { |c| c.to_sourcekit(module_name) }\n        end\n      end\n    end\n\n    # A SymNode is a node of the reconstructed syntax tree holding a symbol.\n    # It can turn itself into SourceKit and helps decode extensions.\n    class SymNode < BaseNode\n      attr_accessor :symbol\n      attr_writer :override\n      attr_writer :protocol_requirement\n      attr_writer :unlisted\n      attr_accessor :superclass_name\n\n      def override?\n        @override\n      end\n\n      def protocol_requirement?\n        @protocol_requirement\n      end\n\n      def top_level_decl?\n        !@unlisted && parent.nil?\n      end\n\n      def initialize(symbol)\n        self.symbol = symbol\n        super()\n      end\n\n      def qualified_name\n        symbol.path_components.join('.')\n      end\n\n      def parent_qualified_name\n        symbol.path_components[0...-1].join('.')\n      end\n\n      def protocol?\n        symbol.kind.end_with?('protocol')\n      end\n\n      def actor?\n        symbol.kind.end_with?('actor')\n      end\n\n      def constraints\n        symbol.constraints\n      end\n\n      # Add another SymNode as a member if possible.\n      # It must go in an extension if either:\n      #  - it has different generic constraints to us; or\n      #  - we're a protocol and it's a default impl / ext method\n      def add_child?(node, unique_context_constraints)\n        unless unique_context_constraints.empty? &&\n               (!protocol? || node.protocol_requirement?)\n          return false\n        end\n\n        add_child(node)\n        true\n      end\n\n      # The `Constraint`s on this decl that are both:\n      # 1. Unique, ie. not just inherited from its context; and\n      # 2. Constraining the *context's* gen params rather than our own.\n      def unique_context_constraints(context)\n        return symbol.constraints unless context\n\n        new_generic_type_params =\n          symbol.generic_type_params - context.symbol.generic_type_params\n\n        (symbol.constraints - context.symbol.constraints)\n          .select { |con| con.type_names.disjoint?(new_generic_type_params) }\n      end\n\n      # Messy check whether we need to fabricate an extension for a protocol\n      # conformance: don't bother if it's already in the type declaration.\n      def conformance?(protocol)\n        return false unless symbol.declaration =~ /(?<=:).*?(?=(where|$))/\n\n        Regexp.last_match[0] =~ /\\b#{protocol}\\b/\n      end\n\n      # Generate the 'where' clause for the declaration\n      def where_clause\n        parent_constraints = parent&.constraints || []\n        (constraints - parent_constraints).to_where_clause\n      end\n\n      def inherits_clause\n        return '' unless superclass_name\n\n        \" : #{superclass_name}\"\n      end\n\n      # approximately...\n      def async?\n        symbol.declaration =~ /\\basync\\b[^)]*$/\n      end\n\n      def full_declaration\n        symbol.attributes\n          .append(symbol.declaration + inherits_clause + where_clause)\n          .join(\"\\n\")\n      end\n\n      def to_sourcekit(module_name)\n        declaration = full_declaration\n        xml_declaration = \"<swift>#{CGI.escapeHTML(declaration)}</swift>\"\n\n        hash = {\n          'key.kind' => symbol.kind,\n          'key.usr' => symbol.usr,\n          'key.name' => symbol.name,\n          'key.modulename' => module_name,\n          'key.parsed_declaration' => declaration,\n          'key.annotated_decl' => xml_declaration,\n          'key.symgraph_async' => async?,\n        }\n        if params = symbol.parameter_names\n          hash['key.doc.parameters'] =\n            params.map { |name| { 'name' => name } }\n        end\n        hash['key.symgraph_spi'] = true if symbol.spi\n\n        add_children_to_sourcekit(hash, module_name)\n        symbol.add_to_sourcekit(hash)\n      end\n\n      # Sort order - by symbol\n      include Comparable\n\n      def <=>(other)\n        symbol <=> other.symbol\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/symbol_graph/symbol.rb",
    "content": "# frozen_string_literal: true\n\n# rubocop:disable Metrics/ClassLength\nmodule Jazzy\n  module SymbolGraph\n    # A Symbol is a tidied-up SymbolGraph JSON object\n    class Symbol\n      attr_accessor :usr\n      attr_accessor :path_components\n      attr_accessor :declaration\n      attr_accessor :kind\n      attr_accessor :acl\n      attr_accessor :spi\n      attr_accessor :location # can be nil, keys :filename :line :character\n      attr_accessor :constraints # array, can be empty\n      attr_accessor :doc_comments # can be nil\n      attr_accessor :attributes # array, can be empty\n      attr_accessor :generic_type_params # set, can be empty\n      attr_accessor :parameter_names # array, can be nil\n\n      def name\n        path_components[-1] || '??'\n      end\n\n      def full_name\n        path_components.join('.')\n      end\n\n      def initialize(hash)\n        self.usr = hash[:identifier][:precise]\n        self.path_components = hash[:pathComponents]\n        raw_decl, keywords = parse_decl_fragments(hash[:declarationFragments])\n        init_kind(hash[:kind][:identifier], keywords)\n        init_declaration(raw_decl)\n        if func_signature = hash[:functionSignature]\n          init_func_signature(func_signature)\n        end\n        init_acl(hash[:accessLevel])\n        self.spi = hash[:spi]\n        if location = hash[:location]\n          init_location(location)\n        end\n        init_constraints(hash, raw_decl)\n        if comments_hash = hash[:docComment]\n          init_doc_comments(comments_hash)\n        end\n        init_attributes(hash[:availability] || [])\n        init_generic_type_params(hash)\n      end\n\n      def parse_decl_fragments(fragments)\n        decl = ''\n        keywords = Set.new\n        fragments.each do |frag|\n          decl += frag[:spelling]\n          keywords.add(frag[:spelling]) if frag[:kind] == 'keyword'\n        end\n        [decl, keywords]\n      end\n\n      # Repair problems with SymbolGraph's declprinter\n\n      def init_declaration(raw_decl)\n        # Too much 'Self.TypeName'; omitted arg labels look odd;\n        # duplicated constraints; swift 5.3 vs. master workaround\n        self.declaration = raw_decl\n          .gsub(/\\bSelf\\./, '')\n          .gsub(/(?<=\\(|, )_: /, '_ arg: ')\n          .gsub(/ where.*$/, '')\n        if kind == 'source.lang.swift.decl.class'\n          declaration.sub!(/\\s*:.*$/, '')\n        end\n      end\n\n      # Remember pieces of methods for later markdown parsing\n\n      def init_func_signature(func_signature)\n        self.parameter_names =\n          (func_signature[:parameters] || []).map { |h| h[:name] }\n      end\n\n      # Mapping SymbolGraph's declkinds to SourceKit\n\n      KIND_MAP = {\n        'class' => 'class',\n        'struct' => 'struct',\n        'enum' => 'enum',\n        'enum.case' => 'enumelement', # intentional\n        'protocol' => 'protocol',\n        'init' => 'function.constructor',\n        'deinit' => 'function.destructor',\n        'func.op' => 'function.operator',\n        'type.method' => 'function.method.class',\n        'static.method' => 'function.method.static',\n        'method' => 'function.method.instance',\n        'func' => 'function.free',\n        'type.property' => 'var.class',\n        'static.property' => 'var.static',\n        'property' => 'var.instance',\n        'var' => 'var.global',\n        'subscript' => 'function.subscript',\n        'type.subscript' => 'function.subscript',\n        'static.subscript' => 'function.subscript',\n        'typealias' => 'typealias',\n        'associatedtype' => 'associatedtype',\n        'actor' => 'actor',\n        'macro' => 'macro',\n        'extension' => 'extension',\n      }.freeze\n\n      # We treat 'static var' differently to 'class var'\n      # We treat actors as first-class entities\n      def adjust_kind_for_declaration(kind, keywords)\n        if kind == 'swift.class' && keywords.member?('actor')\n          return 'swift.actor'\n        end\n        return kind unless keywords.member?('static')\n\n        kind.gsub('type', 'static')\n      end\n\n      def init_kind(kind, keywords)\n        adjusted = adjust_kind_for_declaration(kind, keywords)\n        sourcekit_kind = KIND_MAP[adjusted.sub('swift.', '')]\n        raise \"Unknown symbol kind '#{kind}'\" unless sourcekit_kind\n\n        self.kind = \"source.lang.swift.decl.#{sourcekit_kind}\"\n      end\n\n      def extension?\n        kind.end_with?('extension')\n      end\n\n      # Mapping SymbolGraph's ACL to SourceKit\n\n      def init_acl(acl)\n        self.acl = \"source.lang.swift.accessibility.#{acl}\"\n      end\n\n      # Symbol location - only available for public+ decls\n\n      def init_location(loc_hash)\n        self.location = {}\n        location[:filename] = loc_hash[:uri].sub(%r{^file://}, '')\n        location[:line] = loc_hash[:position][:line]\n        location[:character] = loc_hash[:position][:character]\n      end\n\n      # Generic constraints: in one or both of two places.\n      # There can be duplicates; these are removed by `Constraint`.\n      def init_constraints(hash, raw_decl)\n        raw_constraints = %i[swiftGenerics swiftExtension].flat_map do |key|\n          next [] unless container = hash[key]\n\n          container[:constraints] || []\n        end\n\n        constraints =\n          Constraint.new_list_for_symbol(raw_constraints, path_components)\n        if raw_decl =~ / where (.*)$/\n          constraints +=\n            Constraint.new_list_from_declaration(Regexp.last_match[1])\n        end\n\n        self.constraints = constraints.sort.uniq\n      end\n\n      # Generic type params\n      def init_generic_type_params(hash)\n        self.generic_type_params = Set.new(\n          if (generics = hash[:swiftGenerics]) &&\n             (parameters = generics[:parameters])\n            parameters.map { |p| p[:name] }\n          else\n            []\n          end,\n        )\n      end\n\n      def init_doc_comments(comments_hash)\n        self.doc_comments = comments_hash[:lines]\n          .map { |l| l[:text] }\n          .join(\"\\n\")\n      end\n\n      # Availability\n      # Re-encode this as Swift.  Should really teach Jazzy about these,\n      # could maybe then do something smarter here.\n      def availability_attributes(avail_hash_list)\n        avail_hash_list.map do |avail|\n          str = '@available('\n          if avail[:isUnconditionallyDeprecated]\n            str += '*, deprecated'\n          elsif domain = avail[:domain]\n            str += domain\n            %i[introduced deprecated obsoleted].each do |event|\n              if version = avail[event]\n                str += \", #{event}: #{decode_version(version)}\"\n              end\n            end\n          else\n            warn \"Found confusing availability: #{avail}\"\n            next nil\n          end\n\n          str += \", message: \\\"#{avail[:message]}\\\"\" if avail[:message]\n          str += \", renamed: \\\"#{avail[:renamed]}\\\"\" if avail[:renamed]\n\n          str + ')'\n        end.compact\n      end\n\n      def decode_version(hash)\n        str = hash[:major].to_s\n        str += \".#{hash[:minor]}\" if hash[:minor]\n        str += \".#{hash[:patch]}\" if hash[:patch]\n        str\n      end\n\n      def spi_attributes\n        spi ? ['@_spi(Unknown)'] : []\n      end\n\n      def init_attributes(avail_hash_list)\n        self.attributes =\n          availability_attributes(avail_hash_list) + spi_attributes\n      end\n\n      # SourceKit common fields, shared by extension and regular symbols.\n      # Things we do not know for fabricated extensions.\n      def add_to_sourcekit(hash)\n        unless doc_comments.nil?\n          hash['key.doc.comment'] = doc_comments\n          hash['key.doc.full_as_xml'] = ''\n        end\n\n        hash['key.accessibility'] = acl\n\n        unless location.nil?\n          hash['key.filepath'] = location[:filename]\n          hash['key.doc.line'] = location[:line] + 1\n          hash['key.doc.column'] = location[:character] + 1\n        end\n\n        hash\n      end\n\n      # Sort order\n      include Comparable\n\n      def <=>(other)\n        # Things with location: order by file/line/column\n        # (pls tell what wheel i am reinventing :/)\n        if location && other_loc = other.location\n          if location[:filename] == other_loc[:filename]\n            if location[:line] == other_loc[:line]\n              return location[:character] <=> other_loc[:character]\n            end\n\n            return location[:line] <=> other_loc[:line]\n          end\n          return location[:filename] <=> other_loc[:filename]\n        end\n\n        # Things with a location before things without a location\n        return +1 if location.nil? && other.location\n        return -1 if location && other.location.nil?\n\n        # Things without a location: by name and then USR\n        return usr <=> other.usr if name == other.name\n\n        name <=> other.name\n      end\n    end\n  end\nend\n# rubocop:enable Metrics/ClassLength\n"
  },
  {
    "path": "lib/jazzy/symbol_graph.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'set'\nrequire 'jazzy/symbol_graph/graph'\nrequire 'jazzy/symbol_graph/constraint'\nrequire 'jazzy/symbol_graph/symbol'\nrequire 'jazzy/symbol_graph/relationship'\nrequire 'jazzy/symbol_graph/sym_node'\nrequire 'jazzy/symbol_graph/ext_node'\nrequire 'jazzy/symbol_graph/ext_key'\n\n# This is the top-level symbolgraph driver that deals with\n# figuring out arguments, running the tool, and loading the\n# results.\n\nmodule Jazzy\n  module SymbolGraph\n    # Find swift symbol graph files, either having been passed\n    # in directly, or generated by running`swift symbolgraph-extract`\n    # with configured args.\n    # Then parse the results, and return as JSON in SourceKit[ten]\n    # format.\n    def self.build(module_config)\n      if module_config.symbolgraph_directory.nil?\n        Dir.mktmpdir do |tmp_dir|\n          args = arguments(module_config, tmp_dir)\n\n          Executable.execute_command('swift',\n                                     args.unshift('symbolgraph-extract'),\n                                     true) # raise on error\n\n          parse_symbols(tmp_dir)\n        end\n      else\n        parse_symbols(module_config.symbolgraph_directory.to_s)\n      end\n    end\n\n    # Figure out the args to pass to symbolgraph-extract\n    def self.arguments(module_config, output_path)\n      if module_config.module_name.empty?\n        raise 'error: `--swift-build-tool symbolgraph` requires `--module`.'\n      end\n\n      user_args = module_config.build_tool_arguments.join\n\n      if user_args =~ /-(?:module-name|minimum-access-level|output-dir)/\n        raise 'error: `--build-tool-arguments` for ' \\\n          \"`--swift-build-tool symbolgraph` can't use `-module`, \" \\\n          '`-minimum-access-level`, or `-output-dir`.'\n      end\n\n      # Default set\n      args = [\n        '-module-name', module_config.module_name,\n        '-minimum-access-level', 'private',\n        '-output-dir', output_path,\n        '-skip-synthesized-members'\n      ]\n\n      # Things user can override\n      args += ['-sdk', sdk(module_config)] unless user_args =~ /-sdk/\n      args += ['-target', target] unless user_args =~ /-target/\n      args += ['-F', module_config.source_directory.to_s] unless user_args =~ /-F(?!s)/\n      args += ['-I', module_config.source_directory.to_s] unless user_args =~ /-I/\n\n      args + module_config.build_tool_arguments\n    end\n\n    # Parse the symbol files in the given directory\n    def self.parse_symbols(directory)\n      Dir[directory + '/*.symbols.json'].sort.map do |filename|\n        # The @ part is for extensions in our module (before the @)\n        # of types in another module (after the @).\n        File.basename(filename) =~ /(.*?)(@(.*?))?\\.symbols/\n        module_name = Regexp.last_match[1]\n        ext_module_name = Regexp.last_match[3] || module_name\n        json = File.read(filename)\n        {\n          filename =>\n            Graph.new(json, module_name, ext_module_name).to_sourcekit,\n        }\n      end.to_json\n    end\n\n    # Get the SDK path.  On !darwin this just isn't needed.\n    def self.sdk(module_config)\n      `xcrun --show-sdk-path --sdk #{module_config.sdk}`.chomp\n    end\n\n    # Guess a default LLVM target.  Feels like the tool should figure this\n    # out from sdk + the binary somehow?\n    def self.target\n      `swift -version` =~ /Target: (.*?)$/\n      Regexp.last_match[1] || 'x86_64-apple-macosx10.15'\n    end\n\n    # This is a last-ditch fallback for when symbolgraph doesn't\n    # provide a name - at least conforming external types to local\n    # protocols.\n    def self.demangle(usr)\n      args = %w[demangle -simplified -compact].append(usr.sub(/^s:/, 's'))\n      output, = Executable.execute_command('swift', args, true)\n      output.chomp\n    rescue StandardError\n      usr\n    end\n  end\nend\n"
  },
  {
    "path": "lib/jazzy/themes/apple/assets/css/highlight.css.scss",
    "content": "/*! Jazzy - https://github.com/realm/jazzy\n *  Copyright Realm Inc.\n *  SPDX-License-Identifier: MIT\n */\n/* Credit to https://gist.github.com/wataru420/2048287 */\n\n.highlight {\n  .c { color: #999988; font-style: italic } // Comment\n  .err { color: #a61717; background-color: #e3d2d2 } // Error\n  .k { color: #000000; font-weight: bold } // Keyword\n  .o { color: #000000; font-weight: bold } // Operator\n  .cm { color: #999988; font-style: italic } // Comment.Multiline\n  .cp { color: #999999; font-weight: bold } // Comment.Preproc\n  .c1 { color: #999988; font-style: italic } // Comment.Single\n  .cs { color: #999999; font-weight: bold; font-style: italic } // Comment.Special\n  .gd { color: #000000; background-color: #ffdddd } // Generic.Deleted\n  .gd .x { color: #000000; background-color: #ffaaaa } // Generic.Deleted.Specific\n  .ge { color: #000000; font-style: italic } // Generic.Emph\n  .gr { color: #aa0000 } // Generic.Error\n  .gh { color: #999999 } // Generic.Heading\n  .gi { color: #000000; background-color: #ddffdd } // Generic.Inserted\n  .gi .x { color: #000000; background-color: #aaffaa } // Generic.Inserted.Specific\n  .go { color: #888888 } // Generic.Output\n  .gp { color: #555555 } // Generic.Prompt\n  .gs { font-weight: bold } // Generic.Strong\n  .gu { color: #aaaaaa } // Generic.Subheading\n  .gt { color: #aa0000 } // Generic.Traceback\n  .kc { color: #000000; font-weight: bold } // Keyword.Constant\n  .kd { color: #000000; font-weight: bold } // Keyword.Declaration\n  .kp { color: #000000; font-weight: bold } // Keyword.Pseudo\n  .kr { color: #000000; font-weight: bold } // Keyword.Reserved\n  .kt { color: #445588; } // Keyword.Type\n  .m { color: #009999 } // Literal.Number\n  .s { color: #d14 } // Literal.String\n  .na { color: #008080 } // Name.Attribute\n  .nb { color: #0086B3 } // Name.Builtin\n  .nc { color: #445588; font-weight: bold } // Name.Class\n  .no { color: #008080 } // Name.Constant\n  .ni { color: #800080 } // Name.Entity\n  .ne { color: #990000; font-weight: bold } // Name.Exception\n  .nf { color: #990000; } // Name.Function\n  .nn { color: #555555 } // Name.Namespace\n  .nt { color: #000080 } // Name.Tag\n  .nv { color: #008080 } // Name.Variable\n  .ow { color: #000000; font-weight: bold } // Operator.Word\n  .w { color: #bbbbbb } // Text.Whitespace\n  .mf { color: #009999 } // Literal.Number.Float\n  .mh { color: #009999 } // Literal.Number.Hex\n  .mi { color: #009999 } // Literal.Number.Integer\n  .mo { color: #009999 } // Literal.Number.Oct\n  .sb { color: #d14 } // Literal.String.Backtick\n  .sc { color: #d14 } // Literal.String.Char\n  .sd { color: #d14 } // Literal.String.Doc\n  .s2 { color: #d14 } // Literal.String.Double\n  .se { color: #d14 } // Literal.String.Escape\n  .sh { color: #d14 } // Literal.String.Heredoc\n  .si { color: #d14 } // Literal.String.Interpol\n  .sx { color: #d14 } // Literal.String.Other\n  .sr { color: #009926 } // Literal.String.Regex\n  .s1 { color: #d14 } // Literal.String.Single\n  .ss { color: #990073 } // Literal.String.Symbol\n  .bp { color: #999999 } // Name.Builtin.Pseudo\n  .vc { color: #008080 } // Name.Variable.Class\n  .vg { color: #008080 } // Name.Variable.Global\n  .vi { color: #008080 } // Name.Variable.Instance\n  .il { color: #009999 } // Literal.Number.Integer.Long\n}\n"
  },
  {
    "path": "lib/jazzy/themes/apple/assets/css/jazzy.css.scss",
    "content": "/*! Jazzy - https://github.com/realm/jazzy\n *  Copyright Realm Inc.\n *  SPDX-License-Identifier: MIT\n */\n////////////////////////////////\n// Constants\n////////////////////////////////\n\n$bg_color: #414141;\n$doc_coverage_color: #999;\n$code_color: #777;\n$code_bg_color: #eee;\n$link_color: #0088cc;\n$white_color: #fff;\n$light_gray_bg_color: #f2f2f2;\n$declaration_bg_color: #f9f9f9;\n$sidebar_bg_color: #f9f9f9;\n$declaration_title_language_color: #4b8afb;\n\n$sidebar_width: 230px;\n$content_wrapper_width: 980px;\n$content_top_offset: 70px;\n$content_body_margin: 16px;\n$content_body_left_offset: $sidebar_width + $content_body_margin;\n$header_height: 32px;\n$breadcrumb_padding_top: 12px;\n\n$code_font: 0.95em Menlo, monospace;\n\n$gray_border_color: #e2e2e2;\n$gray_border: 1px solid $gray_border_color;\n$declaration_language_border: 5px solid #cde9f4;\n\n$aside_color: #aaa;\n$aside_border: 5px solid lighten($aside_color, 20%);\n$aside_warning_color: #ff0000;\n$aside_warning_border: 5px solid lighten($aside_warning_color, 20%);\n\n////////////////////////////////\n// Reset\n////////////////////////////////\n\nhtml, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td {\n  background: transparent;\n  border: 0;\n  margin: 0;\n  outline: 0;\n  padding: 0;\n  vertical-align: baseline;\n}\n\n////////////////////////////////\n// Global\n////////////////////////////////\n\nbody {\n  background-color: $light_gray_bg_color;\n  font-family: Helvetica, freesans, Arial, sans-serif;\n  font-size: 14px;\n  -webkit-font-smoothing: subpixel-antialiased;\n  word-wrap: break-word;\n}\n\n// Headers\n\nh1, h2, h3 {\n  margin-top: 0.8em;\n  margin-bottom: 0.3em;\n  font-weight: 100;\n  color: black;\n}\nh1 {\n  font-size: 2.5em;\n}\nh2 {\n  font-size: 2em;\n  border-bottom: $gray_border;\n}\nh4 {\n  font-size: 13px;\n  line-height: 1.5;\n  margin-top: 21px;\n}\nh5 {\n  font-size: 1.1em;\n}\nh6 {\n  font-size: 1.1em;\n  color: $code_color;\n}\n.section-name {\n  color: rgba(128,128,128,1);\n  display: block;\n  font-family: Helvetica;\n  font-size: 22px;\n  font-weight: 100;\n  margin-bottom: 15px;\n}\n\n// Code\n\npre, code {\n  font: $code_font;\n  color: $code_color;\n  word-wrap: normal;\n}\np code, li code {\n  background-color: $code_bg_color;\n  padding: 2px 4px;\n  border-radius: 4px;\n}\npre > code {\n  padding: 0;\n}\n\n// Links\n\na {\n  color: $link_color;\n  text-decoration: none;\n  code {\n    color: inherit;\n  }\n}\n\n// Lists\n\nul {\n  padding-left: 15px;\n}\nli {\n  line-height: 1.8em;\n}\n\n// Images\n\nimg {\n  max-width: 100%;\n}\n\n// Blockquotes\n\nblockquote {\n  margin-left: 0;\n  padding: 0 10px;\n  border-left: 4px solid #ccc;\n}\n\n// HRs\n\nhr {\n  height: 1px;\n  border: none;\n  background-color: $gray_border_color;\n}\n\n// Footnotes\n\n.footnote-ref {\n  display: inline-block;\n  scroll-margin-top: $content-top-offset;\n}\n\n.footnote-def {\n  scroll-margin-top: $content-top-offset;\n}\n\n// General Content Wrapper\n\n.content-wrapper {\n  margin: 0 auto;\n  width: $content_wrapper_width;\n}\n\n////////////////////////////////\n// Header & Top Breadcrumbs\n////////////////////////////////\n\nheader {\n  font-size: 0.85em;\n  line-height: $header_height;\n  background-color: $bg_color;\n  position: fixed;\n  width: 100%;\n  z-index: 3;\n  img {\n    padding-right: 6px;\n    vertical-align: -3px;\n    height: 16px;\n  }\n  a {\n    color: $white_color;\n  }\n  p {\n    float: left;\n    color: $doc_coverage_color;\n  }\n  .header-right {\n    float: right;\n    margin-left: 16px;\n  }\n}\n\n#breadcrumbs {\n  background-color: $light_gray_bg_color;\n  height: $content_top_offset - $header_height - $breadcrumb_padding_top;\n  padding-top: $breadcrumb_padding_top;\n  position: fixed;\n  width: inherit;\n  z-index: 2;\n  margin-top: $header_height;\n  white-space: nowrap;\n  overflow-x: scroll;\n  #carat {\n    height: 10px;\n    margin: 0 5px;\n  }\n}\n\n////////////////////////////////\n// Side Navigation\n////////////////////////////////\n\n.sidebar {\n  background-color: $sidebar_bg_color;\n  border: $gray_border;\n  overflow-y: auto;\n  overflow-x: hidden;\n  position: fixed;\n  top: $content_top_offset;\n  bottom: 0;\n  width: $sidebar_width;\n  word-wrap: normal;\n}\n\n.nav-groups {\n  list-style-type: none;\n  background: $white_color;\n  padding-left: 0;\n}\n\n.nav-group-name {\n  border-bottom: $gray_border;\n  font-size: 1.1em;\n  font-weight: 100;\n  padding: 15px 0 15px 20px;\n  > a {\n    color: #333;\n  }\n}\n\n.nav-group-tasks {\n  margin-top: 5px;\n}\n\n.nav-group-task {\n  font-size: 0.9em;\n  list-style-type: none;\n  white-space: nowrap;\n  a {\n    color: #888;\n  }\n}\n\n////////////////////////////////\n// Main Content\n////////////////////////////////\n\n.main-content {\n  background-color: $white_color;\n  border: $gray_border;\n  margin-left: $content_body_left_offset;\n  position: absolute;\n  overflow: hidden;\n  padding-bottom: 20px;\n  top: $content_top_offset;\n  width: $content_wrapper_width - $content_body_left_offset;\n  p, a, code, em, ul, table, blockquote {\n    margin-bottom: 1em;\n  }\n  p {\n    line-height: 1.8em;\n  }\n  section {\n    .section:first-child {\n      margin-top: 0;\n      padding-top: 0;\n    }\n\n    .task-group-section .task-group:first-of-type {\n      padding-top: 10px;\n\n      .section-name {\n        padding-top: 15px;\n      }\n    }\n\n    .heading:before {\n      content: \"\";\n      display: block;\n      padding-top: $content_top_offset;\n      margin: -$content_top_offset 0 0;\n    }\n  }\n  .section-name {\n    p {\n       margin-bottom: inherit;\n       line-height: inherit;\n    }\n    code {\n      background-color: inherit;\n      padding: inherit;\n      color: inherit;\n    }\n  }\n}\n\n.section {\n  padding: 0 25px;\n}\n\n.highlight {\n  background-color: $code_bg_color;\n  padding: 10px 12px;\n  border: $gray_border;\n  border-radius: 4px;\n  overflow-x: auto;\n}\n\n.declaration .highlight {\n  overflow-x: initial; // This allows the scrollbar to show up inside declarations\n  padding: 0 40px 40px 0;\n  margin-bottom: -25px;\n  background-color: transparent;\n  border: none;\n}\n\n.section-name {\n  margin: 0;\n  margin-left: 18px;\n}\n\n.task-group-section {\n  margin-top: 10px;\n  padding-left: 6px;\n  border-top: $gray_border;\n}\n\n.task-group {\n  padding-top: 0px;\n}\n\n.task-name-container {\n  a[name] {\n    &:before {\n      content: \"\";\n      display: block;\n      padding-top: $content_top_offset;\n      margin: -$content_top_offset 0 0;\n    }\n  }\n}\n\n.section-name-container {\n  position: relative;\n  display: inline-block;\n\n  .section-name-link {\n    position: absolute;\n    top: 0;\n    left: 0;\n    bottom: 0;\n    right: 0;\n    margin-bottom: 0;\n  }\n\n  .section-name {\n    position: relative;\n    pointer-events: none;\n    z-index: 1;\n    a {\n      pointer-events: auto;\n    }\n  }\n}\n\n.item {\n  padding-top: 8px;\n  width: 100%;\n  list-style-type: none;\n  a[name] {\n    &:before {\n      content: \"\";\n      display: block;\n      padding-top: $content_top_offset;\n      margin: -$content_top_offset 0 0;\n    }\n  }\n  code {\n    background-color: transparent;\n    padding: 0;\n  }\n  .token, .direct-link {\n    display: inline-block;\n    text-indent: -20px;\n    padding-left: 3px;\n    margin-left: 35px;\n    font-size: 11.9px;\n    transition: all 300ms;\n  }\n  .token-open {\n    margin-left: 20px;\n  }\n  .discouraged {\n    text-decoration: line-through;\n  }\n}\n\n.declaration-note {\n  font-size: .85em;\n  color: rgba(128,128,128,1);\n  font-style: italic;\n}\n\n.pointer-container {\n  border-bottom: $gray_border;\n  left: -23px;\n  padding-bottom: 13px;\n  position: relative;\n  width: 110%;\n}\n\n.pointer {\n  background: $declaration_bg_color;\n  border-left: $gray_border;\n  border-top: $gray_border;\n  height: 12px;\n  left: 21px;\n  top: -7px;\n  -webkit-transform: rotate(45deg);\n  -moz-transform: rotate(45deg);\n  -o-transform: rotate(45deg);\n  transform: rotate(45deg);\n  position: absolute;\n  width: 12px;\n}\n\n.height-container {\n  display: none;\n  left: -25px;\n  padding: 0 25px;\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n  .section {\n    background: $declaration_bg_color;\n    border-bottom: $gray_border;\n    left: -25px;\n    position: relative;\n    width: 100%;\n    padding-top: 10px;\n    padding-bottom: 5px;\n  }\n}\n\n.aside, .language {\n  padding: 6px 12px;\n  margin: 12px 0;\n  border-left: $aside_border;\n  overflow-y: hidden;\n  .aside-title {\n    font-size: 9px;\n    letter-spacing: 2px;\n    text-transform: uppercase;\n    padding-bottom: 0;\n    margin: 0;\n    color: $aside_color;\n    -webkit-user-select: none;\n  }\n  p:last-child {\n    margin-bottom: 0;\n  }\n}\n\n.language {\n  border-left: $declaration_language_border;\n  .aside-title {\n    color: $declaration_title_language_color;\n  }\n}\n\n.aside-warning, .aside-deprecated, .aside-unavailable {\n  border-left: $aside_warning_border;\n  .aside-title {\n    color: $aside_warning_color;\n  }\n}\n\n.graybox {\n  border-collapse: collapse;\n  width: 100%;\n  p {\n    margin: 0;\n    word-break: break-word;\n    min-width: 50px;\n  }\n  td {\n    border: $gray_border;\n    padding: 5px 25px 5px 10px;\n    vertical-align: middle;\n  }\n  tr td:first-of-type {\n    text-align: right;\n    padding: 7px;\n    vertical-align: top;\n    word-break: normal;\n    width: 40px;\n  }\n}\n\n.slightly-smaller {\n  font-size: 0.9em;\n}\n\n#footer {\n  position: relative;\n  top: 10px;\n  bottom: 0px;\n  margin-left: 25px;\n  p {\n    margin: 0;\n    color: #aaa;\n    font-size: 0.8em;\n  }\n}\n\n////////////////////////////////\n// Dash\n////////////////////////////////\n\nhtml.dash {\n  header, #breadcrumbs, .sidebar {\n    display: none;\n  }\n  .main-content {\n    width: $content_wrapper_width;\n    margin-left: 0;\n    border: none;\n    width: 100%;\n    top: 0;\n    padding-bottom: 0;\n  }\n  .height-container {\n    display: block;\n  }\n  .item .token {\n    margin-left: 0;\n  }\n  .content-wrapper {\n    width: auto;\n  }\n  #footer {\n    position: static;\n  }\n}\n\n// ===========================================================================\n//\n//  Search\n//\n// ===========================================================================\nform[role=search] {\n  float: right;\n\n  input {\n    font: Helvetica, freesans, Arial, sans-serif;\n    margin-top: 6px;\n    font-size: 13px;\n    line-height: 20px;\n    padding: 0px 10px;\n    border: none;\n    border-radius: 1em;\n    .loading & {\n      background: white url(../img/spinner.gif) center right 4px no-repeat;\n    }\n  }\n\n  // Typeahead elements\n\n  .tt-menu {\n    margin: 0;\n    min-width: 300px;\n    background: $white_color;\n    color: #333;\n    border: $gray_border;\n    z-index: 4;\n  }\n\n  .tt-highlight {\n    font-weight: bold;\n  }\n\n  .tt-suggestion {\n    font: Helvetica, freesans, Arial, sans-serif;\n    font-size: 14px;\n    padding: 0 8px;\n    span {\n      display: table-cell;\n      white-space: nowrap;\n    }\n    .doc-parent-name {\n      width: 100%;\n      text-align: right;\n      font-weight: normal;\n      font-size: 0.9em;\n      padding-left: 16px;\n    }\n  }\n\n  .tt-suggestion:hover,\n  .tt-suggestion.tt-cursor {\n    cursor: pointer;\n    background-color: #4183c4;\n    color: #fff;\n  }\n\n  .tt-suggestion:hover .doc-parent-name,\n  .tt-suggestion.tt-cursor .doc-parent-name {\n    color: #fff;\n  }\n}\n"
  },
  {
    "path": "lib/jazzy/themes/apple/assets/js/jazzy.js",
    "content": "// Jazzy - https://github.com/realm/jazzy\n// Copyright Realm Inc.\n// SPDX-License-Identifier: MIT\n\nwindow.jazzy = {'docset': false}\nif (typeof window.dash != 'undefined') {\n  document.documentElement.className += ' dash'\n  window.jazzy.docset = true\n}\nif (navigator.userAgent.match(/xcode/i)) {\n  document.documentElement.className += ' xcode'\n  window.jazzy.docset = true\n}\n\nfunction toggleItem($link, $content) {\n  var animationDuration = 300;\n  $link.toggleClass('token-open');\n  $content.slideToggle(animationDuration);\n}\n\nfunction itemLinkToContent($link) {\n  return $link.parent().parent().next();\n}\n\n// On doc load + hash-change, open any targeted item\nfunction openCurrentItemIfClosed() {\n  if (window.jazzy.docset) {\n    return;\n  }\n  var $link = $(`a[name=\"${location.hash.substring(1)}\"]`).nextAll('.token');\n  $content = itemLinkToContent($link);\n  if ($content.is(':hidden')) {\n    toggleItem($link, $content);\n  }\n}\n\n$(openCurrentItemIfClosed);\n$(window).on('hashchange', openCurrentItemIfClosed);\n\n// On item link ('token') click, toggle its discussion\n$('.token').on('click', function(event) {\n  if (window.jazzy.docset) {\n    return;\n  }\n  var $link = $(this);\n  toggleItem($link, itemLinkToContent($link));\n\n  // Keeps the document from jumping to the hash.\n  var href = $link.attr('href');\n  if (history.pushState) {\n    history.pushState({}, '', href);\n  } else {\n    location.hash = href;\n  }\n  event.preventDefault();\n});\n\n// Clicks on links to the current, closed, item need to open the item\n$(\"a:not('.token')\").on('click', function() {\n  if (location == this.href) {\n    openCurrentItemIfClosed();\n  }\n});\n\n// KaTeX rendering\nif (\"katex\" in window) {\n  $($('.math').each( (_, element) => {\n    katex.render(element.textContent, element, {\n      displayMode: $(element).hasClass('m-block'),\n      throwOnError: false,\n      trust: true\n    });\n  }))\n}\n"
  },
  {
    "path": "lib/jazzy/themes/apple/assets/js/jazzy.search.js",
    "content": "// Jazzy - https://github.com/realm/jazzy\n// Copyright Realm Inc.\n// SPDX-License-Identifier: MIT\n\n$(function(){\n  var $typeahead = $('[data-typeahead]');\n  var $form = $typeahead.parents('form');\n  var searchURL = $form.attr('action');\n\n  function displayTemplate(result) {\n    return result.name;\n  }\n\n  function suggestionTemplate(result) {\n    var t = '<div class=\"list-group-item clearfix\">';\n    t += '<span class=\"doc-name\">' + result.name + '</span>';\n    if (result.parent_name) {\n     t += '<span class=\"doc-parent-name label\">' + result.parent_name + '</span>';\n    }\n    t += '</div>';\n    return t;\n  }\n\n  $typeahead.one('focus', function() {\n    $form.addClass('loading');\n\n    $.getJSON(searchURL).then(function(searchData) {\n      const searchIndex = lunr(function() {\n        this.ref('url');\n        this.field('name');\n        this.field('abstract');\n        for (const [url, doc] of Object.entries(searchData)) {\n          this.add({url: url, name: doc.name, abstract: doc.abstract});\n        }\n      });\n\n      $typeahead.typeahead(\n        {\n          highlight: true,\n          minLength: 3,\n          autoselect: true\n        },\n        {\n          limit: 10,\n          display: displayTemplate,\n          templates: { suggestion: suggestionTemplate },\n          source: function(query, sync) {\n            const lcSearch = query.toLowerCase();\n            const results = searchIndex.query(function(q) {\n                q.term(lcSearch, { boost: 100 });\n                q.term(lcSearch, {\n                  boost: 10,\n                  wildcard: lunr.Query.wildcard.TRAILING\n                });\n            }).map(function(result) {\n              var doc = searchData[result.ref];\n              doc.url = result.ref;\n              return doc;\n            });\n            sync(results);\n          }\n        }\n      );\n      $form.removeClass('loading');\n      $typeahead.trigger('focus');\n    });\n  });\n\n  var baseURL = searchURL.slice(0, -\"search.json\".length);\n\n  $typeahead.on('typeahead:select', function(e, result) {\n    window.location = baseURL + result.url;\n  });\n});\n"
  },
  {
    "path": "lib/jazzy/themes/apple/assets/js/typeahead.jquery.js",
    "content": "/*!\n * typeahead.js 1.3.3\n * https://github.com/corejavascript/typeahead.js\n * Copyright 2013-2024 Twitter, Inc. and other contributors; Licensed MIT\n */\n\n\n(function(root, factory) {\n    if (typeof define === \"function\" && define.amd) {\n        define([ \"jquery\" ], function(a0) {\n            return factory(a0);\n        });\n    } else if (typeof module === \"object\" && module.exports) {\n        module.exports = factory(require(\"jquery\"));\n    } else {\n        factory(root[\"jQuery\"]);\n    }\n})(this, function($) {\n    var _ = function() {\n        \"use strict\";\n        return {\n            isMsie: function() {\n                return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\\d+(.\\d+)?)/i)[2] : false;\n            },\n            isBlankString: function(str) {\n                return !str || /^\\s*$/.test(str);\n            },\n            escapeRegExChars: function(str) {\n                return str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\");\n            },\n            isString: function(obj) {\n                return typeof obj === \"string\";\n            },\n            isNumber: function(obj) {\n                return typeof obj === \"number\";\n            },\n            isArray: $.isArray,\n            isFunction: $.isFunction,\n            isObject: $.isPlainObject,\n            isUndefined: function(obj) {\n                return typeof obj === \"undefined\";\n            },\n            isElement: function(obj) {\n                return !!(obj && obj.nodeType === 1);\n            },\n            isJQuery: function(obj) {\n                return obj instanceof $;\n            },\n            toStr: function toStr(s) {\n                return _.isUndefined(s) || s === null ? \"\" : s + \"\";\n            },\n            bind: $.proxy,\n            each: function(collection, cb) {\n                $.each(collection, reverseArgs);\n                function reverseArgs(index, value) {\n                    return cb(value, index);\n                }\n            },\n            map: $.map,\n            filter: $.grep,\n            every: function(obj, test) {\n                var result = true;\n                if (!obj) {\n                    return result;\n                }\n                $.each(obj, function(key, val) {\n                    if (!(result = test.call(null, val, key, obj))) {\n                        return false;\n                    }\n                });\n                return !!result;\n            },\n            some: function(obj, test) {\n                var result = false;\n                if (!obj) {\n                    return result;\n                }\n                $.each(obj, function(key, val) {\n                    if (result = test.call(null, val, key, obj)) {\n                        return false;\n                    }\n                });\n                return !!result;\n            },\n            mixin: $.extend,\n            identity: function(x) {\n                return x;\n            },\n            clone: function(obj) {\n                return $.extend(true, {}, obj);\n            },\n            getIdGenerator: function() {\n                var counter = 0;\n                return function() {\n                    return counter++;\n                };\n            },\n            templatify: function templatify(obj) {\n                return $.isFunction(obj) ? obj : template;\n                function template() {\n                    return String(obj);\n                }\n            },\n            defer: function(fn) {\n                setTimeout(fn, 0);\n            },\n            debounce: function(func, wait, immediate) {\n                var timeout, result;\n                return function() {\n                    var context = this, args = arguments, later, callNow;\n                    later = function() {\n                        timeout = null;\n                        if (!immediate) {\n                            result = func.apply(context, args);\n                        }\n                    };\n                    callNow = immediate && !timeout;\n                    clearTimeout(timeout);\n                    timeout = setTimeout(later, wait);\n                    if (callNow) {\n                        result = func.apply(context, args);\n                    }\n                    return result;\n                };\n            },\n            throttle: function(func, wait) {\n                var context, args, timeout, result, previous, later;\n                previous = 0;\n                later = function() {\n                    previous = new Date();\n                    timeout = null;\n                    result = func.apply(context, args);\n                };\n                return function() {\n                    var now = new Date(), remaining = wait - (now - previous);\n                    context = this;\n                    args = arguments;\n                    if (remaining <= 0) {\n                        clearTimeout(timeout);\n                        timeout = null;\n                        previous = now;\n                        result = func.apply(context, args);\n                    } else if (!timeout) {\n                        timeout = setTimeout(later, remaining);\n                    }\n                    return result;\n                };\n            },\n            stringify: function(val) {\n                return _.isString(val) ? val : JSON.stringify(val);\n            },\n            guid: function() {\n                function _p8(s) {\n                    var p = (Math.random().toString(16) + \"000000000\").substr(2, 8);\n                    return s ? \"-\" + p.substr(0, 4) + \"-\" + p.substr(4, 4) : p;\n                }\n                return \"tt-\" + _p8() + _p8(true) + _p8(true) + _p8();\n            },\n            noop: function() {}\n        };\n    }();\n    var WWW = function() {\n        \"use strict\";\n        var defaultClassNames = {\n            wrapper: \"twitter-typeahead\",\n            input: \"tt-input\",\n            hint: \"tt-hint\",\n            menu: \"tt-menu\",\n            dataset: \"tt-dataset\",\n            suggestion: \"tt-suggestion\",\n            selectable: \"tt-selectable\",\n            empty: \"tt-empty\",\n            open: \"tt-open\",\n            cursor: \"tt-cursor\",\n            highlight: \"tt-highlight\"\n        };\n        return build;\n        function build(o) {\n            var www, classes;\n            classes = _.mixin({}, defaultClassNames, o);\n            www = {\n                css: buildCss(),\n                classes: classes,\n                html: buildHtml(classes),\n                selectors: buildSelectors(classes)\n            };\n            return {\n                css: www.css,\n                html: www.html,\n                classes: www.classes,\n                selectors: www.selectors,\n                mixin: function(o) {\n                    _.mixin(o, www);\n                }\n            };\n        }\n        function buildHtml(c) {\n            return {\n                wrapper: '<span class=\"' + c.wrapper + '\"></span>',\n                menu: '<div role=\"listbox\" class=\"' + c.menu + '\"></div>'\n            };\n        }\n        function buildSelectors(classes) {\n            var selectors = {};\n            _.each(classes, function(v, k) {\n                selectors[k] = \".\" + v;\n            });\n            return selectors;\n        }\n        function buildCss() {\n            var css = {\n                wrapper: {\n                    position: \"relative\",\n                    display: \"inline-block\"\n                },\n                hint: {\n                    position: \"absolute\",\n                    top: \"0\",\n                    left: \"0\",\n                    borderColor: \"transparent\",\n                    boxShadow: \"none\",\n                    opacity: \"1\"\n                },\n                input: {\n                    position: \"relative\",\n                    verticalAlign: \"top\",\n                    backgroundColor: \"transparent\"\n                },\n                inputWithNoHint: {\n                    position: \"relative\",\n                    verticalAlign: \"top\"\n                },\n                menu: {\n                    position: \"absolute\",\n                    top: \"100%\",\n                    left: \"0\",\n                    zIndex: \"100\",\n                    display: \"none\"\n                },\n                ltr: {\n                    left: \"0\",\n                    right: \"auto\"\n                },\n                rtl: {\n                    left: \"auto\",\n                    right: \" 0\"\n                }\n            };\n            if (_.isMsie()) {\n                _.mixin(css.input, {\n                    backgroundImage: \"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)\"\n                });\n            }\n            return css;\n        }\n    }();\n    var EventBus = function() {\n        \"use strict\";\n        var namespace, deprecationMap;\n        namespace = \"typeahead:\";\n        deprecationMap = {\n            render: \"rendered\",\n            cursorchange: \"cursorchanged\",\n            select: \"selected\",\n            autocomplete: \"autocompleted\"\n        };\n        function EventBus(o) {\n            if (!o || !o.el) {\n                $.error(\"EventBus initialized without el\");\n            }\n            this.$el = $(o.el);\n        }\n        _.mixin(EventBus.prototype, {\n            _trigger: function(type, args) {\n                var $e = $.Event(namespace + type);\n                this.$el.trigger.call(this.$el, $e, args || []);\n                return $e;\n            },\n            before: function(type) {\n                var args, $e;\n                args = [].slice.call(arguments, 1);\n                $e = this._trigger(\"before\" + type, args);\n                return $e.isDefaultPrevented();\n            },\n            trigger: function(type) {\n                var deprecatedType;\n                this._trigger(type, [].slice.call(arguments, 1));\n                if (deprecatedType = deprecationMap[type]) {\n                    this._trigger(deprecatedType, [].slice.call(arguments, 1));\n                }\n            }\n        });\n        return EventBus;\n    }();\n    var EventEmitter = function() {\n        \"use strict\";\n        var splitter = /\\s+/, nextTick = getNextTick();\n        return {\n            onSync: onSync,\n            onAsync: onAsync,\n            off: off,\n            trigger: trigger\n        };\n        function on(method, types, cb, context) {\n            var type;\n            if (!cb) {\n                return this;\n            }\n            types = types.split(splitter);\n            cb = context ? bindContext(cb, context) : cb;\n            this._callbacks = this._callbacks || {};\n            while (type = types.shift()) {\n                this._callbacks[type] = this._callbacks[type] || {\n                    sync: [],\n                    async: []\n                };\n                this._callbacks[type][method].push(cb);\n            }\n            return this;\n        }\n        function onAsync(types, cb, context) {\n            return on.call(this, \"async\", types, cb, context);\n        }\n        function onSync(types, cb, context) {\n            return on.call(this, \"sync\", types, cb, context);\n        }\n        function off(types) {\n            var type;\n            if (!this._callbacks) {\n                return this;\n            }\n            types = types.split(splitter);\n            while (type = types.shift()) {\n                delete this._callbacks[type];\n            }\n            return this;\n        }\n        function trigger(types) {\n            var type, callbacks, args, syncFlush, asyncFlush;\n            if (!this._callbacks) {\n                return this;\n            }\n            types = types.split(splitter);\n            args = [].slice.call(arguments, 1);\n            while ((type = types.shift()) && (callbacks = this._callbacks[type])) {\n                syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));\n                asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));\n                syncFlush() && nextTick(asyncFlush);\n            }\n            return this;\n        }\n        function getFlush(callbacks, context, args) {\n            return flush;\n            function flush() {\n                var cancelled;\n                for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {\n                    cancelled = callbacks[i].apply(context, args) === false;\n                }\n                return !cancelled;\n            }\n        }\n        function getNextTick() {\n            var nextTickFn;\n            if (window.setImmediate) {\n                nextTickFn = function nextTickSetImmediate(fn) {\n                    setImmediate(function() {\n                        fn();\n                    });\n                };\n            } else {\n                nextTickFn = function nextTickSetTimeout(fn) {\n                    setTimeout(function() {\n                        fn();\n                    }, 0);\n                };\n            }\n            return nextTickFn;\n        }\n        function bindContext(fn, context) {\n            return fn.bind ? fn.bind(context) : function() {\n                fn.apply(context, [].slice.call(arguments, 0));\n            };\n        }\n    }();\n    var highlight = function(doc) {\n        \"use strict\";\n        var defaults = {\n            node: null,\n            pattern: null,\n            tagName: \"strong\",\n            className: null,\n            wordsOnly: false,\n            caseSensitive: false,\n            diacriticInsensitive: false\n        };\n        var accented = {\n            A: \"[AaªÀ-Åà-åĀ-ąǍǎȀ-ȃȦȧᴬᵃḀḁẚẠ-ảₐ℀℁℻⒜Ⓐⓐ㍱-㍴㎀-㎄㎈㎉㎩-㎯㏂㏊㏟㏿Ａａ]\",\n            B: \"[BbᴮᵇḂ-ḇℬ⒝Ⓑⓑ㍴㎅-㎇㏃㏈㏔㏝Ｂｂ]\",\n            C: \"[CcÇçĆ-čᶜ℀ℂ℃℅℆ℭⅭⅽ⒞Ⓒⓒ㍶㎈㎉㎝㎠㎤㏄-㏇Ｃｃ]\",\n            D: \"[DdĎďǄ-ǆǱ-ǳᴰᵈḊ-ḓⅅⅆⅮⅾ⒟Ⓓⓓ㋏㍲㍷-㍹㎗㎭-㎯㏅㏈Ｄｄ]\",\n            E: \"[EeÈ-Ëè-ëĒ-ěȄ-ȇȨȩᴱᵉḘ-ḛẸ-ẽₑ℡ℯℰⅇ⒠Ⓔⓔ㉐㋍㋎Ｅｅ]\",\n            F: \"[FfᶠḞḟ℉ℱ℻⒡Ⓕⓕ㎊-㎌㎙ﬀ-ﬄＦｆ]\",\n            G: \"[GgĜ-ģǦǧǴǵᴳᵍḠḡℊ⒢Ⓖⓖ㋌㋍㎇㎍-㎏㎓㎬㏆㏉㏒㏿Ｇｇ]\",\n            H: \"[HhĤĥȞȟʰᴴḢ-ḫẖℋ-ℎ⒣Ⓗⓗ㋌㍱㎐-㎔㏊㏋㏗Ｈｈ]\",\n            I: \"[IiÌ-Ïì-ïĨ-İĲĳǏǐȈ-ȋᴵᵢḬḭỈ-ịⁱℐℑℹⅈⅠ-ⅣⅥ-ⅨⅪⅫⅰ-ⅳⅵ-ⅸⅺⅻ⒤Ⓘⓘ㍺㏌㏕ﬁﬃＩｉ]\",\n            J: \"[JjĲ-ĵǇ-ǌǰʲᴶⅉ⒥ⒿⓙⱼＪｊ]\",\n            K: \"[KkĶķǨǩᴷᵏḰ-ḵK⒦Ⓚⓚ㎄㎅㎉㎏㎑㎘㎞㎢㎦㎪㎸㎾㏀㏆㏍-㏏Ｋｋ]\",\n            L: \"[LlĹ-ŀǇ-ǉˡᴸḶḷḺ-ḽℒℓ℡Ⅼⅼ⒧Ⓛⓛ㋏㎈㎉㏐-㏓㏕㏖㏿ﬂﬄＬｌ]\",\n            M: \"[MmᴹᵐḾ-ṃ℠™ℳⅯⅿ⒨Ⓜⓜ㍷-㍹㎃㎆㎎㎒㎖㎙-㎨㎫㎳㎷㎹㎽㎿㏁㏂㏎㏐㏔-㏖㏘㏙㏞㏟Ｍｍ]\",\n            N: \"[NnÑñŃ-ŉǊ-ǌǸǹᴺṄ-ṋⁿℕ№⒩Ⓝⓝ㎁㎋㎚㎱㎵㎻㏌㏑Ｎｎ]\",\n            O: \"[OoºÒ-Öò-öŌ-őƠơǑǒǪǫȌ-ȏȮȯᴼᵒỌ-ỏₒ℅№ℴ⒪Ⓞⓞ㍵㏇㏒㏖Ｏｏ]\",\n            P: \"[PpᴾᵖṔ-ṗℙ⒫Ⓟⓟ㉐㍱㍶㎀㎊㎩-㎬㎰㎴㎺㏋㏗-㏚Ｐｐ]\",\n            Q: \"[Qqℚ⒬Ⓠⓠ㏃Ｑｑ]\",\n            R: \"[RrŔ-řȐ-ȓʳᴿᵣṘ-ṛṞṟ₨ℛ-ℝ⒭Ⓡⓡ㋍㍴㎭-㎯㏚㏛Ｒｒ]\",\n            S: \"[SsŚ-šſȘșˢṠ-ṣ₨℁℠⒮Ⓢⓢ㎧㎨㎮-㎳㏛㏜ﬆＳｓ]\",\n            T: \"[TtŢ-ťȚțᵀᵗṪ-ṱẗ℡™⒯Ⓣⓣ㉐㋏㎔㏏ﬅﬆＴｔ]\",\n            U: \"[UuÙ-Üù-üŨ-ųƯưǓǔȔ-ȗᵁᵘᵤṲ-ṷỤ-ủ℆⒰Ⓤⓤ㍳㍺Ｕｕ]\",\n            V: \"[VvᵛᵥṼ-ṿⅣ-Ⅷⅳ-ⅷ⒱Ⓥⓥⱽ㋎㍵㎴-㎹㏜㏞Ｖｖ]\",\n            W: \"[WwŴŵʷᵂẀ-ẉẘ⒲Ⓦⓦ㎺-㎿㏝Ｗｗ]\",\n            X: \"[XxˣẊ-ẍₓ℻Ⅸ-Ⅻⅸ-ⅻ⒳Ⓧⓧ㏓Ｘｘ]\",\n            Y: \"[YyÝýÿŶ-ŸȲȳʸẎẏẙỲ-ỹ⒴Ⓨⓨ㏉Ｙｙ]\",\n            Z: \"[ZzŹ-žǱ-ǳᶻẐ-ẕℤℨ⒵Ⓩⓩ㎐-㎔Ｚｚ]\"\n        };\n        return function hightlight(o) {\n            var regex;\n            o = _.mixin({}, defaults, o);\n            if (!o.node || !o.pattern) {\n                return;\n            }\n            o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];\n            regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly, o.diacriticInsensitive);\n            traverse(o.node, hightlightTextNode);\n            function hightlightTextNode(textNode) {\n                var match, patternNode, wrapperNode;\n                if (match = regex.exec(textNode.data)) {\n                    wrapperNode = doc.createElement(o.tagName);\n                    o.className && (wrapperNode.className = o.className);\n                    patternNode = textNode.splitText(match.index);\n                    patternNode.splitText(match[0].length);\n                    wrapperNode.appendChild(patternNode.cloneNode(true));\n                    textNode.parentNode.replaceChild(wrapperNode, patternNode);\n                }\n                return !!match;\n            }\n            function traverse(el, hightlightTextNode) {\n                var childNode, TEXT_NODE_TYPE = 3;\n                for (var i = 0; i < el.childNodes.length; i++) {\n                    childNode = el.childNodes[i];\n                    if (childNode.nodeType === TEXT_NODE_TYPE) {\n                        i += hightlightTextNode(childNode) ? 1 : 0;\n                    } else {\n                        traverse(childNode, hightlightTextNode);\n                    }\n                }\n            }\n        };\n        function accent_replacer(chr) {\n            return accented[chr.toUpperCase()] || chr;\n        }\n        function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensitive) {\n            var escapedPatterns = [], regexStr;\n            for (var i = 0, len = patterns.length; i < len; i++) {\n                var escapedWord = _.escapeRegExChars(patterns[i]);\n                if (diacriticInsensitive) {\n                    escapedWord = escapedWord.replace(/\\S/g, accent_replacer);\n                }\n                escapedPatterns.push(escapedWord);\n            }\n            regexStr = wordsOnly ? \"\\\\b(\" + escapedPatterns.join(\"|\") + \")\\\\b\" : \"(\" + escapedPatterns.join(\"|\") + \")\";\n            return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, \"i\");\n        }\n    }(window.document);\n    var Input = function() {\n        \"use strict\";\n        var specialKeyCodeMap;\n        specialKeyCodeMap = {\n            9: \"tab\",\n            27: \"esc\",\n            37: \"left\",\n            39: \"right\",\n            13: \"enter\",\n            38: \"up\",\n            40: \"down\"\n        };\n        function Input(o, www) {\n            var id;\n            o = o || {};\n            if (!o.input) {\n                $.error(\"input is missing\");\n            }\n            www.mixin(this);\n            this.$hint = $(o.hint);\n            this.$input = $(o.input);\n            this.$menu = $(o.menu);\n            id = this.$input.attr(\"id\") || _.guid();\n            this.$menu.attr(\"id\", id + \"_listbox\");\n            this.$hint.attr({\n                \"aria-hidden\": true\n            });\n            this.$input.attr({\n                \"aria-owns\": id + \"_listbox\",\n                \"aria-controls\": id + \"_listbox\",\n                role: \"combobox\",\n                \"aria-autocomplete\": \"list\",\n                \"aria-expanded\": false\n            });\n            this.query = this.$input.val();\n            this.queryWhenFocused = this.hasFocus() ? this.query : null;\n            this.$overflowHelper = buildOverflowHelper(this.$input);\n            this._checkLanguageDirection();\n            if (this.$hint.length === 0) {\n                this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;\n            }\n            this.onSync(\"cursorchange\", this._updateDescendent);\n        }\n        Input.normalizeQuery = function(str) {\n            return _.toStr(str).replace(/^\\s*/g, \"\").replace(/\\s{2,}/g, \" \");\n        };\n        _.mixin(Input.prototype, EventEmitter, {\n            _onBlur: function onBlur() {\n                this.resetInputValue();\n                this.trigger(\"blurred\");\n            },\n            _onFocus: function onFocus() {\n                this.queryWhenFocused = this.query;\n                this.trigger(\"focused\");\n            },\n            _onKeydown: function onKeydown($e) {\n                var keyName = specialKeyCodeMap[$e.which || $e.keyCode];\n                this._managePreventDefault(keyName, $e);\n                if (keyName && this._shouldTrigger(keyName, $e)) {\n                    this.trigger(keyName + \"Keyed\", $e);\n                }\n            },\n            _onInput: function onInput() {\n                this._setQuery(this.getInputValue());\n                this.clearHintIfInvalid();\n                this._checkLanguageDirection();\n            },\n            _managePreventDefault: function managePreventDefault(keyName, $e) {\n                var preventDefault;\n                switch (keyName) {\n                  case \"up\":\n                  case \"down\":\n                    preventDefault = !withModifier($e);\n                    break;\n\n                  default:\n                    preventDefault = false;\n                }\n                preventDefault && $e.preventDefault();\n            },\n            _shouldTrigger: function shouldTrigger(keyName, $e) {\n                var trigger;\n                switch (keyName) {\n                  case \"tab\":\n                    trigger = !withModifier($e);\n                    break;\n\n                  default:\n                    trigger = true;\n                }\n                return trigger;\n            },\n            _checkLanguageDirection: function checkLanguageDirection() {\n                var dir = (this.$input.css(\"direction\") || \"ltr\").toLowerCase();\n                if (this.dir !== dir) {\n                    this.dir = dir;\n                    this.$hint.attr(\"dir\", dir);\n                    this.trigger(\"langDirChanged\", dir);\n                }\n            },\n            _setQuery: function setQuery(val, silent) {\n                var areEquivalent, hasDifferentWhitespace;\n                areEquivalent = areQueriesEquivalent(val, this.query);\n                hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false;\n                this.query = val;\n                if (!silent && !areEquivalent) {\n                    this.trigger(\"queryChanged\", this.query);\n                } else if (!silent && hasDifferentWhitespace) {\n                    this.trigger(\"whitespaceChanged\", this.query);\n                }\n            },\n            _updateDescendent: function updateDescendent(event, id) {\n                this.$input.attr(\"aria-activedescendant\", id);\n            },\n            bind: function() {\n                var that = this, onBlur, onFocus, onKeydown, onInput;\n                onBlur = _.bind(this._onBlur, this);\n                onFocus = _.bind(this._onFocus, this);\n                onKeydown = _.bind(this._onKeydown, this);\n                onInput = _.bind(this._onInput, this);\n                this.$input.on(\"blur.tt\", onBlur).on(\"focus.tt\", onFocus).on(\"keydown.tt\", onKeydown);\n                if (!_.isMsie() || _.isMsie() > 9) {\n                    this.$input.on(\"input.tt\", onInput);\n                } else {\n                    this.$input.on(\"keydown.tt keypress.tt cut.tt paste.tt\", function($e) {\n                        if (specialKeyCodeMap[$e.which || $e.keyCode]) {\n                            return;\n                        }\n                        _.defer(_.bind(that._onInput, that, $e));\n                    });\n                }\n                return this;\n            },\n            focus: function focus() {\n                this.$input.focus();\n            },\n            blur: function blur() {\n                this.$input.blur();\n            },\n            getLangDir: function getLangDir() {\n                return this.dir;\n            },\n            getQuery: function getQuery() {\n                return this.query || \"\";\n            },\n            setQuery: function setQuery(val, silent) {\n                this.setInputValue(val);\n                this._setQuery(val, silent);\n            },\n            hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() {\n                return this.query !== this.queryWhenFocused;\n            },\n            getInputValue: function getInputValue() {\n                return this.$input.val();\n            },\n            setInputValue: function setInputValue(value) {\n                this.$input.val(value);\n                this.clearHintIfInvalid();\n                this._checkLanguageDirection();\n            },\n            resetInputValue: function resetInputValue() {\n                this.setInputValue(this.query);\n            },\n            getHint: function getHint() {\n                return this.$hint.val();\n            },\n            setHint: function setHint(value) {\n                this.$hint.val(value);\n            },\n            clearHint: function clearHint() {\n                this.setHint(\"\");\n            },\n            clearHintIfInvalid: function clearHintIfInvalid() {\n                var val, hint, valIsPrefixOfHint, isValid;\n                val = this.getInputValue();\n                hint = this.getHint();\n                valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;\n                isValid = val !== \"\" && valIsPrefixOfHint && !this.hasOverflow();\n                !isValid && this.clearHint();\n            },\n            hasFocus: function hasFocus() {\n                return this.$input.is(\":focus\");\n            },\n            hasOverflow: function hasOverflow() {\n                var constraint = this.$input.width() - 2;\n                this.$overflowHelper.text(this.getInputValue());\n                return this.$overflowHelper.width() >= constraint;\n            },\n            isCursorAtEnd: function() {\n                var valueLength, selectionStart, range;\n                valueLength = this.$input.val().length;\n                selectionStart = this.$input[0].selectionStart;\n                if (_.isNumber(selectionStart)) {\n                    return selectionStart === valueLength;\n                } else if (document.selection) {\n                    range = document.selection.createRange();\n                    range.moveStart(\"character\", -valueLength);\n                    return valueLength === range.text.length;\n                }\n                return true;\n            },\n            destroy: function destroy() {\n                this.$hint.off(\".tt\");\n                this.$input.off(\".tt\");\n                this.$overflowHelper.remove();\n                this.$hint = this.$input = this.$overflowHelper = $(\"<div>\");\n            },\n            setAriaExpanded: function setAriaExpanded(value) {\n                this.$input.attr(\"aria-expanded\", value);\n            }\n        });\n        return Input;\n        function buildOverflowHelper($input) {\n            return $('<pre aria-hidden=\"true\"></pre>').css({\n                position: \"absolute\",\n                visibility: \"hidden\",\n                whiteSpace: \"pre\",\n                fontFamily: $input.css(\"font-family\"),\n                fontSize: $input.css(\"font-size\"),\n                fontStyle: $input.css(\"font-style\"),\n                fontVariant: $input.css(\"font-variant\"),\n                fontWeight: $input.css(\"font-weight\"),\n                wordSpacing: $input.css(\"word-spacing\"),\n                letterSpacing: $input.css(\"letter-spacing\"),\n                textIndent: $input.css(\"text-indent\"),\n                textRendering: $input.css(\"text-rendering\"),\n                textTransform: $input.css(\"text-transform\")\n            }).insertAfter($input);\n        }\n        function areQueriesEquivalent(a, b) {\n            return Input.normalizeQuery(a) === Input.normalizeQuery(b);\n        }\n        function withModifier($e) {\n            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;\n        }\n    }();\n    var Dataset = function() {\n        \"use strict\";\n        var keys, nameGenerator;\n        keys = {\n            dataset: \"tt-selectable-dataset\",\n            val: \"tt-selectable-display\",\n            obj: \"tt-selectable-object\"\n        };\n        nameGenerator = _.getIdGenerator();\n        function Dataset(o, www) {\n            o = o || {};\n            o.templates = o.templates || {};\n            o.templates.notFound = o.templates.notFound || o.templates.empty;\n            if (!o.source) {\n                $.error(\"missing source\");\n            }\n            if (!o.node) {\n                $.error(\"missing node\");\n            }\n            if (o.name && !isValidName(o.name)) {\n                $.error(\"invalid dataset name: \" + o.name);\n            }\n            www.mixin(this);\n            this.highlight = !!o.highlight;\n            this.name = _.toStr(o.name || nameGenerator());\n            this.limit = o.limit || 5;\n            this.displayFn = getDisplayFn(o.display || o.displayKey);\n            this.templates = getTemplates(o.templates, this.displayFn);\n            this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source;\n            this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async;\n            this._resetLastSuggestion();\n            this.$el = $(o.node).attr(\"role\", \"presentation\").addClass(this.classes.dataset).addClass(this.classes.dataset + \"-\" + this.name);\n        }\n        Dataset.extractData = function extractData(el) {\n            var $el = $(el);\n            if ($el.data(keys.obj)) {\n                return {\n                    dataset: $el.data(keys.dataset) || \"\",\n                    val: $el.data(keys.val) || \"\",\n                    obj: $el.data(keys.obj) || null\n                };\n            }\n            return null;\n        };\n        _.mixin(Dataset.prototype, EventEmitter, {\n            _overwrite: function overwrite(query, suggestions) {\n                suggestions = suggestions || [];\n                if (suggestions.length) {\n                    this._renderSuggestions(query, suggestions);\n                } else if (this.async && this.templates.pending) {\n                    this._renderPending(query);\n                } else if (!this.async && this.templates.notFound) {\n                    this._renderNotFound(query);\n                } else {\n                    this._empty();\n                }\n                this.trigger(\"rendered\", suggestions, false, this.name);\n            },\n            _append: function append(query, suggestions) {\n                suggestions = suggestions || [];\n                if (suggestions.length && this.$lastSuggestion.length) {\n                    this._appendSuggestions(query, suggestions);\n                } else if (suggestions.length) {\n                    this._renderSuggestions(query, suggestions);\n                } else if (!this.$lastSuggestion.length && this.templates.notFound) {\n                    this._renderNotFound(query);\n                }\n                this.trigger(\"rendered\", suggestions, true, this.name);\n            },\n            _renderSuggestions: function renderSuggestions(query, suggestions) {\n                var $fragment;\n                $fragment = this._getSuggestionsFragment(query, suggestions);\n                this.$lastSuggestion = $fragment.children().last();\n                this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions));\n            },\n            _appendSuggestions: function appendSuggestions(query, suggestions) {\n                var $fragment, $lastSuggestion;\n                $fragment = this._getSuggestionsFragment(query, suggestions);\n                $lastSuggestion = $fragment.children().last();\n                this.$lastSuggestion.after($fragment);\n                this.$lastSuggestion = $lastSuggestion;\n            },\n            _renderPending: function renderPending(query) {\n                var template = this.templates.pending;\n                this._resetLastSuggestion();\n                template && this.$el.html(template({\n                    query: query,\n                    dataset: this.name\n                }));\n            },\n            _renderNotFound: function renderNotFound(query) {\n                var template = this.templates.notFound;\n                this._resetLastSuggestion();\n                template && this.$el.html(template({\n                    query: query,\n                    dataset: this.name\n                }));\n            },\n            _empty: function empty() {\n                this.$el.empty();\n                this._resetLastSuggestion();\n            },\n            _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) {\n                var that = this, fragment;\n                fragment = document.createDocumentFragment();\n                _.each(suggestions, function getSuggestionNode(suggestion) {\n                    var $el, context;\n                    context = that._injectQuery(query, suggestion);\n                    $el = $(that.templates.suggestion(context)).data(keys.dataset, that.name).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + \" \" + that.classes.selectable);\n                    fragment.appendChild($el[0]);\n                });\n                this.highlight && highlight({\n                    className: this.classes.highlight,\n                    node: fragment,\n                    pattern: query\n                });\n                return $(fragment);\n            },\n            _getFooter: function getFooter(query, suggestions) {\n                return this.templates.footer ? this.templates.footer({\n                    query: query,\n                    suggestions: suggestions,\n                    dataset: this.name\n                }) : null;\n            },\n            _getHeader: function getHeader(query, suggestions) {\n                return this.templates.header ? this.templates.header({\n                    query: query,\n                    suggestions: suggestions,\n                    dataset: this.name\n                }) : null;\n            },\n            _resetLastSuggestion: function resetLastSuggestion() {\n                this.$lastSuggestion = $();\n            },\n            _injectQuery: function injectQuery(query, obj) {\n                return _.isObject(obj) ? _.mixin({\n                    _query: query\n                }, obj) : obj;\n            },\n            update: function update(query) {\n                var that = this, canceled = false, syncCalled = false, rendered = 0;\n                this.cancel();\n                this.cancel = function cancel() {\n                    canceled = true;\n                    that.cancel = $.noop;\n                    that.async && that.trigger(\"asyncCanceled\", query, that.name);\n                };\n                this.source(query, sync, async);\n                !syncCalled && sync([]);\n                function sync(suggestions) {\n                    if (syncCalled) {\n                        return;\n                    }\n                    syncCalled = true;\n                    suggestions = (suggestions || []).slice(0, that.limit);\n                    rendered = suggestions.length;\n                    that._overwrite(query, suggestions);\n                    if (rendered < that.limit && that.async) {\n                        that.trigger(\"asyncRequested\", query, that.name);\n                    }\n                }\n                function async(suggestions) {\n                    suggestions = suggestions || [];\n                    if (!canceled && rendered < that.limit) {\n                        that.cancel = $.noop;\n                        var idx = Math.abs(rendered - that.limit);\n                        rendered += idx;\n                        that._append(query, suggestions.slice(0, idx));\n                        that.async && that.trigger(\"asyncReceived\", query, that.name);\n                    }\n                }\n            },\n            cancel: $.noop,\n            clear: function clear() {\n                this._empty();\n                this.cancel();\n                this.trigger(\"cleared\");\n            },\n            isEmpty: function isEmpty() {\n                return this.$el.is(\":empty\");\n            },\n            destroy: function destroy() {\n                this.$el = $(\"<div>\");\n            }\n        });\n        return Dataset;\n        function getDisplayFn(display) {\n            display = display || _.stringify;\n            return _.isFunction(display) ? display : displayFn;\n            function displayFn(obj) {\n                return obj[display];\n            }\n        }\n        function getTemplates(templates, displayFn) {\n            return {\n                notFound: templates.notFound && _.templatify(templates.notFound),\n                pending: templates.pending && _.templatify(templates.pending),\n                header: templates.header && _.templatify(templates.header),\n                footer: templates.footer && _.templatify(templates.footer),\n                suggestion: templates.suggestion ? userSuggestionTemplate : suggestionTemplate\n            };\n            function userSuggestionTemplate(context) {\n                var template = templates.suggestion;\n                return $(template(context)).attr(\"id\", _.guid());\n            }\n            function suggestionTemplate(context) {\n                return $('<div role=\"option\">').attr(\"id\", _.guid()).text(displayFn(context));\n            }\n        }\n        function isValidName(str) {\n            return /^[_a-zA-Z0-9-]+$/.test(str);\n        }\n    }();\n    var Menu = function() {\n        \"use strict\";\n        function Menu(o, www) {\n            var that = this;\n            o = o || {};\n            if (!o.node) {\n                $.error(\"node is required\");\n            }\n            www.mixin(this);\n            this.$node = $(o.node);\n            this.query = null;\n            this.datasets = _.map(o.datasets, initializeDataset);\n            function initializeDataset(oDataset) {\n                var node = that.$node.find(oDataset.node).first();\n                oDataset.node = node.length ? node : $(\"<div>\").appendTo(that.$node);\n                return new Dataset(oDataset, www);\n            }\n        }\n        _.mixin(Menu.prototype, EventEmitter, {\n            _onSelectableClick: function onSelectableClick($e) {\n                this.trigger(\"selectableClicked\", $($e.currentTarget));\n            },\n            _onRendered: function onRendered(type, dataset, suggestions, async) {\n                this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());\n                this.trigger(\"datasetRendered\", dataset, suggestions, async);\n            },\n            _onCleared: function onCleared() {\n                this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());\n                this.trigger(\"datasetCleared\");\n            },\n            _propagate: function propagate() {\n                this.trigger.apply(this, arguments);\n            },\n            _allDatasetsEmpty: function allDatasetsEmpty() {\n                return _.every(this.datasets, _.bind(function isDatasetEmpty(dataset) {\n                    var isEmpty = dataset.isEmpty();\n                    this.$node.attr(\"aria-expanded\", !isEmpty);\n                    return isEmpty;\n                }, this));\n            },\n            _getSelectables: function getSelectables() {\n                return this.$node.find(this.selectors.selectable);\n            },\n            _removeCursor: function _removeCursor() {\n                var $selectable = this.getActiveSelectable();\n                $selectable && $selectable.removeClass(this.classes.cursor);\n            },\n            _ensureVisible: function ensureVisible($el) {\n                var elTop, elBottom, nodeScrollTop, nodeHeight;\n                elTop = $el.position().top;\n                elBottom = elTop + $el.outerHeight(true);\n                nodeScrollTop = this.$node.scrollTop();\n                nodeHeight = this.$node.height() + parseInt(this.$node.css(\"paddingTop\"), 10) + parseInt(this.$node.css(\"paddingBottom\"), 10);\n                if (elTop < 0) {\n                    this.$node.scrollTop(nodeScrollTop + elTop);\n                } else if (nodeHeight < elBottom) {\n                    this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight));\n                }\n            },\n            bind: function() {\n                var that = this, onSelectableClick;\n                onSelectableClick = _.bind(this._onSelectableClick, this);\n                this.$node.on(\"click.tt\", this.selectors.selectable, onSelectableClick);\n                this.$node.on(\"mouseover\", this.selectors.selectable, function() {\n                    that.setCursor($(this));\n                });\n                this.$node.on(\"mouseleave\", function() {\n                    that._removeCursor();\n                });\n                _.each(this.datasets, function(dataset) {\n                    dataset.onSync(\"asyncRequested\", that._propagate, that).onSync(\"asyncCanceled\", that._propagate, that).onSync(\"asyncReceived\", that._propagate, that).onSync(\"rendered\", that._onRendered, that).onSync(\"cleared\", that._onCleared, that);\n                });\n                return this;\n            },\n            isOpen: function isOpen() {\n                return this.$node.hasClass(this.classes.open);\n            },\n            open: function open() {\n                this.$node.scrollTop(0);\n                this.$node.addClass(this.classes.open);\n            },\n            close: function close() {\n                this.$node.attr(\"aria-expanded\", false);\n                this.$node.removeClass(this.classes.open);\n                this._removeCursor();\n            },\n            setLanguageDirection: function setLanguageDirection(dir) {\n                this.$node.attr(\"dir\", dir);\n            },\n            selectableRelativeToCursor: function selectableRelativeToCursor(delta) {\n                var $selectables, $oldCursor, oldIndex, newIndex;\n                $oldCursor = this.getActiveSelectable();\n                $selectables = this._getSelectables();\n                oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1;\n                newIndex = oldIndex + delta;\n                newIndex = (newIndex + 1) % ($selectables.length + 1) - 1;\n                newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex;\n                return newIndex === -1 ? null : $selectables.eq(newIndex);\n            },\n            setCursor: function setCursor($selectable) {\n                this._removeCursor();\n                if ($selectable = $selectable && $selectable.first()) {\n                    $selectable.addClass(this.classes.cursor);\n                    this._ensureVisible($selectable);\n                }\n            },\n            getSelectableData: function getSelectableData($el) {\n                return $el && $el.length ? Dataset.extractData($el) : null;\n            },\n            getActiveSelectable: function getActiveSelectable() {\n                var $selectable = this._getSelectables().filter(this.selectors.cursor).first();\n                return $selectable.length ? $selectable : null;\n            },\n            getTopSelectable: function getTopSelectable() {\n                var $selectable = this._getSelectables().first();\n                return $selectable.length ? $selectable : null;\n            },\n            update: function update(query) {\n                var isValidUpdate = query !== this.query;\n                if (isValidUpdate) {\n                    this.query = query;\n                    _.each(this.datasets, updateDataset);\n                }\n                return isValidUpdate;\n                function updateDataset(dataset) {\n                    dataset.update(query);\n                }\n            },\n            empty: function empty() {\n                _.each(this.datasets, clearDataset);\n                this.query = null;\n                this.$node.addClass(this.classes.empty);\n                function clearDataset(dataset) {\n                    dataset.clear();\n                }\n            },\n            destroy: function destroy() {\n                this.$node.off(\".tt\");\n                this.$node = $(\"<div>\");\n                _.each(this.datasets, destroyDataset);\n                function destroyDataset(dataset) {\n                    dataset.destroy();\n                }\n            }\n        });\n        return Menu;\n    }();\n    var Status = function() {\n        \"use strict\";\n        function Status(options) {\n            this.$el = $(\"<span></span>\", {\n                role: \"status\",\n                \"aria-live\": \"polite\"\n            }).css({\n                position: \"absolute\",\n                padding: \"0\",\n                border: \"0\",\n                height: \"1px\",\n                width: \"1px\",\n                \"margin-bottom\": \"-1px\",\n                \"margin-right\": \"-1px\",\n                overflow: \"hidden\",\n                clip: \"rect(0 0 0 0)\",\n                \"white-space\": \"nowrap\"\n            });\n            options.$input.after(this.$el);\n            _.each(options.menu.datasets, _.bind(function(dataset) {\n                if (dataset.onSync) {\n                    dataset.onSync(\"rendered\", _.bind(this.update, this));\n                    dataset.onSync(\"cleared\", _.bind(this.cleared, this));\n                }\n            }, this));\n        }\n        _.mixin(Status.prototype, {\n            update: function update(event, suggestions) {\n                var length = suggestions.length;\n                var words;\n                if (length === 1) {\n                    words = {\n                        result: \"result\",\n                        is: \"is\"\n                    };\n                } else {\n                    words = {\n                        result: \"results\",\n                        is: \"are\"\n                    };\n                }\n                this.$el.text(length + \" \" + words.result + \" \" + words.is + \" available, use up and down arrow keys to navigate.\");\n            },\n            cleared: function() {\n                this.$el.text(\"\");\n            }\n        });\n        return Status;\n    }();\n    var DefaultMenu = function() {\n        \"use strict\";\n        var s = Menu.prototype;\n        function DefaultMenu() {\n            Menu.apply(this, [].slice.call(arguments, 0));\n        }\n        _.mixin(DefaultMenu.prototype, Menu.prototype, {\n            open: function open() {\n                !this._allDatasetsEmpty() && this._show();\n                return s.open.apply(this, [].slice.call(arguments, 0));\n            },\n            close: function close() {\n                this._hide();\n                return s.close.apply(this, [].slice.call(arguments, 0));\n            },\n            _onRendered: function onRendered() {\n                if (this._allDatasetsEmpty()) {\n                    this._hide();\n                } else {\n                    this.isOpen() && this._show();\n                }\n                return s._onRendered.apply(this, [].slice.call(arguments, 0));\n            },\n            _onCleared: function onCleared() {\n                if (this._allDatasetsEmpty()) {\n                    this._hide();\n                } else {\n                    this.isOpen() && this._show();\n                }\n                return s._onCleared.apply(this, [].slice.call(arguments, 0));\n            },\n            setLanguageDirection: function setLanguageDirection(dir) {\n                this.$node.css(dir === \"ltr\" ? this.css.ltr : this.css.rtl);\n                return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0));\n            },\n            _hide: function hide() {\n                this.$node.hide();\n            },\n            _show: function show() {\n                this.$node.css(\"display\", \"block\");\n            }\n        });\n        return DefaultMenu;\n    }();\n    var Typeahead = function() {\n        \"use strict\";\n        function Typeahead(o, www) {\n            var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged;\n            o = o || {};\n            if (!o.input) {\n                $.error(\"missing input\");\n            }\n            if (!o.menu) {\n                $.error(\"missing menu\");\n            }\n            if (!o.eventBus) {\n                $.error(\"missing event bus\");\n            }\n            www.mixin(this);\n            this.eventBus = o.eventBus;\n            this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;\n            this.input = o.input;\n            this.menu = o.menu;\n            this.enabled = true;\n            this.autoselect = !!o.autoselect;\n            this.active = false;\n            this.input.hasFocus() && this.activate();\n            this.dir = this.input.getLangDir();\n            this._hacks();\n            this.menu.bind().onSync(\"selectableClicked\", this._onSelectableClicked, this).onSync(\"asyncRequested\", this._onAsyncRequested, this).onSync(\"asyncCanceled\", this._onAsyncCanceled, this).onSync(\"asyncReceived\", this._onAsyncReceived, this).onSync(\"datasetRendered\", this._onDatasetRendered, this).onSync(\"datasetCleared\", this._onDatasetCleared, this);\n            onFocused = c(this, \"activate\", \"open\", \"_onFocused\");\n            onBlurred = c(this, \"deactivate\", \"_onBlurred\");\n            onEnterKeyed = c(this, \"isActive\", \"isOpen\", \"_onEnterKeyed\");\n            onTabKeyed = c(this, \"isActive\", \"isOpen\", \"_onTabKeyed\");\n            onEscKeyed = c(this, \"isActive\", \"_onEscKeyed\");\n            onUpKeyed = c(this, \"isActive\", \"open\", \"_onUpKeyed\");\n            onDownKeyed = c(this, \"isActive\", \"open\", \"_onDownKeyed\");\n            onLeftKeyed = c(this, \"isActive\", \"isOpen\", \"_onLeftKeyed\");\n            onRightKeyed = c(this, \"isActive\", \"isOpen\", \"_onRightKeyed\");\n            onQueryChanged = c(this, \"_openIfActive\", \"_onQueryChanged\");\n            onWhitespaceChanged = c(this, \"_openIfActive\", \"_onWhitespaceChanged\");\n            this.input.bind().onSync(\"focused\", onFocused, this).onSync(\"blurred\", onBlurred, this).onSync(\"enterKeyed\", onEnterKeyed, this).onSync(\"tabKeyed\", onTabKeyed, this).onSync(\"escKeyed\", onEscKeyed, this).onSync(\"upKeyed\", onUpKeyed, this).onSync(\"downKeyed\", onDownKeyed, this).onSync(\"leftKeyed\", onLeftKeyed, this).onSync(\"rightKeyed\", onRightKeyed, this).onSync(\"queryChanged\", onQueryChanged, this).onSync(\"whitespaceChanged\", onWhitespaceChanged, this).onSync(\"langDirChanged\", this._onLangDirChanged, this);\n        }\n        _.mixin(Typeahead.prototype, {\n            _hacks: function hacks() {\n                var $input, $menu;\n                $input = this.input.$input || $(\"<div>\");\n                $menu = this.menu.$node || $(\"<div>\");\n                $input.on(\"blur.tt\", function($e) {\n                    var active, isActive, hasActive;\n                    active = document.activeElement;\n                    isActive = $menu.is(active);\n                    hasActive = $menu.has(active).length > 0;\n                    if (_.isMsie() && (isActive || hasActive)) {\n                        $e.preventDefault();\n                        $e.stopImmediatePropagation();\n                        _.defer(function() {\n                            $input.focus();\n                        });\n                    }\n                });\n                $menu.on(\"mousedown.tt\", function($e) {\n                    $e.preventDefault();\n                });\n            },\n            _onSelectableClicked: function onSelectableClicked(type, $el) {\n                this.select($el);\n            },\n            _onDatasetCleared: function onDatasetCleared() {\n                this._updateHint();\n            },\n            _onDatasetRendered: function onDatasetRendered(type, suggestions, async, dataset) {\n                this._updateHint();\n                if (this.autoselect) {\n                    var cursorClass = this.selectors.cursor.substr(1);\n                    this.menu.$node.find(this.selectors.suggestion).first().addClass(cursorClass);\n                }\n                this.eventBus.trigger(\"render\", suggestions, async, dataset);\n            },\n            _onAsyncRequested: function onAsyncRequested(type, dataset, query) {\n                this.eventBus.trigger(\"asyncrequest\", query, dataset);\n            },\n            _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) {\n                this.eventBus.trigger(\"asynccancel\", query, dataset);\n            },\n            _onAsyncReceived: function onAsyncReceived(type, dataset, query) {\n                this.eventBus.trigger(\"asyncreceive\", query, dataset);\n            },\n            _onFocused: function onFocused() {\n                this._minLengthMet() && this.menu.update(this.input.getQuery());\n            },\n            _onBlurred: function onBlurred() {\n                if (this.input.hasQueryChangedSinceLastFocus()) {\n                    this.eventBus.trigger(\"change\", this.input.getQuery());\n                }\n            },\n            _onEnterKeyed: function onEnterKeyed(type, $e) {\n                var $selectable;\n                if ($selectable = this.menu.getActiveSelectable()) {\n                    if (this.select($selectable)) {\n                        $e.preventDefault();\n                        $e.stopPropagation();\n                    }\n                } else if (this.autoselect) {\n                    if (this.select(this.menu.getTopSelectable())) {\n                        $e.preventDefault();\n                        $e.stopPropagation();\n                    }\n                }\n            },\n            _onTabKeyed: function onTabKeyed(type, $e) {\n                var $selectable;\n                if ($selectable = this.menu.getActiveSelectable()) {\n                    this.select($selectable) && $e.preventDefault();\n                } else if (this.autoselect) {\n                    if ($selectable = this.menu.getTopSelectable()) {\n                        this.autocomplete($selectable) && $e.preventDefault();\n                    }\n                }\n            },\n            _onEscKeyed: function onEscKeyed() {\n                this.close();\n            },\n            _onUpKeyed: function onUpKeyed() {\n                this.moveCursor(-1);\n            },\n            _onDownKeyed: function onDownKeyed() {\n                this.moveCursor(+1);\n            },\n            _onLeftKeyed: function onLeftKeyed() {\n                if (this.dir === \"rtl\" && this.input.isCursorAtEnd()) {\n                    this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable());\n                }\n            },\n            _onRightKeyed: function onRightKeyed() {\n                if (this.dir === \"ltr\" && this.input.isCursorAtEnd()) {\n                    this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable());\n                }\n            },\n            _onQueryChanged: function onQueryChanged(e, query) {\n                this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty();\n            },\n            _onWhitespaceChanged: function onWhitespaceChanged() {\n                this._updateHint();\n            },\n            _onLangDirChanged: function onLangDirChanged(e, dir) {\n                if (this.dir !== dir) {\n                    this.dir = dir;\n                    this.menu.setLanguageDirection(dir);\n                }\n            },\n            _openIfActive: function openIfActive() {\n                this.isActive() && this.open();\n            },\n            _minLengthMet: function minLengthMet(query) {\n                query = _.isString(query) ? query : this.input.getQuery() || \"\";\n                return query.length >= this.minLength;\n            },\n            _updateHint: function updateHint() {\n                var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match;\n                $selectable = this.menu.getTopSelectable();\n                data = this.menu.getSelectableData($selectable);\n                val = this.input.getInputValue();\n                if (data && !_.isBlankString(val) && !this.input.hasOverflow()) {\n                    query = Input.normalizeQuery(val);\n                    escapedQuery = _.escapeRegExChars(query);\n                    frontMatchRegEx = new RegExp(\"^(?:\" + escapedQuery + \")(.+$)\", \"i\");\n                    match = frontMatchRegEx.exec(data.val);\n                    match && this.input.setHint(val + match[1]);\n                } else {\n                    this.input.clearHint();\n                }\n            },\n            isEnabled: function isEnabled() {\n                return this.enabled;\n            },\n            enable: function enable() {\n                this.enabled = true;\n            },\n            disable: function disable() {\n                this.enabled = false;\n            },\n            isActive: function isActive() {\n                return this.active;\n            },\n            activate: function activate() {\n                if (this.isActive()) {\n                    return true;\n                } else if (!this.isEnabled() || this.eventBus.before(\"active\")) {\n                    return false;\n                } else {\n                    this.active = true;\n                    this.eventBus.trigger(\"active\");\n                    return true;\n                }\n            },\n            deactivate: function deactivate() {\n                if (!this.isActive()) {\n                    return true;\n                } else if (this.eventBus.before(\"idle\")) {\n                    return false;\n                } else {\n                    this.active = false;\n                    this.close();\n                    this.eventBus.trigger(\"idle\");\n                    return true;\n                }\n            },\n            isOpen: function isOpen() {\n                return this.menu.isOpen();\n            },\n            open: function open() {\n                if (!this.isOpen() && !this.eventBus.before(\"open\")) {\n                    this.input.setAriaExpanded(true);\n                    this.menu.open();\n                    this._updateHint();\n                    this.eventBus.trigger(\"open\");\n                }\n                return this.isOpen();\n            },\n            close: function close() {\n                if (this.isOpen() && !this.eventBus.before(\"close\")) {\n                    this.input.setAriaExpanded(false);\n                    this.menu.close();\n                    this.input.clearHint();\n                    this.input.resetInputValue();\n                    this.eventBus.trigger(\"close\");\n                }\n                return !this.isOpen();\n            },\n            setVal: function setVal(val) {\n                this.input.setQuery(_.toStr(val));\n            },\n            getVal: function getVal() {\n                return this.input.getQuery();\n            },\n            select: function select($selectable) {\n                var data = this.menu.getSelectableData($selectable);\n                if (data && !this.eventBus.before(\"select\", data.obj, data.dataset)) {\n                    this.input.setQuery(data.val, true);\n                    this.eventBus.trigger(\"select\", data.obj, data.dataset);\n                    this.close();\n                    return true;\n                }\n                return false;\n            },\n            autocomplete: function autocomplete($selectable) {\n                var query, data, isValid;\n                query = this.input.getQuery();\n                data = this.menu.getSelectableData($selectable);\n                isValid = data && query !== data.val;\n                if (isValid && !this.eventBus.before(\"autocomplete\", data.obj, data.dataset)) {\n                    this.input.setQuery(data.val);\n                    this.eventBus.trigger(\"autocomplete\", data.obj, data.dataset);\n                    return true;\n                }\n                return false;\n            },\n            moveCursor: function moveCursor(delta) {\n                var query, $candidate, data, suggestion, datasetName, cancelMove, id;\n                query = this.input.getQuery();\n                $candidate = this.menu.selectableRelativeToCursor(delta);\n                data = this.menu.getSelectableData($candidate);\n                suggestion = data ? data.obj : null;\n                datasetName = data ? data.dataset : null;\n                id = $candidate ? $candidate.attr(\"id\") : null;\n                this.input.trigger(\"cursorchange\", id);\n                cancelMove = this._minLengthMet() && this.menu.update(query);\n                if (!cancelMove && !this.eventBus.before(\"cursorchange\", suggestion, datasetName)) {\n                    this.menu.setCursor($candidate);\n                    if (data) {\n                        if (typeof data.val === \"string\") {\n                            this.input.setInputValue(data.val);\n                        }\n                    } else {\n                        this.input.resetInputValue();\n                        this._updateHint();\n                    }\n                    this.eventBus.trigger(\"cursorchange\", suggestion, datasetName);\n                    return true;\n                }\n                return false;\n            },\n            destroy: function destroy() {\n                this.input.destroy();\n                this.menu.destroy();\n            }\n        });\n        return Typeahead;\n        function c(ctx) {\n            var methods = [].slice.call(arguments, 1);\n            return function() {\n                var args = [].slice.call(arguments);\n                _.each(methods, function(method) {\n                    return ctx[method].apply(ctx, args);\n                });\n            };\n        }\n    }();\n    (function() {\n        \"use strict\";\n        var old, keys, methods;\n        old = $.fn.typeahead;\n        keys = {\n            www: \"tt-www\",\n            attrs: \"tt-attrs\",\n            typeahead: \"tt-typeahead\"\n        };\n        methods = {\n            initialize: function initialize(o, datasets) {\n                var www;\n                datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);\n                o = o || {};\n                www = WWW(o.classNames);\n                return this.each(attach);\n                function attach() {\n                    var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, status, typeahead, MenuConstructor;\n                    _.each(datasets, function(d) {\n                        d.highlight = !!o.highlight;\n                    });\n                    $input = $(this);\n                    $wrapper = $(www.html.wrapper);\n                    $hint = $elOrNull(o.hint);\n                    $menu = $elOrNull(o.menu);\n                    defaultHint = o.hint !== false && !$hint;\n                    defaultMenu = o.menu !== false && !$menu;\n                    defaultHint && ($hint = buildHintFromInput($input, www));\n                    defaultMenu && ($menu = $(www.html.menu).css(www.css.menu));\n                    $hint && $hint.val(\"\");\n                    $input = prepInput($input, www);\n                    if (defaultHint || defaultMenu) {\n                        $wrapper.css(www.css.wrapper);\n                        $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint);\n                        $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null);\n                    }\n                    MenuConstructor = defaultMenu ? DefaultMenu : Menu;\n                    eventBus = new EventBus({\n                        el: $input\n                    });\n                    input = new Input({\n                        hint: $hint,\n                        input: $input,\n                        menu: $menu\n                    }, www);\n                    menu = new MenuConstructor({\n                        node: $menu,\n                        datasets: datasets\n                    }, www);\n                    status = new Status({\n                        $input: $input,\n                        menu: menu\n                    });\n                    typeahead = new Typeahead({\n                        input: input,\n                        menu: menu,\n                        eventBus: eventBus,\n                        minLength: o.minLength,\n                        autoselect: o.autoselect\n                    }, www);\n                    $input.data(keys.www, www);\n                    $input.data(keys.typeahead, typeahead);\n                }\n            },\n            isEnabled: function isEnabled() {\n                var enabled;\n                ttEach(this.first(), function(t) {\n                    enabled = t.isEnabled();\n                });\n                return enabled;\n            },\n            enable: function enable() {\n                ttEach(this, function(t) {\n                    t.enable();\n                });\n                return this;\n            },\n            disable: function disable() {\n                ttEach(this, function(t) {\n                    t.disable();\n                });\n                return this;\n            },\n            isActive: function isActive() {\n                var active;\n                ttEach(this.first(), function(t) {\n                    active = t.isActive();\n                });\n                return active;\n            },\n            activate: function activate() {\n                ttEach(this, function(t) {\n                    t.activate();\n                });\n                return this;\n            },\n            deactivate: function deactivate() {\n                ttEach(this, function(t) {\n                    t.deactivate();\n                });\n                return this;\n            },\n            isOpen: function isOpen() {\n                var open;\n                ttEach(this.first(), function(t) {\n                    open = t.isOpen();\n                });\n                return open;\n            },\n            open: function open() {\n                ttEach(this, function(t) {\n                    t.open();\n                });\n                return this;\n            },\n            close: function close() {\n                ttEach(this, function(t) {\n                    t.close();\n                });\n                return this;\n            },\n            select: function select(el) {\n                var success = false, $el = $(el);\n                ttEach(this.first(), function(t) {\n                    success = t.select($el);\n                });\n                return success;\n            },\n            autocomplete: function autocomplete(el) {\n                var success = false, $el = $(el);\n                ttEach(this.first(), function(t) {\n                    success = t.autocomplete($el);\n                });\n                return success;\n            },\n            moveCursor: function moveCursoe(delta) {\n                var success = false;\n                ttEach(this.first(), function(t) {\n                    success = t.moveCursor(delta);\n                });\n                return success;\n            },\n            val: function val(newVal) {\n                var query;\n                if (!arguments.length) {\n                    ttEach(this.first(), function(t) {\n                        query = t.getVal();\n                    });\n                    return query;\n                } else {\n                    ttEach(this, function(t) {\n                        t.setVal(_.toStr(newVal));\n                    });\n                    return this;\n                }\n            },\n            destroy: function destroy() {\n                ttEach(this, function(typeahead, $input) {\n                    revert($input);\n                    typeahead.destroy();\n                });\n                return this;\n            }\n        };\n        $.fn.typeahead = function(method) {\n            if (methods[method]) {\n                return methods[method].apply(this, [].slice.call(arguments, 1));\n            } else {\n                return methods.initialize.apply(this, arguments);\n            }\n        };\n        $.fn.typeahead.noConflict = function noConflict() {\n            $.fn.typeahead = old;\n            return this;\n        };\n        function ttEach($els, fn) {\n            $els.each(function() {\n                var $input = $(this), typeahead;\n                (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input);\n            });\n        }\n        function buildHintFromInput($input, www) {\n            return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop({\n                readonly: true,\n                required: false\n            }).removeAttr(\"id name placeholder\").removeClass(\"required\").attr({\n                spellcheck: \"false\",\n                tabindex: -1\n            });\n        }\n        function prepInput($input, www) {\n            $input.data(keys.attrs, {\n                dir: $input.attr(\"dir\"),\n                autocomplete: $input.attr(\"autocomplete\"),\n                spellcheck: $input.attr(\"spellcheck\"),\n                style: $input.attr(\"style\")\n            });\n            $input.addClass(www.classes.input).attr({\n                spellcheck: false\n            });\n            try {\n                !$input.attr(\"dir\") && $input.attr(\"dir\", \"auto\");\n            } catch (e) {}\n            return $input;\n        }\n        function getBackgroundStyles($el) {\n            return {\n                backgroundAttachment: $el.css(\"background-attachment\"),\n                backgroundClip: $el.css(\"background-clip\"),\n                backgroundColor: $el.css(\"background-color\"),\n                backgroundImage: $el.css(\"background-image\"),\n                backgroundOrigin: $el.css(\"background-origin\"),\n                backgroundPosition: $el.css(\"background-position\"),\n                backgroundRepeat: $el.css(\"background-repeat\"),\n                backgroundSize: $el.css(\"background-size\")\n            };\n        }\n        function revert($input) {\n            var www, $wrapper;\n            www = $input.data(keys.www);\n            $wrapper = $input.parent().filter(www.selectors.wrapper);\n            _.each($input.data(keys.attrs), function(val, key) {\n                _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);\n            });\n            $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input);\n            if ($wrapper.length) {\n                $input.detach().insertAfter($wrapper);\n                $wrapper.remove();\n            }\n        }\n        function $elOrNull(obj) {\n            var isValid, $el;\n            isValid = _.isJQuery(obj) || _.isElement(obj);\n            $el = isValid ? $(obj).first() : [];\n            return $el.length ? $el : null;\n        }\n    })();\n});"
  },
  {
    "path": "lib/jazzy/themes/apple/templates/deprecation.mustache",
    "content": "{{#deprecation_message}}\n<div class=\"aside aside-deprecated\">\n  <p class=\"aside-title\">Deprecated</p>\n  {{{deprecation_message}}}\n</div>\n{{/deprecation_message}}\n{{#unavailable_message}}\n<div class=\"aside aside-unavailable\">\n  <p class=\"aside-title\">Unavailable</p>\n  {{{unavailable_message}}}\n</div>\n{{/unavailable_message}}\n"
  },
  {
    "path": "lib/jazzy/themes/apple/templates/doc.mustache",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>{{name}} {{kind}} Reference</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{path_to_root}}css/jazzy.css\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{path_to_root}}css/highlight.css\" />\n    {{#enable_katex}}\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{path_to_root}}css/katex.min.css\" />\n    {{/enable_katex}}\n    <meta charset='utf-8'>\n    <script src=\"{{path_to_root}}js/jquery.min.js\" defer></script>\n    {{#enable_katex}}\n    <script src=\"{{path_to_root}}js/katex.min.js\" defer></script>\n    {{/enable_katex}}\n    <script src=\"{{path_to_root}}js/jazzy.js\" defer></script>\n    {{{custom_head}}}\n    {{^disable_search}}\n    <script src=\"{{path_to_root}}js/lunr.min.js\" defer></script>\n    <script src=\"{{path_to_root}}js/typeahead.jquery.js\" defer></script>\n    <script src=\"{{path_to_root}}js/jazzy.search.js\" defer></script>\n    {{/disable_search}}\n  </head>\n  <body>\n    {{#dash_type}}\n    <a name=\"//apple_ref/{{language_stub}}/{{dash_type}}/{{name}}\" class=\"dashAnchor\"></a>\n    {{/dash_type}}\n    <a title=\"{{name}} {{kind}} Reference\"></a>\n    {{> header}}\n    <div class=\"content-wrapper\">\n      <p id=\"breadcrumbs\">\n        <a href=\"{{path_to_root}}index.html\">{{readme_title}}</a>\n        {{#breadcrumbs}}\n        <img id=\"carat\" src=\"{{path_to_root}}img/carat.png\" alt=\"\"/>\n        {{#last}}\n        {{name}} {{kind}} Reference\n        {{/last}}\n        {{^last}}\n        <a href=\"{{path_to_root}}{{url}}\">{{name}}</a>\n        {{/last}}\n        {{/breadcrumbs}}\n      </p>\n    </div>\n    <div class=\"content-wrapper\">\n      {{> nav}}\n      <article class=\"main-content\">\n        <section>\n          <section class=\"section\">\n            {{^hide_name}}<h1>{{name}}</h1>{{/hide_name}}\n            {{> deprecation}}\n            {{#declaration}}\n              <div class=\"declaration\">\n                <div class=\"language\">\n                  {{#other_language_declaration}}<p class=\"aside-title\">{{language}}</p>{{/other_language_declaration}}\n                  {{{declaration}}}\n                </div>\n                {{#other_language_declaration}}\n                <div class=\"language\">\n                  <p class=\"aside-title\">Swift</p>\n                  {{{other_language_declaration}}}\n                </div>\n                {{/other_language_declaration}}\n              </div>\n            {{/declaration}}\n            {{{overview}}}\n            {{#parameters.any?}}\n              <div>\n                <h4>Parameters</h4>\n                <table class=\"graybox\">\n                  <tbody>\n                    {{#parameters}}\n                      {{> parameter}}\n                    {{/parameters}}\n                  </tbody>\n                </table>\n              </div>\n            {{/parameters.any?}}\n            {{#return}}\n              <div>\n                <h4>Return Value</h4>\n                {{{return}}}\n              </div>\n            {{/return}}\n            {{#source_host_item_url}}\n              <div class=\"slightly-smaller\">\n                <a href=\"{{{.}}}\">Show on {{source_host_name}}</a>\n              </div>\n            {{/source_host_item_url}}\n          </section>\n          {{> tasks}}\n        </section>\n        {{> footer}}\n      </article>\n    </div>\n  </body>\n</html>\n"
  },
  {
    "path": "lib/jazzy/themes/apple/templates/footer.mustache",
    "content": "<section id=\"footer\">\n  {{{copyright}}}\n  <p>Generated by <a class=\"link\" href=\"https://github.com/realm/jazzy\" target=\"_blank\" rel=\"external noopener\">jazzy ♪♫ v{{jazzy_version}}</a>, a <a class=\"link\" href=\"https://realm.io\" target=\"_blank\" rel=\"external noopener\">Realm</a> project.</p>\n</section>\n"
  },
  {
    "path": "lib/jazzy/themes/apple/templates/header.mustache",
    "content": "<header>\n  <div class=\"content-wrapper\">\n    <p><a href=\"{{path_to_root}}index.html\">{{docs_title}}</a>{{#doc_coverage}} ({{doc_coverage}}% documented){{/doc_coverage}}</p>\n    {{#source_host_url}}\n    <p class=\"header-right\"><a href=\"{{.}}\"><img src=\"{{path_to_root}}img/{{source_host_image}}\" alt=\"{{source_host_name}}\"/>View on {{source_host_name}}</a></p>\n    {{/source_host_url}}\n    {{#dash_url}}\n    <p class=\"header-right\"><a href=\"{{dash_url}}\"><img src=\"{{path_to_root}}img/dash.png\" alt=\"Dash\"/>Install in Dash</a></p>\n    {{/dash_url}}\n    {{^disable_search}}\n    <div class=\"header-right\">\n      <form role=\"search\" action=\"{{path_to_root}}search.json\">\n        <input type=\"text\" placeholder=\"Search documentation\" data-typeahead>\n      </form>\n    </div>\n    {{/disable_search}}\n  </div>\n</header>\n"
  },
  {
    "path": "lib/jazzy/themes/apple/templates/nav.mustache",
    "content": "<nav class=\"sidebar\">\n  <ul class=\"nav-groups\">\n    {{#structure}}\n    <li class=\"nav-group-name\">\n      <a href=\"{{path_to_root}}{{url}}\">{{section}}</a>\n      <ul class=\"nav-group-tasks\">\n        {{#children}}\n        <li class=\"nav-group-task\">\n          <a href=\"{{path_to_root}}{{url}}\">{{name}}</a>\n        </li>\n        {{/children}}\n      </ul>\n    </li>\n    {{/structure}}\n  </ul>\n</nav>\n"
  },
  {
    "path": "lib/jazzy/themes/apple/templates/parameter.mustache",
    "content": "<tr>\n  <td>\n    <code>\n    <em>{{name}}</em>\n    </code>\n  </td>\n  <td>\n    <div>\n      {{{discussion}}}\n    </div>\n  </td>\n</tr>\n"
  },
  {
    "path": "lib/jazzy/themes/apple/templates/task.mustache",
    "content": "<div class=\"task-group\">\n  {{#name}}\n  <div class=\"task-name-container\">\n    <a name=\"/{{uid}}\"></a>\n    <a name=\"//apple_ref/{{language_stub}}/Section/{{name}}\" class=\"dashAnchor\"></a>\n    <div class=\"section-name-container\">\n      <a class=\"section-name-link\" href=\"#/{{uid}}\"></a>\n      <h3 class=\"section-name\">{{{name_html}}}</h3>\n    </div>\n  </div>\n  {{/name}}\n  <ul>\n    {{#items}}\n    <li class=\"item\">\n      <div>\n        <code>\n        <a name=\"/{{usr}}\"></a>\n        <a name=\"//apple_ref/{{language_stub}}/{{dash_type}}/{{name}}\" class=\"dashAnchor\"></a>\n        {{#direct_link}}\n        <a class=\"direct-link{{#usage_discouraged}} discouraged{{/usage_discouraged}}\" href=\"{{{path_to_root}}}{{{url}}}\">{{name}}</a>\n        </code>\n        {{/direct_link}}\n        {{^direct_link}}\n        {{^usage_discouraged}}\n        <a class=\"token\" href=\"#/{{usr}}\">{{{name_html}}}</a>\n        {{/usage_discouraged}}\n        {{#usage_discouraged}}\n        <a class=\"token discouraged\" href=\"#/{{usr}}\">{{{name_html}}}</a>\n        {{/usage_discouraged}}\n        </code>\n        {{#declaration_note}}\n          <span class=\"declaration-note\">\n            {{.}}\n          </span>\n        {{/declaration_note}}\n      </div>\n      <div class=\"height-container\">\n        <div class=\"pointer-container\"></div>\n        <section class=\"section\">\n          <div class=\"pointer\"></div>\n          {{> deprecation}}\n          {{#abstract}}\n          <div class=\"abstract\">\n            {{{abstract}}}\n            {{#url}}\n            <a href=\"{{{path_to_root}}}{{{url}}}\" class=\"slightly-smaller\">See more</a>\n            {{/url}}\n          </div>\n          {{/abstract}}\n          {{#default_impl_abstract}}\n          <h4>Default Implementation</h4>\n          <div class=\"default_impl abstract\">\n            {{{default_impl_abstract}}}\n          </div>\n          {{/default_impl_abstract}}\n          {{#declaration}}\n          <div class=\"declaration\">\n            <h4>Declaration</h4>\n            <div class=\"language\">\n              <p class=\"aside-title\">{{language}}</p>\n              {{{declaration}}}\n            </div>\n            {{#other_language_declaration}}\n            <div class=\"language\">\n              <p class=\"aside-title\">Swift</p>\n              {{{other_language_declaration}}}\n            </div>\n            {{/other_language_declaration}}\n          </div>\n          {{/declaration}}\n          {{#parameters.count}}\n          <div>\n            <h4>Parameters</h4>\n            <table class=\"graybox\">\n              <tbody>\n                {{#parameters}}\n                {{> parameter}}\n                {{/parameters}}\n              </tbody>\n            </table>\n          </div>\n          {{/parameters.count}}\n          {{#return}}\n          <div>\n            <h4>Return Value</h4>\n            {{{return}}}\n          </div>\n          {{/return}}\n          {{#source_host_item_url}}\n          <div class=\"slightly-smaller\">\n            <a href=\"{{{.}}}\">Show on {{source_host_name}}</a>\n          </div>\n          {{/source_host_item_url}}\n        </section>\n        {{/direct_link}}\n      </div>\n    </li>\n    {{/items}}\n  </ul>\n</div>\n"
  },
  {
    "path": "lib/jazzy/themes/apple/templates/tasks.mustache",
    "content": "{{#tasks.count}}\n<section class=\"section task-group-section\">\n  {{#tasks}}\n  {{> task}}\n  {{/tasks}}\n</section>\n{{/tasks.count}}\n"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/assets/css/highlight.css.scss",
    "content": "/*! Jazzy - https://github.com/realm/jazzy\n *  Copyright Realm Inc.\n *  SPDX-License-Identifier: MIT\n */\n/* Credit to https://gist.github.com/wataru420/2048287 */\n\n.highlight {\n  .c { color: #999988; font-style: italic } // Comment\n  .err { color: #a61717; background-color: #e3d2d2 } // Error\n  .k { color: #000000; font-weight: bold } // Keyword\n  .o { color: #000000; font-weight: bold } // Operator\n  .cm { color: #999988; font-style: italic } // Comment.Multiline\n  .cp { color: #999999; font-weight: bold } // Comment.Preproc\n  .c1 { color: #999988; font-style: italic } // Comment.Single\n  .cs { color: #999999; font-weight: bold; font-style: italic } // Comment.Special\n  .gd { color: #000000; background-color: #ffdddd } // Generic.Deleted\n  .gd .x { color: #000000; background-color: #ffaaaa } // Generic.Deleted.Specific\n  .ge { color: #000000; font-style: italic } // Generic.Emph\n  .gr { color: #aa0000 } // Generic.Error\n  .gh { color: #999999 } // Generic.Heading\n  .gi { color: #000000; background-color: #ddffdd } // Generic.Inserted\n  .gi .x { color: #000000; background-color: #aaffaa } // Generic.Inserted.Specific\n  .go { color: #888888 } // Generic.Output\n  .gp { color: #555555 } // Generic.Prompt\n  .gs { font-weight: bold } // Generic.Strong\n  .gu { color: #aaaaaa } // Generic.Subheading\n  .gt { color: #aa0000 } // Generic.Traceback\n  .kc { color: #000000; font-weight: bold } // Keyword.Constant\n  .kd { color: #000000; font-weight: bold } // Keyword.Declaration\n  .kp { color: #000000; font-weight: bold } // Keyword.Pseudo\n  .kr { color: #000000; font-weight: bold } // Keyword.Reserved\n  .kt { color: #445588; } // Keyword.Type\n  .m { color: #009999 } // Literal.Number\n  .s { color: #d14 } // Literal.String\n  .na { color: #008080 } // Name.Attribute\n  .nb { color: #0086B3 } // Name.Builtin\n  .nc { color: #445588; font-weight: bold } // Name.Class\n  .no { color: #008080 } // Name.Constant\n  .ni { color: #800080 } // Name.Entity\n  .ne { color: #990000; font-weight: bold } // Name.Exception\n  .nf { color: #990000; } // Name.Function\n  .nn { color: #555555 } // Name.Namespace\n  .nt { color: #000080 } // Name.Tag\n  .nv { color: #008080 } // Name.Variable\n  .ow { color: #000000; font-weight: bold } // Operator.Word\n  .w { color: #bbbbbb } // Text.Whitespace\n  .mf { color: #009999 } // Literal.Number.Float\n  .mh { color: #009999 } // Literal.Number.Hex\n  .mi { color: #009999 } // Literal.Number.Integer\n  .mo { color: #009999 } // Literal.Number.Oct\n  .sb { color: #d14 } // Literal.String.Backtick\n  .sc { color: #d14 } // Literal.String.Char\n  .sd { color: #d14 } // Literal.String.Doc\n  .s2 { color: #d14 } // Literal.String.Double\n  .se { color: #d14 } // Literal.String.Escape\n  .sh { color: #d14 } // Literal.String.Heredoc\n  .si { color: #d14 } // Literal.String.Interpol\n  .sx { color: #d14 } // Literal.String.Other\n  .sr { color: #009926 } // Literal.String.Regex\n  .s1 { color: #d14 } // Literal.String.Single\n  .ss { color: #990073 } // Literal.String.Symbol\n  .bp { color: #999999 } // Name.Builtin.Pseudo\n  .vc { color: #008080 } // Name.Variable.Class\n  .vg { color: #008080 } // Name.Variable.Global\n  .vi { color: #008080 } // Name.Variable.Instance\n  .il { color: #009999 } // Literal.Number.Integer.Long\n}\n"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/assets/css/jazzy.css.scss",
    "content": "/*! Jazzy - https://github.com/realm/jazzy\n *  Copyright Realm Inc.\n *  SPDX-License-Identifier: MIT\n */\n// ===========================================================================\n//\n//  Variables\n//\n// ===========================================================================\n\n$body_background: #fff;\n$body_font: 16px/1.7 'Helvetica Neue', Helvetica, Arial, sans-serif;\n$text_color: #333;\n$gray_border: 1px solid #ddd;\n\n$heading_weight: 700;\n$light_heading_color: #777;\n\n$quote_color: #858585;\n$quote_border: 4px solid #e5e5e5;\n\n$link_color: #4183c4;\n\n$table_alt_row_color: #fbfbfb;\n$table_border_color: #ddd;\n\n$code_bg_color: #f7f7f7;\n$code_font: Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n\n\n// ----- Layout\n\n$gutter: 16px;\n$navigation_max_width: 300px;\n\n\n// ----- Header\n\n$header_bg_color: #444;\n$header_link_color: #fff;\n$doc_coverage_color: #999;\n\n\n// ----- Breadcrumbs\n\n$breadcrumbs_bg_color: #fbfbfb;\n$breadcrumbs_border_color: #ddd;\n\n\n// ----- Navigation\n\n$navigation_max_width: 300px;\n$navigation_bg_color: #fbfbfb;\n$navigation_border_color: #ddd;\n$navigation_title_color: #333;\n$navigation_task_color: #808080;\n\n// ----- Content\n\n$declaration_title_language_color: #4183c4;\n$declaration_language_border: 5px solid #cde9f4;\n$declaration_bg_color: #fff;\n$declaration_border_color: #ddd;\n\n$aside_color: #aaa;\n$aside_border: 5px solid lighten($aside_color, 20%);\n$aside_warning_color: #ff0000;\n$aside_warning_border: 5px solid lighten($aside_warning_color, 20%);\n\n// ----- Footer\n\n$footer_bg_color: #444;\n$footer_text_color: #ddd;\n$footer_link_color: #fff;\n\n\n// ===========================================================================\n//\n//  Base\n//\n// ===========================================================================\n\n*, *:before, *:after {\n  box-sizing: inherit;\n}\n\nbody {\n  margin: 0;\n  background: $body_background;\n  color: $text_color;\n  font: $body_font;\n  letter-spacing: .2px;\n  -webkit-font-smoothing: antialiased;\n  box-sizing: border-box;\n}\n\n// ----- Block elements\n\n@mixin heading($font-size: 1rem, $margin: 1.275em 0 0.85em) {\n  font-size: $font-size;\n  font-weight: $heading_weight;\n  margin: $margin;\n}\n\nh1 {\n  @include heading(2rem, 1.275em 0 0.6em);\n}\n\nh2 {\n  @include heading(1.75rem, 1.275em 0 0.3em);\n}\n\nh3 {\n  @include heading(1.5rem, 1em 0 0.3em);\n}\n\nh4 {\n  @include heading(1.25rem);\n}\n\nh5 {\n  @include heading;\n}\n\nh6 {\n  @include heading;\n  color: $light_heading_color;\n}\n\np {\n  margin: 0 0 1em;\n}\n\nul, ol {\n  padding: 0 0 0 2em;\n  margin: 0 0 0.85em;\n}\n\nblockquote {\n  margin: 0 0 0.85em;\n  padding: 0 15px;\n  color: $quote_color;\n  border-left: $quote_border;\n}\n\n\n// ----- Inline elements\n\nimg {\n  max-width: 100%;\n}\n\na {\n  color: $link_color;\n  text-decoration: none;\n\n  &:hover, &:focus {\n    outline: 0;\n    text-decoration: underline;\n  }\n\n  &.discouraged {\n    text-decoration: line-through;\n    &:hover, &:focus {\n      text-decoration: underline line-through;\n    }\n  }\n}\n\n// ----- Tables\n\ntable {\n  background: $body_background;\n  width: 100%;\n  border-collapse: collapse;\n  border-spacing: 0;\n  overflow: auto;\n  margin: 0 0 0.85em;\n}\n\ntr {\n  &:nth-child(2n) {\n    background-color: $table_alt_row_color;\n  }\n}\n\nth, td {\n  padding: 6px 13px;\n  border: 1px solid $table_border_color;\n}\n\nhr {\n  height: 1px;\n  border: none;\n  background-color: $table_border_color;\n}\n\n// ----- Code\n\npre {\n  margin: 0 0 1.275em;\n  padding: .85em 1em;\n  overflow: auto;\n  background: $code_bg_color;\n  font-size: .85em;\n  font-family: $code_font;\n}\n\ncode {\n  font-family: $code_font;\n}\n\n.item-container, .top-matter {\n  p, li {\n    > code {\n      background: $code_bg_color;\n      padding: .2em;\n      &:before, &:after {\n        letter-spacing: -.2em;\n        content: \"\\00a0\";\n      }\n    }\n  }\n}\n\npre code {\n  padding: 0;\n  white-space: pre;\n}\n\n\n// ===========================================================================\n//\n//  Layout\n//\n// ===========================================================================\n\n.content-wrapper {\n  display: flex;\n  flex-direction: column;\n  @media (min-width: 768px) {\n    flex-direction: row;\n  }\n}\n\n\n// ===========================================================================\n//\n//  Header\n//\n// ===========================================================================\n\n.header {\n  display: flex;\n  padding: $gutter/2;\n  font-size: 0.875em;\n  background: $header_bg_color;\n  color: $doc_coverage_color;\n}\n\n.header-col {\n  margin: 0;\n  padding: 0 $gutter/2\n}\n\n.header-col--primary {\n  flex: 1;\n}\n\n.header-link {\n  color: $header_link_color;\n}\n\n.header-icon {\n  padding-right: 2px;\n  vertical-align: -3px;\n  height: 16px;\n}\n\n\n\n// ===========================================================================\n//\n//  Breadcrumbs\n//\n// ===========================================================================\n\n.breadcrumbs {\n  font-size: 0.875em;\n  padding: $gutter / 2 $gutter;\n  margin: 0;\n  background: $breadcrumbs_bg_color;\n  border-bottom: 1px solid $breadcrumbs_border_color;\n}\n\n.carat {\n  height: 10px;\n  margin: 0 5px;\n}\n\n\n// ===========================================================================\n//\n//  Navigation\n//\n// ===========================================================================\n\n.navigation {\n  order: 2;\n\n  @media (min-width: 768px) {\n    order: 1;\n    width: 25%;\n    max-width: $navigation_max_width;\n    padding-bottom: $gutter*4;\n    overflow: hidden;\n    word-wrap: normal;\n    background: $navigation_bg_color;\n    border-right: 1px solid $navigation_border_color;\n  }\n}\n\n.nav-groups {\n  list-style-type: none;\n  padding-left: 0;\n}\n\n.nav-group-name {\n  border-bottom: 1px solid $navigation_border_color;\n  padding: $gutter/2 0 $gutter/2 $gutter;\n}\n\n.nav-group-name-link {\n  color: $navigation_title_color;\n}\n\n.nav-group-tasks {\n  margin: $gutter/2 0;\n  padding: 0 0 0 $gutter/2;\n}\n\n.nav-group-task {\n  font-size: 1em;\n  list-style-type: none;\n  white-space: nowrap;\n}\n\n.nav-group-task-link {\n  color: $navigation_task_color;\n}\n\n// ===========================================================================\n//\n//  Content\n//\n// ===========================================================================\n\n.main-content {\n  order: 1;\n  @media (min-width: 768px) {\n    order: 2;\n    flex: 1;\n    padding-bottom: 60px;\n  }\n}\n\n.section {\n  padding: 0 $gutter * 2;\n  border-bottom: 1px solid $navigation_border_color;\n}\n\n.section-content {\n  max-width: 834px;\n  margin: 0 auto;\n  padding: $gutter 0;\n}\n\n.section-name {\n  color: #666;\n  display: block;\n\n  p {\n    margin-bottom: inherit;\n  }\n}\n\n.declaration .highlight {\n  overflow-x: initial; // This allows the scrollbar to show up inside declarations\n  padding: $gutter/2 0;\n  margin: 0;\n  background-color: transparent;\n  border: none;\n}\n\n.task-group-section {\n  border-top: $gray_border;\n}\n\n.task-group {\n  padding-top: 0px;\n}\n\n.task-name-container {\n  a[name] {\n    &:before {\n      content: \"\";\n      display: block;\n    }\n  }\n}\n\n.section-name-container {\n  position: relative;\n\n  .section-name-link {\n    position: absolute;\n    top: 0;\n    left: 0;\n    bottom: 0;\n    right: 0;\n    margin-bottom: 0;\n  }\n\n  .section-name {\n    position: relative;\n    pointer-events: none;\n    z-index: 1;\n    a {\n      pointer-events: auto;\n    }\n  }\n}\n\n.item-container {\n  padding: 0;\n}\n\n.item {\n  padding-top: 8px;\n  width: 100%;\n  list-style-type: none;\n\n  a[name] {\n    &:before {\n      content: \"\";\n      display: block;\n    }\n  }\n\n  .token, .direct-link {\n    display: inline-block;\n    text-indent: -20px;\n    padding-left: 3px;\n    margin-left: 20px;\n    font-size: 1rem;\n  }\n}\n\n.declaration-note {\n  font-size: .85em;\n  color: #808080;\n  font-style: italic;\n}\n\n.pointer-container {\n  border-bottom: $gray_border;\n  left: -23px;\n  padding-bottom: 13px;\n  position: relative;\n  width: 110%;\n}\n\n.pointer {\n  left: 21px;\n  top: 7px;\n  display: block;\n  position: absolute;\n  width: 12px;\n  height: 12px;\n  border-left: 1px solid $declaration_border_color;\n  border-top: 1px solid $declaration_border_color;\n  background: $declaration_bg_color;\n  transform: rotate(45deg);\n}\n\n.height-container {\n  display: none;\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n  .section {\n    background: $declaration_bg_color;\n    border: $gray_border;\n    border-top-width: 0;\n    padding-top: 10px;\n    padding-bottom: 5px;\n    padding: $gutter / 2 $gutter;\n  }\n}\n\n.aside, .language {\n  padding: 6px 12px;\n  margin: 12px 0;\n  border-left: $aside_border;\n  overflow-y: hidden;\n  .aside-title {\n    font-size: 9px;\n    letter-spacing: 2px;\n    text-transform: uppercase;\n    padding-bottom: 0;\n    margin: 0;\n    color: $aside_color;\n    -webkit-user-select: none;\n  }\n  p:last-child {\n    margin-bottom: 0;\n  }\n}\n\n.language {\n  border-left: $declaration_language_border;\n  .aside-title {\n    color: $declaration_title_language_color;\n  }\n}\n\n.aside-warning, .aside-deprecated, .aside-unavailable {\n  border-left: $aside_warning_border;\n  .aside-title {\n    color: $aside_warning_color;\n  }\n}\n\n.graybox {\n  border-collapse: collapse;\n  width: 100%;\n  p {\n    margin: 0;\n    word-break: break-word;\n    min-width: 50px;\n  }\n  td {\n    border: $gray_border;\n    padding: 5px 25px 5px 10px;\n    vertical-align: middle;\n  }\n  tr td:first-of-type {\n    text-align: right;\n    padding: 7px;\n    vertical-align: top;\n    word-break: normal;\n    width: 40px;\n  }\n}\n\n.slightly-smaller {\n  font-size: 0.9em;\n}\n\n\n// ===========================================================================\n//\n//  Footer\n//\n// ===========================================================================\n\n.footer {\n  padding: $gutter/2 $gutter;\n  background: $footer_bg_color;\n  color: $footer_text_color;\n  font-size: 0.8em;\n\n  p {\n    margin: $gutter/2 0;\n  }\n\n  a {\n    color: $footer_link_color;\n  }\n}\n\n\n// ===========================================================================\n//\n//  Dash\n//\n// ===========================================================================\n\nhtml.dash {\n\n  .header, .breadcrumbs, .navigation {\n    display: none;\n  }\n\n  .height-container {\n    display: block;\n  }\n}\n\n// ===========================================================================\n//\n//  Search\n//\n// ===========================================================================\nform[role=search] {\n  input {\n    font: $body_font;\n    font-size: 14px;\n    line-height: 24px;\n    padding: 0 10px;\n    margin: 0;\n    border: none;\n    border-radius: 1em;\n    .loading & {\n      background: white url(../img/spinner.gif) center right 4px no-repeat;\n    }\n  }\n\n  // Typeahead elements\n\n  .tt-menu {\n    margin: 0;\n    min-width: 300px;\n    background: $navigation_bg_color;\n    color: $text_color;\n    border: 1px solid $navigation_border_color;\n  }\n\n  .tt-highlight {\n    font-weight: bold;\n  }\n\n  .tt-suggestion {\n    font: $body_font;\n    padding: 0 $gutter/2;\n    span {\n      display: table-cell;\n      white-space: nowrap;\n    }\n    .doc-parent-name {\n      width: 100%;\n      text-align: right;\n      font-weight: normal;\n      font-size: 0.9em;\n      padding-left: $gutter;\n    }\n  }\n\n  .tt-suggestion:hover,\n  .tt-suggestion.tt-cursor {\n    cursor: pointer;\n    background-color: $link_color;\n    color: #fff;\n  }\n\n  .tt-suggestion:hover .doc-parent-name,\n  .tt-suggestion.tt-cursor .doc-parent-name {\n    color: #fff;\n  }\n}\n"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/assets/js/jazzy.js",
    "content": "// Jazzy - https://github.com/realm/jazzy\n// Copyright Realm Inc.\n// SPDX-License-Identifier: MIT\n\nwindow.jazzy = {'docset': false}\nif (typeof window.dash != 'undefined') {\n  document.documentElement.className += ' dash'\n  window.jazzy.docset = true\n}\nif (navigator.userAgent.match(/xcode/i)) {\n  document.documentElement.className += ' xcode'\n  window.jazzy.docset = true\n}\n\nfunction toggleItem($link, $content) {\n  var animationDuration = 300;\n  $link.toggleClass('token-open');\n  $content.slideToggle(animationDuration);\n}\n\nfunction itemLinkToContent($link) {\n  return $link.parent().parent().next();\n}\n\n// On doc load + hash-change, open any targeted item\nfunction openCurrentItemIfClosed() {\n  if (window.jazzy.docset) {\n    return;\n  }\n  var $link = $(`a[name=\"${location.hash.substring(1)}\"]`).nextAll('.token');\n  $content = itemLinkToContent($link);\n  if ($content.is(':hidden')) {\n    toggleItem($link, $content);\n  }\n}\n\n$(openCurrentItemIfClosed);\n$(window).on('hashchange', openCurrentItemIfClosed);\n\n// On item link ('token') click, toggle its discussion\n$('.token').on('click', function(event) {\n  if (window.jazzy.docset) {\n    return;\n  }\n  var $link = $(this);\n  toggleItem($link, itemLinkToContent($link));\n\n  // Keeps the document from jumping to the hash.\n  var href = $link.attr('href');\n  if (history.pushState) {\n    history.pushState({}, '', href);\n  } else {\n    location.hash = href;\n  }\n  event.preventDefault();\n});\n\n// Clicks on links to the current, closed, item need to open the item\n$(\"a:not('.token')\").on('click', function() {\n  if (location == this.href) {\n    openCurrentItemIfClosed();\n  }\n});\n\n// KaTeX rendering\nif (\"katex\" in window) {\n  $($('.math').each( (_, element) => {\n    katex.render(element.textContent, element, {\n      displayMode: $(element).hasClass('m-block'),\n      throwOnError: false,\n      trust: true\n    });\n  }))\n}\n"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/assets/js/jazzy.search.js",
    "content": "// Jazzy - https://github.com/realm/jazzy\n// Copyright Realm Inc.\n// SPDX-License-Identifier: MIT\n\n$(function(){\n  var $typeahead = $('[data-typeahead]');\n  var $form = $typeahead.parents('form');\n  var searchURL = $form.attr('action');\n\n  function displayTemplate(result) {\n    return result.name;\n  }\n\n  function suggestionTemplate(result) {\n    var t = '<div class=\"list-group-item clearfix\">';\n    t += '<span class=\"doc-name\">' + result.name + '</span>';\n    if (result.parent_name) {\n     t += '<span class=\"doc-parent-name label\">' + result.parent_name + '</span>';\n    }\n    t += '</div>';\n    return t;\n  }\n\n  $typeahead.one('focus', function() {\n    $form.addClass('loading');\n\n    $.getJSON(searchURL).then(function(searchData) {\n      const searchIndex = lunr(function() {\n        this.ref('url');\n        this.field('name');\n        this.field('abstract');\n        for (const [url, doc] of Object.entries(searchData)) {\n          this.add({url: url, name: doc.name, abstract: doc.abstract});\n        }\n      });\n\n      $typeahead.typeahead(\n        {\n          highlight: true,\n          minLength: 3,\n          autoselect: true\n        },\n        {\n          limit: 10,\n          display: displayTemplate,\n          templates: { suggestion: suggestionTemplate },\n          source: function(query, sync) {\n            const lcSearch = query.toLowerCase();\n            const results = searchIndex.query(function(q) {\n                q.term(lcSearch, { boost: 100 });\n                q.term(lcSearch, {\n                  boost: 10,\n                  wildcard: lunr.Query.wildcard.TRAILING\n                });\n            }).map(function(result) {\n              var doc = searchData[result.ref];\n              doc.url = result.ref;\n              return doc;\n            });\n            sync(results);\n          }\n        }\n      );\n      $form.removeClass('loading');\n      $typeahead.trigger('focus');\n    });\n  });\n\n  var baseURL = searchURL.slice(0, -\"search.json\".length);\n\n  $typeahead.on('typeahead:select', function(e, result) {\n    window.location = baseURL + result.url;\n  });\n});\n"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/assets/js/typeahead.jquery.js",
    "content": "/*!\n * typeahead.js 1.3.3\n * https://github.com/corejavascript/typeahead.js\n * Copyright 2013-2024 Twitter, Inc. and other contributors; Licensed MIT\n */\n\n\n(function(root, factory) {\n    if (typeof define === \"function\" && define.amd) {\n        define([ \"jquery\" ], function(a0) {\n            return factory(a0);\n        });\n    } else if (typeof module === \"object\" && module.exports) {\n        module.exports = factory(require(\"jquery\"));\n    } else {\n        factory(root[\"jQuery\"]);\n    }\n})(this, function($) {\n    var _ = function() {\n        \"use strict\";\n        return {\n            isMsie: function() {\n                return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\\d+(.\\d+)?)/i)[2] : false;\n            },\n            isBlankString: function(str) {\n                return !str || /^\\s*$/.test(str);\n            },\n            escapeRegExChars: function(str) {\n                return str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\");\n            },\n            isString: function(obj) {\n                return typeof obj === \"string\";\n            },\n            isNumber: function(obj) {\n                return typeof obj === \"number\";\n            },\n            isArray: $.isArray,\n            isFunction: $.isFunction,\n            isObject: $.isPlainObject,\n            isUndefined: function(obj) {\n                return typeof obj === \"undefined\";\n            },\n            isElement: function(obj) {\n                return !!(obj && obj.nodeType === 1);\n            },\n            isJQuery: function(obj) {\n                return obj instanceof $;\n            },\n            toStr: function toStr(s) {\n                return _.isUndefined(s) || s === null ? \"\" : s + \"\";\n            },\n            bind: $.proxy,\n            each: function(collection, cb) {\n                $.each(collection, reverseArgs);\n                function reverseArgs(index, value) {\n                    return cb(value, index);\n                }\n            },\n            map: $.map,\n            filter: $.grep,\n            every: function(obj, test) {\n                var result = true;\n                if (!obj) {\n                    return result;\n                }\n                $.each(obj, function(key, val) {\n                    if (!(result = test.call(null, val, key, obj))) {\n                        return false;\n                    }\n                });\n                return !!result;\n            },\n            some: function(obj, test) {\n                var result = false;\n                if (!obj) {\n                    return result;\n                }\n                $.each(obj, function(key, val) {\n                    if (result = test.call(null, val, key, obj)) {\n                        return false;\n                    }\n                });\n                return !!result;\n            },\n            mixin: $.extend,\n            identity: function(x) {\n                return x;\n            },\n            clone: function(obj) {\n                return $.extend(true, {}, obj);\n            },\n            getIdGenerator: function() {\n                var counter = 0;\n                return function() {\n                    return counter++;\n                };\n            },\n            templatify: function templatify(obj) {\n                return $.isFunction(obj) ? obj : template;\n                function template() {\n                    return String(obj);\n                }\n            },\n            defer: function(fn) {\n                setTimeout(fn, 0);\n            },\n            debounce: function(func, wait, immediate) {\n                var timeout, result;\n                return function() {\n                    var context = this, args = arguments, later, callNow;\n                    later = function() {\n                        timeout = null;\n                        if (!immediate) {\n                            result = func.apply(context, args);\n                        }\n                    };\n                    callNow = immediate && !timeout;\n                    clearTimeout(timeout);\n                    timeout = setTimeout(later, wait);\n                    if (callNow) {\n                        result = func.apply(context, args);\n                    }\n                    return result;\n                };\n            },\n            throttle: function(func, wait) {\n                var context, args, timeout, result, previous, later;\n                previous = 0;\n                later = function() {\n                    previous = new Date();\n                    timeout = null;\n                    result = func.apply(context, args);\n                };\n                return function() {\n                    var now = new Date(), remaining = wait - (now - previous);\n                    context = this;\n                    args = arguments;\n                    if (remaining <= 0) {\n                        clearTimeout(timeout);\n                        timeout = null;\n                        previous = now;\n                        result = func.apply(context, args);\n                    } else if (!timeout) {\n                        timeout = setTimeout(later, remaining);\n                    }\n                    return result;\n                };\n            },\n            stringify: function(val) {\n                return _.isString(val) ? val : JSON.stringify(val);\n            },\n            guid: function() {\n                function _p8(s) {\n                    var p = (Math.random().toString(16) + \"000000000\").substr(2, 8);\n                    return s ? \"-\" + p.substr(0, 4) + \"-\" + p.substr(4, 4) : p;\n                }\n                return \"tt-\" + _p8() + _p8(true) + _p8(true) + _p8();\n            },\n            noop: function() {}\n        };\n    }();\n    var WWW = function() {\n        \"use strict\";\n        var defaultClassNames = {\n            wrapper: \"twitter-typeahead\",\n            input: \"tt-input\",\n            hint: \"tt-hint\",\n            menu: \"tt-menu\",\n            dataset: \"tt-dataset\",\n            suggestion: \"tt-suggestion\",\n            selectable: \"tt-selectable\",\n            empty: \"tt-empty\",\n            open: \"tt-open\",\n            cursor: \"tt-cursor\",\n            highlight: \"tt-highlight\"\n        };\n        return build;\n        function build(o) {\n            var www, classes;\n            classes = _.mixin({}, defaultClassNames, o);\n            www = {\n                css: buildCss(),\n                classes: classes,\n                html: buildHtml(classes),\n                selectors: buildSelectors(classes)\n            };\n            return {\n                css: www.css,\n                html: www.html,\n                classes: www.classes,\n                selectors: www.selectors,\n                mixin: function(o) {\n                    _.mixin(o, www);\n                }\n            };\n        }\n        function buildHtml(c) {\n            return {\n                wrapper: '<span class=\"' + c.wrapper + '\"></span>',\n                menu: '<div role=\"listbox\" class=\"' + c.menu + '\"></div>'\n            };\n        }\n        function buildSelectors(classes) {\n            var selectors = {};\n            _.each(classes, function(v, k) {\n                selectors[k] = \".\" + v;\n            });\n            return selectors;\n        }\n        function buildCss() {\n            var css = {\n                wrapper: {\n                    position: \"relative\",\n                    display: \"inline-block\"\n                },\n                hint: {\n                    position: \"absolute\",\n                    top: \"0\",\n                    left: \"0\",\n                    borderColor: \"transparent\",\n                    boxShadow: \"none\",\n                    opacity: \"1\"\n                },\n                input: {\n                    position: \"relative\",\n                    verticalAlign: \"top\",\n                    backgroundColor: \"transparent\"\n                },\n                inputWithNoHint: {\n                    position: \"relative\",\n                    verticalAlign: \"top\"\n                },\n                menu: {\n                    position: \"absolute\",\n                    top: \"100%\",\n                    left: \"0\",\n                    zIndex: \"100\",\n                    display: \"none\"\n                },\n                ltr: {\n                    left: \"0\",\n                    right: \"auto\"\n                },\n                rtl: {\n                    left: \"auto\",\n                    right: \" 0\"\n                }\n            };\n            if (_.isMsie()) {\n                _.mixin(css.input, {\n                    backgroundImage: \"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)\"\n                });\n            }\n            return css;\n        }\n    }();\n    var EventBus = function() {\n        \"use strict\";\n        var namespace, deprecationMap;\n        namespace = \"typeahead:\";\n        deprecationMap = {\n            render: \"rendered\",\n            cursorchange: \"cursorchanged\",\n            select: \"selected\",\n            autocomplete: \"autocompleted\"\n        };\n        function EventBus(o) {\n            if (!o || !o.el) {\n                $.error(\"EventBus initialized without el\");\n            }\n            this.$el = $(o.el);\n        }\n        _.mixin(EventBus.prototype, {\n            _trigger: function(type, args) {\n                var $e = $.Event(namespace + type);\n                this.$el.trigger.call(this.$el, $e, args || []);\n                return $e;\n            },\n            before: function(type) {\n                var args, $e;\n                args = [].slice.call(arguments, 1);\n                $e = this._trigger(\"before\" + type, args);\n                return $e.isDefaultPrevented();\n            },\n            trigger: function(type) {\n                var deprecatedType;\n                this._trigger(type, [].slice.call(arguments, 1));\n                if (deprecatedType = deprecationMap[type]) {\n                    this._trigger(deprecatedType, [].slice.call(arguments, 1));\n                }\n            }\n        });\n        return EventBus;\n    }();\n    var EventEmitter = function() {\n        \"use strict\";\n        var splitter = /\\s+/, nextTick = getNextTick();\n        return {\n            onSync: onSync,\n            onAsync: onAsync,\n            off: off,\n            trigger: trigger\n        };\n        function on(method, types, cb, context) {\n            var type;\n            if (!cb) {\n                return this;\n            }\n            types = types.split(splitter);\n            cb = context ? bindContext(cb, context) : cb;\n            this._callbacks = this._callbacks || {};\n            while (type = types.shift()) {\n                this._callbacks[type] = this._callbacks[type] || {\n                    sync: [],\n                    async: []\n                };\n                this._callbacks[type][method].push(cb);\n            }\n            return this;\n        }\n        function onAsync(types, cb, context) {\n            return on.call(this, \"async\", types, cb, context);\n        }\n        function onSync(types, cb, context) {\n            return on.call(this, \"sync\", types, cb, context);\n        }\n        function off(types) {\n            var type;\n            if (!this._callbacks) {\n                return this;\n            }\n            types = types.split(splitter);\n            while (type = types.shift()) {\n                delete this._callbacks[type];\n            }\n            return this;\n        }\n        function trigger(types) {\n            var type, callbacks, args, syncFlush, asyncFlush;\n            if (!this._callbacks) {\n                return this;\n            }\n            types = types.split(splitter);\n            args = [].slice.call(arguments, 1);\n            while ((type = types.shift()) && (callbacks = this._callbacks[type])) {\n                syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));\n                asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));\n                syncFlush() && nextTick(asyncFlush);\n            }\n            return this;\n        }\n        function getFlush(callbacks, context, args) {\n            return flush;\n            function flush() {\n                var cancelled;\n                for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {\n                    cancelled = callbacks[i].apply(context, args) === false;\n                }\n                return !cancelled;\n            }\n        }\n        function getNextTick() {\n            var nextTickFn;\n            if (window.setImmediate) {\n                nextTickFn = function nextTickSetImmediate(fn) {\n                    setImmediate(function() {\n                        fn();\n                    });\n                };\n            } else {\n                nextTickFn = function nextTickSetTimeout(fn) {\n                    setTimeout(function() {\n                        fn();\n                    }, 0);\n                };\n            }\n            return nextTickFn;\n        }\n        function bindContext(fn, context) {\n            return fn.bind ? fn.bind(context) : function() {\n                fn.apply(context, [].slice.call(arguments, 0));\n            };\n        }\n    }();\n    var highlight = function(doc) {\n        \"use strict\";\n        var defaults = {\n            node: null,\n            pattern: null,\n            tagName: \"strong\",\n            className: null,\n            wordsOnly: false,\n            caseSensitive: false,\n            diacriticInsensitive: false\n        };\n        var accented = {\n            A: \"[AaªÀ-Åà-åĀ-ąǍǎȀ-ȃȦȧᴬᵃḀḁẚẠ-ảₐ℀℁℻⒜Ⓐⓐ㍱-㍴㎀-㎄㎈㎉㎩-㎯㏂㏊㏟㏿Ａａ]\",\n            B: \"[BbᴮᵇḂ-ḇℬ⒝Ⓑⓑ㍴㎅-㎇㏃㏈㏔㏝Ｂｂ]\",\n            C: \"[CcÇçĆ-čᶜ℀ℂ℃℅℆ℭⅭⅽ⒞Ⓒⓒ㍶㎈㎉㎝㎠㎤㏄-㏇Ｃｃ]\",\n            D: \"[DdĎďǄ-ǆǱ-ǳᴰᵈḊ-ḓⅅⅆⅮⅾ⒟Ⓓⓓ㋏㍲㍷-㍹㎗㎭-㎯㏅㏈Ｄｄ]\",\n            E: \"[EeÈ-Ëè-ëĒ-ěȄ-ȇȨȩᴱᵉḘ-ḛẸ-ẽₑ℡ℯℰⅇ⒠Ⓔⓔ㉐㋍㋎Ｅｅ]\",\n            F: \"[FfᶠḞḟ℉ℱ℻⒡Ⓕⓕ㎊-㎌㎙ﬀ-ﬄＦｆ]\",\n            G: \"[GgĜ-ģǦǧǴǵᴳᵍḠḡℊ⒢Ⓖⓖ㋌㋍㎇㎍-㎏㎓㎬㏆㏉㏒㏿Ｇｇ]\",\n            H: \"[HhĤĥȞȟʰᴴḢ-ḫẖℋ-ℎ⒣Ⓗⓗ㋌㍱㎐-㎔㏊㏋㏗Ｈｈ]\",\n            I: \"[IiÌ-Ïì-ïĨ-İĲĳǏǐȈ-ȋᴵᵢḬḭỈ-ịⁱℐℑℹⅈⅠ-ⅣⅥ-ⅨⅪⅫⅰ-ⅳⅵ-ⅸⅺⅻ⒤Ⓘⓘ㍺㏌㏕ﬁﬃＩｉ]\",\n            J: \"[JjĲ-ĵǇ-ǌǰʲᴶⅉ⒥ⒿⓙⱼＪｊ]\",\n            K: \"[KkĶķǨǩᴷᵏḰ-ḵK⒦Ⓚⓚ㎄㎅㎉㎏㎑㎘㎞㎢㎦㎪㎸㎾㏀㏆㏍-㏏Ｋｋ]\",\n            L: \"[LlĹ-ŀǇ-ǉˡᴸḶḷḺ-ḽℒℓ℡Ⅼⅼ⒧Ⓛⓛ㋏㎈㎉㏐-㏓㏕㏖㏿ﬂﬄＬｌ]\",\n            M: \"[MmᴹᵐḾ-ṃ℠™ℳⅯⅿ⒨Ⓜⓜ㍷-㍹㎃㎆㎎㎒㎖㎙-㎨㎫㎳㎷㎹㎽㎿㏁㏂㏎㏐㏔-㏖㏘㏙㏞㏟Ｍｍ]\",\n            N: \"[NnÑñŃ-ŉǊ-ǌǸǹᴺṄ-ṋⁿℕ№⒩Ⓝⓝ㎁㎋㎚㎱㎵㎻㏌㏑Ｎｎ]\",\n            O: \"[OoºÒ-Öò-öŌ-őƠơǑǒǪǫȌ-ȏȮȯᴼᵒỌ-ỏₒ℅№ℴ⒪Ⓞⓞ㍵㏇㏒㏖Ｏｏ]\",\n            P: \"[PpᴾᵖṔ-ṗℙ⒫Ⓟⓟ㉐㍱㍶㎀㎊㎩-㎬㎰㎴㎺㏋㏗-㏚Ｐｐ]\",\n            Q: \"[Qqℚ⒬Ⓠⓠ㏃Ｑｑ]\",\n            R: \"[RrŔ-řȐ-ȓʳᴿᵣṘ-ṛṞṟ₨ℛ-ℝ⒭Ⓡⓡ㋍㍴㎭-㎯㏚㏛Ｒｒ]\",\n            S: \"[SsŚ-šſȘșˢṠ-ṣ₨℁℠⒮Ⓢⓢ㎧㎨㎮-㎳㏛㏜ﬆＳｓ]\",\n            T: \"[TtŢ-ťȚțᵀᵗṪ-ṱẗ℡™⒯Ⓣⓣ㉐㋏㎔㏏ﬅﬆＴｔ]\",\n            U: \"[UuÙ-Üù-üŨ-ųƯưǓǔȔ-ȗᵁᵘᵤṲ-ṷỤ-ủ℆⒰Ⓤⓤ㍳㍺Ｕｕ]\",\n            V: \"[VvᵛᵥṼ-ṿⅣ-Ⅷⅳ-ⅷ⒱Ⓥⓥⱽ㋎㍵㎴-㎹㏜㏞Ｖｖ]\",\n            W: \"[WwŴŵʷᵂẀ-ẉẘ⒲Ⓦⓦ㎺-㎿㏝Ｗｗ]\",\n            X: \"[XxˣẊ-ẍₓ℻Ⅸ-Ⅻⅸ-ⅻ⒳Ⓧⓧ㏓Ｘｘ]\",\n            Y: \"[YyÝýÿŶ-ŸȲȳʸẎẏẙỲ-ỹ⒴Ⓨⓨ㏉Ｙｙ]\",\n            Z: \"[ZzŹ-žǱ-ǳᶻẐ-ẕℤℨ⒵Ⓩⓩ㎐-㎔Ｚｚ]\"\n        };\n        return function hightlight(o) {\n            var regex;\n            o = _.mixin({}, defaults, o);\n            if (!o.node || !o.pattern) {\n                return;\n            }\n            o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];\n            regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly, o.diacriticInsensitive);\n            traverse(o.node, hightlightTextNode);\n            function hightlightTextNode(textNode) {\n                var match, patternNode, wrapperNode;\n                if (match = regex.exec(textNode.data)) {\n                    wrapperNode = doc.createElement(o.tagName);\n                    o.className && (wrapperNode.className = o.className);\n                    patternNode = textNode.splitText(match.index);\n                    patternNode.splitText(match[0].length);\n                    wrapperNode.appendChild(patternNode.cloneNode(true));\n                    textNode.parentNode.replaceChild(wrapperNode, patternNode);\n                }\n                return !!match;\n            }\n            function traverse(el, hightlightTextNode) {\n                var childNode, TEXT_NODE_TYPE = 3;\n                for (var i = 0; i < el.childNodes.length; i++) {\n                    childNode = el.childNodes[i];\n                    if (childNode.nodeType === TEXT_NODE_TYPE) {\n                        i += hightlightTextNode(childNode) ? 1 : 0;\n                    } else {\n                        traverse(childNode, hightlightTextNode);\n                    }\n                }\n            }\n        };\n        function accent_replacer(chr) {\n            return accented[chr.toUpperCase()] || chr;\n        }\n        function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensitive) {\n            var escapedPatterns = [], regexStr;\n            for (var i = 0, len = patterns.length; i < len; i++) {\n                var escapedWord = _.escapeRegExChars(patterns[i]);\n                if (diacriticInsensitive) {\n                    escapedWord = escapedWord.replace(/\\S/g, accent_replacer);\n                }\n                escapedPatterns.push(escapedWord);\n            }\n            regexStr = wordsOnly ? \"\\\\b(\" + escapedPatterns.join(\"|\") + \")\\\\b\" : \"(\" + escapedPatterns.join(\"|\") + \")\";\n            return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, \"i\");\n        }\n    }(window.document);\n    var Input = function() {\n        \"use strict\";\n        var specialKeyCodeMap;\n        specialKeyCodeMap = {\n            9: \"tab\",\n            27: \"esc\",\n            37: \"left\",\n            39: \"right\",\n            13: \"enter\",\n            38: \"up\",\n            40: \"down\"\n        };\n        function Input(o, www) {\n            var id;\n            o = o || {};\n            if (!o.input) {\n                $.error(\"input is missing\");\n            }\n            www.mixin(this);\n            this.$hint = $(o.hint);\n            this.$input = $(o.input);\n            this.$menu = $(o.menu);\n            id = this.$input.attr(\"id\") || _.guid();\n            this.$menu.attr(\"id\", id + \"_listbox\");\n            this.$hint.attr({\n                \"aria-hidden\": true\n            });\n            this.$input.attr({\n                \"aria-owns\": id + \"_listbox\",\n                \"aria-controls\": id + \"_listbox\",\n                role: \"combobox\",\n                \"aria-autocomplete\": \"list\",\n                \"aria-expanded\": false\n            });\n            this.query = this.$input.val();\n            this.queryWhenFocused = this.hasFocus() ? this.query : null;\n            this.$overflowHelper = buildOverflowHelper(this.$input);\n            this._checkLanguageDirection();\n            if (this.$hint.length === 0) {\n                this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;\n            }\n            this.onSync(\"cursorchange\", this._updateDescendent);\n        }\n        Input.normalizeQuery = function(str) {\n            return _.toStr(str).replace(/^\\s*/g, \"\").replace(/\\s{2,}/g, \" \");\n        };\n        _.mixin(Input.prototype, EventEmitter, {\n            _onBlur: function onBlur() {\n                this.resetInputValue();\n                this.trigger(\"blurred\");\n            },\n            _onFocus: function onFocus() {\n                this.queryWhenFocused = this.query;\n                this.trigger(\"focused\");\n            },\n            _onKeydown: function onKeydown($e) {\n                var keyName = specialKeyCodeMap[$e.which || $e.keyCode];\n                this._managePreventDefault(keyName, $e);\n                if (keyName && this._shouldTrigger(keyName, $e)) {\n                    this.trigger(keyName + \"Keyed\", $e);\n                }\n            },\n            _onInput: function onInput() {\n                this._setQuery(this.getInputValue());\n                this.clearHintIfInvalid();\n                this._checkLanguageDirection();\n            },\n            _managePreventDefault: function managePreventDefault(keyName, $e) {\n                var preventDefault;\n                switch (keyName) {\n                  case \"up\":\n                  case \"down\":\n                    preventDefault = !withModifier($e);\n                    break;\n\n                  default:\n                    preventDefault = false;\n                }\n                preventDefault && $e.preventDefault();\n            },\n            _shouldTrigger: function shouldTrigger(keyName, $e) {\n                var trigger;\n                switch (keyName) {\n                  case \"tab\":\n                    trigger = !withModifier($e);\n                    break;\n\n                  default:\n                    trigger = true;\n                }\n                return trigger;\n            },\n            _checkLanguageDirection: function checkLanguageDirection() {\n                var dir = (this.$input.css(\"direction\") || \"ltr\").toLowerCase();\n                if (this.dir !== dir) {\n                    this.dir = dir;\n                    this.$hint.attr(\"dir\", dir);\n                    this.trigger(\"langDirChanged\", dir);\n                }\n            },\n            _setQuery: function setQuery(val, silent) {\n                var areEquivalent, hasDifferentWhitespace;\n                areEquivalent = areQueriesEquivalent(val, this.query);\n                hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false;\n                this.query = val;\n                if (!silent && !areEquivalent) {\n                    this.trigger(\"queryChanged\", this.query);\n                } else if (!silent && hasDifferentWhitespace) {\n                    this.trigger(\"whitespaceChanged\", this.query);\n                }\n            },\n            _updateDescendent: function updateDescendent(event, id) {\n                this.$input.attr(\"aria-activedescendant\", id);\n            },\n            bind: function() {\n                var that = this, onBlur, onFocus, onKeydown, onInput;\n                onBlur = _.bind(this._onBlur, this);\n                onFocus = _.bind(this._onFocus, this);\n                onKeydown = _.bind(this._onKeydown, this);\n                onInput = _.bind(this._onInput, this);\n                this.$input.on(\"blur.tt\", onBlur).on(\"focus.tt\", onFocus).on(\"keydown.tt\", onKeydown);\n                if (!_.isMsie() || _.isMsie() > 9) {\n                    this.$input.on(\"input.tt\", onInput);\n                } else {\n                    this.$input.on(\"keydown.tt keypress.tt cut.tt paste.tt\", function($e) {\n                        if (specialKeyCodeMap[$e.which || $e.keyCode]) {\n                            return;\n                        }\n                        _.defer(_.bind(that._onInput, that, $e));\n                    });\n                }\n                return this;\n            },\n            focus: function focus() {\n                this.$input.focus();\n            },\n            blur: function blur() {\n                this.$input.blur();\n            },\n            getLangDir: function getLangDir() {\n                return this.dir;\n            },\n            getQuery: function getQuery() {\n                return this.query || \"\";\n            },\n            setQuery: function setQuery(val, silent) {\n                this.setInputValue(val);\n                this._setQuery(val, silent);\n            },\n            hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() {\n                return this.query !== this.queryWhenFocused;\n            },\n            getInputValue: function getInputValue() {\n                return this.$input.val();\n            },\n            setInputValue: function setInputValue(value) {\n                this.$input.val(value);\n                this.clearHintIfInvalid();\n                this._checkLanguageDirection();\n            },\n            resetInputValue: function resetInputValue() {\n                this.setInputValue(this.query);\n            },\n            getHint: function getHint() {\n                return this.$hint.val();\n            },\n            setHint: function setHint(value) {\n                this.$hint.val(value);\n            },\n            clearHint: function clearHint() {\n                this.setHint(\"\");\n            },\n            clearHintIfInvalid: function clearHintIfInvalid() {\n                var val, hint, valIsPrefixOfHint, isValid;\n                val = this.getInputValue();\n                hint = this.getHint();\n                valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;\n                isValid = val !== \"\" && valIsPrefixOfHint && !this.hasOverflow();\n                !isValid && this.clearHint();\n            },\n            hasFocus: function hasFocus() {\n                return this.$input.is(\":focus\");\n            },\n            hasOverflow: function hasOverflow() {\n                var constraint = this.$input.width() - 2;\n                this.$overflowHelper.text(this.getInputValue());\n                return this.$overflowHelper.width() >= constraint;\n            },\n            isCursorAtEnd: function() {\n                var valueLength, selectionStart, range;\n                valueLength = this.$input.val().length;\n                selectionStart = this.$input[0].selectionStart;\n                if (_.isNumber(selectionStart)) {\n                    return selectionStart === valueLength;\n                } else if (document.selection) {\n                    range = document.selection.createRange();\n                    range.moveStart(\"character\", -valueLength);\n                    return valueLength === range.text.length;\n                }\n                return true;\n            },\n            destroy: function destroy() {\n                this.$hint.off(\".tt\");\n                this.$input.off(\".tt\");\n                this.$overflowHelper.remove();\n                this.$hint = this.$input = this.$overflowHelper = $(\"<div>\");\n            },\n            setAriaExpanded: function setAriaExpanded(value) {\n                this.$input.attr(\"aria-expanded\", value);\n            }\n        });\n        return Input;\n        function buildOverflowHelper($input) {\n            return $('<pre aria-hidden=\"true\"></pre>').css({\n                position: \"absolute\",\n                visibility: \"hidden\",\n                whiteSpace: \"pre\",\n                fontFamily: $input.css(\"font-family\"),\n                fontSize: $input.css(\"font-size\"),\n                fontStyle: $input.css(\"font-style\"),\n                fontVariant: $input.css(\"font-variant\"),\n                fontWeight: $input.css(\"font-weight\"),\n                wordSpacing: $input.css(\"word-spacing\"),\n                letterSpacing: $input.css(\"letter-spacing\"),\n                textIndent: $input.css(\"text-indent\"),\n                textRendering: $input.css(\"text-rendering\"),\n                textTransform: $input.css(\"text-transform\")\n            }).insertAfter($input);\n        }\n        function areQueriesEquivalent(a, b) {\n            return Input.normalizeQuery(a) === Input.normalizeQuery(b);\n        }\n        function withModifier($e) {\n            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;\n        }\n    }();\n    var Dataset = function() {\n        \"use strict\";\n        var keys, nameGenerator;\n        keys = {\n            dataset: \"tt-selectable-dataset\",\n            val: \"tt-selectable-display\",\n            obj: \"tt-selectable-object\"\n        };\n        nameGenerator = _.getIdGenerator();\n        function Dataset(o, www) {\n            o = o || {};\n            o.templates = o.templates || {};\n            o.templates.notFound = o.templates.notFound || o.templates.empty;\n            if (!o.source) {\n                $.error(\"missing source\");\n            }\n            if (!o.node) {\n                $.error(\"missing node\");\n            }\n            if (o.name && !isValidName(o.name)) {\n                $.error(\"invalid dataset name: \" + o.name);\n            }\n            www.mixin(this);\n            this.highlight = !!o.highlight;\n            this.name = _.toStr(o.name || nameGenerator());\n            this.limit = o.limit || 5;\n            this.displayFn = getDisplayFn(o.display || o.displayKey);\n            this.templates = getTemplates(o.templates, this.displayFn);\n            this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source;\n            this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async;\n            this._resetLastSuggestion();\n            this.$el = $(o.node).attr(\"role\", \"presentation\").addClass(this.classes.dataset).addClass(this.classes.dataset + \"-\" + this.name);\n        }\n        Dataset.extractData = function extractData(el) {\n            var $el = $(el);\n            if ($el.data(keys.obj)) {\n                return {\n                    dataset: $el.data(keys.dataset) || \"\",\n                    val: $el.data(keys.val) || \"\",\n                    obj: $el.data(keys.obj) || null\n                };\n            }\n            return null;\n        };\n        _.mixin(Dataset.prototype, EventEmitter, {\n            _overwrite: function overwrite(query, suggestions) {\n                suggestions = suggestions || [];\n                if (suggestions.length) {\n                    this._renderSuggestions(query, suggestions);\n                } else if (this.async && this.templates.pending) {\n                    this._renderPending(query);\n                } else if (!this.async && this.templates.notFound) {\n                    this._renderNotFound(query);\n                } else {\n                    this._empty();\n                }\n                this.trigger(\"rendered\", suggestions, false, this.name);\n            },\n            _append: function append(query, suggestions) {\n                suggestions = suggestions || [];\n                if (suggestions.length && this.$lastSuggestion.length) {\n                    this._appendSuggestions(query, suggestions);\n                } else if (suggestions.length) {\n                    this._renderSuggestions(query, suggestions);\n                } else if (!this.$lastSuggestion.length && this.templates.notFound) {\n                    this._renderNotFound(query);\n                }\n                this.trigger(\"rendered\", suggestions, true, this.name);\n            },\n            _renderSuggestions: function renderSuggestions(query, suggestions) {\n                var $fragment;\n                $fragment = this._getSuggestionsFragment(query, suggestions);\n                this.$lastSuggestion = $fragment.children().last();\n                this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions));\n            },\n            _appendSuggestions: function appendSuggestions(query, suggestions) {\n                var $fragment, $lastSuggestion;\n                $fragment = this._getSuggestionsFragment(query, suggestions);\n                $lastSuggestion = $fragment.children().last();\n                this.$lastSuggestion.after($fragment);\n                this.$lastSuggestion = $lastSuggestion;\n            },\n            _renderPending: function renderPending(query) {\n                var template = this.templates.pending;\n                this._resetLastSuggestion();\n                template && this.$el.html(template({\n                    query: query,\n                    dataset: this.name\n                }));\n            },\n            _renderNotFound: function renderNotFound(query) {\n                var template = this.templates.notFound;\n                this._resetLastSuggestion();\n                template && this.$el.html(template({\n                    query: query,\n                    dataset: this.name\n                }));\n            },\n            _empty: function empty() {\n                this.$el.empty();\n                this._resetLastSuggestion();\n            },\n            _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) {\n                var that = this, fragment;\n                fragment = document.createDocumentFragment();\n                _.each(suggestions, function getSuggestionNode(suggestion) {\n                    var $el, context;\n                    context = that._injectQuery(query, suggestion);\n                    $el = $(that.templates.suggestion(context)).data(keys.dataset, that.name).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + \" \" + that.classes.selectable);\n                    fragment.appendChild($el[0]);\n                });\n                this.highlight && highlight({\n                    className: this.classes.highlight,\n                    node: fragment,\n                    pattern: query\n                });\n                return $(fragment);\n            },\n            _getFooter: function getFooter(query, suggestions) {\n                return this.templates.footer ? this.templates.footer({\n                    query: query,\n                    suggestions: suggestions,\n                    dataset: this.name\n                }) : null;\n            },\n            _getHeader: function getHeader(query, suggestions) {\n                return this.templates.header ? this.templates.header({\n                    query: query,\n                    suggestions: suggestions,\n                    dataset: this.name\n                }) : null;\n            },\n            _resetLastSuggestion: function resetLastSuggestion() {\n                this.$lastSuggestion = $();\n            },\n            _injectQuery: function injectQuery(query, obj) {\n                return _.isObject(obj) ? _.mixin({\n                    _query: query\n                }, obj) : obj;\n            },\n            update: function update(query) {\n                var that = this, canceled = false, syncCalled = false, rendered = 0;\n                this.cancel();\n                this.cancel = function cancel() {\n                    canceled = true;\n                    that.cancel = $.noop;\n                    that.async && that.trigger(\"asyncCanceled\", query, that.name);\n                };\n                this.source(query, sync, async);\n                !syncCalled && sync([]);\n                function sync(suggestions) {\n                    if (syncCalled) {\n                        return;\n                    }\n                    syncCalled = true;\n                    suggestions = (suggestions || []).slice(0, that.limit);\n                    rendered = suggestions.length;\n                    that._overwrite(query, suggestions);\n                    if (rendered < that.limit && that.async) {\n                        that.trigger(\"asyncRequested\", query, that.name);\n                    }\n                }\n                function async(suggestions) {\n                    suggestions = suggestions || [];\n                    if (!canceled && rendered < that.limit) {\n                        that.cancel = $.noop;\n                        var idx = Math.abs(rendered - that.limit);\n                        rendered += idx;\n                        that._append(query, suggestions.slice(0, idx));\n                        that.async && that.trigger(\"asyncReceived\", query, that.name);\n                    }\n                }\n            },\n            cancel: $.noop,\n            clear: function clear() {\n                this._empty();\n                this.cancel();\n                this.trigger(\"cleared\");\n            },\n            isEmpty: function isEmpty() {\n                return this.$el.is(\":empty\");\n            },\n            destroy: function destroy() {\n                this.$el = $(\"<div>\");\n            }\n        });\n        return Dataset;\n        function getDisplayFn(display) {\n            display = display || _.stringify;\n            return _.isFunction(display) ? display : displayFn;\n            function displayFn(obj) {\n                return obj[display];\n            }\n        }\n        function getTemplates(templates, displayFn) {\n            return {\n                notFound: templates.notFound && _.templatify(templates.notFound),\n                pending: templates.pending && _.templatify(templates.pending),\n                header: templates.header && _.templatify(templates.header),\n                footer: templates.footer && _.templatify(templates.footer),\n                suggestion: templates.suggestion ? userSuggestionTemplate : suggestionTemplate\n            };\n            function userSuggestionTemplate(context) {\n                var template = templates.suggestion;\n                return $(template(context)).attr(\"id\", _.guid());\n            }\n            function suggestionTemplate(context) {\n                return $('<div role=\"option\">').attr(\"id\", _.guid()).text(displayFn(context));\n            }\n        }\n        function isValidName(str) {\n            return /^[_a-zA-Z0-9-]+$/.test(str);\n        }\n    }();\n    var Menu = function() {\n        \"use strict\";\n        function Menu(o, www) {\n            var that = this;\n            o = o || {};\n            if (!o.node) {\n                $.error(\"node is required\");\n            }\n            www.mixin(this);\n            this.$node = $(o.node);\n            this.query = null;\n            this.datasets = _.map(o.datasets, initializeDataset);\n            function initializeDataset(oDataset) {\n                var node = that.$node.find(oDataset.node).first();\n                oDataset.node = node.length ? node : $(\"<div>\").appendTo(that.$node);\n                return new Dataset(oDataset, www);\n            }\n        }\n        _.mixin(Menu.prototype, EventEmitter, {\n            _onSelectableClick: function onSelectableClick($e) {\n                this.trigger(\"selectableClicked\", $($e.currentTarget));\n            },\n            _onRendered: function onRendered(type, dataset, suggestions, async) {\n                this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());\n                this.trigger(\"datasetRendered\", dataset, suggestions, async);\n            },\n            _onCleared: function onCleared() {\n                this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());\n                this.trigger(\"datasetCleared\");\n            },\n            _propagate: function propagate() {\n                this.trigger.apply(this, arguments);\n            },\n            _allDatasetsEmpty: function allDatasetsEmpty() {\n                return _.every(this.datasets, _.bind(function isDatasetEmpty(dataset) {\n                    var isEmpty = dataset.isEmpty();\n                    this.$node.attr(\"aria-expanded\", !isEmpty);\n                    return isEmpty;\n                }, this));\n            },\n            _getSelectables: function getSelectables() {\n                return this.$node.find(this.selectors.selectable);\n            },\n            _removeCursor: function _removeCursor() {\n                var $selectable = this.getActiveSelectable();\n                $selectable && $selectable.removeClass(this.classes.cursor);\n            },\n            _ensureVisible: function ensureVisible($el) {\n                var elTop, elBottom, nodeScrollTop, nodeHeight;\n                elTop = $el.position().top;\n                elBottom = elTop + $el.outerHeight(true);\n                nodeScrollTop = this.$node.scrollTop();\n                nodeHeight = this.$node.height() + parseInt(this.$node.css(\"paddingTop\"), 10) + parseInt(this.$node.css(\"paddingBottom\"), 10);\n                if (elTop < 0) {\n                    this.$node.scrollTop(nodeScrollTop + elTop);\n                } else if (nodeHeight < elBottom) {\n                    this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight));\n                }\n            },\n            bind: function() {\n                var that = this, onSelectableClick;\n                onSelectableClick = _.bind(this._onSelectableClick, this);\n                this.$node.on(\"click.tt\", this.selectors.selectable, onSelectableClick);\n                this.$node.on(\"mouseover\", this.selectors.selectable, function() {\n                    that.setCursor($(this));\n                });\n                this.$node.on(\"mouseleave\", function() {\n                    that._removeCursor();\n                });\n                _.each(this.datasets, function(dataset) {\n                    dataset.onSync(\"asyncRequested\", that._propagate, that).onSync(\"asyncCanceled\", that._propagate, that).onSync(\"asyncReceived\", that._propagate, that).onSync(\"rendered\", that._onRendered, that).onSync(\"cleared\", that._onCleared, that);\n                });\n                return this;\n            },\n            isOpen: function isOpen() {\n                return this.$node.hasClass(this.classes.open);\n            },\n            open: function open() {\n                this.$node.scrollTop(0);\n                this.$node.addClass(this.classes.open);\n            },\n            close: function close() {\n                this.$node.attr(\"aria-expanded\", false);\n                this.$node.removeClass(this.classes.open);\n                this._removeCursor();\n            },\n            setLanguageDirection: function setLanguageDirection(dir) {\n                this.$node.attr(\"dir\", dir);\n            },\n            selectableRelativeToCursor: function selectableRelativeToCursor(delta) {\n                var $selectables, $oldCursor, oldIndex, newIndex;\n                $oldCursor = this.getActiveSelectable();\n                $selectables = this._getSelectables();\n                oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1;\n                newIndex = oldIndex + delta;\n                newIndex = (newIndex + 1) % ($selectables.length + 1) - 1;\n                newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex;\n                return newIndex === -1 ? null : $selectables.eq(newIndex);\n            },\n            setCursor: function setCursor($selectable) {\n                this._removeCursor();\n                if ($selectable = $selectable && $selectable.first()) {\n                    $selectable.addClass(this.classes.cursor);\n                    this._ensureVisible($selectable);\n                }\n            },\n            getSelectableData: function getSelectableData($el) {\n                return $el && $el.length ? Dataset.extractData($el) : null;\n            },\n            getActiveSelectable: function getActiveSelectable() {\n                var $selectable = this._getSelectables().filter(this.selectors.cursor).first();\n                return $selectable.length ? $selectable : null;\n            },\n            getTopSelectable: function getTopSelectable() {\n                var $selectable = this._getSelectables().first();\n                return $selectable.length ? $selectable : null;\n            },\n            update: function update(query) {\n                var isValidUpdate = query !== this.query;\n                if (isValidUpdate) {\n                    this.query = query;\n                    _.each(this.datasets, updateDataset);\n                }\n                return isValidUpdate;\n                function updateDataset(dataset) {\n                    dataset.update(query);\n                }\n            },\n            empty: function empty() {\n                _.each(this.datasets, clearDataset);\n                this.query = null;\n                this.$node.addClass(this.classes.empty);\n                function clearDataset(dataset) {\n                    dataset.clear();\n                }\n            },\n            destroy: function destroy() {\n                this.$node.off(\".tt\");\n                this.$node = $(\"<div>\");\n                _.each(this.datasets, destroyDataset);\n                function destroyDataset(dataset) {\n                    dataset.destroy();\n                }\n            }\n        });\n        return Menu;\n    }();\n    var Status = function() {\n        \"use strict\";\n        function Status(options) {\n            this.$el = $(\"<span></span>\", {\n                role: \"status\",\n                \"aria-live\": \"polite\"\n            }).css({\n                position: \"absolute\",\n                padding: \"0\",\n                border: \"0\",\n                height: \"1px\",\n                width: \"1px\",\n                \"margin-bottom\": \"-1px\",\n                \"margin-right\": \"-1px\",\n                overflow: \"hidden\",\n                clip: \"rect(0 0 0 0)\",\n                \"white-space\": \"nowrap\"\n            });\n            options.$input.after(this.$el);\n            _.each(options.menu.datasets, _.bind(function(dataset) {\n                if (dataset.onSync) {\n                    dataset.onSync(\"rendered\", _.bind(this.update, this));\n                    dataset.onSync(\"cleared\", _.bind(this.cleared, this));\n                }\n            }, this));\n        }\n        _.mixin(Status.prototype, {\n            update: function update(event, suggestions) {\n                var length = suggestions.length;\n                var words;\n                if (length === 1) {\n                    words = {\n                        result: \"result\",\n                        is: \"is\"\n                    };\n                } else {\n                    words = {\n                        result: \"results\",\n                        is: \"are\"\n                    };\n                }\n                this.$el.text(length + \" \" + words.result + \" \" + words.is + \" available, use up and down arrow keys to navigate.\");\n            },\n            cleared: function() {\n                this.$el.text(\"\");\n            }\n        });\n        return Status;\n    }();\n    var DefaultMenu = function() {\n        \"use strict\";\n        var s = Menu.prototype;\n        function DefaultMenu() {\n            Menu.apply(this, [].slice.call(arguments, 0));\n        }\n        _.mixin(DefaultMenu.prototype, Menu.prototype, {\n            open: function open() {\n                !this._allDatasetsEmpty() && this._show();\n                return s.open.apply(this, [].slice.call(arguments, 0));\n            },\n            close: function close() {\n                this._hide();\n                return s.close.apply(this, [].slice.call(arguments, 0));\n            },\n            _onRendered: function onRendered() {\n                if (this._allDatasetsEmpty()) {\n                    this._hide();\n                } else {\n                    this.isOpen() && this._show();\n                }\n                return s._onRendered.apply(this, [].slice.call(arguments, 0));\n            },\n            _onCleared: function onCleared() {\n                if (this._allDatasetsEmpty()) {\n                    this._hide();\n                } else {\n                    this.isOpen() && this._show();\n                }\n                return s._onCleared.apply(this, [].slice.call(arguments, 0));\n            },\n            setLanguageDirection: function setLanguageDirection(dir) {\n                this.$node.css(dir === \"ltr\" ? this.css.ltr : this.css.rtl);\n                return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0));\n            },\n            _hide: function hide() {\n                this.$node.hide();\n            },\n            _show: function show() {\n                this.$node.css(\"display\", \"block\");\n            }\n        });\n        return DefaultMenu;\n    }();\n    var Typeahead = function() {\n        \"use strict\";\n        function Typeahead(o, www) {\n            var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged;\n            o = o || {};\n            if (!o.input) {\n                $.error(\"missing input\");\n            }\n            if (!o.menu) {\n                $.error(\"missing menu\");\n            }\n            if (!o.eventBus) {\n                $.error(\"missing event bus\");\n            }\n            www.mixin(this);\n            this.eventBus = o.eventBus;\n            this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;\n            this.input = o.input;\n            this.menu = o.menu;\n            this.enabled = true;\n            this.autoselect = !!o.autoselect;\n            this.active = false;\n            this.input.hasFocus() && this.activate();\n            this.dir = this.input.getLangDir();\n            this._hacks();\n            this.menu.bind().onSync(\"selectableClicked\", this._onSelectableClicked, this).onSync(\"asyncRequested\", this._onAsyncRequested, this).onSync(\"asyncCanceled\", this._onAsyncCanceled, this).onSync(\"asyncReceived\", this._onAsyncReceived, this).onSync(\"datasetRendered\", this._onDatasetRendered, this).onSync(\"datasetCleared\", this._onDatasetCleared, this);\n            onFocused = c(this, \"activate\", \"open\", \"_onFocused\");\n            onBlurred = c(this, \"deactivate\", \"_onBlurred\");\n            onEnterKeyed = c(this, \"isActive\", \"isOpen\", \"_onEnterKeyed\");\n            onTabKeyed = c(this, \"isActive\", \"isOpen\", \"_onTabKeyed\");\n            onEscKeyed = c(this, \"isActive\", \"_onEscKeyed\");\n            onUpKeyed = c(this, \"isActive\", \"open\", \"_onUpKeyed\");\n            onDownKeyed = c(this, \"isActive\", \"open\", \"_onDownKeyed\");\n            onLeftKeyed = c(this, \"isActive\", \"isOpen\", \"_onLeftKeyed\");\n            onRightKeyed = c(this, \"isActive\", \"isOpen\", \"_onRightKeyed\");\n            onQueryChanged = c(this, \"_openIfActive\", \"_onQueryChanged\");\n            onWhitespaceChanged = c(this, \"_openIfActive\", \"_onWhitespaceChanged\");\n            this.input.bind().onSync(\"focused\", onFocused, this).onSync(\"blurred\", onBlurred, this).onSync(\"enterKeyed\", onEnterKeyed, this).onSync(\"tabKeyed\", onTabKeyed, this).onSync(\"escKeyed\", onEscKeyed, this).onSync(\"upKeyed\", onUpKeyed, this).onSync(\"downKeyed\", onDownKeyed, this).onSync(\"leftKeyed\", onLeftKeyed, this).onSync(\"rightKeyed\", onRightKeyed, this).onSync(\"queryChanged\", onQueryChanged, this).onSync(\"whitespaceChanged\", onWhitespaceChanged, this).onSync(\"langDirChanged\", this._onLangDirChanged, this);\n        }\n        _.mixin(Typeahead.prototype, {\n            _hacks: function hacks() {\n                var $input, $menu;\n                $input = this.input.$input || $(\"<div>\");\n                $menu = this.menu.$node || $(\"<div>\");\n                $input.on(\"blur.tt\", function($e) {\n                    var active, isActive, hasActive;\n                    active = document.activeElement;\n                    isActive = $menu.is(active);\n                    hasActive = $menu.has(active).length > 0;\n                    if (_.isMsie() && (isActive || hasActive)) {\n                        $e.preventDefault();\n                        $e.stopImmediatePropagation();\n                        _.defer(function() {\n                            $input.focus();\n                        });\n                    }\n                });\n                $menu.on(\"mousedown.tt\", function($e) {\n                    $e.preventDefault();\n                });\n            },\n            _onSelectableClicked: function onSelectableClicked(type, $el) {\n                this.select($el);\n            },\n            _onDatasetCleared: function onDatasetCleared() {\n                this._updateHint();\n            },\n            _onDatasetRendered: function onDatasetRendered(type, suggestions, async, dataset) {\n                this._updateHint();\n                if (this.autoselect) {\n                    var cursorClass = this.selectors.cursor.substr(1);\n                    this.menu.$node.find(this.selectors.suggestion).first().addClass(cursorClass);\n                }\n                this.eventBus.trigger(\"render\", suggestions, async, dataset);\n            },\n            _onAsyncRequested: function onAsyncRequested(type, dataset, query) {\n                this.eventBus.trigger(\"asyncrequest\", query, dataset);\n            },\n            _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) {\n                this.eventBus.trigger(\"asynccancel\", query, dataset);\n            },\n            _onAsyncReceived: function onAsyncReceived(type, dataset, query) {\n                this.eventBus.trigger(\"asyncreceive\", query, dataset);\n            },\n            _onFocused: function onFocused() {\n                this._minLengthMet() && this.menu.update(this.input.getQuery());\n            },\n            _onBlurred: function onBlurred() {\n                if (this.input.hasQueryChangedSinceLastFocus()) {\n                    this.eventBus.trigger(\"change\", this.input.getQuery());\n                }\n            },\n            _onEnterKeyed: function onEnterKeyed(type, $e) {\n                var $selectable;\n                if ($selectable = this.menu.getActiveSelectable()) {\n                    if (this.select($selectable)) {\n                        $e.preventDefault();\n                        $e.stopPropagation();\n                    }\n                } else if (this.autoselect) {\n                    if (this.select(this.menu.getTopSelectable())) {\n                        $e.preventDefault();\n                        $e.stopPropagation();\n                    }\n                }\n            },\n            _onTabKeyed: function onTabKeyed(type, $e) {\n                var $selectable;\n                if ($selectable = this.menu.getActiveSelectable()) {\n                    this.select($selectable) && $e.preventDefault();\n                } else if (this.autoselect) {\n                    if ($selectable = this.menu.getTopSelectable()) {\n                        this.autocomplete($selectable) && $e.preventDefault();\n                    }\n                }\n            },\n            _onEscKeyed: function onEscKeyed() {\n                this.close();\n            },\n            _onUpKeyed: function onUpKeyed() {\n                this.moveCursor(-1);\n            },\n            _onDownKeyed: function onDownKeyed() {\n                this.moveCursor(+1);\n            },\n            _onLeftKeyed: function onLeftKeyed() {\n                if (this.dir === \"rtl\" && this.input.isCursorAtEnd()) {\n                    this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable());\n                }\n            },\n            _onRightKeyed: function onRightKeyed() {\n                if (this.dir === \"ltr\" && this.input.isCursorAtEnd()) {\n                    this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable());\n                }\n            },\n            _onQueryChanged: function onQueryChanged(e, query) {\n                this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty();\n            },\n            _onWhitespaceChanged: function onWhitespaceChanged() {\n                this._updateHint();\n            },\n            _onLangDirChanged: function onLangDirChanged(e, dir) {\n                if (this.dir !== dir) {\n                    this.dir = dir;\n                    this.menu.setLanguageDirection(dir);\n                }\n            },\n            _openIfActive: function openIfActive() {\n                this.isActive() && this.open();\n            },\n            _minLengthMet: function minLengthMet(query) {\n                query = _.isString(query) ? query : this.input.getQuery() || \"\";\n                return query.length >= this.minLength;\n            },\n            _updateHint: function updateHint() {\n                var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match;\n                $selectable = this.menu.getTopSelectable();\n                data = this.menu.getSelectableData($selectable);\n                val = this.input.getInputValue();\n                if (data && !_.isBlankString(val) && !this.input.hasOverflow()) {\n                    query = Input.normalizeQuery(val);\n                    escapedQuery = _.escapeRegExChars(query);\n                    frontMatchRegEx = new RegExp(\"^(?:\" + escapedQuery + \")(.+$)\", \"i\");\n                    match = frontMatchRegEx.exec(data.val);\n                    match && this.input.setHint(val + match[1]);\n                } else {\n                    this.input.clearHint();\n                }\n            },\n            isEnabled: function isEnabled() {\n                return this.enabled;\n            },\n            enable: function enable() {\n                this.enabled = true;\n            },\n            disable: function disable() {\n                this.enabled = false;\n            },\n            isActive: function isActive() {\n                return this.active;\n            },\n            activate: function activate() {\n                if (this.isActive()) {\n                    return true;\n                } else if (!this.isEnabled() || this.eventBus.before(\"active\")) {\n                    return false;\n                } else {\n                    this.active = true;\n                    this.eventBus.trigger(\"active\");\n                    return true;\n                }\n            },\n            deactivate: function deactivate() {\n                if (!this.isActive()) {\n                    return true;\n                } else if (this.eventBus.before(\"idle\")) {\n                    return false;\n                } else {\n                    this.active = false;\n                    this.close();\n                    this.eventBus.trigger(\"idle\");\n                    return true;\n                }\n            },\n            isOpen: function isOpen() {\n                return this.menu.isOpen();\n            },\n            open: function open() {\n                if (!this.isOpen() && !this.eventBus.before(\"open\")) {\n                    this.input.setAriaExpanded(true);\n                    this.menu.open();\n                    this._updateHint();\n                    this.eventBus.trigger(\"open\");\n                }\n                return this.isOpen();\n            },\n            close: function close() {\n                if (this.isOpen() && !this.eventBus.before(\"close\")) {\n                    this.input.setAriaExpanded(false);\n                    this.menu.close();\n                    this.input.clearHint();\n                    this.input.resetInputValue();\n                    this.eventBus.trigger(\"close\");\n                }\n                return !this.isOpen();\n            },\n            setVal: function setVal(val) {\n                this.input.setQuery(_.toStr(val));\n            },\n            getVal: function getVal() {\n                return this.input.getQuery();\n            },\n            select: function select($selectable) {\n                var data = this.menu.getSelectableData($selectable);\n                if (data && !this.eventBus.before(\"select\", data.obj, data.dataset)) {\n                    this.input.setQuery(data.val, true);\n                    this.eventBus.trigger(\"select\", data.obj, data.dataset);\n                    this.close();\n                    return true;\n                }\n                return false;\n            },\n            autocomplete: function autocomplete($selectable) {\n                var query, data, isValid;\n                query = this.input.getQuery();\n                data = this.menu.getSelectableData($selectable);\n                isValid = data && query !== data.val;\n                if (isValid && !this.eventBus.before(\"autocomplete\", data.obj, data.dataset)) {\n                    this.input.setQuery(data.val);\n                    this.eventBus.trigger(\"autocomplete\", data.obj, data.dataset);\n                    return true;\n                }\n                return false;\n            },\n            moveCursor: function moveCursor(delta) {\n                var query, $candidate, data, suggestion, datasetName, cancelMove, id;\n                query = this.input.getQuery();\n                $candidate = this.menu.selectableRelativeToCursor(delta);\n                data = this.menu.getSelectableData($candidate);\n                suggestion = data ? data.obj : null;\n                datasetName = data ? data.dataset : null;\n                id = $candidate ? $candidate.attr(\"id\") : null;\n                this.input.trigger(\"cursorchange\", id);\n                cancelMove = this._minLengthMet() && this.menu.update(query);\n                if (!cancelMove && !this.eventBus.before(\"cursorchange\", suggestion, datasetName)) {\n                    this.menu.setCursor($candidate);\n                    if (data) {\n                        if (typeof data.val === \"string\") {\n                            this.input.setInputValue(data.val);\n                        }\n                    } else {\n                        this.input.resetInputValue();\n                        this._updateHint();\n                    }\n                    this.eventBus.trigger(\"cursorchange\", suggestion, datasetName);\n                    return true;\n                }\n                return false;\n            },\n            destroy: function destroy() {\n                this.input.destroy();\n                this.menu.destroy();\n            }\n        });\n        return Typeahead;\n        function c(ctx) {\n            var methods = [].slice.call(arguments, 1);\n            return function() {\n                var args = [].slice.call(arguments);\n                _.each(methods, function(method) {\n                    return ctx[method].apply(ctx, args);\n                });\n            };\n        }\n    }();\n    (function() {\n        \"use strict\";\n        var old, keys, methods;\n        old = $.fn.typeahead;\n        keys = {\n            www: \"tt-www\",\n            attrs: \"tt-attrs\",\n            typeahead: \"tt-typeahead\"\n        };\n        methods = {\n            initialize: function initialize(o, datasets) {\n                var www;\n                datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);\n                o = o || {};\n                www = WWW(o.classNames);\n                return this.each(attach);\n                function attach() {\n                    var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, status, typeahead, MenuConstructor;\n                    _.each(datasets, function(d) {\n                        d.highlight = !!o.highlight;\n                    });\n                    $input = $(this);\n                    $wrapper = $(www.html.wrapper);\n                    $hint = $elOrNull(o.hint);\n                    $menu = $elOrNull(o.menu);\n                    defaultHint = o.hint !== false && !$hint;\n                    defaultMenu = o.menu !== false && !$menu;\n                    defaultHint && ($hint = buildHintFromInput($input, www));\n                    defaultMenu && ($menu = $(www.html.menu).css(www.css.menu));\n                    $hint && $hint.val(\"\");\n                    $input = prepInput($input, www);\n                    if (defaultHint || defaultMenu) {\n                        $wrapper.css(www.css.wrapper);\n                        $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint);\n                        $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null);\n                    }\n                    MenuConstructor = defaultMenu ? DefaultMenu : Menu;\n                    eventBus = new EventBus({\n                        el: $input\n                    });\n                    input = new Input({\n                        hint: $hint,\n                        input: $input,\n                        menu: $menu\n                    }, www);\n                    menu = new MenuConstructor({\n                        node: $menu,\n                        datasets: datasets\n                    }, www);\n                    status = new Status({\n                        $input: $input,\n                        menu: menu\n                    });\n                    typeahead = new Typeahead({\n                        input: input,\n                        menu: menu,\n                        eventBus: eventBus,\n                        minLength: o.minLength,\n                        autoselect: o.autoselect\n                    }, www);\n                    $input.data(keys.www, www);\n                    $input.data(keys.typeahead, typeahead);\n                }\n            },\n            isEnabled: function isEnabled() {\n                var enabled;\n                ttEach(this.first(), function(t) {\n                    enabled = t.isEnabled();\n                });\n                return enabled;\n            },\n            enable: function enable() {\n                ttEach(this, function(t) {\n                    t.enable();\n                });\n                return this;\n            },\n            disable: function disable() {\n                ttEach(this, function(t) {\n                    t.disable();\n                });\n                return this;\n            },\n            isActive: function isActive() {\n                var active;\n                ttEach(this.first(), function(t) {\n                    active = t.isActive();\n                });\n                return active;\n            },\n            activate: function activate() {\n                ttEach(this, function(t) {\n                    t.activate();\n                });\n                return this;\n            },\n            deactivate: function deactivate() {\n                ttEach(this, function(t) {\n                    t.deactivate();\n                });\n                return this;\n            },\n            isOpen: function isOpen() {\n                var open;\n                ttEach(this.first(), function(t) {\n                    open = t.isOpen();\n                });\n                return open;\n            },\n            open: function open() {\n                ttEach(this, function(t) {\n                    t.open();\n                });\n                return this;\n            },\n            close: function close() {\n                ttEach(this, function(t) {\n                    t.close();\n                });\n                return this;\n            },\n            select: function select(el) {\n                var success = false, $el = $(el);\n                ttEach(this.first(), function(t) {\n                    success = t.select($el);\n                });\n                return success;\n            },\n            autocomplete: function autocomplete(el) {\n                var success = false, $el = $(el);\n                ttEach(this.first(), function(t) {\n                    success = t.autocomplete($el);\n                });\n                return success;\n            },\n            moveCursor: function moveCursoe(delta) {\n                var success = false;\n                ttEach(this.first(), function(t) {\n                    success = t.moveCursor(delta);\n                });\n                return success;\n            },\n            val: function val(newVal) {\n                var query;\n                if (!arguments.length) {\n                    ttEach(this.first(), function(t) {\n                        query = t.getVal();\n                    });\n                    return query;\n                } else {\n                    ttEach(this, function(t) {\n                        t.setVal(_.toStr(newVal));\n                    });\n                    return this;\n                }\n            },\n            destroy: function destroy() {\n                ttEach(this, function(typeahead, $input) {\n                    revert($input);\n                    typeahead.destroy();\n                });\n                return this;\n            }\n        };\n        $.fn.typeahead = function(method) {\n            if (methods[method]) {\n                return methods[method].apply(this, [].slice.call(arguments, 1));\n            } else {\n                return methods.initialize.apply(this, arguments);\n            }\n        };\n        $.fn.typeahead.noConflict = function noConflict() {\n            $.fn.typeahead = old;\n            return this;\n        };\n        function ttEach($els, fn) {\n            $els.each(function() {\n                var $input = $(this), typeahead;\n                (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input);\n            });\n        }\n        function buildHintFromInput($input, www) {\n            return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop({\n                readonly: true,\n                required: false\n            }).removeAttr(\"id name placeholder\").removeClass(\"required\").attr({\n                spellcheck: \"false\",\n                tabindex: -1\n            });\n        }\n        function prepInput($input, www) {\n            $input.data(keys.attrs, {\n                dir: $input.attr(\"dir\"),\n                autocomplete: $input.attr(\"autocomplete\"),\n                spellcheck: $input.attr(\"spellcheck\"),\n                style: $input.attr(\"style\")\n            });\n            $input.addClass(www.classes.input).attr({\n                spellcheck: false\n            });\n            try {\n                !$input.attr(\"dir\") && $input.attr(\"dir\", \"auto\");\n            } catch (e) {}\n            return $input;\n        }\n        function getBackgroundStyles($el) {\n            return {\n                backgroundAttachment: $el.css(\"background-attachment\"),\n                backgroundClip: $el.css(\"background-clip\"),\n                backgroundColor: $el.css(\"background-color\"),\n                backgroundImage: $el.css(\"background-image\"),\n                backgroundOrigin: $el.css(\"background-origin\"),\n                backgroundPosition: $el.css(\"background-position\"),\n                backgroundRepeat: $el.css(\"background-repeat\"),\n                backgroundSize: $el.css(\"background-size\")\n            };\n        }\n        function revert($input) {\n            var www, $wrapper;\n            www = $input.data(keys.www);\n            $wrapper = $input.parent().filter(www.selectors.wrapper);\n            _.each($input.data(keys.attrs), function(val, key) {\n                _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);\n            });\n            $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input);\n            if ($wrapper.length) {\n                $input.detach().insertAfter($wrapper);\n                $wrapper.remove();\n            }\n        }\n        function $elOrNull(obj) {\n            var isValid, $el;\n            isValid = _.isJQuery(obj) || _.isElement(obj);\n            $el = isValid ? $(obj).first() : [];\n            return $el.length ? $el : null;\n        }\n    })();\n});"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/templates/deprecation.mustache",
    "content": "{{#deprecation_message}}\n<div class=\"aside aside-deprecated\">\n  <p class=\"aside-title\">Deprecated</p>\n  {{{deprecation_message}}}\n</div>\n{{/deprecation_message}}\n{{#unavailable_message}}\n<div class=\"aside aside-unavailable\">\n  <p class=\"aside-title\">Unavailable</p>\n  {{{unavailable_message}}}\n</div>\n{{/unavailable_message}}\n"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/templates/doc.mustache",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>{{name}} {{kind}} Reference</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{path_to_root}}css/jazzy.css\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{path_to_root}}css/highlight.css\" />\n    {{#enable_katex}}\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{path_to_root}}css/katex.min.css\" />\n    {{/enable_katex}}\n    <meta charset=\"utf-8\">\n    <script src=\"{{path_to_root}}js/jquery.min.js\" defer></script>\n    {{#enable_katex}}\n    <script src=\"{{path_to_root}}js/katex.min.js\" defer></script>\n    {{/enable_katex}}\n    <script src=\"{{path_to_root}}js/jazzy.js\" defer></script>\n    {{{custom_head}}}\n    {{^disable_search}}\n    <script src=\"{{path_to_root}}js/lunr.min.js\" defer></script>\n    <script src=\"{{path_to_root}}js/typeahead.jquery.js\" defer></script>\n    <script src=\"{{path_to_root}}js/jazzy.search.js\" defer></script>\n    {{/disable_search}}\n  </head>\n  <body>\n\n    {{#dash_type}}\n    <a name=\"//apple_ref/{{language_stub}}/{{dash_type}}/{{name}}\" class=\"dashAnchor\"></a>\n    {{/dash_type}}\n\n    <a title=\"{{name}} {{kind}} Reference\"></a>\n\n    {{> header}}\n\n    <p class=\"breadcrumbs\">\n      <a class=\"breadcrumb\" href=\"{{path_to_root}}index.html\">{{readme_title}}</a>\n      {{#breadcrumbs}}\n      <img class=\"carat\" src=\"{{path_to_root}}img/carat.png\" alt=\"\"/>\n      {{#last}}\n      {{name}} {{kind}} Reference\n      {{/last}}\n      {{^last}}\n      <a class=\"breadcrumb\" href=\"{{path_to_root}}{{url}}\">{{name}}</a>\n      {{/last}}\n      {{/breadcrumbs}}\n    </p>\n\n    <div class=\"content-wrapper\">\n      {{> nav}}\n      <article class=\"main-content\">\n\n        <section class=\"section\">\n          <div class=\"section-content top-matter\">\n            {{^hide_name}}<h1>{{name}}</h1>{{/hide_name}}\n            {{> deprecation}}\n            {{#declaration}}\n              <div class=\"declaration\">\n                <div class=\"language\">\n                  {{#other_language_declaration}}<p class=\"aside-title\">{{language}}</p>{{/other_language_declaration}}\n                  {{{declaration}}}\n                </div>\n                {{#other_language_declaration}}\n                <div class=\"language\">\n                  <p class=\"aside-title\">Swift</p>\n                  {{{other_language_declaration}}}\n                </div>\n                {{/other_language_declaration}}\n              </div>\n            {{/declaration}}\n            {{{overview}}}\n            {{#parameters.any?}}\n              <div>\n                <h4>Parameters</h4>\n                <table class=\"graybox\">\n                  <tbody>\n                    {{#parameters}}\n                      {{> parameter}}\n                    {{/parameters}}\n                  </tbody>\n                </table>\n              </div>\n            {{/parameters.any?}}\n            {{#return}}\n              <div>\n                <h4>Return Value</h4>\n                {{{return}}}\n              </div>\n            {{/return}}\n            {{#source_host_item_url}}\n              <div class=\"slightly-smaller\">\n                <a href=\"{{{.}}}\">Show on {{source_host_name}}</a>\n              </div>\n            {{/source_host_item_url}}\n          </div>\n        </section>\n\n        {{> tasks}}\n\n      </article>\n    </div>\n    {{> footer}}\n  </body>\n</html>\n"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/templates/footer.mustache",
    "content": "<section class=\"footer\">\n  {{{copyright}}}\n  <p>Generated by <a class=\"link\" href=\"https://github.com/realm/jazzy\" target=\"_blank\" rel=\"external noopener\">jazzy ♪♫ v{{jazzy_version}}</a>, a <a class=\"link\" href=\"https://realm.io\" target=\"_blank\" rel=\"external noopener\">Realm</a> project.</p>\n</section>\n"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/templates/header.mustache",
    "content": "<header class=\"header\">\n  <p class=\"header-col header-col--primary\">\n    <a class=\"header-link\" href=\"{{path_to_root}}index.html\">\n      {{docs_title}}\n    </a>\n    {{#doc_coverage}} ({{doc_coverage}}% documented){{/doc_coverage}}\n  </p>\n\n  {{^disable_search}}\n  <div class=\"header-col--secondary\">\n    <form role=\"search\" action=\"{{path_to_root}}search.json\">\n      <input type=\"text\" placeholder=\"Search documentation\" data-typeahead>\n    </form>\n  </div>\n  {{/disable_search}}\n\n  {{#source_host_url}}\n    <p class=\"header-col header-col--secondary\">\n      <a class=\"header-link\" href=\"{{.}}\">\n        <img class=\"header-icon\" src=\"{{path_to_root}}img/{{source_host_image}}\" alt=\"{{source_host_name}}\"/>\n        View on {{source_host_name}}\n      </a>\n    </p>\n  {{/source_host_url}}\n\n  {{#dash_url}}\n    <p class=\"header-col header-col--secondary\">\n      <a class=\"header-link\" href=\"{{dash_url}}\">\n        <img class=\"header-icon\" src=\"{{path_to_root}}img/dash.png\" alt=\"Dash\"/>\n        Install in Dash\n      </a>\n    </p>\n  {{/dash_url}}\n</header>\n"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/templates/nav.mustache",
    "content": "<nav class=\"navigation\">\n  <ul class=\"nav-groups\">\n    {{#structure}}\n    <li class=\"nav-group-name\">\n      <a class=\"nav-group-name-link\" href=\"{{path_to_root}}{{url}}\">{{section}}</a>\n      <ul class=\"nav-group-tasks\">\n        {{#children}}\n        <li class=\"nav-group-task\">\n          <a class=\"nav-group-task-link\" href=\"{{path_to_root}}{{url}}\">{{name}}</a>\n        </li>\n        {{/children}}\n      </ul>\n    </li>\n    {{/structure}}\n  </ul>\n</nav>\n"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/templates/parameter.mustache",
    "content": "<tr>\n  <td>\n    <code>\n    <em>{{name}}</em>\n    </code>\n  </td>\n  <td>\n    <div>\n      {{{discussion}}}\n    </div>\n  </td>\n</tr>\n"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/templates/task.mustache",
    "content": "<div class=\"task-group\">\n  {{#name}}\n  <div class=\"task-name-container\">\n    <a name=\"/{{uid}}\"></a>\n    <a name=\"//apple_ref/{{language_stub}}/Section/{{name}}\" class=\"dashAnchor\"></a>\n    <div class=\"section-name-container\">\n      <a class=\"section-name-link\" href=\"#/{{uid}}\"></a>\n      <h3 class=\"section-name\">{{{name_html}}}</h3>\n    </div>\n  </div>\n  {{/name}}\n  <ul class=\"item-container\">\n    {{#items}}\n    <li class=\"item\">\n      <div>\n        <code>\n        <a name=\"/{{usr}}\"></a>\n        <a name=\"//apple_ref/{{language_stub}}/{{dash_type}}/{{name}}\" class=\"dashAnchor\"></a>\n        {{#direct_link}}\n        <a class=\"direct-link{{#usage_discouraged}} discouraged{{/usage_discouraged}}\" href=\"{{{path_to_root}}}{{{url}}}\">{{name}}</a>\n        </code>\n        {{/direct_link}}\n        {{^direct_link}}\n        {{^usage_discouraged}}\n        <a class=\"token\" href=\"#/{{usr}}\">{{{name_html}}}</a>\n        {{/usage_discouraged}}\n        {{#usage_discouraged}}\n        <a class=\"token discouraged\" href=\"#/{{usr}}\">{{{name_html}}}</a>\n        {{/usage_discouraged}}\n        </code>\n        {{#declaration_note}}\n          <span class=\"declaration-note\">\n            {{.}}\n          </span>\n        {{/declaration_note}}\n      </div>\n      <div class=\"height-container\">\n        <div class=\"pointer-container\"></div>\n        <section class=\"section\">\n          <div class=\"pointer\"></div>\n          {{> deprecation}}\n          {{#abstract}}\n          <div class=\"abstract\">\n            {{{abstract}}}\n            {{#url}}\n            <a href=\"{{{path_to_root}}}{{{url}}}\" class=\"slightly-smaller\">See more</a>\n            {{/url}}\n          </div>\n          {{/abstract}}\n          {{#default_impl_abstract}}\n          <h4>Default Implementation</h4>\n          <div class=\"default_impl abstract\">\n            {{{default_impl_abstract}}}\n          </div>\n          {{/default_impl_abstract}}\n          {{#declaration}}\n          <div class=\"declaration\">\n            <h4>Declaration</h4>\n            <div class=\"language\">\n              <p class=\"aside-title\">{{language}}</p>\n              {{{declaration}}}\n            </div>\n            {{#other_language_declaration}}\n            <div class=\"language\">\n              <p class=\"aside-title\">Swift</p>\n              {{{other_language_declaration}}}\n            </div>\n            {{/other_language_declaration}}\n          </div>\n          {{/declaration}}\n          {{#parameters.count}}\n          <div>\n            <h4>Parameters</h4>\n            <table class=\"graybox\">\n              <tbody>\n                {{#parameters}}\n                {{> parameter}}\n                {{/parameters}}\n              </tbody>\n            </table>\n          </div>\n          {{/parameters.count}}\n          {{#return}}\n          <div>\n            <h4>Return Value</h4>\n            {{{return}}}\n          </div>\n          {{/return}}\n          {{#source_host_item_url}}\n          <div class=\"slightly-smaller\">\n            <a href=\"{{{.}}}\">Show on {{source_host_name}}</a>\n          </div>\n          {{/source_host_item_url}}\n        </section>\n        {{/direct_link}}\n      </div>\n    </li>\n    {{/items}}\n  </ul>\n</div>\n"
  },
  {
    "path": "lib/jazzy/themes/fullwidth/templates/tasks.mustache",
    "content": "{{#tasks.count}}\n<section class=\"section\">\n  <div class=\"section-content\">\n    {{#tasks}}\n    {{> task}}\n    {{/tasks}}\n  </div>\n</section>\n{{/tasks.count}}\n"
  },
  {
    "path": "lib/jazzy/themes/jony/assets/css/highlight.css.scss",
    "content": "/*! Jazzy - https://github.com/realm/jazzy\n *  Copyright Realm Inc.\n *  SPDX-License-Identifier: MIT\n */\n/* Credit to https://gist.github.com/wataru420/2048287 */\n\n.highlight {\n  .c { color: #999988; font-style: italic } // Comment\n  .err { color: #a61717; background-color: #e3d2d2 } // Error\n  .k { color: #000000; font-weight: bold } // Keyword\n  .o { color: #000000; font-weight: bold } // Operator\n  .cm { color: #999988; font-style: italic } // Comment.Multiline\n  .cp { color: #999999; font-weight: bold } // Comment.Preproc\n  .c1 { color: #999988; font-style: italic } // Comment.Single\n  .cs { color: #999999; font-weight: bold; font-style: italic } // Comment.Special\n  .gd { color: #000000; background-color: #ffdddd } // Generic.Deleted\n  .gd .x { color: #000000; background-color: #ffaaaa } // Generic.Deleted.Specific\n  .ge { color: #000000; font-style: italic } // Generic.Emph\n  .gr { color: #aa0000 } // Generic.Error\n  .gh { color: #999999 } // Generic.Heading\n  .gi { color: #000000; background-color: #ddffdd } // Generic.Inserted\n  .gi .x { color: #000000; background-color: #aaffaa } // Generic.Inserted.Specific\n  .go { color: #888888 } // Generic.Output\n  .gp { color: #555555 } // Generic.Prompt\n  .gs { font-weight: bold } // Generic.Strong\n  .gu { color: #aaaaaa } // Generic.Subheading\n  .gt { color: #aa0000 } // Generic.Traceback\n  .kc { color: #000000; font-weight: bold } // Keyword.Constant\n  .kd { color: #000000; font-weight: bold } // Keyword.Declaration\n  .kp { color: #000000; font-weight: bold } // Keyword.Pseudo\n  .kr { color: #000000; font-weight: bold } // Keyword.Reserved\n  .kt { color: #445588; } // Keyword.Type\n  .m { color: #009999 } // Literal.Number\n  .s { color: #d14 } // Literal.String\n  .na { color: #008080 } // Name.Attribute\n  .nb { color: #0086B3 } // Name.Builtin\n  .nc { color: #445588; font-weight: bold } // Name.Class\n  .no { color: #008080 } // Name.Constant\n  .ni { color: #800080 } // Name.Entity\n  .ne { color: #990000; font-weight: bold } // Name.Exception\n  .nf { color: #990000; } // Name.Function\n  .nn { color: #555555 } // Name.Namespace\n  .nt { color: #000080 } // Name.Tag\n  .nv { color: #008080 } // Name.Variable\n  .ow { color: #000000; font-weight: bold } // Operator.Word\n  .w { color: #bbbbbb } // Text.Whitespace\n  .mf { color: #009999 } // Literal.Number.Float\n  .mh { color: #009999 } // Literal.Number.Hex\n  .mi { color: #009999 } // Literal.Number.Integer\n  .mo { color: #009999 } // Literal.Number.Oct\n  .sb { color: #d14 } // Literal.String.Backtick\n  .sc { color: #d14 } // Literal.String.Char\n  .sd { color: #d14 } // Literal.String.Doc\n  .s2 { color: #d14 } // Literal.String.Double\n  .se { color: #d14 } // Literal.String.Escape\n  .sh { color: #d14 } // Literal.String.Heredoc\n  .si { color: #d14 } // Literal.String.Interpol\n  .sx { color: #d14 } // Literal.String.Other\n  .sr { color: #009926 } // Literal.String.Regex\n  .s1 { color: #d14 } // Literal.String.Single\n  .ss { color: #990073 } // Literal.String.Symbol\n  .bp { color: #999999 } // Name.Builtin.Pseudo\n  .vc { color: #008080 } // Name.Variable.Class\n  .vg { color: #008080 } // Name.Variable.Global\n  .vi { color: #008080 } // Name.Variable.Instance\n  .il { color: #009999 } // Literal.Number.Integer.Long\n}\n"
  },
  {
    "path": "lib/jazzy/themes/jony/assets/css/jazzy.css.scss",
    "content": "/*! Jazzy - https://github.com/realm/jazzy\n *  Copyright Realm Inc.\n *  SPDX-License-Identifier: MIT\n */\n////////////////////////////////\n// Constants\n////////////////////////////////\n\n$bg_color: #2C2C2C;\n$doc_coverage_color: #999;\n$code_color: #777;\n$code_bg_color: #eee;\n$link_color: #0088cc;\n$white_color: #fff;\n$light_gray_bg_color: #fafafa;\n$normal_gray_bg_color: #f2f2f2;\n$declaration_bg_color: #f9f9f9;\n$declaration_title_language_color: #4b8afb;\n\n$content_wrapper_width: calc(100% - 32px);\n$content_wrapper_max_width: 980px;\n$article_max_width: 750px;\n\n$mobile_breakpoint: 767px;\n$content_top_offset: 87px;\n$header_height: 48px;\n$breadcrumb_padding: 10px;\n\n$code_font: 'SF Mono', Menlo, monospace;\n\n$gray_border_color: #e2e2e2;\n$gray_border: 1px solid $gray_border_color;\n$declaration_language_border: 5px solid #cde9f4;\n\n$aside_color: #aaa;\n$aside_border: 5px solid lighten($aside_color, 20%);\n$aside_warning_color: #ff0000;\n$aside_warning_border: 5px solid lighten($aside_warning_color, 20%);\n\n////////////////////////////////\n// Reset\n////////////////////////////////\n\nhtml, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td {\n  background: transparent;\n  border: 0;\n  margin: 0;\n  outline: 0;\n  padding: 0;\n  vertical-align: baseline;\n}\n\n////////////////////////////////\n// Global\n////////////////////////////////\n\nbody {\n  background-color: $white_color;\n  font-family: -apple-system, Helvetica, freesans, Arial, sans-serif;\n  font-size: 16px;\n  line-height: 1.6;\n  -webkit-font-smoothing: subpixel-antialiased;\n  word-wrap: break-word;\n  min-height: 100vh;\n}\n\n// Headers\n\nh1, h2, h3 {\n  margin-top: 0.8em;\n  margin-bottom: 0.3em;\n  font-weight: 400;\n  color: black;\n}\nh1 {\n  font-size: 2.5em;\n}\nh2 {\n  font-size: 2em;\n  border-bottom: $gray_border;\n}\nh4 {\n  font-size: 13px;\n  line-height: 1.5;\n  margin-top: 21px;\n}\nh5 {\n  font-size: 1.1em;\n}\nh6 {\n  font-size: 1.1em;\n  color: $code_color;\n}\n\n@media screen and (max-width: $mobile_breakpoint) {\n  h1 { font-size: 1.75em; }\n  h2 { font-size: 1.4em; }\n}\n\n// Code\n\npre, code {\n  font-family: $code_font;\n  font-size: 0.95em;\n  color: $code_color;\n  word-wrap: normal;\n}\n\npre {\n  line-height: 1.6;\n}\n\n// Links\n\na {\n  color: $link_color;\n  text-decoration: none;\n  code {\n    color: inherit;\n  }\n}\n\n// Lists\n\nul {\n  padding-left: 15px;\n}\nli {\n  line-height: 1.8em;\n}\n\n// Images\n\nimg {\n  max-width: 100%;\n}\n\n// Blockquotes\n\nblockquote {\n  margin-left: 0;\n  padding: 0 10px;\n  border-left: 4px solid #ccc;\n}\n\n// HRs\n\nhr {\n  height: 1px;\n  border: none;\n  background-color: $gray_border_color;\n}\n\n// Footnotes\n\n.footnote-ref {\n  display: inline-block;\n  scroll-margin-top: $content-top-offset;\n}\n\n.footnote-def {\n  scroll-margin-top: $content-top-offset;\n}\n\n// General Content Wrapper\n\n.content-wrapper {\n  margin: 0 auto;\n  width: $content_wrapper_width;\n  max-width: $content_wrapper_max_width;\n}\n\n\n////////////////////////////////\n// Content Wrappers\n////////////////////////////////\n\n.wrapper {\n  display: flex;\n  flex-direction: column;\n  min-height: inherit;\n  overflow: auto;\n}\n\n.article-wrapper  > *,\n.nav-wrapper  > *,\n.footer-wrapper > * {\n  margin: 0 auto;\n  width: $content_wrapper_width;\n  max-width: $content_wrapper_max_width;\n}\n\n.article-wrapper {\n  flex: 1;\n  background-color: $white_color;\n}\n\n.nav-wrapper {\n  background-color: $light_gray_bg_color;\n}\n\n.footer-wrapper {\n  background-color: $normal_gray_bg_color;\n}\n\n////////////////////////////////\n// Header & Top Breadcrumbs\n////////////////////////////////\n\nheader {\n  // font-size: 0.85em;\n  line-height: $header_height;\n  background-color: $bg_color;\n  position: fixed;\n  width: 100%;\n  z-index: 3;\n  img {\n    padding-right: 6px;\n    vertical-align: -2px;\n    height: 16px;\n  }\n  a {\n    color: $white_color;\n  }\n  p {\n    float: left;\n    color: $doc_coverage_color;\n  }\n  .header-right {\n    float: right;\n    margin-left: 16px;\n  }\n}\n\n#breadcrumbs-container {\n  background-color: $bg_color;\n  position: fixed;\n  z-index: 2;\n  width: 100%;\n}\n\n#breadcrumbs {\n  color: rgba(255, 255, 255, 0.6);\n  height: $content_top_offset - $header_height - $breadcrumb_padding;\n  padding-bottom: $breadcrumb_padding;\n  width: 100%;\n  margin-top: $header_height;\n  white-space: nowrap;\n  overflow-x: scroll;\n  #carat {\n    height: 10px;\n    margin: 0 5px;\n  }\n  a {\n    color: white;\n  }\n}\n\n@media screen and (max-width: $mobile_breakpoint) {\n  #breadcrumbs {\n    color: white;\n  }\n}\n\n////////////////////////////////\n// Navigation\n////////////////////////////////\n\n.nav-groups {\n  list-style-type: none;\n  padding-left: 0;\n}\n\n.nav-group-name {\n  font-size: 1.5rem;\n  font-weight: 500;\n  padding: 20px 0;\n  &:not(:last-child) {\n    border-bottom: $gray_border;\n  }\n  > a {\n    color: #333;\n  }\n}\n\n.nav-group-tasks {\n  column-count: 2;\n  list-style: none;\n  padding: 0;\n  margin-top: 5px;\n}\n\n.nav-group-task {\n  font-size: 1.1rem;\n  font-weight: 400;\n  a {\n    color: #888;\n  }\n}\n\n@media screen and (max-width: $mobile_breakpoint) {\n  .nav-group-tasks {\n    column-count: 1;\n  }\n}\n\n////////////////////////////////\n// Main Content\n////////////////////////////////\n\n.main-content {\n  overflow: hidden;\n  padding-bottom: 60px;\n  margin-top: $content_top_offset;\n  p, a, code, em, ul, table, blockquote {\n    margin-bottom: 1em;\n  }\n  p {\n    line-height: 1.5;\n  }\n  section {\n    max-width: $article_max_width;\n\n    .section:first-child {\n      margin-top: 0;\n      padding-top: 0;\n    }\n\n    .task-group-section .task-group:first-of-type {\n      padding-top: 10px;\n\n      .section-name {\n        padding-top: 15px;\n      }\n    }\n\n    .heading:before {\n      content: \"\";\n      display: block;\n      padding-top: $content_top_offset;\n      margin: -$content_top_offset 0 0;\n    }\n  }\n\n  .section-name {\n    p {\n       margin-bottom: inherit;\n       line-height: inherit;\n    }\n    code {\n      color: inherit;\n    }\n  }\n}\n\n.highlight {\n  background-color: $code_bg_color;\n  padding: 10px 12px;\n  border: $gray_border;\n  border-radius: 4px;\n  overflow-x: auto;\n}\n\n.declaration .highlight {\n  overflow-x: initial; // This allows the scrollbar to show up inside declarations\n  padding: 0 40px 40px 0;\n  margin-bottom: -25px;\n  background-color: transparent;\n  border: none;\n}\n\n.section-name {\n  font-size: 1.5rem;\n  font-weight: 500;\n  margin: 0;\n}\n\n.task-group-section {\n  margin-top: 10px;\n  border-top: $gray_border;\n}\n\n.task-group {\n  padding-top: 0px;\n  > ul {\n    padding-left: 0;\n  }\n}\n\n.task-name-container {\n  a[name] {\n    &:before {\n      content: \"\";\n      display: block;\n      padding-top: $content_top_offset;\n      margin: -$content_top_offset 0 0;\n    }\n  }\n}\n\n.section-name-container {\n  position: relative;\n  display: inline-block;\n\n  .section-name-link {\n    position: absolute;\n    top: 0;\n    left: 0;\n    bottom: 0;\n    right: 0;\n    margin-bottom: 0;\n  }\n\n  .section-name {\n    position: relative;\n    pointer-events: none;\n    z-index: 1;\n    a {\n      pointer-events: auto;\n    }\n  }\n}\n\n.item {\n  padding-top: 8px;\n  width: 100%;\n  list-style-type: none;\n  a[name] {\n    &:before {\n      content: \"\";\n      display: block;\n      padding-top: $content_top_offset;\n      margin: -$content_top_offset 0 0;\n    }\n  }\n  code {\n    background-color: transparent;\n    padding: 0;\n  }\n  .token, .direct-link {\n    display: inline-block;\n    text-indent: -20px;\n    padding-left: 3px;\n    margin-left: 55px;\n    transition: all 300ms;\n  }\n  .discouraged {\n    text-decoration: line-through;\n  }\n  .token-open {\n    margin-left: 45px;\n  }\n}\n\n.declaration-note {\n  font-size: .85em;\n  color: rgba(128,128,128,1);\n  font-style: italic;\n}\n\n.pointer-container {\n  left: -23px;\n  padding-bottom: 13px;\n  position: relative;\n  width: 110%;\n}\n\n.pointer {\n  background: $declaration_bg_color;\n  border-left: $gray_border;\n  border-top: $gray_border;\n  height: 12px;\n  left: 21px;\n  top: -7px;\n  -webkit-transform: rotate(45deg);\n  -moz-transform: rotate(45deg);\n  -o-transform: rotate(45deg);\n  transform: rotate(45deg);\n  position: absolute;\n  width: 12px;\n}\n\n.height-container {\n  display: none;\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n  .section {\n    position: relative;\n    background: $declaration_bg_color;\n    width: 100%;\n    padding: 10px 25px;\n    border: $gray_border;\n    border-radius: 8px;\n    box-sizing: border-box;\n  }\n}\n\n.aside, .language {\n  padding: 6px 12px;\n  margin: 12px 0;\n  border-left: $aside_border;\n  overflow-y: hidden;\n  .aside-title {\n    font-size: 12px;\n    font-weight: 600;\n    letter-spacing: 2px;\n    text-transform: uppercase;\n    padding-bottom: 0;\n    margin: 0;\n    color: $aside_color;\n    -webkit-user-select: none;\n  }\n  p:last-child {\n    margin-bottom: 0;\n  }\n}\n\n.language {\n  border-left: $declaration_language_border;\n  .aside-title {\n    color: $declaration_title_language_color;\n  }\n}\n\n.aside-warning, .aside-deprecated, .aside-unavailable {\n  border-left: $aside_warning_border;\n  .aside-title {\n    color: $aside_warning_color;\n  }\n}\n\n.graybox {\n  border-collapse: collapse;\n  width: 100%;\n  p {\n    margin: 0;\n    word-break: break-word;\n    min-width: 50px;\n  }\n  td {\n    border: $gray_border;\n    padding: 5px 25px 5px 10px;\n    vertical-align: middle;\n  }\n  tr td:first-of-type {\n    text-align: right;\n    padding: 7px;\n    vertical-align: top;\n    word-break: normal;\n    width: 40px;\n  }\n}\n\n.slightly-smaller {\n  font-size: 0.9em;\n}\n\n#footer {\n  padding: 25px 0;\n  box-sizing: border-box;\n\n  p {\n    margin: 0;\n    color: #aaa;\n    font-size: 0.8em;\n  }\n}\n\n////////////////////////////////\n// Dash\n////////////////////////////////\n\nhtml.dash {\n  header, #breadcrumbs {\n    display: none;\n  }\n  .main-content {\n    width: $content_wrapper_width;\n    max-width: $content_wrapper_max_width;\n    margin-left: 0;\n    border: none;\n    width: 100%;\n    top: 0;\n    padding-bottom: 0;\n  }\n  .height-container {\n    display: block;\n  }\n  .item .token {\n    margin-left: 0;\n  }\n  .content-wrapper {\n    width: auto;\n  }\n  #footer {\n    position: static;\n  }\n}\n\n////////////////////////////////\n// Responsive design\n////////////////////////////////\n\n@media screen and (max-width: $mobile_breakpoint) {\n  .no-mobile {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "lib/jazzy/themes/jony/assets/js/jazzy.js",
    "content": "// Jazzy - https://github.com/realm/jazzy\n// Copyright Realm Inc.\n// SPDX-License-Identifier: MIT\n\nwindow.jazzy = {'docset': false}\nif (typeof window.dash != 'undefined') {\n  document.documentElement.className += ' dash'\n  window.jazzy.docset = true\n}\nif (navigator.userAgent.match(/xcode/i)) {\n  document.documentElement.className += ' xcode'\n  window.jazzy.docset = true\n}\n\nfunction toggleItem($link, $content) {\n  var animationDuration = 300;\n  $link.toggleClass('token-open');\n  $content.slideToggle(animationDuration);\n}\n\nfunction itemLinkToContent($link) {\n  return $link.parent().parent().next();\n}\n\n// On doc load + hash-change, open any targeted item\nfunction openCurrentItemIfClosed() {\n  if (window.jazzy.docset) {\n    return;\n  }\n  var $link = $(`a[name=\"${location.hash.substring(1)}\"]`).nextAll('.token');\n  $content = itemLinkToContent($link);\n  if ($content.is(':hidden')) {\n    toggleItem($link, $content);\n  }\n}\n\n$(openCurrentItemIfClosed);\n$(window).on('hashchange', openCurrentItemIfClosed);\n\n// On item link ('token') click, toggle its discussion\n$('.token').on('click', function(event) {\n  if (window.jazzy.docset) {\n    return;\n  }\n  var $link = $(this);\n  toggleItem($link, itemLinkToContent($link));\n\n  // Keeps the document from jumping to the hash.\n  var href = $link.attr('href');\n  if (history.pushState) {\n    history.pushState({}, '', href);\n  } else {\n    location.hash = href;\n  }\n  event.preventDefault();\n});\n\n// Clicks on links to the current, closed, item need to open the item\n$(\"a:not('.token')\").on('click', function() {\n  if (location == this.href) {\n    openCurrentItemIfClosed();\n  }\n});\n\n// KaTeX rendering\nif (\"katex\" in window) {\n  $($('.math').each( (_, element) => {\n    katex.render(element.textContent, element, {\n      displayMode: $(element).hasClass('m-block'),\n      throwOnError: false,\n      trust: true\n    });\n  }))\n}\n"
  },
  {
    "path": "lib/jazzy/themes/jony/templates/deprecation.mustache",
    "content": "{{#deprecation_message}}\n<div class=\"aside aside-deprecated\">\n  <p class=\"aside-title\">Deprecated</p>\n  {{{deprecation_message}}}\n</div>\n{{/deprecation_message}}\n{{#unavailable_message}}\n<div class=\"aside aside-unavailable\">\n  <p class=\"aside-title\">Unavailable</p>\n  {{{unavailable_message}}}\n</div>\n{{/unavailable_message}}\n"
  },
  {
    "path": "lib/jazzy/themes/jony/templates/doc.mustache",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>{{name}} {{kind}} Reference</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{path_to_root}}css/jazzy.css\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{path_to_root}}css/highlight.css\" />\n    {{#enable_katex}}\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{path_to_root}}css/katex.min.css\" />\n    {{/enable_katex}}\n    <meta charset='utf-8'>\n\t<meta name=\"viewport\" content=\"width=device-width, viewport-fit=cover, initial-scale=1.0\" />\n    <script src=\"{{path_to_root}}js/jquery.min.js\" defer></script>\n    {{#enable_katex}}\n    <script src=\"{{path_to_root}}js/katex.min.js\" defer></script>\n    {{/enable_katex}}\n    <script src=\"{{path_to_root}}js/jazzy.js\" defer></script>\n    {{{custom_head}}}\n  </head>\n  <body>\n    {{#dash_type}}\n    <a name=\"//apple_ref/{{language_stub}}/{{dash_type}}/{{name}}\" class=\"dashAnchor\"></a>\n    {{/dash_type}}\n    <a title=\"{{name}} {{kind}} Reference\"></a>\n    {{> header}}\n    <div id=\"breadcrumbs-container\">\n      <div class=\"content-wrapper\">\n        <p id=\"breadcrumbs\">\n          <span class=\"no-mobile\">\n            <a href=\"{{path_to_root}}index.html\">{{readme_title}}</a>\n            {{#breadcrumbs}}\n            <img id=\"carat\" src=\"{{path_to_root}}img/carat.png\" alt=\"\"/>\n            {{#last}}\n            {{name}} {{kind}} Reference\n            {{/last}}\n            {{^last}}\n            <a href=\"{{path_to_root}}{{url}}\">{{name}}</a>\n            {{/last}}\n            {{/breadcrumbs}}\n          </span>\n        </p>\n      </div>\n    </div>\n    <div class=\"wrapper\">\n      <div class=\"article-wrapper\">\n        <article class=\"main-content\">\n          <section>\n            <section class=\"section\">\n              {{^hide_name}}<h1>{{name}}</h1>{{/hide_name}}\n              {{> deprecation}}\n              {{#declaration}}\n                <div class=\"declaration\">\n                  <div class=\"language\">\n                    {{#other_language_declaration}}<p class=\"aside-title\">{{language}}</p>{{/other_language_declaration}}\n                    {{{declaration}}}\n                  </div>\n                  {{#other_language_declaration}}\n                  <div class=\"language\">\n                    <p class=\"aside-title\">Swift</p>\n                    {{{other_language_declaration}}}\n                  </div>\n                  {{/other_language_declaration}}\n                </div>\n              {{/declaration}}\n              {{{overview}}}\n              {{#parameters.any?}}\n                <div>\n                  <h4>Parameters</h4>\n                  <table class=\"graybox\">\n                    <tbody>\n                      {{#parameters}}\n                        {{> parameter}}\n                      {{/parameters}}\n                    </tbody>\n                  </table>\n                </div>\n              {{/parameters.any?}}\n              {{#return}}\n                <div>\n                  <h4>Return Value</h4>\n                  {{{return}}}\n                </div>\n              {{/return}}\n              {{#source_host_item_url}}\n                <div class=\"slightly-smaller\">\n                  <a href=\"{{{.}}}\">Show on {{source_host_name}}</a>\n                </div>\n              {{/source_host_item_url}}\n            </section>\n            {{> tasks}}\n          </section>\n        </article>\n      </div>\n      <div class=\"nav-wrapper\">\n        {{> nav}}\n      </div>\n      <div class=\"footer-wrapper\">\n        {{> footer}}\n      </div>\n    </div>\n  </body>\n</html>\n"
  },
  {
    "path": "lib/jazzy/themes/jony/templates/footer.mustache",
    "content": "<section id=\"footer\">\n  {{{copyright}}}\n  <p>Generated by <a class=\"link\" href=\"https://github.com/realm/jazzy\" target=\"_blank\" rel=\"external noopener\">jazzy ♪♫ v{{jazzy_version}}</a>, a <a class=\"link\" href=\"https://realm.io\" target=\"_blank\" rel=\"external noopener\">Realm</a> project.</p>\n</section>\n"
  },
  {
    "path": "lib/jazzy/themes/jony/templates/header.mustache",
    "content": "<header>\n  <div class=\"content-wrapper\">\n    <p>\n      <a href=\"{{path_to_root}}index.html\">{{docs_title}}</a>\n      <span class=\"no-mobile\">{{#doc_coverage}} ({{doc_coverage}}% documented){{/doc_coverage}}</span>\n    </p>\n\n    {{#source_host_url}}\n    <p class=\"header-right\">\n      <a href=\"{{.}}\">\n        <img src=\"{{path_to_root}}img/{{source_host_image}}\" alt=\"{{source_host_name}}\"/>\n        <span class=\"no-mobile\">View on {{source_host_name}}</span>\n      </a>\n    </p>\n    {{/source_host_url}}\n\n    {{#dash_url}}\n    <p class=\"header-right\">\n      <a href=\"{{dash_url}}\">\n        <img src=\"{{path_to_root}}img/dash.png\" alt=\"Dash\"/>\n        <span class=\"no-mobile\">Install in Dash</span>\n      </a>\n    </p>\n    {{/dash_url}}\n  </div>\n</header>\n"
  },
  {
    "path": "lib/jazzy/themes/jony/templates/nav.mustache",
    "content": "<nav class=\"nav-bottom\">\n  <ul class=\"nav-groups\">\n    {{#structure}}\n    <li class=\"nav-group-name\">\n      <a href=\"{{path_to_root}}{{url}}\">{{section}}</a>\n      <ul class=\"nav-group-tasks\">\n        {{#children}}\n        <li class=\"nav-group-task\">\n          <a href=\"{{path_to_root}}{{url}}\">{{name}}</a>\n        </li>\n        {{/children}}\n      </ul>\n    </li>\n    {{/structure}}\n  </ul>\n</nav>\n"
  },
  {
    "path": "lib/jazzy/themes/jony/templates/parameter.mustache",
    "content": "<tr>\n  <td>\n    <code>\n    <em>{{name}}</em>\n    </code>\n  </td>\n  <td>\n    <div>\n      {{{discussion}}}\n    </div>\n  </td>\n</tr>\n"
  },
  {
    "path": "lib/jazzy/themes/jony/templates/task.mustache",
    "content": "<div class=\"task-group\">\n  {{#name}}\n  <div class=\"task-name-container\">\n    <a name=\"/{{uid}}\"></a>\n    <a name=\"//apple_ref/{{language_stub}}/Section/{{name}}\" class=\"dashAnchor\"></a>\n    <div class=\"section-name-container\">\n      <a class=\"section-name-link\" href=\"#/{{uid}}\"></a>\n      <h3 class=\"section-name\">{{{name_html}}}</h3>\n    </div>\n  </div>\n  {{/name}}\n  <ul>\n    {{#items}}\n    <li class=\"item\">\n      <div>\n        <code>\n        <a name=\"/{{usr}}\"></a>\n        <a name=\"//apple_ref/{{language_stub}}/{{dash_type}}/{{name}}\" class=\"dashAnchor\"></a>\n        {{#direct_link}}\n        <a class=\"direct-link{{#usage_discouraged}} discouraged{{/usage_discouraged}}\" href=\"{{{path_to_root}}}{{{url}}}\">{{name}}</a>\n        </code>\n        {{/direct_link}}\n        {{^direct_link}}\n        {{^usage_discouraged}}\n        <a class=\"token\" href=\"#/{{usr}}\">{{{name_html}}}</a>\n        {{/usage_discouraged}}\n        {{#usage_discouraged}}\n        <a class=\"token discouraged\" href=\"#/{{usr}}\">{{{name_html}}}</a>\n        {{/usage_discouraged}}\n        </code>\n        {{#declaration_note}}\n          <span class=\"declaration-note\">\n            {{.}}\n          </span>\n        {{/declaration_note}}\n      </div>\n      <div class=\"height-container\">\n        <div class=\"pointer-container\"></div>\n        <section class=\"section\">\n          <div class=\"pointer\"></div>\n          {{> deprecation}}\n          {{#abstract}}\n          <div class=\"abstract\">\n            {{{abstract}}}\n            {{#url}}\n            <a href=\"{{{path_to_root}}}{{{url}}}\" class=\"slightly-smaller\">See more</a>\n            {{/url}}\n          </div>\n          {{/abstract}}\n          {{#default_impl_abstract}}\n          <h4>Default Implementation</h4>\n          <div class=\"default_impl abstract\">\n            {{{default_impl_abstract}}}\n          </div>\n          {{/default_impl_abstract}}\n          {{#declaration}}\n          <div class=\"declaration\">\n            <h4>Declaration</h4>\n            <div class=\"language\">\n              <p class=\"aside-title\">{{language}}</p>\n              {{{declaration}}}\n            </div>\n            {{#other_language_declaration}}\n            <div class=\"language\">\n              <p class=\"aside-title\">Swift</p>\n              {{{other_language_declaration}}}\n            </div>\n            {{/other_language_declaration}}\n          </div>\n          {{/declaration}}\n          {{#parameters.count}}\n          <div>\n            <h4>Parameters</h4>\n            <table class=\"graybox\">\n              <tbody>\n                {{#parameters}}\n                {{> parameter}}\n                {{/parameters}}\n              </tbody>\n            </table>\n          </div>\n          {{/parameters.count}}\n          {{#return}}\n          <div>\n            <h4>Return Value</h4>\n            {{{return}}}\n          </div>\n          {{/return}}\n          {{#source_host_item_url}}\n          <div class=\"slightly-smaller\">\n            <a href=\"{{{.}}}\">Show on {{source_host_name}}</a>\n          </div>\n          {{/source_host_item_url}}\n        </section>\n        {{/direct_link}}\n      </div>\n    </li>\n    {{/items}}\n  </ul>\n</div>\n"
  },
  {
    "path": "lib/jazzy/themes/jony/templates/tasks.mustache",
    "content": "{{#tasks.count}}\n<section class=\"section task-group-section\">\n  {{#tasks}}\n  {{> task}}\n  {{/tasks}}\n</section>\n{{/tasks.count}}\n"
  },
  {
    "path": "lib/jazzy.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'jazzy/config'\nrequire 'jazzy/doc_builder'\n\nEncoding.default_external = Encoding::UTF_8\n"
  },
  {
    "path": "spec/Moya.podspec",
    "content": "Pod::Spec.new do |s|\n  s.name         = \"Moya\"\n  s.version      = \"15.0.0\"\n  s.summary      = \"Network abstraction layer written in Swift\"\n  s.description  = <<-EOS\n  Moya abstracts network commands using Swift Generics to provide developers\n  with more compile-time confidence.\n\n  ReactiveSwift and RxSwift extensions exist as well. Instructions for installation\n  are in [the README](https://github.com/Moya/Moya).\n  EOS\n  s.homepage     = \"https://github.com/Moya/Moya\"\n  s.license      = { :type => \"MIT\", :file => \"License.md\" }\n  s.author             = { \"Ash Furrow\" => \"ash@ashfurrow.com\" }\n  s.social_media_url   = \"http://twitter.com/ashfurrow\"\n  s.ios.deployment_target = '11.0'\n  s.osx.deployment_target = '10.13'\n  s.tvos.deployment_target = '10.0'\n  s.watchos.deployment_target = '3.0'\n  s.source       = { :git => \"https://github.com/Moya/Moya.git\", :tag => s.version }\n  s.default_subspec = \"Core\"\n  s.swift_version = '5.3'\n  s.cocoapods_version = '>= 1.4.0'\n\n  s.subspec \"Core\" do |ss|\n    ss.source_files  = \"Sources/Moya/\", \"Sources/Moya/Plugins/\"\n    ss.dependency \"Alamofire\", \"~> 5.0\"\n    ss.framework  = \"Foundation\"\n    s.ios.deployment_target = '11.0'\n    s.osx.deployment_target = '10.13'\n    s.tvos.deployment_target = '10.0'\n    s.watchos.deployment_target = '3.0'\n  end\n\n  s.subspec \"Combine\" do |ss|\n    ss.source_files  = \"Sources/CombineMoya/\"\n    ss.dependency \"Moya/Core\"\n    ss.framework  = \"Combine\"\n    ss.ios.deployment_target = '13.0'\n    ss.osx.deployment_target = '10.15'\n    ss.tvos.deployment_target = '13.0'\n    ss.watchos.deployment_target = '6.0'\n  end\n\n  s.subspec \"ReactiveSwift\" do |ss|\n    ss.source_files = \"Sources/ReactiveMoya/\"\n    ss.dependency \"Moya/Core\"\n    ss.dependency \"ReactiveSwift\", \"~> 7.0\"\n    ss.ios.deployment_target = '11.0'\n    ss.osx.deployment_target = '10.13'\n    ss.tvos.deployment_target = '10.0'\n    ss.watchos.deployment_target = '3.0'\n  end\n\nend\n"
  },
  {
    "path": "spec/integration_spec.rb",
    "content": "# frozen_string_literal: true\n\n# ------------------------------------ #\n#  Jazzy Integration tests             #\n# ------------------------------------ #\n\n#-----------------------------------------------------------------------------#\n\n# The following integrations tests are based on file comparison.\n#\n# 1.  For each test there is a folder with a `before` and `after` subfolders.\n# 2.  The contents of the before folder are copied to the `TMP_DIR` folder and\n#     then the given arguments are passed to the `JAZZY_BINARY`.\n# 3.  After the jazzy command completes the execution the each file in the\n#     `after` subfolder is compared to the contents of the temporary\n#     directory.  If the contents of the file do not match an error is\n#     registered.\n#\n# Notes:\n#\n# - The output of the jazzy command is saved in the `execution_output.txt` file\n#   which should be added to the `after` folder to test the Jazzy UI.\n# - To create a new test, just create a before folder with the environment to\n#   test, copy it to the after folder and run the tested pod command inside.\n#   Then just add the tests below this files with the name of the folder and\n#   the arguments.\n#\n# Rationale:\n#\n# - Have a way to track precisely the evolution of the artifacts (and of the\n#   UI) produced by jazzy (git diff of the after folders).\n# - Allow uses to submit pull requests with the environment necessary to\n#   reproduce an issue.\n# - Have robust tests which don't depend on the programmatic interface of\n#   Jazzy. These tests depend only the binary and its arguments an thus are\n#   suitable for testing Jazzy regardless of the implementation (they could even\n#   work for a Swift one)\n\n#-----------------------------------------------------------------------------#\n\n# @return [Pathname] The root of the repo.\n#\nROOT = Pathname.new(File.expand_path('..', __dir__)) unless defined? ROOT\n$:.unshift((ROOT + 'spec').to_s)\n\nrequire 'rubygems'\nrequire 'bundler/setup'\nrequire 'pretty_bacon'\nrequire 'colored2'\nrequire 'CLIntegracon'\n\nrequire 'cocoapods'\n\ndef configure_cocoapods\n  Pod::Config.instance.with_changes(silent: true) do\n    Pod::Command::Setup.invoke\n    Pod::Command::Repo::AddCDN.invoke(%w[trunk https://cdn.cocoapods.org/])\n    Pod::Command::Repo::Update.invoke(%w[trunk])\n  end\nend\n\nCLIntegracon.configure do |c|\n  c.spec_path = ROOT + 'spec/integration_specs'\n  c.temp_path = ROOT + 'tmp'\n\n  # Ignore certain OSX files\n  c.ignores '.DS_Store'\n  c.ignores '.git'\n  c.ignores %r{^(?!((api-)?docs(/|\\z)|execution_output.txt))}\n  c.ignores '**/*.tgz'\n\n  # Remove absolute paths from output\n  c.transform_produced '**/undocumented.json' do |path|\n    File.write(\n      path,\n      File.read(path).gsub(\n        c.temp_path.to_s,\n        '<TMP>',\n      ).gsub(\n        c.spec_path.to_s,\n        '<SPEC>',\n      ).gsub(\n        '/transformed',\n        '',\n      ),\n    )\n  end\n\n  # Transform produced databases to csv\n  c.transform_produced '**/*.dsidx' do |path|\n    File.write(\"#{path}.csv\",\n               `sqlite3 -header -csv #{path} \"select * from searchIndex;\"`)\n  end\n  # Now that we're comparing the CSV, we don't care about the binary\n  c.ignores '**/*.dsidx'\n\n  c.hook_into :bacon\nend\n\ndescribe_cli 'jazzy' do\n  subject do |s|\n    s.executable = \"ruby #{ROOT + 'bin/jazzy'}\"\n    s.environment_vars = {\n      'JAZZY_FAKE_DATE' => 'YYYY-MM-DD',\n      'JAZZY_FAKE_VERSION' => 'X.X.X',\n      'COCOAPODS_SKIP_UPDATE_MESSAGE' => 'TRUE',\n      'JAZZY_INTEGRATION_SPECS' => 'TRUE',\n      'JAZZY_FAKE_MODULE_VERSION' => 'Y.Y.Y',\n    }\n    s.default_args = []\n    s.replace_path ROOT.to_s, 'ROOT'\n    s.replace_pattern /^[\\d\\s:.-]+ ruby\\[\\d+:\\d+\\] warning:.*$\\n?/, ''\n    # Remove version numbers from CocoaPods dependencies\n    # to make specs resilient against dependency updates.\n    s.replace_pattern(/(Installing \\w+ )\\((.*)\\)/, '\\1(X.Y.Z)')\n    # Xcode 13.3 etc workaround\n    s.replace_pattern(/202[\\d.:\\- ]+xcodebuild.*?\\n/, '')\n    # Xcode 14 / in-proc sourcekitd workaround\n    s.replace_pattern(/<unknown>:0: remark.*?\\n/, '')\n    # CLIntegracon 0.8\n    s.replace_pattern(%r{/transformed/}, '/')\n    # Xcode 15 workaround\n    s.replace_pattern(/objc\\[.....\\]: Class _?DTX\\w+ is implemented in both.*?\\n/, '')\n    # arm vs. intel workaround\n    s.replace_pattern(%r{(?<=build/)(arm64|x86_64)(?=-apple)}, '')\n  end\n\n  require 'shellwords'\n  realm_head = <<-HTML\n<link rel=\"icon\" href=\"https://realm.io/img/favicon.ico\">\n<link rel=\"apple-touch-icon-precomposed\" sizes=\"57x57\" href=\"https://realm.io/img/favicon-57x57.png\" />\n<link rel=\"apple-touch-icon-precomposed\" sizes=\"114x114\" href=\"https://realm.io/img/favicon-114x114.png\" />\n<link rel=\"apple-touch-icon-precomposed\" sizes=\"72x72\" href=\"https://realm.io/img/favicon-72x72.png\" />\n<link rel=\"apple-touch-icon-precomposed\" sizes=\"144x144\" href=\"https://realm.io/img/favicon-144x144.png\" />\n<link rel=\"apple-touch-icon-precomposed\" sizes=\"120x120\" href=\"https://realm.io/img/favicon-120x120.png\" />\n<link rel=\"apple-touch-icon-precomposed\" sizes=\"152x152\" href=\"https://realm.io/img/favicon-152x152.png\" />\n<link rel=\"icon\" type=\"image/png\" href=\"https://realm.io/img/favicon-32x32.png\" sizes=\"32x32\" />\n<link rel=\"icon\" type=\"image/png\" href=\"https://realm.io/img/favicon-16x16.png\" sizes=\"16x16\" />\n<script defer>\n  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');\n  ga('create', 'UA-50247013-1', 'realm.io');\n  ga('send', 'pageview');\n</script>\n  HTML\n\n  realm_jazzy_yaml = <<-YAML\nbuild_tool_arguments:\n  - \"-scheme\"\n  - \"RealmSwift\"\n  - \"SWIFT_VERSION=4.2\"\n  - \"-destination\"\n  - \"platform=OS X,arch=x86_64\"\n  YAML\n\n  spec_subset = ENV.fetch('JAZZY_SPEC_SUBSET', nil)\n\n  # rubocop:disable Style/MultilineIfModifier\n\n  describe 'jazzy objective-c' do\n    describe 'Creates Realm Objective-C docs' do\n      realm_version = ''\n      relative_path = 'spec/integration_specs/document_realm_objc/before'\n      Dir.chdir(ROOT + relative_path) do\n        realm_version = `./build.sh get-version`.chomp\n        # jazzy will fail if it can't find all public header files\n        `touch Realm/RLMPlatform.h`\n      end\n      behaves_like cli_spec 'document_realm_objc',\n                            '--objc ' \\\n                              '--author Realm ' \\\n                              '--author_url \"https://realm.io\" ' \\\n                              '--source-host-url ' \\\n                              'https://github.com/realm/realm-cocoa ' \\\n                              '--source-host-files-url https://github.com/realm/' \\\n                              \"realm-cocoa/tree/v#{realm_version} \" \\\n                              '--module Realm ' \\\n                              \"--module-version #{realm_version} \" \\\n                              '--root-url https://realm.io/docs/objc/' \\\n                              \"#{realm_version}/api/ \" \\\n                              '--umbrella-header Realm/Realm.h ' \\\n                              '--framework-root . ' \\\n                              \"--head #{realm_head.shellescape}\"\n    end\n\n    describe 'Creates docs for ObjC-Swift project with a variety of contents' do\n      base = ROOT + 'spec/integration_specs/misc_jazzy_objc_features/before'\n      Dir.chdir(base) do\n        sourcekitten = ROOT + 'bin/sourcekitten'\n        sdk = `xcrun --show-sdk-path --sdk iphonesimulator`.chomp\n        objc_args = \"#{base}/MiscJazzyObjCFeatures/MiscJazzyObjCFeatures.h \" \\\n          '-- -x objective-c ' \\\n          \"-isysroot #{sdk} \" \\\n          \"-I #{base} \" \\\n          '-fmodules'\n        `#{sourcekitten} doc --objc #{objc_args} > objc.json`\n        `#{sourcekitten} doc -- clean build > swift.json`\n      end\n\n      behaves_like cli_spec 'misc_jazzy_objc_features',\n                            '--theme fullwidth ' \\\n                              '-s objc.json,swift.json'\n    end\n  end if !spec_subset || spec_subset == 'objc'\n\n  describe 'jazzy swift' do\n    describe 'Creates docs with a module name, author name, project URL, ' \\\n      'xcodebuild options, and github info' do\n      behaves_like cli_spec 'document_alamofire',\n                            '--skip-undocumented ' \\\n                              '--clean ' \\\n                              '--xcodebuild-arguments ' \\\n                              \"-destination,'platform=OS X'\"\n    end\n\n    describe 'Creates Realm Swift docs' do\n      realm_version = ''\n      realm_path = ROOT + 'spec/integration_specs/document_realm_swift/before'\n      realm_jazzy_path = realm_path + '.jazzy.yaml'\n\n      Dir.chdir(realm_path) do\n        realm_version = `./build.sh get-version`.chomp\n      end\n      # Xcode 16 workaround\n      File.write(realm_jazzy_path, realm_jazzy_yaml)\n\n      behaves_like cli_spec 'document_realm_swift',\n                            '--author Realm ' \\\n                              '--author_url \"https://realm.io\" ' \\\n                              '--source-host-url ' \\\n                              'https://github.com/realm/realm-cocoa ' \\\n                              '--source-host-files-url https://github.com/realm/' \\\n                              \"realm-cocoa/tree/v#{realm_version} \" \\\n                              '--module RealmSwift ' \\\n                              \"--module-version #{realm_version} \" \\\n                              '--root-url https://realm.io/docs/swift/' \\\n                              \"#{realm_version}/api/ \" \\\n                              \"--head #{realm_head.shellescape}\"\n      FileUtils.rm_rf realm_jazzy_path\n    end\n\n    describe 'Creates Siesta docs' do\n      # Siesta already has Docs/\n      # Use the default Swift version rather than the specified 4.0\n      behaves_like cli_spec 'document_siesta',\n                            '--output api-docs ' \\\n                              '--swift-version= '\n    end\n\n    describe 'Creates docs for Swift project with a variety of contents' do\n      behaves_like cli_spec 'misc_jazzy_features'\n    end\n\n    describe 'Creates docs for Swift project from a .swiftmodule' do\n      build_path = Dir.getwd + '/tmp/.build'\n      package_path =\n        ROOT + 'spec/integration_specs/misc_jazzy_symgraph_features/before'\n      `swift build --package-path #{package_path} --scratch-path #{build_path}`\n      module_path = `swift build --scratch-path #{build_path} --show-bin-path`\n      behaves_like cli_spec 'misc_jazzy_symgraph_features',\n                            '--swift-build-tool symbolgraph ' \\\n                              '--build-tool-arguments ' \\\n                              '-emit-extension-block-symbols,-I,' \\\n                              \"#{module_path.chomp}/Modules\"\n    end\n\n    describe 'Creates docs for a multiple-module project' do\n      behaves_like cli_spec 'jazzy_multi_modules'\n    end\n  end if !spec_subset || spec_subset == 'swift'\n\n  describe 'jazzy cocoapods' do\n    # Xcode 14.3 workaround, special podspec\n    podspec_patch = ROOT + 'spec/Moya.podspec'\n    podspec_used = ROOT + 'spec/integration_specs/document_moya_podspec/before/Moya.podspec'\n    podspec_save = ROOT + 'spec/Moya.podspec.safe'\n    FileUtils.cp_r podspec_used, podspec_save, remove_destination: true\n    FileUtils.cp_r podspec_patch, podspec_used, remove_destination: true\n    configure_cocoapods\n    describe 'Creates docs for a podspec with dependencies and subspecs' do\n      behaves_like cli_spec 'document_moya_podspec',\n                            '--podspec=Moya.podspec'\n    end\n    FileUtils.cp_r podspec_save, podspec_used, remove_destination: true\n    FileUtils.rm_rf podspec_save\n  end if !spec_subset || spec_subset == 'cocoapods'\n\n  # rubocop:enable Style/MultilineIfModifier\nend\n"
  },
  {
    "path": "spec/spec_helper/pre_flight.rb",
    "content": "# frozen_string_literal: true\n\n# Restores the config to the default state before each requirement\n\nmodule Bacon\n  class Context\n    old_run_requirement = instance_method(:run_requirement)\n\n    define_method(:run_requirement) do |description, spec|\n      temporary_directory = SpecHelper.temporary_directory\n\n      ::Jazzy::Config.instance = nil\n      ::Jazzy::Config.instance.tap do |c|\n        c.source_directory = temporary_directory\n      end\n\n      temporary_directory.rmtree if temporary_directory.exist?\n      temporary_directory.mkpath\n\n      old_run_requirement.bind(self).call(description, spec)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/spec_helper.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rubygems'\nrequire 'bundler/setup'\nrequire 'bacon'\nrequire 'mocha-on-bacon'\nrequire 'pretty_bacon'\nrequire 'pathname'\n\nROOT = Pathname.new(File.expand_path('..', __dir__))\n$LOAD_PATH.unshift((ROOT + 'lib').to_s)\n$LOAD_PATH.unshift((ROOT + 'spec').to_s)\n\nrequire 'jazzy'\n\nrequire 'spec_helper/pre_flight'\n\nBacon.summary_at_exit\n\nmodule Bacon\n  class Context\n    include Jazzy::Config::Mixin\n\n    def temporary_directory\n      SpecHelper.temporary_directory\n    end\n  end\nend\n\nMocha::Configuration.prevent(:stubbing_non_existent_method)\n\nmodule SpecHelper\n  def self.temporary_directory\n    ROOT + 'tmp'\n  end\nend\n"
  }
]