Full Code of NSHipster/nshipster.com for AI

master 55b55723be84 cached
257 files
16.0 MB
60.2k tokens
59 symbols
1 requests
Download .txt
Showing preview only (227K chars total). Download the full file or copy to clipboard to get everything.
Repository: NSHipster/nshipster.com
Branch: master
Commit: 55b55723be84
Files: 257
Total size: 16.0 MB

Directory structure:
gitextract_5m6loz3c/

├── .gitignore
├── .gitmodules
├── .ruby-version
├── .tool-versions
├── .well-known/
│   ├── brave-payments-verification.txt
│   ├── browserconfig.xml
│   ├── humans.txt
│   ├── robots.txt
│   └── site.webmanifest
├── 404.md
├── Gemfile
├── LICENSE.md
├── README.md
├── _bibliography/
│   └── references.bib
├── _config/
│   ├── default.yml
│   ├── nshipster.cn.yml
│   ├── nshipster.co.kr.yml
│   ├── nshipster.com.ru.yml
│   ├── nshipster.com.yml
│   ├── nshipster.es.yml
│   ├── nshipster.fr.yml
│   └── nsmutablehipster.com.yml
├── _functions/
│   └── search/
│       ├── package.json
│       └── search.js
├── _i18n/
│   ├── en-US.yml
│   ├── es-ES.yml
│   ├── fr-FR.yml
│   ├── ko-KR.yml
│   ├── ru-RU.yml
│   └── zh-Hans.yml
├── _includes/
│   ├── book.html
│   ├── contributor.html
│   ├── json-ld/
│   │   ├── article.html
│   │   ├── book.html
│   │   ├── breadcrumblist.html
│   │   ├── organization.html
│   │   └── website.html
│   └── promo.html
├── _layouts/
│   ├── author.html
│   ├── default.html
│   ├── error.html
│   ├── page.html
│   ├── post.html
│   └── translator.html
├── _plugins/
│   ├── admonition-block.rb
│   ├── camel-case-thin-space-break-filter.rb
│   ├── extended-date-filter.rb
│   ├── jwt-lexer.rb
│   ├── localization-filter.rb
│   ├── markdown-converter.rb
│   ├── page-translation-hook.rb
│   ├── post-commit-history-hook.rb
│   ├── post-revisions-hook.rb
│   ├── post-translation-hook.rb
│   ├── search-index-generator.rb
│   ├── shuffle-filter.rb
│   ├── translate-tag.rb
│   ├── unwrap-filter.rb
│   ├── url-filter.rb
│   └── well-known-hook.rb
├── assets/
│   ├── css/
│   │   ├── _admonitions.scss
│   │   ├── _animations.scss
│   │   ├── _code.scss
│   │   ├── _colors.scss
│   │   ├── _functions.scss
│   │   ├── _inputs.scss
│   │   ├── _layout.scss
│   │   ├── _typography.scss
│   │   ├── articles/
│   │   │   ├── 1password-cli.scss
│   │   │   ├── as-we-may-code.scss
│   │   │   ├── availability.scss
│   │   │   ├── caemitterlayer.scss
│   │   │   ├── callable.scss
│   │   │   ├── characterset.scss
│   │   │   ├── dark-mode.scss
│   │   │   ├── formatter.scss
│   │   │   ├── ios-13.scss
│   │   │   ├── keyvaluepairs.scss
│   │   │   ├── mapkit-js.scss
│   │   │   ├── message-id.scss
│   │   │   ├── metrickit.scss
│   │   │   ├── model-context-protocol.scss
│   │   │   ├── swift-format.scss
│   │   │   ├── swift-log.scss
│   │   │   ├── swift-package-registry.scss
│   │   │   └── swiftui-previews.scss
│   │   ├── fonts/
│   │   │   ├── _batang.scss
│   │   │   ├── _cc.scss
│   │   │   └── _merriweather.scss
│   │   ├── media-queries/
│   │   │   ├── _hover.scss
│   │   │   ├── _inverted-colors.scss
│   │   │   ├── _monochrome.scss
│   │   │   ├── _prefers-color-scheme.scss
│   │   │   ├── _prefers-contrast.scss
│   │   │   ├── _prefers-reduced-motion.scss
│   │   │   ├── _print.scss
│   │   │   └── _width.scss
│   │   └── screen.scss
│   ├── images/
│   │   └── NSShowMe.tiff
│   ├── js/
│   │   ├── application.js
│   │   ├── articles/
│   │   │   ├── caemitterlayer.js
│   │   │   ├── mapkit-js.js
│   │   │   ├── swift-format.js
│   │   │   └── wwdc-2020.js
│   │   └── nsmutablehipster.js
│   └── videos/
│       ├── TrickXORTreat.srt
│       └── caemitterlayer-final-product.m4v
├── collections/
│   ├── en/
│   │   ├── _authors/
│   │   │   ├── croath-liu.md
│   │   │   ├── delisa-mason.md
│   │   │   ├── em-lazer-walker.md
│   │   │   ├── jack-flintermann.md
│   │   │   ├── jemmons.md
│   │   │   ├── jordan-morgan.md
│   │   │   ├── matt-massicotte.md
│   │   │   ├── mattt.md
│   │   │   ├── natasha-murashev.md
│   │   │   ├── nate-cook.md
│   │   │   ├── reda-lemeden.md
│   │   │   └── zoe-smith.md
│   │   └── _books/
│   │       ├── cfhipsterref.md
│   │       ├── fake-book-objective-c.md
│   │       ├── flight-school-guide-to-swift-codable.md
│   │       ├── flight-school-guide-to-swift-numbers.md
│   │       ├── flight-school-guide-to-swift-strings.md
│   │       └── nshipster.md
│   ├── es/
│   │   ├── _authors/
│   │   │   ├── croath-liu.md
│   │   │   ├── delisa-mason.md
│   │   │   ├── jack-flintermann.md
│   │   │   ├── jordan-morgan.md
│   │   │   ├── mattt.md
│   │   │   ├── mike-lazer-walker.md
│   │   │   ├── natasha-murashev.md
│   │   │   └── nate-cook.md
│   │   ├── _books/
│   │   │   ├── 01-nshipster-swift.md
│   │   │   ├── 02-cfhipsterref.md
│   │   │   └── 03-nshipster-fake-book-objective-c.md
│   │   └── _translators/
│   │       └── juan-fernandez-sagasti.md
│   ├── fr/
│   │   ├── _authors/
│   │   │   ├── croath-liu.md
│   │   │   ├── delisa-mason.md
│   │   │   ├── jack-flintermann.md
│   │   │   ├── jordan-morgan.md
│   │   │   ├── mattt.md
│   │   │   ├── mike-lazer-walker.md
│   │   │   ├── natasha-murashev.md
│   │   │   └── nate-cook.md
│   │   ├── _books/
│   │   │   ├── 01-nshipster-swift.md
│   │   │   ├── 02-cfhipsterref.md
│   │   │   └── 03-nshipster-fake-book-objective-c.md
│   │   └── _translators/
│   │       └── vincent-pradeilles.md
│   ├── ko/
│   │   ├── _authors/
│   │   │   ├── croath-liu.md
│   │   │   ├── delisa-mason.md
│   │   │   ├── jack-flintermann.md
│   │   │   ├── jemmons.md
│   │   │   ├── mattt.md
│   │   │   ├── mike-lazer-walker.md
│   │   │   ├── natasha-murashev.md
│   │   │   └── nate-cook.md
│   │   ├── _books/
│   │   │   ├── 01-nshipster-swift.md
│   │   │   ├── 02-cfhipsterref.md
│   │   │   └── 03-nshipster-fake-book-objective-c.md
│   │   └── _translators/
│   │       └── pilgwon.md
│   ├── ru/
│   │   ├── _authors/
│   │   │   ├── croath-liu.md
│   │   │   ├── delisa-mason.md
│   │   │   ├── jack-flintermann.md
│   │   │   ├── jordan-morgan.md
│   │   │   ├── mattt.md
│   │   │   ├── mike-lazer-walker.md
│   │   │   ├── natasha-murashev.md
│   │   │   └── nate-cook.md
│   │   └── _books/
│   │       ├── 01-nshipster-swift.md
│   │       ├── 02-cfhipsterref.md
│   │       └── 03-nshipster-fake-book-objective-c.md
│   └── zh-Hans/
│       ├── _authors/
│       │   ├── croath-liu.md
│       │   ├── delisa-mason.md
│       │   ├── jack-flintermann.md
│       │   ├── mattt.md
│       │   ├── mike-lazer-walker.md
│       │   ├── natasha-murashev.md
│       │   └── nate-cook.md
│       ├── _books/
│       │   ├── 01-nshipster-swift.md
│       │   ├── 02-cfhipsterref.md
│       │   └── 03-nshipster-fake-book-objective-c.md
│       └── _translators/
│           ├── Candyan.md
│           ├── andrew-yang.md
│           ├── april-peng.md
│           ├── chester-liu.md
│           ├── croath-liu.md
│           ├── david-liu.md
│           ├── henry-lee.md
│           ├── ricky-tan.md
│           ├── steven-wang.md
│           └── tiny-tian.md
├── contribute.json
├── feed.xml
├── flight-school.md
├── index.html
├── return.md
├── sitemap.xml
├── status.md
└── vendor/
    └── cache/
        ├── activesupport-6.1.4.1.gem
        ├── addressable-2.8.0.gem
        ├── bibtex-ruby-6.0.0.gem
        ├── camertron-eprun-1.1.1.gem
        ├── citeproc-1.0.10.gem
        ├── citeproc-ruby-1.1.14.gem
        ├── cldr-plurals-runtime-rb-1.1.0.gem
        ├── colorator-1.1.0.gem
        ├── concurrent-ruby-1.1.9.gem
        ├── csl-1.6.0.gem
        ├── csl-styles-1.0.1.11.gem
        ├── em-websocket-0.5.2.gem
        ├── eventmachine-1.2.7.gem
        ├── execjs-2.8.1.gem
        ├── extras-0.3.0.gem
        ├── fastimage-2.2.5.gem
        ├── ffi-1.16.3.gem
        ├── foreman-0.87.2.gem
        ├── forwardable-extended-2.6.0.gem
        ├── htmlbeautifier-1.3.1.gem
        ├── htmlcompressor-0.4.0.gem
        ├── http_parser.rb-0.6.0.gem
        ├── i18n-1.8.10.gem
        ├── jekyll-4.2.1.gem
        ├── jekyll-include-cache-0.2.1.gem
        ├── jekyll-sanity-1.6.0.gem
        ├── jekyll-sass-converter-2.1.0.gem
        ├── jekyll-scholar-7.0.0.gem
        ├── jekyll-tidy-0.2.2.gem
        ├── jekyll-watch-2.2.1.gem
        ├── kramdown-2.3.1.gem
        ├── kramdown-parser-gfm-1.1.0.gem
        ├── latex-decode-0.3.2.gem
        ├── liquid-4.0.3.gem
        ├── liquid-tag-parser-2.0.2.gem
        ├── listen-3.7.0.gem
        ├── mercenary-0.4.0.gem
        ├── mini_portile2-2.8.7.gem
        ├── minitest-5.14.4.gem
        ├── namae-1.1.1.gem
        ├── nokogiri-1.15.6-arm64-darwin.gem
        ├── pathutil-0.16.2.gem
        ├── public_suffix-4.0.6.gem
        ├── racc-1.8.1.gem
        ├── rack-2.2.3.gem
        ├── rake-13.0.6.gem
        ├── rb-fsevent-0.11.0.gem
        ├── rb-inotify-0.10.1.gem
        ├── rexml-3.2.5.gem
        ├── safe_yaml-1.0.5.gem
        ├── sassc-2.4.0.gem
        ├── sprockets-4.0.2.gem
        ├── terminal-table-2.0.0.gem
        ├── twitter_cldr-6.7.0.gem
        ├── tzinfo-2.0.4.gem
        ├── uglifier-4.2.0.gem
        ├── unicode-display_width-1.8.0.gem
        └── zeitwerk-2.4.2.gem

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

================================================
FILE: .gitignore
================================================
.s3cfg
_site
_drafts
build
nshipster.com/articles
nshipster.com/books
nshipster.com/training
.sass-cache
.vscode
.jekyll-cache
.jekyll-metadata
Procfile
_functions/search/index.json
node_modules


================================================
FILE: .gitmodules
================================================
[submodule "collections/en/_posts"]
	path = collections/en/_posts
	url = https://github.com/NSHipster/articles.git
	branch = master
	ignore = all
	update = merge
[submodule "collections/zh-Hans/_posts"]
	path = collections/zh-Hans/_posts
	url = https://github.com/NSHipster/articles-zh-Hans.git
	branch = master
	ignore = all
	update = merge
[submodule "collections/es/_posts"]
	path = collections/es/_posts
	url = https://github.com/NSHipster/articles-es.git
	branch = master
	ignore = all
	update = merge
[submodule "collections/ko/_posts"]
	path = collections/ko/_posts
	url = https://github.com/NSHipster/articles-ko.git
	branch = master
	ignore = all
	update = merge
[submodule "collections/fr/_posts"]
	path = collections/fr/_posts
	url = https://github.com/NSHipster/articles-fr.git
	branch = master
	ignore = all
	update = merge


================================================
FILE: .ruby-version
================================================
2.7.5


================================================
FILE: .tool-versions
================================================
ruby 2.7.5


================================================
FILE: .well-known/brave-payments-verification.txt
================================================
This is a Brave Payments publisher verification file.

Domain: nshipster.com
Token: 9427d793d5eb646c66ff42e31086f6e792c31f252ba241ce213f98d6dd1ddfce


================================================
FILE: .well-known/browserconfig.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
    <msapplication>
        <tile>
            <square150x150logo src="/mstile-150x150.png"/>
            <TileColor>#f8f7f5</TileColor>
        </tile>
    </msapplication>
</browserconfig>


================================================
FILE: .well-known/humans.txt
================================================
---
layout: null
permalink: /humans.txt
---

/* TEAM */

Managing Editor: Mattt
Site: https://mat.tt
Contact: mattt [at] nshipster.com
Twitter: @mattt
Location: Portland, OR, United States

/* SITE */

Last update: {{ site.time | date: "%Y/%-m/%-d" }}
Language: {{ site.lang }}
Standards: HTML5, CSS3, WAI-ARIA
Components: Zepto
Software: Jekyll
IDE: Visual Studio Code


================================================
FILE: .well-known/robots.txt
================================================
---
layout: null
permalink: /robots.txt
---

User-agent: *
Allow: /

Sitemap: {{ site.url }}/sitemap.xml


================================================
FILE: .well-known/site.webmanifest
================================================
{
    "name": "NSHipster",
    "short_name": "NSHipster",
    "icons": [{
            "src": "/android-chrome-192x192.png",
            "sizes": "192x192",
            "type": "image/png"
        },
        {
            "src": "/android-chrome-384x384.png",
            "sizes": "384x384",
            "type": "image/png"
        }
    ],
    "theme_color": "#f8f7f5",
    "background_color": "#f8f7f5",
    "display": "standalone"
}


================================================
FILE: 404.md
================================================
---
layout: error
title: NSError 404 - NSHipster
permalink: 404.html
---

```swift
let domain = "{{ site.url | host }}"
let code = 404
let userInfo = [
    NSLocalizedDescriptionKey:
        "Requested page is too obscure, and probably does not exist.",
    NSLocalizedRecoverySuggestionErrorKey:
        "Go back to the mainstream site."
]

throw NSError(domain: domain, code: code, userInfo: userInfo)
```

```objc
NSString *domain = @"{{ site.url | host }}";
NSInteger code = 404;
NSDictionary *userInfo = @{
    NSLocalizedDescriptionKey:
        @"Requested page is too obscure, and probably does not exist.",
    NSLocalizedRecoverySuggestionErrorKey:
        @"Go back to the mainstream site."
};

NSError *error = [[NSError alloc] initWithDomain:domain
                                            code:code
                                        userInfo:userInfo];
```


================================================
FILE: Gemfile
================================================
# frozen_string_literal: true

source 'https://rubygems.org'

gem 'jekyll'
gem 'rack', '>= 2.0.6'

gem 'sprockets', '~> 4.0.beta'
gem 'uglifier', '~> 4.0'

gem 'kramdown'

gem 'rouge', git: 'https://github.com/NSHipster/rouge.git',
             branch: 'master'

gem 'nokogiri'
gem 'sassc'
gem 'ffi', '1.16.3'

gem 'twitter_cldr'

group :jekyll_plugins do
  gem 'jekyll-assets', git: 'https://github.com/envygeeks/jekyll-assets.git',
                       branch: 'master'
  gem 'jekyll-include-cache'
  gem 'jekyll-scholar'
  gem 'jekyll-tidy'
end

group :development do
  gem 'foreman'
  gem 'rake'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]


================================================
FILE: LICENSE.md
================================================
Copyright 2012 – 2025 NSHipster (https://nshipster.com)

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
# NSHipster.com

[NSHipster](https://nshipster.com) is a journal of the overlooked bits in
Swift, Objective-C and Cocoa.
Updated weekly.

This repository hosts the source code that generates and deploys
[NSHipster.com](https://nshipster.com) and its translations.
For the articles themselves,
see [this repository](https://github.com/nshipster/articles).

---

## Requirements

- Git 2.16.2+
- Ruby 2.4.3+
- [Bundler](https://bundler.io)

## Running Locally

First, clone the repository by opening Terminal.app
and running the following commands:

```terminal
$ git clone git@github.com:NSHipster/nshipster.com.git
$ cd nshipster.com
```

Next, clone the articles submodules
with the following commands:

```terminal
$ git submodule update --init --remote --merge
```

NSHipster is built using
[Jekyll](https://github.com/jekyll/jekyll),
a blog-aware, static site generator in Ruby.

Download and update the project dependencies with Bundler
using the command:

```terminal
$ bundle install
```

To run the site locally,
you must specify the configuration file
corresponding to the NSHipster website you'd like to build
(i.e. NSHipster.com, NSHipster.cn, etc.).
You can run the site locally with the following commands:

```terminal
$ bundle exec jekyll serve --config _config/default.yml,_config/$DOMAIN.yml --trace
```

Now open the server address in a web browser to see a local copy of the site
(by default, Jekyll serves to localhost on port 4000):

```terminal
$ open http://localhost:4000
```

## Deploying

NSHipster.com is hosted by [Netlify](https://netlify.com).
The site is configured with continuous deployment
such that any push to the `master` branch on this repository
automatically triggers a build and deploys the site, if successful.

Users with Push access can deploy the site by running the following command:

```terminal
$ git push origin master
```

You can monitor the status of a deploy in real-time
[on this dashboard](https://app.netlify.com/sites/nshipster/deploys/).

## Contact

Follow NSHipster on Twitter
([@NSHipster](https://twitter.com/NSHipster))

## License

All code is published under the
[MIT License](https://opensource.org/licenses/MIT).

All content is released under the
[Creative Commons BY-NC License](https://creativecommons.org/licenses/by-nc/4.0/).

NSHipster® and the NSHipster Logo
are registered trademarks of Read Evaluate Press, LLC.


================================================
FILE: _bibliography/references.bib
================================================
---
---

@article{de_montjoye_2013,
    title = {Unique in the {Crowd}: {The} privacy bounds of human mobility},
    volume = {3},
    copyright = {2013 Nature Publishing Group},
    issn = {2045-2322},
    shorttitle = {Unique in the {Crowd}},
    url = {https://www.nature.com/articles/srep01376},
    doi = {10.1038/srep01376},
    abstract = {We study fifteen months of human mobility data for one and a half million individuals and find that human mobility traces are highly unique. In fact, in a dataset where the location of an individual is specified hourly, and with a spatial resolution equal to that given by the carrier's antennas, four spatio-temporal points are enough to uniquely identify 95\% of the individuals. We coarsen the data spatially and temporally to find a formula for the uniqueness of human mobility traces given their resolution and the available outside information. This formula shows that the uniqueness of mobility traces decays approximately as the 1/10 power of their resolution. Hence, even coarse datasets provide little anonymity. These findings represent fundamental constraints to an individual's privacy and have important implications for the design of frameworks and institutions dedicated to protect the privacy of individuals.},
    language = {en},
    urldate = {2019-10-30},
    journal = {Scientific Reports},
    author = {de Montjoye, Yves-Alexandre and Hidalgo, César A. and Verleysen, Michel and Blondel, Vincent D.},
    month = mar,
    year = {2013},
    pages = {1376}
}

@article {sweeney_2000,
    title = {Simple Demographics Often Identify People Uniquely},
    journal = {Carnegie Mellon University, Data Privacy},
    year = {2000},
    type = {Working paper},
    url = {http://dataprivacylab.org/projects/identifiability/},
    author = {Sweeney, Latanya}
}

@inproceedings{zhang_2019,
    author = {Zhang, Jiexin and Beresford, Alastair R. and Sheret, Ian},
    title = {SensorID: Sensor Calibration Fingerprinting for Smartphones},
    booktitle = {Proceedings of the 40th IEEE Symposium on Security and Privacy (SP)},
    year = {2019},
    month = {May},
    publisher = {IEEE}
}

@inproceedings{olejnik_2015,
 author = {Olejnik, \Lukasz and Acar, Gunes and Castelluccia, Claude and Diaz, Claudia},
 title = {The Leaking Battery},
 booktitle = {Revised Selected Papers of the 10th International Workshop on Data Privacy Management, and Security Assurance - Volume 9481},
 year = {2016},
 isbn = {978-3-319-29882-5},
 pages = {254--263},
 numpages = {10},
 url = {http://dx.doi.org/10.1007/978-3-319-29883-2_18},
 doi = {10.1007/978-3-319-29883-2_18},
 acmid = {2979465},
 publisher = {Springer-Verlag New York, Inc.},
 address = {New York, NY, USA},
}

@inproceedings{inproceedings,
author = {rizzo_2016},
year = {2016},
month = {07},
pages = {97-104},
title = {Content-preserving Text Watermarking through Unicode Homoglyph Substitution},
doi = {10.1145/2938503.2938510}
}

@ARTICLE{artz_2001,
author={D. {Artz}},
journal={IEEE Internet Computing},
title={Digital steganography: hiding data within data},
year={2001},
volume={5},
number={3},
pages={75-80},
doi={10.1109/4236.935180},
ISSN={},
month={May},}

@inproceedings{weinberg_2018,
 author = {Weinberg, Zachary and Cho, Shinyoung and Christin, Nicolas and Sekar, Vyas and Gill, Phillipa},
 title = {How to Catch when Proxies Lie: Verifying the Physical Locations of Network Proxies with Active Geolocation},
 booktitle = {Proceedings of the Internet Measurement Conference 2018},
 series = {IMC '18},
 year = {2018},
 isbn = {978-1-4503-5619-0},
 location = {Boston, MA, USA},
 pages = {203--217},
 numpages = {15},
 url = {http://doi.acm.org/10.1145/3278532.3278551},
 doi = {10.1145/3278532.3278551},
 acmid = {3278551},
 publisher = {ACM},
 address = {New York, NY, USA},
 keywords = {active geolocation, network proxies, virtual private networks},
}

@inproceedings{meli_2019,
 author = {Meli, Michael and McNiece, Matthew R. and Reaves, Bradley},
 title = {How Bad Can It Git? Characterizing Secret Leakage in Public GitHub Repositories},
 booktitle = {Proceedings of the NDSS Symposium 2019},
 series = {NDSS’19},
 year = {2019},
 location = {San Diego, CA, USA},
 url = {https://www.ndss-symposium.org/ndss-paper/how-bad-can-it-git-characterizing-secret-leakage-in-public-github-repositories/},
}

@INPROCEEDINGS{wen_2018,
author={H. {Wen} and J. {Li} and Y. {Zhang} and D. {Gu}},
booktitle={2018 25th Asia-Pacific Software Engineering Conference (APSEC)},
title={An Empirical Study of SDK Credential Misuse in iOS Apps},
year={2018},
volume={},
number={},
pages={258-267},
keywords={data privacy;Internet;mobile computing;software engineering;mobile developers;SDK credential misuse issue;iOS platform;software development kit;popular iOS apps;app token;APP ID;serious security threats;typical SDK misuses;app developers;second-tier problem;security issues;mobile payment;push notification;third-party SDKs;web-based mobile apps;misuse case;popular mobile SDKs;Binary codes;Web services;Authentication;Tools;Performance analysis;iOS apps, Third-party SDKs, Binary code anal ysis, Credential exposure},
doi={10.1109/APSEC.2018.00040},
ISSN={},
month={Dec},}

@INPROCEEDINGS{wang_2018,
author={P. {Wang} and D. {Wu} and Z. {Chen} and T. {Wei}},
booktitle={2018 IEEE/ACM 40th International Conference on Software Engineering: Software Engineering in Practice Track (ICSE-SEIP)},
title={Protecting Million-User iOS Apps with Obfuscation: Motivations, Pitfalls, and Experience},
year={2018},
volume={},
number={},
pages={235-244},
keywords={Internet;mobile computing;reverse engineering;security of data;app vendors;software obfuscation;mobile app;multiple commercial iOS apps;million-user iOS apps;app-provided services;Web-based services whose important program logic;Software;Reverse engineering;Security;Servers;Business;Software protection;obfuscation;software protection;reverse engineering;mobile;iOS},
doi={},
ISSN={},
month={May},}


================================================
FILE: _config/default.yml
================================================
title: NSHipster
permalink: /:title/

twitter: 629523445
facebook: 418545184954768
issn: 2373-9800

domains:
  en: https://nshipster.com

author:
  name: Mattt
  email: mattt@nshipster.com
  url: /authors/mattt

markdown: NSHipsterProcessor
highlighter: rouge

kramdown:
  parse_block_html: true
  parse_span_html: true

future: true

strict_front_matter: true

defaults:
  - scope:
      path: ""
    values:
      layout: "default"
  - scope:
      path: ""
      type: "authors"
    values:
      layout: "author"
  - scope:
      path: ""
      type: "translators"
    values:
      layout: "translator"
  - scope:
      path: ""
      type: "posts"
    values:
      layout: "post"

groups:
  - Cocoa
  - Swift
  - Xcode
  - Open Source
  - Miscellaneous
  - Trivia
  - Objective-C

include: [".well-known"]

exclude:
  - README*
  - LICENSE*
  - Gemfile*
  - Procfile
  - Rakefile
  - rakelib/
  - netlify.toml
  - _redirects
  - _functions/
  - vendor/
  - node_modules

assets:
  source_maps: false
  compression: true
  defaults:
    js: { integrity: true }
    css: { integrity: true }
    img: { integrity: true }

jekyll_tidy:
  exclude:
    - robots.txt
    - humans.txt


================================================
FILE: _config/nshipster.cn.yml
================================================
url: https://nshipster.cn
lang: zh-Hans

description: >-
  **NSHipster** 关注被忽略的 Objective-C、Swift 和 Cocoa 特性。
timezone: Asia/Shanghai

collections_dir: collections/zh-Hans
collections:
  authors:
    output: true
    permalink: /authors/:path/
  translators:
    output: true
    permalink: /translators/:path/
  books:
    output: false


================================================
FILE: _config/nshipster.co.kr.yml
================================================
url: https://nshipster.co.kr
lang: ko-KR

description: >-
  **NSHipster**는 간과 된 비트의 저널입니다
  Objective-C, Swift 및 Cocoa에서.

timezone: Asia/Seoul

collections_dir: collections/ko
collections:
  authors:
    output: true
    permalink: /authors/:path/
  translators:
    output: true
    permalink: /translators/:path/
  books:
    output: false


================================================
FILE: _config/nshipster.com.ru.yml
================================================
url: https://nshipster.com.ru
lang: ru-RU

description: >-
  **NSHipster** это журнал пропущенных бит в
  Objective-C, Swift и Cocoa.
timezone: Europe/Moscow

collections_dir: collections/en
collections:
  authors:
    output: true
    permalink: /authors/:path/
  translators:
    output: true
    permalink: /translators/:path/
  books:
    output: false


================================================
FILE: _config/nshipster.com.yml
================================================
url: https://nshipster.com
lang: en-US

description: >-
  **NSHipster** is a journal of the overlooked bits
  in Objective-C, Swift, and Cocoa.
timezone: America/Los_Angeles

collections_dir: collections/en
collections:
  authors:
    output: true
    permalink: /authors/:path/
  books:
    output: false


================================================
FILE: _config/nshipster.es.yml
================================================
url: https://nshipster.es
lang: es-ES

description: >-
  **NSHipster** es una publicación de los bits pasados por alto
  en Objective-C, Swift y Cocoa.
timezone: Europe/Madrid

collections_dir: collections/es
collections:
  authors:
    output: true
    permalink: /authors/:path/
  translators:
    output: true
    permalink: /translators/:path/
  books:
    output: false


================================================
FILE: _config/nshipster.fr.yml
================================================
url: https://nshipster.fr
lang: fr-FR

description: >-
  **NSHipster** est une publication qui s'intéresse aux
  parties obscures de l'Objective-C, de Swift et de Cocoa.
timezone: Europe/Paris

collections_dir: collections/fr
collections:
  authors:
    output: true
    permalink: /authors/:path/
  translators:
    output: true
    permalink: /translators/:path/
  books:
    output: false


================================================
FILE: _config/nsmutablehipster.com.yml
================================================
title: NSMutableHipster
url: https://nsmutablehipster.com
lang: en-US

description: >-
  **NSHipster** is a journal of the overlooked bits
  in Objective-C, Swift, and Cocoa.
timezone: America/Los_Angeles

collections_dir: collections/en
collections:
  authors:
    output: true
    permalink: /authors/:path/
  books:
    output: false


================================================
FILE: _functions/search/package.json
================================================
{
  "name": "nshipster-netlify-functions",
  "version": "1.0.0",
  "description": "",
  "main": "search.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "lunr": "^2.3.8"
  }
}


================================================
FILE: _functions/search/search.js
================================================
const fs = require("fs");
const lunr = require("lunr");

const json = JSON.parse(fs.readFileSync(require.resolve("./index.json")));
var index = lunr(function() {
  this.ref("url");
  this.field("title", { boost: 10 });
  this.field("category");
  this.field("excerpt");

  json.forEach(function(doc) {
    console.log(doc);
    this.add(doc);
  }, this);
});

exports.handler = function(event, context, callback) {
  const query = event.queryStringParameters.q;

  if (!query || query === "") {
    callback(null, {
      statusCode: 400,
      body: JSON.stringify({ message: "Invalid query" })
    });
  } else {
    const results = index.search(query);
    callback(null, {
      statusCode: 200,
      body: JSON.stringify(results)
    });
  }
};


================================================
FILE: _i18n/en-US.yml
================================================
format:
  date: "%B %-d<sup>%o</sup>, %Y"

this_week: This Week...
continue_reading: Continue Reading
recent_articles: Recent Articles
publications: Recommended Reading
popular_articles: Popular Articles
contributors: Contributors
translated_into: "This article has been translated into:"

written_by: Written by
translated_by: Translated by
revised: revised

next_article: Next Article
related_articles: Related Articles

articles: Articles

corrections: Questions? Corrections? <a href="https://twitter.com/NSHipster">@NSHipster</a> or <a href="https://github.com/NSHipster/articles">on GitHub</a>.
license: NSHipster.com is released under a <a href="https://creativecommons.org/licenses/by-nc/4.0/" rel="license">Creative Commons BY-NC License</a>.


================================================
FILE: _i18n/es-ES.yml
================================================
format:
  date: "%-d/%-m/%Y"

this_week: Esta semana...
continue_reading: Sigue leyendo
recent_articles: Artículos recientes
publications: Libros
popular_articles: Artículos populares
contributors: Colaboradores
translated_into: "Este artículo ha sido traducido a:"

written_by: Escrito por
translated_by: Traducido por
revised: revisado

next_article: Artículo siguiente
related_articles: Artículos relacionados

articles: Artículos

corrections: ¿Preguntas? Correcciones? <a href="https://twitter.com/NSHipster">@NSHipster</a> y <a href="https://github.com/NSHipster/articles">on GitHub</a>.
license: NSHipster.com tiene licencia de <a href="https://creativecommons.org/licenses/by-nc/4.0/" rel="license">Creative Commons BY-NC License</a>.


================================================
FILE: _i18n/fr-FR.yml
================================================
format:
  date: "%-d/%-m/%Y"

this_week: Cette semaine...
continue_reading: Lire la suite
recent_articles: Articles récents
publications: Livres
popular_articles: Articles populaires
contributors: Contributeurs
all_articles: Tous les articles
translated_into: "Cet article a été traduit en :"

written_by: Écrit par
translated_by: Traduit par
revised: modifié

next_article: Article suivant
related_articles: Articles connexes

articles: Articles

corrections: Des questions ? Des corrections ? <a href="https://twitter.com/NSHipster">@NSHipster</a> et <a href="https://github.com/NSHipster/articles">sur GitHub</a>.
license: NSHipster est publié sous licence <a href="https://creativecommons.org/licenses/by-nc/4.0/" rel="license">Creative Commons BY-NC License</a>.


================================================
FILE: _i18n/ko-KR.yml
================================================
format:
  date: "%Y년 %-m월 %-d일"

this_week: 이번 주
continue_reading: 더 읽기
recent_articles: 최근 기사
publications: 책
popular_articles: 인기 기사
contributors: 기여자
all_articles: 모든 기사
translated_into: "이 기사는 다음과 같이 번역되었습니다 :"

written_by: "작성자 :"
translated_by: "번역자 :"
revised: 개정 된

next_article: 다음 글
related_articles: 관련 글

articles: 기사

corrections: 궁금하거나 잘못된 내용이 있나요? <a href="https://twitter.com/NSHipster">@NSHipster</a> 또는 <a href="https://github.com/NSHipster/articles">GitHub</a> 에 알려주세요.
license: NSHipster는 <a href="https://creativecommons.org/licenses/by-nc/4.0/" rel="license">Creative Commons BY-NC</a>에 따라 라이센스가 부여됩니다.


================================================
FILE: _i18n/ru-RU.yml
================================================
format:
  date: "%-d.%-m.%Y"

this_week: На этой неделе...
continue_reading: Продолжить чтение
recent_articles: Последние статьи
publications: Книги
popular_articles: Популярные статьи
contributors: Авторы
translated_into: "Данная статья переведена на:"

written_by: Написано
translated_by: Переведено
revised: пересмотренный

next_article: Следующая статья
related_articles: Статьи по Теме

articles: Статьи

corrections: Вопросов? Поправки? <a href="https://twitter.com/NSHipster">@NSHipster</a> или <a href="https://github.com/NSHipster/articles">на GitHub</a>.
license: NSHipster выпущен под лицензией <a href="https://creativecommons.org/licenses/by-nc/4.0/" rel="license">Лицензия Creative Commons BY-NC</a>.


================================================
FILE: _i18n/zh-Hans.yml
================================================
format:
  date: "%Y年%-m月%-d日"

this_week: 本周发布
continue_reading: 继续阅读
recent_articles: 最近的文章
publications: 书籍
popular_articles: 热门文章
contributors: 贡献者
translated_into: "本文已翻译为:"

written_by: 作者
translated_by: 翻译者
revised: 有改动

next_article: 下一篇文章
related_articles: 相关文章

articles: 文章

corrections: " "
license: 除非另有声明、本网站采用知识共享「<a href="http://creativecommons.org/licenses/by-nc/3.0/cn/" rel="license">署名-非商业性使用 3.0 中国大陆</a>」许可协议授权。


================================================
FILE: _includes/book.html
================================================
{% assign book = site.books | where:"name", include.book | first %}

<div id="{{ book.name }}" class="book">
    <a href="{{ book.book_url }}" title="{{ book.title }}" rel="noopener noreferrer" target="_blank">
      <img src="{% asset "{{ book.image }}" @path %}" class="cover" alt="{{ book.title }}" />
    </a>

    {% include json-ld/book.html %}
</div>


================================================
FILE: _includes/contributor.html
================================================
{% case include.role %}
{% when 'author' %}
  {% assign contributor = site.authors | where:"name", page.author | first %}
{% when 'translator' %}
  {% assign contributor = site.translators | where:"name", page.translator | first %}
{% endcase %}

<div class="contributor">
    {% case include.role %}
    {% when 'author' %}
        <small>{% t written_by %}</small>
    {% when 'translator' %}
        <small>{% t translated_by %}</small>
    {% endcase %}

    {% if contributor %}
        {% if contributor.image %}
            <img class="avatar" alt="{{ contributor.name }}" src="{% asset "{{ contributor.image }}" @path %}" draggable="false"/>
        {% else %}
            <img class="avatar" src="//0.gravatar.com/avatar/{{ contributor.gravatar }}?size=300" draggable="false"/>
        {% endif %}

        <div class="details">
            <span><a href="{{ contributor.url }}">{{ contributor.name }}</a></span>

            {{ contributor.content | markdownify }}
        </div>
    {% endif %}
</div>


================================================
FILE: _includes/json-ld/article.html
================================================
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "{{ page.title | strip_html | strip }}",
  "description": "{{ page.excerpt | markdownify | strip_html | strip }}",
  "image": "{{ '/logo.png' | absolute_url }}",
  "datePublished": "{{ page.date | date_to_xmlschema }}",
  "dateModified": "{{ page.last_revised_on | date_to_xmlschema }}",
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "{{ site.url }}"
  },
  "author": {
    "@type": "Person",
    "name": "Mattt"
  },
  "publisher": {
    "@type": "Organization",
    "name": "NSHipster",
    "logo": {
      "@type": "ImageObject",
      "url": "{{ '/logo.png' | absolute_url }}"
    }
  },
  "speakable": {
    "@type": "SpeakableSpecification",
    "xpath": [
        "/html/head/title",
        "/html/head/meta[@name='description']/@content"
    ]
  }
}
</script>


================================================
FILE: _includes/json-ld/book.html
================================================
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Book",
  "author": {
    "@type": "Person",
    "name": "Mattt"
  },
  "bookFormat": "https://schema.org/EBook",
  "datePublished": "{{ book.date }}",
  "image": "{% asset '{{ book.image }}' @path %}",
  "inLanguage": "English",
  "isbn": "{{ book.isbn }}",
  "name": "{{ book.title | strip_html | strip }}",
  "description": "{{ book.summary | markdownify | strip_html | strip }}",
  "numberOfPages": "{{ book.number_of_pages }}",
  "offers": {
    "@type": "Offer",
    "availability": "https://schema.org/InStock",
    "price": "{{ book.price }}",
    "priceCurrency": "USD",
    "url": "{{ book.book_url }}"
  },
  "publisher": {
    "@type": "Organization",
    "name": "Read Evaluate Press, LLC"
  }
}
</script>


================================================
FILE: _includes/json-ld/breadcrumblist.html
================================================
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
      "@type": "ListItem",
      "position": 1,
      "item": {
        "@id": "{{ site.url }}",
        "name": "Articles"
      }
    },
    {
      "@type": "ListItem",
      "position": 2,
      "item": {
        "@id": "{{ page.url | absolute_url }}",
        "name": "{{ page.title | strip_html }}"
      }
    }
  ]
}
</script>


================================================
FILE: _includes/json-ld/organization.html
================================================
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "NSHipster",
  "legalName": "NSHipster, LLC",
  "url": "https://nshipster.com",
  "logo": {
      "@type": "ImageObject",
      "url": "{{ '/logo.png' | absolute_url }}"
  },
  "foundingDate": "2012-07-07",
  "founders": [{
    "@type": "Person",
    "name": "Mattt"
  }],
  "sameAs": [
    "https://twitter.com/nshipster",
    "https://github.com/nshipster"
  ]
}
</script>


================================================
FILE: _includes/json-ld/website.html
================================================
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "url": "{{ site.url }}",
  "name": "{{ site.title | strip_html | strip }}",
  "author": {
    "@type": "Person",
    "name": "Mattt"
  },
  "description": "{{ site.description | markdownify | strip_html | strip }}",
  "publisher": {
    "@type": "Organization",
    "name": "NSHipster",
    "logo": {
      "@type": "ImageObject",
      "url": "{{ '/logo.png' | absolute_url }}"
    }
  }
}
</script>


================================================
FILE: _includes/promo.html
================================================
{% assign book = site.books | where:"name", include.book | first %}

<section id="promotion"{% if include.home %} class="home"{% endif %}>
    <small>Now Available</small>

    <article>
    {% include book.html book=book.name %}
    <div>
        <span class="price">
            $9+
        </span>
        <h3><a href="{{ book.book_url }}" rel="noopener">{{ book.sub_title }}</a></h3>
        <h4>{{ book.edition }}</h4>
        {{ book.summary | markdownify }}

        <a class="buy" href="{{ book.book_url }}" rel="noopener">Buy Now on Gumroad</a>
    </div>
    </article>
</section>


================================================
FILE: _layouts/author.html
================================================
---
layout: default
---

{% assign author = page %}
{% capture date_format %}{% t format.date %}{% endcapture %}

<article class="author">
  <header role="heading">
    {% if author.image %}
      <img class="avatar" alt="{{ author.name }}" src="{% asset "{{ author.image }}" @path %}" draggable="false"/>
    {% elsif author.gravatar %}
      <img class="avatar" src="//0.gravatar.com/avatar/{{ author.gravatar }}?size=300" draggable="false"/>
    {% endif %}
    <h1>{{ author.name }}</h1>

    {{ author.content | markdownify }}
  </header>

  <section class="archive">
    <h1>{% t articles %}</h1>

    <ol>
    {% for post in site.posts %}
      {% if post.author == author.name or post.authors contains author.name %}
        <li>
          <a href="{{ post.url }}" title="{{ post.title }}" class="title">{{ post.title }}</a>
          <time datetime="{{ post.date | date_to_xmlschema }}">{{ post.date | date: date_format }}</time>

          {{ post.excerpt | markdownify }}
        </li>
      {% endif %}
    {% endfor %}
    </ol>
  </section>
</article>



================================================
FILE: _layouts/default.html
================================================
<!DOCTYPE html>
<html lang="{{ site.lang }}">
<head>
  <meta charset="utf-8"/>
  {% if page.id %}
    <title>{{ page.title | strip_html | escape | strip }} - {{ site.title }}</title>
    <meta name="description" content="{{ page.excerpt | markdownify | strip_html }}"/>
    <meta name="revisit-after" content="1 month"/>
  {% else %}
    <title>{{ page.title | strip_html | escape | strip }}</title>
    <meta name="description" content="{{ site.description | markdownify | strip_html }}"/>
    <meta name="revisit-after" content="7 days"/>
  {% endif %}

  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"/>
  <meta name="format-detection" content="telephone=no"/>
  <meta name="color-scheme" content="light dark"/>

  <link rel="alternate" type="application/atom+xml" title="{{ site.title }} Atom Feed" href="/feed.xml"/>

  <link rel="preload" type="font/woff2" as="font" href="{% asset Merriweather-Regular.woff2 @path %}" crossorigin="anonymous" />
  <link rel="preload" type="font/woff2" as="font" href="{% asset Merriweather-Bold.woff2 @path %}" crossorigin="anonymous" />
  <link rel="preload" type="font/woff2" as="font" href="{% asset Merriweather-Italic.woff2 @path %}" crossorigin="anonymous" />
  <link rel="preload" type="font/woff2" as="font" href="{% asset CreativeCommonsSymbols.woff2 @path %}" crossorigin="anonymous" />

  {% asset "screen.css" @inline %}

  <link rel="apple-touch-icon" href="/apple-touch-icon.png"/>
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"/>
  <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/>
  <link rel="manifest" href="/site.webmanifest"/>
  <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#292724"/>
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-title" content="NSHipster"/>
  <meta name="application-name" content="NSHipster"/>
  <meta name="msapplication-TileColor" content="#f8f7f5"/>
  <meta name="theme-color" content="#f8f7f5"/>

  <link rel="author" type="text/plain" href="/humans.txt"/>
  <link rel="license" href="https://creativecommons.org/licenses/by-nc/4.0/"/>

  <meta name="twitter:card" content="summary"/>
  <meta name="twitter:site" content="@NSHipster"/>
  {% if author and author.twitter %}
  <meta name="twitter:creator" content="@{{ author.twitter }}"/>
  {% endif %}
  {% if page.id %}
    <meta name="twitter:title" content="{{ page.title }}"/>
    <meta name="twitter:description" content="{{ page.excerpt | markdownify | strip_html | escape }}"/>
    <meta name="twitter:label1" value="Category" />
    <meta name="twitter:data1" value="{{ page.category }}" />
  {% else %}
    <meta name="twitter:title" content="{{ site.title }}"/>
    <meta name="twitter:description" content="{{ site.description | markdownify | strip_html | escape }}"/>
  {% endif %}
  <meta name="twitter:account_id" content="{{ site.twitter }}"/>

  <meta property="og:site_name" content="{{ site.title }}"/>
  <meta property="og:image" content="{{ '/logo.png' | absolute_url }}"/>
  {% if page.id %}
    <meta property="og:type" content="article"/>
    <meta property="og:title" content="{{ page.title }}"/>
    <meta property="og:url" content="{{ page.url | absolute_url }}"/>
    <meta property="og:description" content="{{ page.excerpt | markdownify | strip_html | escape }}"/>
    <meta property="article:published_time" content="{{ page.date | date_to_xmlschema }}"/>
    <meta property="article:modified_time" content="{{ site.time | date_to_xmlschema }}"/>
    <meta property="article:tag" content="{{ page.categories | join: ',' }}"/>
    <meta property="article:publisher" content="https://www.facebook.com/NSHipster">
  {% else %}
    <meta property="og:title" content="{{ site.title }}"/>
    <meta property="og:url" content="{{ site.url }}"/>
    <meta property="og:description" content="{{ site.description | markdownify | strip_html | escape }}" />
  {% endif %}

  <link rel="canonical" href="{{ page.url | absolute_url }}" />

  {% for translation in page.translations %}
    {% assign translation_url = site.domains[translation] %}
    {% if translation_url %}
        <link rel="alternate" hreflang="{{ translation }}" href="{{ page.url | prepend:translation_url }}" />
    {% endif %}
  {% endfor %}

  <link rel="alternate" hreflang="x-default" href="{{ page.url | prepend:'https://nshipster.com' }}" />

  {% if page.url == '/' %}
    <link rel="prerender" href="{{ site.posts.first.url | absolute_url }}" />
  {% endif %}

  {% if page.next %}
    <link rel="next" href="{{ page.next.url | absolute_url }}" />
  {% endif %}

  {% if page.previous %}
    <link rel="prev" href="{{ page.previous.url | absolute_url }}" />
  {% endif %}

  {% if page.retired %}
    <meta name="robots" content="noindex,nofollow" />
  {% endif %}

  {% if site.url == "https://nsmutablehipster.com" %}
    <meta name="robots" content="noindex,nofollow" />
  {% endif %}

  <meta name="monetization" content="$coil.xrptipbot.com/nshipster" />
</head>

<body>

  <div class="container">
    <header role="banner">
      <a id="logo" href="/" title="NSHipster" aria-label="NSHipster">
        {% asset logo.svg @inline role="img" aria-hidden="true" %}
      </a>

      {% if page.url == "/" %}
        <h2 class="tagline">{{ site.description | markdownify | unwrap }}</h2>
      {% endif %}
    </header>

    <main>
      {{ content }}
    </main>

    <footer role="contentinfo">
      <section class="credits colophon">
        <p>
          <i aria-hidden="true" class="icon-cc" title="Creative Commons">&#x1F16D;</i>
          <i aria-hidden="true" class="icon-by" title="Attribution">&#x1F16F;</i>
          <i aria-hidden="true" class="icon-nc" title="Non-Commercial">&#x1F10F;</i>
          {% t license %}
        </p>
      </section>
    </footer>
  </div>

  {% asset application.js !type defer='defer' %}

  {% if site.url == "https://nsmutablehipster.com" %}
    {% asset nsmutablehipster.js !type defer="defer" %}
  {% endif %}

  {% if page.id and site.lang == 'en-US' %}
    {% include json-ld/article.html %}
  {% endif %}

  {% include json-ld/organization.html %}
  {% include json-ld/website.html %}
</body>
</html>


================================================
FILE: _layouts/error.html
================================================
---
layout: default
---

<article role="article">
  <h1 class="title">NSError</h1>

  <div class="content">
    {{ content }}
  </div>
</article>


================================================
FILE: _layouts/page.html
================================================
---
layout: default
---

<article role="article">
  <header role="heading">
    <h1 class="title">
      <a href="{{ page.url }}">{{ page.title | escape | camel_break }}</a>
    </h1>
  </header>

  <div class="content">
    {{ content }}
  </div>
</article>


================================================
FILE: _layouts/post.html
================================================
---
layout: default
---

{% assign author = site.authors | where:"name", page.author | first %}
{% assign translator = site.translators | where: "name", page.translator | first %}
{% capture date_format %}{% t format.date %}{% endcapture %}

<article role="article">
  <header role="heading">
    <h1 class="title">
      <a href="{{ page.url }}">{{ page.title | strip_html | escape | camel_break }}</a>
    </h1>

    <div class="byline">
    {% if page.authors %}
        {% t written_by %}
        <span class="authors">
        {% for auth in page.authors %}
          {% if forloop.last %}&amp;{% endif %}
          {% assign author = site.authors | where:"name",auth | first %}
          <a rel="author" class="author" href="{{ author.url }}">{{ author.name }}</a>
        {% endfor %}
        </span>
        <wbr/>
    {% elsif author %}
      {% t written_by %}
      <span class="authors">
        <a class="author" href="{{ author.url }}">{{ author.name }}</a>
      </span>
    {% elsif page.author %}
        {% t written_by %}
        <span class="authors">
            {{ page.translator }}
        </span>
    {% endif %}

    {% if page.translators %}
      {% t translated_by %}
      <span class="translators">
      {% for trans in page.translators %}
          {% if forloop.last %}&amp;{% endif %}
          {% assign translator = site.translators | where:"name",trans | first %}
          {% if translator %}
            <a class="translator" href="{{ translator.url }}">{{ translator.name }}</a>
          {% else %}
            {{ trans }}
          {% endif %}
      {% endfor %}
      </span>
    {% elsif translator %}
        {% t translated_by %}
        <span class="translators">
          <a class="translator" href="{{ translator.url }}">{{ translator.name }}</a>
        </span>
    {% elsif page.translator %}
        {% t translated_by %}
        <span class="translators">
          {{ page.translator }}
        </span>
    {% endif %}

    {% if page.last_revised_on %}
        <time datetime="{{ page.last_revised_on | date_to_xmlschema }}">{{ page.last_revised_on | date: date_format }}</time>
    {% else %}
        <time datetime="{{ page.date | date_to_xmlschema }}">{{ page.date | date: date_format }}</time>
    {% endif %}

    {% if page.revisions %}
        {% if page.commit_history_url %}
            (<a href="{{ page.commit_history_url | uri_escape }}" rel="noopener noreferrer">{% t revised %}</a>)
        {% else %}
            ({% t revised %})
        {% endif %}
    {% endif %}
    </div>
  </header>

  <div class="content">
    {{ content }}
  </div>

  <footer role="complementary">
    {% if site.lang == "en-US" %}
        {% if page.revisions or page.status %}
        <section id="revisions">
        <small>NSMutableHipster</small>

        <p>
        Questions? Corrections? <a href="https://github.com/NSHipster/articles/issues">Issues</a> and <a href="https://github.com/NSHipster/articles/blob/master/{{ page.path | remove_first:'_posts/' }}">pull requests</a> are always welcome.
        </p>

        <p class="status">
        {% if page.status.swift and page.status.swift != "t.b.c." and page.status.swift != "n/a" %}
            {% if page.status.reviewed %}
                <em>This article uses Swift version {{ page.status.swift }} and was last reviewed on {{ page.status.reviewed }}.</em>
            {% else %}
                <em>This article uses Swift version {{ page.status.swift }}.</em>
            {% endif %}

            Find status information for all articles on the <a href="/status/">status page</a>.
        {% elsif page.status.reviewed %}
            <em>This article was last reviewed on {{ page.status.reviewed }}.</em>
        {% endif %}
        </p>
        </section>
        {% endif %}
    {% endif %}

    <section id="attribution">
      {% include contributor.html role="author" %}
      {% if page.translator or page.translators %}
        {% include contributor.html role="translator" %}
      {% endif %}
    </section>

    <section>
      {% assign next_post = page.next %}
      {% if next_post == nil or next_post.url == page.url or next_post.retired %}
        {% assign next_post = site.posts | first %}
      {% endif %}

      {% if next_post and next_post.url != page.url %}
      <div id="continue">
        <small>{% t next_article %}</small>
        <article>
          <h1 class="title">
            <a rel="next" href="{{ next_post.url }}">{{ next_post.title | strip_html | escape | camel_break }}</a>
          </h1>

          {{ next_post.excerpt | markdownify }}
        </article>
      </div>
      {% endif %}
    </section>
  </footer>
</article>

{% include json-ld/breadcrumblist.html %}


================================================
FILE: _layouts/translator.html
================================================
---
layout: default
---

{% assign translator = page %}
{% capture date_format %}{% t format.date %}{% endcapture %}

<article class="author">
  <header role="heading">
    {% if translator.image %}
      <img class="avatar" alt="{{ translator.name }}" src="{% asset "{{ translator.image }}" @path %}" draggable="false"/>
    {% elsif translator.gravatar %}
      <img class="avatar" src="//0.gravatar.com/avatar/{{ translator.gravatar }}?size=300" draggable="false"/>
    {% endif %}
    <h1>{{ translator.name }}</h1>

    {{ translator.content | markdownify }}
  </header>

  <section class="archive">
    <h1>{% t articles %}</h1>

    <ol>
    {% for post in site.posts %}
      {% if post.translator == translator.name or post.translators contains translator.name %}
        <li>
          <a href="{{ post.url }}" title="{{ post.title }}" class="title">{{ post.title }}</a>
          <time datetime="{{ post.date | date_to_xmlschema }}" >{{ post.date | date: date_format }}</time>

          {{ post.excerpt | markdownify }}
        </li>
      {% endif %}
    {% endfor %}
    </ol>
  </section>
</article>



================================================
FILE: _plugins/admonition-block.rb
================================================
# frozen_string_literal: true

module Jekyll
  class AdmonitionBlock < Liquid::Block
    def initialize(tag_name, arguments, tokens)
      super

      @type = tag_name
    end

    def render(context)
      content = super
      <<~EOD
        <aside class="admonition #{@type}" markdown="1">
         #{content}
        </aside>
      EOD
    end
  end
end

%w[info warning error].each do |admonition|
  Liquid::Template.register_tag(admonition, Jekyll::AdmonitionBlock)
end


================================================
FILE: _plugins/camel-case-thin-space-break-filter.rb
================================================
# frozen_string_literal: true

module Jekyll
  module CamelCaseThinSpaceBreakFilter
    REGEX = /(?:([a-z]{2,})([A-Z]+))/.freeze

    def camel_break(string)
      string.gsub(REGEX, "\\1\u200B\\2")
            .gsub(/(mac|tv)\u200B(OS)/, "\\1\\2")
    end
  end
end

Liquid::Template.register_filter(Jekyll::CamelCaseThinSpaceBreakFilter)


================================================
FILE: _plugins/extended-date-filter.rb
================================================
# frozen_string_literal: true

require 'time'

module Jekyll
  module ExtendedDateFilter
    # Reformat a date using Ruby's core Time#strftime( string ) -> string
    # with additional replacements.
    #
    #   %a - The abbreviated weekday name (``Sun'')
    #   %A - The full weekday name (``Sunday'')
    #   %b - The abbreviated month name (``Jan'')
    #   %B - The full month name (``January'')
    #   %c - The preferred local date and time representation
    #   %d - Day of the month (01..31)
    #   %H - Hour of the day, 24-hour clock (00..23)
    #   %I - Hour of the day, 12-hour clock (01..12)
    #   %j - Day of the year (001..366)
    #   %m - Month of the year (01..12)
    #   %M - Minute of the hour (00..59)
    #   %o - Ordinal for the day of the month (st, nd, rd, th...)
    #   %p - Meridian indicator (``AM'' or ``PM'')
    #   %s - Number of seconds since 1970-01-01 00:00:00 UTC.
    #   %S - Second of the minute (00..60)
    #   %U - Week number of the current year,
    #           starting with the first Sunday as the first
    #           day of the first week (00..53)
    #   %W - Week number of the current year,
    #           starting with the first Monday as the first
    #           day of the first week (00..53)
    #   %w - Day of the week (Sunday is 0, 0..6)
    #   %x - Preferred representation for the date alone, no time
    #   %X - Preferred representation for the time alone, no date
    #   %y - Year without a century (00..99)
    #   %Y - Year with century
    #   %Z - Time zone name
    #   %% - Literal ``%'' character
    #
    #   See also: http://www.ruby-doc.org/core/Time.html#method-i-strftime
    def date(input, format)
      return input unless date = datetime(input)
      return input unless (format = format.to_s) && !format.empty?

      date.strftime(format.gsub(/%o/, ordinal(date.day)))
    end

    private

    def ordinal(number)
      return 'th' if (11..13).cover?(number.to_i % 100)

      case number.to_i % 10
      when 1 then 'st'
      when 2 then 'nd'
      when 3 then 'rd'
      else        'th'
      end
    end

    def datetime(date)
      case date
      when String
        Time.parse(date)
      else
        date
      end
    end
  end
end

Liquid::Template.register_filter(Jekyll::ExtendedDateFilter)


================================================
FILE: _plugins/jwt-lexer.rb
================================================
# frozen_string_literal: true

require 'rouge'

module Rouge
  module Lexers
    class JWT < RegexLexer
      tag 'jwt'
      filenames '*.jwt'

      title 'JSON Web Token (JWT)'
      desc 'A compact URL-safe means of representing claims to be transferred between two parties.'

      start { push :root }

      state :root do
        rule %r{^([A-Za-z0-9\-_=]+)(\.)([A-Za-z0-9\-_=]+)(\.?)([A-Za-z0-9\-_.+/=]*)$} do |m|
          token Keyword, m[1]
          token Punctuation, m[2]
          token Literal::Number, m[1]
          token Punctuation, m[4]
          token Name::Variable, m[1]
        end
      end
    end
  end
end


================================================
FILE: _plugins/localization-filter.rb
================================================
# frozen_string_literal: true

require 'twitter_cldr'

module Jekyll
  module LocalizationFilter
    def as_language_code(input, locale = nil)
      return '中文' if input == 'zh-Hans' && locale == 'zh-Hans'

      code = TwitterCldr.convert_locale(input)
      TwitterCldr::Shared::Languages.from_code_for_locale(code, locale || :en)
    end

    def to_sentence(list)
      formatter = TwitterCldr::Formatters::ListFormatter.new(current_locale.language)
      formatter.format(list.map(&:strip).reject(&:empty?))
    end

    private

    def current_locale
      # TwitterCldr.convert_locale(Jekyll.sites.first.config['lang'])
      TwitterCldr::Shared::Locale.parse(Jekyll.sites.first.config['lang']).maximize
    end
  end
end

Liquid::Template.register_filter(Jekyll::LocalizationFilter)


================================================
FILE: _plugins/markdown-converter.rb
================================================
# frozen_string_literal: true

require 'yaml'

require 'jekyll'
require 'nokogiri'
require 'active_support/inflector'

module Jekyll
  module Converters
    class Markdown
      # :nodoc:
      class NSHipsterProcessor
        def initialize(config)
          @kramdown = KramdownParser.new(config)
        end

        def convert(content)
          cache.getset(content) do
            content.gsub!('<#...#>', "\uFFFC")
            html = @kramdown.convert(content)
            doc = Nokogiri::HTML::DocumentFragment.parse(html)

            remove_proprietary_attributes!(doc)
            secure_links_to_cross_origin_destinations!(doc)
            transform_apple_trademarks!(doc)
            transform_code_symbols!(doc)
            transform_placeholder_tokens!(doc)
            add_heading_anchors!(doc)
            unnest_code_listing_markup!(doc)
            consolidate_consecutive_code_listings!(doc)
            improve_accessibility!(doc)
            style_optional_placeholders!(doc)
            delineate_flim_flam!(doc)

            doc.to_html.gsub("\uFFFC", '<var class="placeholder">…</var>')
          end
        end

        private

        def cache
          @@cache ||= Jekyll::Cache.new('ConvertMarkdown')
        end

        def remove_proprietary_attributes!(doc)
          doc.css('[markdown]').each do |element|
            element.remove_attribute('markdown')
          end
        end

        def transform_code_symbols!(doc)
          doc.css(':not(pre) code').each do |code|
            code.remove_attribute('class')
            code.inner_html = code.inner_html.gsub(/(?:([a-z])([A-Z]+))/, '\\1<wbr/>\\2')
          end
        end

        def transform_apple_trademarks!(doc)
          doc.css('p, li, td').each do |p|
            p.inner_html = p.inner_html.gsub(/iPhone X([SR])/, 'iPhone X<small>\\1</small>')
          end
        end

        def secure_links_to_cross_origin_destinations!(doc)
          doc.css('a[href]').each do |a|
            href = a.attr('href')
            next if href =~ %r{^/|#{ENV['DOMAIN']}}

            a['rel'] = 'noopener noreferrer'
          end
        end

        def transform_placeholder_tokens!(doc)
          doc.css('code').each do |code|
            code.inner_html = code.inner_html.gsub(/&lt;#\s*(.*?)\s*#&gt;/, '<var class="placeholder">\\1</var>')
          end
        end

        def add_heading_anchors!(doc)
          selector = (1..6).map { |n| "h#{n}" }.join(', ')
          doc.css(selector).each do |h|
            next unless id = h.attr('id')

            id = ActiveSupport::Inflector.parameterize(id)

            h.remove_attribute('id')
            h.prepend_child(%(<a class="anchor" aria-hidden="true" id="#{id}" href="##{id}"></a>))
          end
        end

        def unnest_code_listing_markup!(doc)
          doc.css('div.highlighter-rouge').each do |div|
            class_name = div.classes.detect { |c| !c.match?(/rouge/) }
            language = case class_name
                       when /swift/ then 'Swift'
                       when /objc|objective-c/ then 'Objective-C'
                       when /json-ld/ then 'JSON-LD'
                       when /json/ then 'JSON'
                       when /python/ then 'Python'
                       when /ruby/ then 'Ruby'
                       when /javascript/ then 'JavaScript'
                       when /terminal/ then 'Terminal'
                       when /html/ then 'HTML'
                       when /xml/ then 'XML'
                       when /jwt/ then 'JWT'
                       when /applescript/ then 'AppleScript'
                       when /lisp/ then 'Lisp'
                       when /fortran/ then 'FORTRAN'
                       when /cobol/ then 'COBOL'
                       when /xcconfig/ then 'Xcode Build Settings'
                       when /turtle/ then 'Turtle'
                       when /sparql/ then 'SPARQL'
                       when /sql/ then 'SQL'
                       when /cypher/ then 'Cypher'
                       when /ntriples/ then 'N-Triples'
                       when nil then ''
                       else
                         class_name.gsub(/language-/, '')
                       end

            pre = div.at('pre')
            pre['class'] = 'highlight'
            pre['data-lang'] = language

            div.swap(pre)
          end
        end

        def consolidate_consecutive_code_listings!(doc)
          doc.css('pre.highlight').each do |pre|
            next if pre.parent['class'] == 'highlight-group'

            group = pre.wrap(%(<div class="highlight-group">)).parent

            while sibling = group.at_xpath('following-sibling::node()[not(self::text()[not(normalize-space())])][1]')
              break unless sibling.classes.include?('highlight')

              group.add_child(sibling)
            end

            group.swap(group.child) if group.children.count == 1
          end

          number = 1
          doc.css('div.highlight-group').each do |group|
            group.prepend_child('<div role="tablist" aria-label="Languages"/>')
            tablist = group.at('[role="tablist"]')

            group.css('pre.highlight').each_with_index do |div, index|
              language = div['data-lang'] || 'text'

              id = "code-listing-#{number}-#{language.downcase}"
              div['id'] = id.to_s
              div['role'] = 'tabpanel'
              div['tabindex'] = '0'
              div['aria-labelledby'] = "#{id}-tab"
              div['hidden'] = 'hidden' unless index == 0

              tablist.add_child(%(
                  <button role="tab"
                          role="tablist"
                          id="#{id}-tab"
                          class="#{language.downcase}"
                          aria-label="Languages"
                          aria-controls="#{id}"
                          aria-selected="#{index == 0 ? 'true' : 'false'}"
                          tabindex="-1">
                      #{language}
                  </button>
              ))
            end
            number += 1
          end
        end

        def improve_accessibility!(doc)
          doc.css('img[src$=".svg"]').each do |img|
            img['role'] = 'img'
          end

          doc.css('img:not([alt])').each do |img|
            img['alt'] = ''
          end
        end

        def style_optional_placeholders!(doc)
          doc.css('var.placeholder').each do |var|
            next unless var.text.match?(/[\[\]]/)

            var.add_class('optional')
            var['title'] = 'Optional'
            var.inner_html = var.inner_html.gsub(/[\[\]]/, '')
          end
        end

        def delineate_flim_flam!(doc)
          if divider = (doc.at_css('hr') || doc.at_css('h2'))
            divider.add_next_sibling(%(<a id="get-on-with-it"/>))
          end
        end
      end
    end
  end
end


================================================
FILE: _plugins/page-translation-hook.rb
================================================
# frozen_string_literal: true

Jekyll::Hooks.register :pages, :pre_render do |page|
  page.data['translations'] = page.site.config['domains'].keys if page.index?
end


================================================
FILE: _plugins/post-commit-history-hook.rb
================================================
# frozen_string_literal: true

require 'uri'

Jekyll::Hooks.register :posts, :pre_render do |post|
  language = post.site.config['lang']

  repository_name = case language
                    when /^en/ then 'articles'
                    when /^es/ then 'articles-es'
                    when /^fr/ then 'articles-fr'
                    when /^ko/ then 'articles-ko'
                    when /^zh-Hans/ then 'articles-zh-Hans'
                    when /^ru/ then 'articles-ru'
                    when nil
                      raise 'Unspecified language in site configuration'
                    else
                      raise "Unknown language: #{language}"
                    end

  filename = File.basename(post.path)

  post.data['commit_history_url'] = "https://github.com/nshipster/#{repository_name}/commits/master/#{filename}"
end


================================================
FILE: _plugins/post-revisions-hook.rb
================================================
# frozen_string_literal: true

require 'date'

Jekyll::Hooks.register :posts, :pre_render do |post|
  if post.data['revisions']
    latest_revision = post.data['revisions'].keys.max
    raise unless latest_revision && (last_revised_on = Time.parse("#{latest_revision}"))

    post.data['revision_description'] = post.data['revisions'][latest_revision]
    post.data['last_revised_on'] = last_revised_on
    post.data['updated_on'] = last_revised_on
  else
    post.data['updated_on'] = post.date
  end
end


================================================
FILE: _plugins/post-translation-hook.rb
================================================
# frozen_string_literal: true

Jekyll::Hooks.register :posts, :pre_render do |post|
  directory = File.expand_path('../../..', post.path)
  filename = File.basename(post.path)
  slug = filename.sub(/\A\d{4}-\d{,2}-\d{,2}-/, '')
  translations = Dir["#{directory}/**/*#{slug}"].reject { |f| f == post.path }

  post.data['translations'] = []
  translations.each do |translation|
    next unless language = File.expand_path('../..', translation).split('/').last
    post.data['translations'] << language
  end
end


================================================
FILE: _plugins/search-index-generator.rb
================================================
# frozen_string_literal: true

module Jekyll
  class SearchIndexGenerator < Generator
    priority :low

    def generate(site)
      index = site.posts.docs.reverse
                  .filter { |post| !post.data['retired'] }
                  .map do |post|
        {
          url: site.config['url'] + post.url,
          title: post.data['title'],
          category: post.data['category'],
          content: post.data['excerpt']
        }
      end

      File.open('_functions/search/index.json', 'w') do |f|
        f.puts index.to_json
      end
    end
  end
end


================================================
FILE: _plugins/shuffle-filter.rb
================================================
# frozen_string_literal: true

module Jekyll
  module ShuffleFilter
    def shuffle(input = [])
      input.sort_by { rand }
    rescue StandardError
      input
    end
  end
end

Liquid::Template.register_filter(Jekyll::ShuffleFilter)


================================================
FILE: _plugins/translate-tag.rb
================================================
# frozen_string_literal: true

module Jekyll
  class Site
    attr_accessor :translations
  end

  class TranslateTag < Liquid::Tag
    def initialize(tag_name, key, tokens)
      super
      @key = key.strip
    end

    def render(context)
      key = key(context)
      translation = translations(context).dig(*key.split('.'))

      if translation.nil? || translation.empty?
        raise "Missing i18n key: #{lang}: #{key}"
      end

      translation
    end

    private

    def key(context)
      key = if context[@key].to_s != ''
              context[@key].to_s
            else
              @key
            end

      key = Liquid::Template.parse(key).render(context)
      raise "Invalid key #{key}" unless key.is_a?(String)

      key
    end

    def translations(context)
      site = context.registers[:site]
      site.translations ||= {}

      lang = site.config['lang']
      unless site.translations.key?(lang)
        puts "Loading translations from #{site.source}/_i18n/#{lang}.yml"
        site.translations[lang] = YAML.load_file("#{site.source}/_i18n/#{lang}.yml")
      end

      site.translations[lang]
    end
  end
end

Liquid::Template.register_tag('t', Jekyll::TranslateTag)
Liquid::Template.register_tag('translate', Jekyll::TranslateTag)


================================================
FILE: _plugins/unwrap-filter.rb
================================================
# frozen_string_literal: true

require 'nokogiri'

module Jekyll
  module UnwrapFilter
    def unwrap(input)
      return '' if input.nil? || input.empty?

      fragment = Nokogiri::HTML::DocumentFragment.parse(input)
      fragment.children.map(&:inner_html).join(' ')
    end
  end
end

Liquid::Template.register_filter(Jekyll::UnwrapFilter)


================================================
FILE: _plugins/url-filter.rb
================================================
# frozen_string_literal: true

require 'uri'

module Jekyll
  module URLFilter
    def host(input)
      return input unless uri = URI(input)

      uri.host
    end
  end
end

Liquid::Template.register_filter(Jekyll::URLFilter)


================================================
FILE: _plugins/well-known-hook.rb
================================================
# frozen_string_literal: true

require 'fileutils'

Jekyll::Hooks.register :site, :post_write do |site|
  site.static_files.select do |f|
    next unless f.relative_path.include?('.well-known')

    FileUtils.cp(f.path, site.dest)
  end
end


================================================
FILE: assets/css/_admonitions.scss
================================================
@mixin border-icon($name) {
  content: " ";
  background-image: asset_url($name + ".svg");
  background-size: 24px 24px;
  width: 24px;
  height: 24px;
  position: absolute;
  display: block;
  margin-left: -54px;
  margin-top: 10px;
  z-index: 100;
}

.admonition {
  --code: var(--link);
  font-family: $sans-serif-font-stack;
  border-left: 4px var(--separator) solid;
  padding: 5px 40px;
  margin: 1.5em 0;
  display: block;
  clear: both;
  overflow: visible;
  font-size: smaller;

  a {
    text-decoration: underline;
  }

  p {
    margin: 0.5em 0;
  }

  dl {
    padding: 0.5em 0 !important;
    margin-bottom: 1em !important;
  }

  pre code {
    font-size: small;
    line-height: 1;
  }

  th,
  td {
    padding: 0.5em !important;
  }

  blockquote {
    margin-left: 0 !important;
    margin-top: 0.25em !important;
    margin-bottom: 0.25em !important;
    border-left-color: var(--separator) !important;
  }

  ins {
    background: transparent !important;
  }

  &.info {
    --link: var(--blue);
    --separator: var(--blue);
    --background: #edf5fa;

    &:before {
      @include border-icon("info");
    }
  }

  &.warning {
    --background: #fcfaf6;
    --separator: var(--yellow);
    --link: rgb(178, 129, 6);

    &:before {
      @include border-icon("warning");
    }
  }

  &.error {
    --background: #fcf2f6;
    --link: var(--pink);
    --separator: var(--pink);

    &:before {
      @include border-icon("error");
    }
  }
}


================================================
FILE: assets/css/_animations.scss
================================================
@keyframes twirl {
    0% {
        transform: scale(1) rotate(0);
    }

    10%,
    20% {
        transform: scale(0.9) rotate(-3deg);
    }

    30%,
    50%,
    70%,
    90% {
        transform: scale(1.1) rotate(3deg);
    }

    40%,
    60%,
    80% {
        transform: scale(1.1) rotate(-3deg);
    }

    100% {
        transform: scale(1) rotate(0);
    }
}


================================================
FILE: assets/css/_code.scss
================================================
pre.highlight {
  background: var(--secondary-background);
  border: 1px var(--separator-opaque) solid;
  border-radius: 4px;
  overflow: auto;
  padding: 0.5em 1em;
  margin-bottom: 1em;

  code {
    color: var(--text);
    background: transparent !important;
  }

  &[data-lang="JWT"] {
    white-space: pre-wrap;
  }
}

.highlight {
  .placeholder {
    color: var(--text);
  }

  .o {
    color: var(--text);
  }

  .p {
    color: var(--gray);
  }

  .err {
    color: var(--gray);
  }

  .s,
  .sa,
  .sb,
  .sc,
  .dl,
  .sd,
  .s2,
  .sh,
  .sx,
  .sr,
  .s1,
  .ss {
    color: var(--orange);
  }

  .se,
  .si {
    color: var(--text);
  }

  .k,
  .kc,
  .kd,
  .kn,
  .kp,
  .kr {
    color: var(--purple);
  }

  .kt {
    color: var(--text);
  }

  .kd + .kt {
    color: var(--text);
  }

  .go,
  .nc,
  .nf,
  .nv {
    color: var(--text);
  }

  .kt + .o + .n,
  .nf {
    color: var(--indigo);
  }

  .cp,
  .c1 {
    color: var(--gray);
  }

  .n,
  .na,
  .nb,
  .bp,
  .no,
  .nd,
  .ni,
  .py,
  .nl,
  .nn,
  .nx,
  .nt,
  .vc,
  .vg,
  .vi {
    color: var(--text);
  }

  .l,
  .ld,
  .s,
  .sb,
  .sc,
  .sd,
  .s2,
  .se,
  .sh,
  .si,
  .sx,
  .sr,
  .s1,
  .ss,
  .m,
  .mf,
  .mh,
  .mi,
  .il,
  .mo,
  .mx,
  .mb {
    color: var(--indigo);
  }
}

@media (prefers-color-scheme: dark) {
  .highlight {
    .p {
      color: var(--gray2);
    }

    .err {
      color: var(--gray);
    }

    .s,
    .sa,
    .sb,
    .sc,
    .dl,
    .sd,
    .s2,
    .sh,
    .sx,
    .sr,
    .s1,
    .ss {
      color: var(--green);
    }

    .se,
    .si {
      color: var(--text);
    }

    .k,
    .kc,
    .kd,
    .kn,
    .kp,
    .kr {
      color: var(--teal);
    }

    .kt {
      color: var(--yellow);
    }

    .kd + .kt {
      color: var(--orange);
    }

    .go,
    .nc,
    .nf,
    .nv {
      color: var(--text);
    }

    .kt + .o + .n,
    .nf {
      color: var(--purple);
    }

    .cp {
      color: var(--red);
    }

    .c1 {
      color: var(--gray2);
    }

    .n + .o + .n,
    .na,
    .nb,
    .bp,
    .no,
    .nd,
    .ni,
    .py,
    .nl,
    .nn,
    .nx,
    .nt,
    .vc,
    .vg,
    .vi {
      color: var(--pink);
    }

    .l,
    .ld,
    .s,
    .sb,
    .sc,
    .sd,
    .s2,
    .se,
    .sh,
    .si,
    .sx,
    .sr,
    .s1,
    .ss,
    .m,
    .mf,
    .mh,
    .mi,
    .il,
    .mo,
    .mx,
    .mb {
      color: var(--orange);
    }
  }
}


================================================
FILE: assets/css/_colors.scss
================================================
:root {
  --red: rgb(255, 59, 48);
  --orange: rgb(255, 128, 0);
  --yellow: rgb(255, 204, 0);
  --green: rgb(52, 199, 89);
  --teal: rgb(90, 200, 250);
  --blue: rgb(0, 122, 255);
  --indigo: rgb(88, 86, 214);
  --purple: rgb(175, 82, 222);
  --pink: rgb(255, 45, 85);
  --gray: rgb(142, 142, 147);
  --gray2: rgb(174, 174, 178);
  --gray3: rgb(199, 199, 204);
  --gray4: rgb(209, 209, 214);
  --gray5: rgb(229, 229, 234);
  --gray6: rgb(242, 242, 247);

  --text: rgb(0, 0, 0);
  --secondary-text: rgb(60, 60, 67);
  --placeholder-text: rgb(60, 60, 67);
  --code: var(--purple);
  --link: var(--orange);
  --separator: rgb(60, 60, 67);
  --opaque-separator: rgb(198, 198, 200);
  --fill: rgb(120, 120, 128);
  --secondary-fill: rgb(120, 120, 128);
  --background: rgb(242, 242, 247);
  --secondary-background: rgb(255, 255, 255);
}

@supports (color: color(display-p3 1 1 1)) {
  * {
    transition: none !important;
  }

  :root {
    --red: color(display-p3 1 0.2314 0.1882);
    --orange: color(display-p3 1 0.5 0);
    --yellow: color(display-p3 1 0.8 0);
    --green: color(display-p3 0.2039 0.7804 0.349);
    --teal: color(display-p3 0.3529 0.7843 0.9804);
    --blue: color(display-p3 0 0.4784 1);
    --indigo: color(display-p3 0.3451 0.3373 0.8392);
    --purple: color(display-p3 0.6863 0.3216 0.8706);
    --pink: color(display-p3 1 0.1765 0.3333);
    --gray: color(display-p3 0.5569 0.5569 0.5765);
    --gray2: color(display-p3 0.6824 0.6824 0.698);
    --gray3: color(display-p3 0.7804 0.7804 0.8);
    --gray4: color(display-p3 0.8196 0.8196 0.8392);
    --gray5: color(display-p3 0.898 0.898 0.9176);
    --gray6: color(display-p3 0.949 0.949 0.9686);

    --text: color(display-p3 0 0 0);
    --secondary-text: color(display-p3 0.2353 0.2353 0.2627);
    --placeholder-text: color(display-p3 0.2353 0.2353 0.2627);
    --separator: color(display-p3 0.2353 0.2353 0.2627);
    --opaque-separator: color(display-p3 0.7765 0.7765 0.7843);
    --fill: color(display-p3 0.4706 0.4706 0.502);
    --secondary-fill: color(display-p3 0.4706 0.4706 0.502);
    --background: color(display-p3 0.949 0.949 0.9686);
    --secondary-background: color(display-p3 1 1 1);
  }
}

html {
  border-top: 3px var(--orange) solid;

  body {
    background-color: var(--background);
    color: var(--text);
  }
}

#logo {
  #ns {
    fill: var(--orange);
  }
}


================================================
FILE: assets/css/_functions.scss
================================================
@mixin clearfix {
  &:after {
    content: " ";
    display: block;
    clear: both;
  }
}

@mixin disable-selection {
  -webkit-touch-callout: none; /* iOS Safari */
  -webkit-user-select: none; /* Safari */
  -khtml-user-select: none; /* Konqueror HTML */
  -moz-user-select: none; /* Firefox */
  -ms-user-select: none; /* Internet Explorer/Edge */
  user-select: none; /* Non-prefixed version, currently supported by Chrome and Opera */
}


================================================
FILE: assets/css/_inputs.scss
================================================
button,
input[type="submit"] {
  -moz-appearance: none;
  -ms-appearance: none;
  -o-appearance: none;
  -webkit-appearance: none;
  -webkit-font-smoothing: antialiased;
  appearance: none;
  background-color: var(--orange);
  border-radius: 4px;
  border: none;
  color: white;
  cursor: pointer;
  display: inline-block;
  font-size: 1em;
  font-weight: bold;
  line-height: 1;
  padding: 0.75em 1em;
  text-decoration: none;
  transition: background-color 0.25s;
  user-select: none;
  vertical-align: middle;
  white-space: nowrap;
}

button:hover,
input[type="submit"]:hover {
  color: white;
}


================================================
FILE: assets/css/_layout.scss
================================================
@import "functions";

html,
body {
  margin: 0;
}

body {
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
    env(safe-area-inset-bottom) env(safe-area-inset-left);
  border-top: 3px var(--orange) solid;
}

hr {
  border: none;
  margin: 1em 0;
  padding: 1em 0;
  display: block;
}

img {
  margin: 0;
  max-width: 100%;
}

video {
  margin: 0 auto;
  max-width: 100%;
  display: block;
}

blockquote {
  border-left: 2px solid var(--separator);
  color: var(--secondary-text);
  margin: 1.5em 0;
  padding-left: 0.75em;
}

cite {
  color: var(--text);
  font-style: italic;

  &:before {
    content: "— ";
  }
}

table {
  border-collapse: collapse;
  margin: 0.75em 0;
  table-layout: fixed;
  width: 100%;
}

thead th {
  border-bottom: 1px solid var(--separator-opaque);
  font-weight: bold;
  padding: 0.75em 0;
  text-align: left;
}

tbody td {
  border-bottom: 1px solid var(--separator);
  padding: 0.75em 0;
}

tbody tr:last-of-type td {
  border-bottom: none;
}

tr,
td,
th {
  vertical-align: middle;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style-type: none;
}

dl {
  margin-bottom: 0.75em;

  dt {
    font-weight: bold;
    margin: 1em 0;
  }

  dd {
    margin: 0 0 0.25rem 1em;
  }
}

.container {
  @include clearfix;

  max-width: 100%;
  margin-left: auto;
  margin-right: auto;
  max-width: 960px;
  margin: 0 auto;
  padding: 2em;

  section {
    @include clearfix;

    display: block;
    max-width: 100%;
    margin-left: auto;
    margin-right: auto;
    margin-bottom: 2em;
    padding-bottom: 1em;
  }
}

html[lang="fr-FR"] [role="banner"] {
  #logo {
    margin-right: 5.5em;
  }

  .tagline {
    font-size: 1.25em;
  }
}

html[lang="zh-Hans"] [role="banner"] {
  #logo {
    margin-right: 9.5em;
  }

  .tagline {
    font-size: 1.4em;
    padding-bottom: 1em;
  }
}

html[lang="ko-KR"] [role="banner"] {
  .tagline {
    font-size: 1.25em;
  }
}

[role="banner"] {
  display: flex;
  margin-bottom: 1.5em;
  padding-bottom: 1.5em;

  #logo {
    display: block;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    font-size: 1em;
    height: 6em;
    margin: 0.25em 6em 0 0;

    a {
      display: block;
    }

    svg {
      width: 146px;
      height: 84px;
      overflow: visible;
      margin-left: -3px;

      #mustache {
        position: absolute;
        transform: rotate(0) scale(1);
        transform-origin: 50% 70% 0;
        transition: transform 1s;
      }

      &:hover,
      &.animated {
        position: relative;
        z-index: 2;

        #mustache {
          animation: twirl 1s ease-in-out;
        }
      }
    }
  }

  .tagline {
    flex: 1;
  }
}

#latest,
#announcement {
  h1 {
    margin-bottom: 0.5rem;
  }
}

#announcement {
  background-color: rgba(255, 128, 0, 0.2);
  margin-left: -1em;
  margin-right: -1em;
  padding: 1em;
}

#recent {
  ul {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1em 2em;

    li {
      min-height: 15em;

      .title {
        height: 4em;
        font-size: 1.75em;
        display: table-cell;
        line-height: 1;
        vertical-align: bottom;
        padding-bottom: 1em;
      }

      p {
        font-size: smaller;
        display: -webkit-box;
        overflow: hidden;
        max-lines: 8;
        -webkit-line-clamp: 8;
        -webkit-box-orient: vertical;
        text-overflow: ellipsis;
      }
    }
  }
}

#merchandise {
  margin-top: -30px;

  h1 {
    margin-bottom: 15px;
  }
}

article.author,
article.translator {
  padding-top: 2em;

  header {
    display: grid;
    grid-template:
      "avatar . title"
      "avatar . description";
    grid-template-columns: 1fr 1em 3fr;
    grid-template-rows: 1fr 2fr;
    gap: 1em 1em;
    margin-bottom: 1em;
    padding-bottom: 1em;

    .avatar {
      grid-area: avatar;
    }

    h1 {
      grid-area: title;
    }

    p {
      grid-area: description;
    }
  }
}

[role="article"] {
  margin-bottom: 1em;
  overflow-x: hidden;

  table {
    overflow: scroll;
    -webkit-overflow-scrolling: touch;
    margin: 2em 0;

    caption {
      margin: 2em 0 1em 0;
    }
  }

  header {
    display: block;
    text-align: center;
    margin-bottom: 3em;

    .byline {
      font-family: $serif-font-stack;
      font-style: italic;
      font-weight: 300;
      color: var(--secondary-text);

      a,
      span,
      time {
        white-space: nowrap;
      }

      .authors,
      .translators {
        &:after {
          content: " — ";
        }
      }
    }
  }

  .content {
    margin-bottom: 4em;

    h1,
    h2,
    h3,
    h4,
    h5 {
      margin-top: 2.5rem;
    }

    object,
    embed,
    figure,
    svg {
      margin: 1em auto;
      display: block;
      width: auto;
    }

    img {
      margin: 1em auto;
      display: block;
    }

    ul,
    ol {
      margin: 1.5em 0;
      padding: 0 3em;

      ul,
      ol {
        margin-top: 0.5em;
      }

      li {
        list-style: disc;
      }
    }

    figure {
      text-align: center;
      margin: 1em 0;
      padding: 1em 0;
    }

    ins {
      background-color: rgba(255, 128, 0, 0.2);
      text-decoration: none;
    }

    dl {
      padding: 1em 0;
    }

    blockquote {
      margin: 2em;
      margin-right: 4em;
      border-left: 3px var(--orange) solid;

      cite {
        margin-top: 1em;
        display: block;
      }
    }

    table {
      thead th {
        text-align: center;
      }

      td {
        padding: 1em;
      }

      table {
        margin: 0;
        th,
        td {
          border: none;
          padding: 0.25em;
        }
      }
    }
  }

  sup {
    font-size: 50%;

    time & {
      margin-right: -0.5em;
    }
  }

  footer {
    .contributor {
      float: left;
      display: block;
      margin-right: 2.35765%;
      width: 48.82117%;
      padding: 1em 0;

      &:last-child,
      &:nth-child(2n) {
        margin-right: 0;
      }

      &:nth-child(2n + 1) {
        clear: left;
      }

      &:only-child {
        width: 100%;

        .avatar {
          padding: 0 1em;
        }
      }

      .avatar {
        float: left;
        display: block;
        margin-right: 4.82916%;
        width: 30.11389%;

        &:last-child {
          margin-right: 0;
        }
      }

      .details {
        float: left;
        display: block;
        margin-right: 4.82916%;
        width: 65.05695%;
        margin-right: 0;
        margin-top: 1em;

        &:last-child {
          margin-right: 0;
        }

        span {
          font-weight: 700;
        }

        p {
          font-size: 0.75em;
          margin-top: 1em;
        }
      }
    }

    small {
      display: block;
      font-size: 1em;
      font-weight: 700;
      color: var(--secondary-text);
      text-transform: lowercase;
      font-family: $sans-serif-font-stack;
      font-variant: small-caps;
      margin-bottom: 1em;
    }
  }
}

[role="complementary"] {
  border-top: 1px #ddd solid;
  padding-top: 2em;
}

[role="contentinfo"] {
  text-align: center;
  margin-top: 2em;
  padding: 1em;

  section {
    margin-bottom: 0;
    padding-bottom: 0;
  }
}

.avatar {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  max-width: 200px;
  max-height: 200px;
  border-radius: 50%;
  pointer-events: none;
  user-select: none;
}

#contributors {
  ul {
    display: flex;
    justify-content: center;
    align-content: space-between;
    flex-flow: row wrap;

    li {
      flex: 0;
      display: block;
      margin-bottom: 1em;
      flex-basis: 15%;
      padding: 0.25em;

      .avatar {
        width: 75%;
        display: block;
        margin: 0 auto 1em auto;
      }

      a {
        text-align: center;
        display: block;
        font-size: small;
      }
    }
  }
}

.archive {
  dl {
    float: left;
    display: block;
    margin-right: 2.5%;
    width: 30%;

    &:last-child,
    &:nth-of-type(3),
    &:nth-of-type(4),
    &:nth-of-type(6) {
      margin-right: 0;
    }
  }

  ol,
  ul {
    list-style: none;

    li {
      margin: 2em 0;
    }

    span,
    time {
      display: block;
    }

    time {
      white-space: nowrap;
      font-style: italic;
      font-weight: 300;
      margin-bottom: 1em;
    }
  }
}

#publications {
  .books {
    display: flex;
  }

  .book {
    flex: 1;

    img {
      display: block;
      margin: 0 auto;
      width: 200px;
      border: 4px transparent solid;
      transition: 0.25s ease-in-out border-color;
      filter: none !important;

      &:hover {
        padding: 0;
        border: 4px var(--orange) solid;
      }
    }
  }
}

.tagline {
  clear: both;
  font-weight: 300;
}

.highlight-group {
  margin-top: 1em;
}

[role="tablist"] {
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
  padding-right: 3px;

  button {
    cursor: pointer;
    flex: 0;
    padding-left: 0.5em;
    color: var(--fill) !important;
    text-decoration: none;
    transition: opacity 0.5s;
    background: transparent !important;
    padding: 0;
    margin: 0 0 0 0.5em;

    &:not([aria-selected="true"]) {
      opacity: 0.25;

      &:hover {
        opacity: 0.5;
      }
    }

    &.active {
      opacity: 1;
    }

    &:focus {
      outline: thin dotted;
      outline-offset: 2px;
    }
  }
}

[role="tabpanel"] {
  margin-top: 0.25em;

  &:focus {
    outline: 0;
  }
}

#promotion {
  article {
    background-color: rgba(255, 128, 0, 0.2);
    background-color: color(p3 1 0.5 0 0.2);
    margin-left: -1em;
    margin-right: -1em;
    margin-top: 0.5em;
    padding: 1.5em 1em;
  }

  .book {
    @include disable-selection;
    float: left;
    width: 500px;
    margin-left: -150px;
    margin-top: -150px;
    margin-right: -20px;

    img {
      margin: 0;
      margin-top: 100px;
    }
  }

  & > small {
    font-style: italic;
  }

  h3 {
    font-family: $serif-font-stack;
    font-size: 1.25em;
    margin-bottom: 0.5em;

    a {
      color: inherit;
    }
  }

  h4 {
    font-family: $serif-font-stack;
    font-style: italic;
    font-weight: 300;
    margin-bottom: 1em;

    sup {
      vertical-align: baseline;
      font-size: 1;
    }
  }

  p {
    font-size: 0.75em;
  }

  a.buy {
    background: var(--orange);
    border-radius: 10px;
    color: white !important;
    font-family: $sans-serif-font-stack;
    font-weight: 700;
    margin-top: 1em;
    padding: 0.5em 1.5em;
    text-align: center;
    display: inline-block;

    &:hover {
      text-decoration: none !important;
    }
  }

  .price {
    cursor: help;
    display: block;
    text-align: right;
    float: right;
    padding-left: 1em;
    * {
      display: block;
    }

    del {
      font-size: smaller;
    }
    ins {
      text-decoration: none;
      font-size: larger;
    }
  }
}

table#status {
  table-layout: fixed;
  margin-top: 2em;

  caption {
    padding: 1em 0;
    color: var(--secondary-text);
  }

  .version {
    text-align: center;

    em {
      color: var(--secondary-text);
    }
  }
}

table#customplaygrounddisplayconvertible-categories {
  table-layout: auto;

  tbody th {
    padding-left: 10px;
    text-align: center;
  }

  ul {
    padding: 0 0 0 20px;

    li {
      margin: 0;
    }
  }

  td img {
    margin: 0;
  }
}

@media screen and (max-width: 600px) {
  table#customplaygrounddisplayconvertible-categories {
    thead tr th:last-child,
    tbody tr td:last-child {
      display: none;
    }
  }
}

details {
  summary {
    cursor: pointer;
    margin-bottom: 1em;
    user-select: none;
    -ms-user-select: none;
    -moz-user-select: none;
    -webkit-user-select: none;
  }
}

#translations {
  font-size: smaller;

  dt,
  dd {
    font-weight: 300 !important;
    display: inline;
    margin: 0;
    font-display: optional;
    font-style: normal;
  }
}

[hidden] {
  display: none !important;
}


================================================
FILE: assets/css/_typography.scss
================================================
@import "fonts/merriweather";
@import "fonts/batang";
@import "fonts/cc";
@import "colors";

$serif-font-stack: "Merriweather", Georgia, serif, "Apple Color Emoji",
  "Segoe UI Emoji", "Segoe UI Symbol";

$sans-serif-font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
  Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
  "Segoe UI Symbol";

$mono-font-stack: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier,
  monospace;

html,
body {
  font-family: $serif-font-stack;
  font-size: 16pt;
  line-height: 21pt;
  font-weight: 300;
  font-kerning: normal;
  -webkit-font-kerning: normal;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

html[lang="ko-KR"] {
  body {
    font-family: "Batang", $serif-font-stack;
    font-weight: lighter;
  }
}

html[lang="ko-KR"],
html[lang="zh-Hans"] {
  a.readmore,
  section > h1,
  article p em,
  article p dfn,
  cite {
    font-style: normal;
    font-weight: bold;
  }

  [role="article"] header .byline {
    font-style: normal;
  }

  .archive {
    ol li time,
    ul li time {
      font-style: normal;
      font-weight: bold;
    }
  }

  #promotion h4 {
    font-style: normal;
    font-weight: bold;
  }

  .highlight span {
    font-style: normal !important;
  }
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: $sans-serif-font-stack;
  line-height: 1.1em;
  margin: 0 0 1rem 0;

  small {
    display: block;
    font-size: small;
    font-variant: small-caps;
    text-transform: uppercase;
    font-weight: normal;
    line-height: 2;
    letter-spacing: 0.2ch;
  }

  em {
    font-style: normal;
  }
}

h1 {
  font-size: 2.5em;
}

h2 {
  font-size: 2em;
}

h3 {
  font-size: 1.5em;
}

h4 {
  font-size: 1.25em;
}

h5 {
  font-size: 1.125em;
}

h6 {
  font-size: 1em;
}

p {
  margin: 0 0 1rem 0;
}

a {
  transition: color 0.1s linear;
  text-decoration: none;

  &,
  &:visited {
    color: var(--link);
  }

  &:hover {
    text-decoration: underline;
  }

  &:active,
  &:focus {
    outline: none;
  }

  code {
    white-space: nowrap;
    text-decoration: underline;
  }
}

p > small {
  font-size: inherit;
  font-variant: small-caps;
  text-transform: lowercase;
}

:not(pre) > code {
  user-select: all;
}

:matches(a, p, li, dd, td) {
  code {
    padding: 0.25em;
    font-size: smaller;
    border-radius: 4px;
  }
}

:matches(p, li, dd, td) {
  code {
    color: var(--code);
  }
}

ol,
ul {
  li {
    margin-bottom: 0.5em;
  }
}

pre {
  font-family: $serif-font-stack;
}

code,
samp {
  font-family: $mono-font-stack;
}

pre code,
samp {
  font-size: smaller;
  line-height: 1.1em;
}

samp {
  white-space: pre;
  overflow: scroll;
  -webkit-overflow-scrolling: touch;
  display: block;
  padding: 0.5em 0;
}

section > h1 {
  font-family: $serif-font-stack;
  font-weight: 300;
  font-size: 1.5em;
  text-align: center;
  margin-bottom: 2rem;
  margin-top: 2rem;
}

article.excerpt h1 {
  font-size: 1.5em;
}

a.readmore {
  font-style: italic;
}

kbd {
  border-radius: 4px;
  border: 1px var(--separator) solid;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px #fff inset;
  font-family: $sans-serif-font-stack;
  font-variant: small-caps;
  margin: 0 0.1em;
  padding: 0.1em 0.6em;
  text-transform: lowercase;
}

abbr,
.small-caps {
  font-variant: small-caps;
  text-transform: lowercase;
}

.placeholder {
  color: var(--placeholder-text);
  display: inline-block;
  padding: 0.25em;
  border: 1px var(--opaque-separator) solid;
  border-radius: 4px;
  font-style: normal;

  &.optional {
    opacity: 0.5;
  }
}

h1,
h2,
h3,
h4,
h5,
h6 {
  &:hover .anchor::before {
    opacity: 1;
  }
}

.title {
  font-family: $sans-serif-font-stack;
  font-weight: 700;
}

.anchor::before {
  content: "#";
  opacity: 0;
  transition: 300ms opacity;
  position: absolute;
  float: left;
  margin-left: -1.5em;
  padding: 0 0.5em;
  color: var(--secondary-text) !important;
  text-decoration: none;

  :focus {
    outline: none;
  }
}

.tagline {
  font-size: 1.33em;
}

#latest,
#announcement {
  small {
    font-style: italic;
  }
}

[role="article"] {
  header {
    h1 {
      font-size: 3.5em;
      line-height: 1;
      margin-bottom: 0.5rem;
      padding: 0.5rem 0;
    }
  }
}

#archive {
  dd {
    font-size: smaller;
    display: list-item;
    list-style: circle;
  }
}

.nowrap {
  white-space: nowrap;
}

[lang*="-fonipa"] {
  font-family: $sans-serif-font-stack;
  font-weight: normal;
  font-style: normal;
}

[lang*="-Zsye"] {
  font-style: normal !important;
}

figcaption {
  font-style: italic;
  font-size: smaller;
}

table * {
  font-feature-settings: "tnum";
}

aside.parenthetical {
  font-size: smaller;
  font-style: italic;
  color: var(--secondary-text);
  padding-bottom: 1em;

  p:before {
    content: "(";
  }

  p:after {
    content: ")";
  }

  a,
  code {
    color: var(--secondary-text) !important;
    background: transparent !important;
  }

  a {
    text-decoration: underline;
  }
}

li aside.parenthetical {
  display: inline-block;
  padding-bottom: 0;

  p {
    margin-bottom: 0;
  }
}

.bibliography {
  font-size: smaller;
}

del {
  opacity: 0.5;
}

[role="contentinfo"] i {
  font-family: "Creative Commons Symbols";
  font-style: normal;
}


================================================
FILE: assets/css/articles/1password-cli.scss
================================================
figure#create-vault-dialog {
    display: block;
    width: 360px !important;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    margin: 0 auto;
    display: block;
    padding: 10px;
    background-color: #fff;
    border: 1px solid #ccc;
}

@media (prefers-color-scheme: dark) {
    figure#create-vault-dialog {
        border-color: #777;
        background-color: #262626;
    }
}

span.field {
    font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
    border: 1px solid #0370eb;
    padding: 0.1rem 0.2rem;
    border-radius: 0.2rem;
}

div.fields {
    margin-top: 0.5rem;
    font-size: 0.8rem;
}

figure#authorization-modal {
    display: block;
    width: 360px !important;
    margin: 0 auto;
}

.highlight {
    .gd {
        background-color: rgba(255, 59, 48, 0.5);
    }

    .gi {
        background-color: rgba(52, 199, 89, 0.5);
    }
}


================================================
FILE: assets/css/articles/as-we-may-code.scss
================================================
.nohighlight * {
  color: var(--gray) !important;
}

p > code {
  .kd {
    color: var(--teal);
  }

  .nf {
    color: var(--purple);
  }

  .p {
    color: var(--gray);
  }
}


================================================
FILE: assets/css/articles/availability.scss
================================================
figure#wavailability {
  table {
    table-layout: auto;
    font-size: smaller;

    td[colspan="7"] {
      text-align: left;
    }

    table {
      td {
        padding: 0.5em;
        border-bottom: 1px solid #b7b7b7;
      }
      tr:last-of-type td {
        border: none;
      }
    }
  }
}


================================================
FILE: assets/css/articles/caemitterlayer.scss
================================================
#webgl-confetti {
    position: relative;
    width: 500px;
    margin: 1em auto;
    display: block;
    canvas {
        position: absolute;
        z-index: 1000;
    }
}

video {
    width: 300px;
}

dl {
    display: grid;
    grid-template-columns: min-content auto;
    gap: 0.5em 1em;
  }

  dt {
    grid-column-start: 1;
    margin: 0 !important;
  }

  dd {
    grid-column-start: 2;
    margin: 0 0 1em 0 !important;
  }

@media (prefers-reduced-motion: reduce) {
    #webgl-confetti {
        display: none !important;
    }
}


================================================
FILE: assets/css/articles/callable.scss
================================================
dl {
  display: grid;
  grid-template-columns: min-content auto;
  gap: 0.5em 1em;
}

dt {
  grid-column-start: 1;
  margin: 0 !important;
}

dd {
  grid-column-start: 2;
  margin: 0 0 1em 0 !important;
}


================================================
FILE: assets/css/articles/characterset.scss
================================================
@import "colors";
@import "functions";

.conversation {
  @include clearfix;

  margin: 1em auto;
  max-width: 650px;

  ruby {
    ruby-align: start;
    ruby-position: over;
    display: block;
    clear: both;
    max-width: 550px;

    &.boke {
      float: left;
      text-align: left;
      margin-bottom: 0.5em;
    }

    &.tsukkomi {
      float: right;
      color: var(--orange);
      text-align: right;
      margin-bottom: 1.5em;
    }
  }
}


================================================
FILE: assets/css/articles/dark-mode.scss
================================================
.color {
  background: var(--color);
  display: inline-block;
}

p .color {
  width: 0.8em;
  height: 0.8em;
  border-radius: 0.2ch;
}

table {
  table-layout: auto;

  thead {
    tr:not(:first-of-type) th {
      font-weight: normal;
      font-size: 0.5em;
    }
  }

  td {
    padding: 0.5em 0 !important;
  }

  .color {
    width: 64px;
    height: 64px;
    border-radius: 8px;
    display: block;
    margin: 0 auto;
  }
}

td.dark {
  background: #2c2a28;
}

@media (prefers-color-scheme: dark) {
  td.light {
    background: #fefefe;
  }
}

@media screen and (max-width: 768px) {
  table td .color {
    width: 32px;
    height: 32px;
    border-radius: 4px;
  }
}

#fixed-colors {
  display: grid;
  grid-template-columns: 1fr 0 1fr;
}

@media screen and (min-width: 768px) {
  #semantic-colors {
    column-count: 2;
    column-fill: balance;

    dl {
      margin-top: 0;
      padding-top: 0;
    }

    dt {
      margin-top: 2em;
    }

    dd {
      break-before: avoid;
      break-inside: avoid;
      -webkit-column-break-before: avoid;
      margin-bottom: 0.5em;
      &:before {
        content: "• ";
      }
    }
  }
}


================================================
FILE: assets/css/articles/formatter.scss
================================================
dl {
    width: auto;
    font-family: initial;
    display: grid;
    grid-template-columns: auto max-content;
    gap: 0 1em;
    padding: 1em 0;
    border-top: 1px solid;
    border-bottom: 1px solid;
    margin: 2em 0;
  }

  dt {
    grid-column-start: 1;
    margin: 0 !important;
  }

  dd {
    grid-column-start: 2;
    margin: 0 0 1em 0 !important;
    &:before {
        content: "• "
    }
  }

  dd + dt {
      &, & + dd {
        padding-top: 2em;
      }
  }


================================================
FILE: assets/css/articles/ios-13.scss
================================================
.conversation {
    max-width: 50ch;
    display: block;
    margin: 0 auto;
    padding: 1em 0;
    p {
        margin: 0;
    }

    p:nth-of-type(2n) {
        display: block;
        font-style: italic;
        text-align: right;
        padding: 0.5em 0 1em 1em;
        &::first-letter {
            font-style: normal;
        }
    }
}

#on-device-speech-recognition-supported-languages {
    text-align: left;

    dl{
        display: grid;
        gap: 1em 2em;
        grid-template-columns: repeat(1fr);
      }

      dt {
        grid-column-start: 1;
        margin: 0;
        padding: 0;
        text-align: right;
      }

      dd {
        grid-column-start: 2;
        margin: 0;
        padding: 0;
      }
}


================================================
FILE: assets/css/articles/keyvaluepairs.scss
================================================
#bagua {
  td {
    text-align: center;
  }
}

#bagua + p ruby:last-of-type {
  -webkit-ruby-position: under;
  ruby-position: under;
}

rtc {
  display: none !important;
}


================================================
FILE: assets/css/articles/mapkit-js.scss
================================================
#jwt-debug {
  h3 {
    margin: 0;

    small {
      display: block;
      font-weight: normal;
      font-size: smaller;
    }
  }

  display: grid;
  grid-template:
    "encoded header"
    "encoded payload"
    "encoded signature";
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: 0.5em 3em;

  #jwt-encoded {
    grid-area: encoded;

    .highlight {
      font-size: larger;
      height: 86%;
    }
  }

  #jwt-header {
    grid-area: header;

    span.s2 {
      color: var(--pink) !important;
    }
  }

  #jwt-payload {
    grid-area: payload;

    span.s2 {
      color: var(--purple) !important;
    }
  }

  #jwt-signature {
    grid-area: signature;

    span.s2,
    span.nx {
      color: var(--teal) !important;
    }
  }

  #jwt-header,
  #jwt-payload,
  #jwt-signature {
    .highlight {
      font-size: smaller;
    }
  }
}

#map {
  display: block;
  width: 100%;
  height: 400px;
  margin-bottom: 2em;
}

.mk-map-view {
  border: 1px transparent solid;
  border-radius: 4px;
}

@media screen and (max-width: 768px) {
  #jwt-debug {
    grid-template:
      "encoded"
      "header"
      "payload"
      "signature";
    grid-template-columns: auto;
    grid-template-rows: auto;
    gap: 0.5em 0;
  }
}


================================================
FILE: assets/css/articles/message-id.scss
================================================
@import "../functions";

@media screen and (min-width: 768px) {
  aside {
    @include clearfix;

    figure {
      float: right;
      padding-left: 20px;
      margin: 0 !important;
      padding: 0 !important;

      img {
        margin: 0 !important;
      }

      & + p:first-of-type {
        margin-top: 2em;
      }
    }
  }
}


================================================
FILE: assets/css/articles/metrickit.scss
================================================
h2 {
  clear: both;
}

@media screen and (min-width: 768px) {
  #battery-usage {
    float: right;
    width: 300px;
    padding-left: 20px;
  }
}


================================================
FILE: assets/css/articles/model-context-protocol.scss
================================================
ol {
    list-style-type: decimal !important;
}

@media (min-width: 768px) {
    dl {
        margin-left: auto;
        margin-right: auto;
        width: 85%;
    }

    dt,
    dd {
        padding-left: 2rem;
        padding-right: 2rem;
    }
}

dl {
    border: 1px solid #b7b7b7;
    padding: 1rem;
    margin-top: 0.25rem;
    margin-bottom: 3rem;
    font-size: 0.8rem;

    dt,
    dd {
        padding-left: 1rem;
        padding-right: 1rem;
    }

    dd {
        margin-left: 0;
    }

    dt {
        padding-top: 1rem;
        margin-bottom: 0.125rem;

        &:first-of-type {
            padding-top: 0;
        }
    }
}

.user {
    text-align: left;
}

.client {
    text-align: center;
}

.assistant {
    text-align: right;

    blockquote {
        text-align: right !important;
        border-left: 0;
    }
}

[role="article"] .content dl blockquote {
    text-align: right !important;
    border-left: 0 !important;
    margin: 0;
    font-style: italic;
}

span.big {
    font-size: 2rem;
    padding-top: 0.5rem;
    display: inline-block;
}

picture img[src$=".svg"] {
    filter: none !important;
}

#imcp-logo {
    max-width: 480px;
    display: block;
    margin: 0 auto;
    cursor: pointer;
}

#emcee-logo {
    max-width: 480px;
    display: block;
    margin: 0 auto;
    cursor: pointer;
}

================================================
FILE: assets/css/articles/swift-format.scss
================================================
div.variable-width {
  resize: horizontal;
  overflow: hidden;
  min-width: 30ch;
  width: 30ch;
  max-width: 100%;
  margin-bottom: 2em;

  .highlight {
    height: 80vh;
    overflow: scroll;
    font-size: 14px !important;
    line-height: 1.2 !important;
  }
}


================================================
FILE: assets/css/articles/swift-log.scss
================================================
#log-levels {
  table-layout: auto;
  tbody td:first-of-type {
    background-color: var(--color);
    code {
      background-color: var(--background);
      color: var(--text) !important;
      display: block;
    }
  }
}

#log-level-trace {
  --color: var(--gray);
}

#log-level-debug {
  --color: var(--blue);
}

#log-level-info {
  --color: var(--green);
}

#log-level-notice {
  --color: var(--yellow);
}

#log-level-warning {
  --color: var(--orange);
}

#log-level-error {
  --color: var(--red);
}

#log-level-critical {
  --color: black;
}


================================================
FILE: assets/css/articles/swift-package-registry.scss
================================================
table {
  table-layout: auto !important;

  td {
    text-align: right !important;
  }
}

.dialogue {
  text-align: left !important;
  margin: 1em auto;

  code,
  samp {
    display: inline-block;
    line-height: 1.6;
  }

  var.placeholder {
    padding: 0 0.25em;
  }

  code {
    color: var(--code);

    i {
      color: var(--gray);
      font-style: normal;
    }
  }

  details {
    margin: 0.5em 0;
    padding: 0.5em 0;
    padding-left: 2em;
    border-top: 1px dotted var(--separator);
    border-bottom: 1px dotted var(--separator);

    summary {
      margin-left: -2em;
      margin-bottom: 0;
    }
  }

  pre {
    width: auto;
    display: block;
    clear: both;
    margin: 0;
  }

  samp {
    overflow: none;
    line-height: 1.2;
    color: var(--gray);
    margin-bottom: 0.5em;
    padding: 0.25em 0;
    font-style: italic;
  }

  .placeholder {
    color: var(--gray) !important;
  }
}

@media screen and (min-width: 768px) {
  .dialogue,
  details {
    &::after {
      content: "";
      clear: both;
      display: table;
    }
  }

  .dialogue {
    padding: 0.5em 2em !important;

    .input {
      text-align: left;
    }

    .output {
      float: right;
    }
  }
}


================================================
FILE: assets/css/articles/swiftui-previews.scss
================================================
.code-with-automatic-preview {
  display: flex;
  align-items: stretch;
  background-color: var(--secondary-background);
  margin-bottom: 2em;

  .highlight {
    flex: 2;
  }

  aside {
    flex: 1;
    max-width: 400px;
    border-left: 1px var(--opaque-separator) solid;
    background-color: var(--secondary-background);
    margin-left: 20px;
    padding: 10px;
  }
}


================================================
FILE: assets/css/fonts/_batang.scss
================================================
@font-face {
    font-family: 'Batang';
    src: url(font_path("Batang.woff2")) format("woff2"),
        url(font_path("Batang.woff")) format("woff");
    font-weight: normal;
    font-style: normal;
    font-display: auto;
    unicode-range: U+AC00-D7A3, U+1100-11FF, U+3130-318F, U+A960-A97F, U+D7B0-D7FF;
}


================================================
FILE: assets/css/fonts/_cc.scss
================================================
@font-face {
  font-family: "Creative Commons Symbols";
  src: url(font_path("CreativeCommonsSymbols.woff2")) format("woff2"),
    url(font_path("CreativeCommonsSymbols.woff")) format("woff");
  font-weight: normal;
  font-style: normal;
  unicode-range: U+1F10D-1F10F, U+1F16D-1F16F;
}


================================================
FILE: assets/css/fonts/_merriweather.scss
================================================
@font-face {
    font-family: "Merriweather";
    src: local("Merriweather Regular"), local("Merriweather-Regular"),
        url(font_path("Merriweather-Regular.woff2")) format("woff2"),
        url(font_path("Merriweather-Regular.woff")) format("woff");
    font-weight: normal;
    font-style: normal;
    font-display: auto;
}

@font-face {
    font-family: "Merriweather";
    src: local("Merriweather Light"), local("Merriweather-Light"),
        url(font_path("Merriweather-Light.woff2")) format("woff2"),
        url(font_path("Merriweather-Light.woff")) format("woff");
    font-weight: 300;
    font-style: normal;
    font-display: auto;
}

@font-face {
    font-family: "Merriweather";
    src: local("Merriweather Black"), local("Merriweather-Black"),
        url(font_path("Merriweather-Black.woff2")) format("woff2"),
        url(font_path("Merriweather-Black.woff")) format("woff");
    font-weight: 900;
    font-style: normal;
    font-display: auto;
}

@font-face {
    font-family: "Merriweather";
    src: local("Merriweather Bold"), local("Merriweather-Bold"),
        url(font_path("Merriweather-Bold.woff2")) format("woff2"),
        url(font_path("Merriweather-Bold.woff")) format("woff");
    font-weight: bold;
    font-style: normal;
    font-display: auto;
}

@font-face {
    font-family: "Merriweather";
    src: local("Merriweather Black Italic"), local("Merriweather-BlackItalic"),
        url(font_path("Merriweather-BlackItalic.woff2")) format("woff2"),
        url(font_path("Merriweather-BlackItalic.woff")) format("woff");
    font-weight: 900;
    font-style: italic;
    font-display: auto;
}

@font-face {
    font-family: "Merriweather";
    src: local("Merriweather Italic"), local("Merriweather-Italic"),
        url(font_path("Merriweather-Italic.woff2")) format("woff2"),
        url(font_path("Merriweather-Italic.woff")) format("woff");
    font-weight: normal;
    font-style: italic;
    font-display: auto;
}

@font-face {
    font-family: "Merriweather";
    src: local("Merriweather Bold Italic"), local("Merriweather-BoldItalic"),
        url(font_path("Merriweather-BoldItalic.woff2")) format("woff2"),
        url(font_path("Merriweather-BoldItalic.woff")) format("woff");
    font-weight: bold;
    font-style: italic;
    font-display: auto;
}

@font-face {
    font-family: "Merriweather";
    src: local("Merriweather Light Italic"), local("Merriweather-LightItalic"),
        url(font_path("Merriweather-LightItalic.woff2")) format("woff2"),
        url(font_path("Merriweather-LightItalic.woff")) format("woff");
    font-weight: 300;
    font-style: italic;
    font-display: auto;
}


================================================
FILE: assets/css/media-queries/_hover.scss
================================================
@media (hover: none) {
    #logo #mustache {
        animation-iteration-count: 1;
    }
}


================================================
FILE: assets/css/media-queries/_inverted-colors.scss
================================================
@media (inverted-colors) {
    * {
        text-shadow: none !important;
        box-shadow: none !important;
    }

    img {
        filter: invert(100%);
    }
}


================================================
FILE: assets/css/media-queries/_monochrome.scss
================================================
@media (monochrome),
  print and (not(color)),
  (prefers-contrast: high),
  screen and (-ms-high-contrast: active) {
  :root {
    --red: black;
    --yellow: black;
    --green: black;
    --teal: black;
    --blue: black;
    --indigo: black;
    --purple: black;
    --pink: black;
    --gray: black;
    --gray2: black;
    --gray3: black;
    --gray4: black;
    --gray5: black;
    --gray6: black;

    --text: black;
    --secondary-text: black;
    --placeholder-text: black;
    --separator: black;
    --opaque-separator: black;
    --fill: white;
    --secondary-fill: white;
    --background: white;
    --secondary-background: white;
  }

  .highlight {
    color: black !important;
    background: #fff !important;

    border: 2px black solid;

    .c,
    .ch,
    .cm,
    .cpf,
    .c1,
    .cs,
    .ge,
    .s,
    .sa,
    .sb,
    .sc,
    .dl,
    .sd,
    .s2,
    .sh,
    .sx,
    .sr,
    .s1,
    .ss {
      font-style: italic;
    }

    .k,
    .gh,
    .gp,
    .gs,
    .gu,
    .kc,
    .kd,
    .kn,
    .kr,
    .nc,
    .ni,
    .ne,
    .nn,
    .nt,
    .ow {
      font-weight: bold;
    }

    .se,
    .si {
      font-weight: bold;
      font-style: italic;
    }
  }

  .admonition:before {
    visibility: hidden;
  }
}


================================================
FILE: assets/css/media-queries/_prefers-color-scheme.scss
================================================
@media (prefers-color-scheme: dark) {
  :root {
    --red: rgb(255, 69, 58);
    --yellow: rgb(255, 214, 10);
    --green: rgb(48, 209, 88);
    --teal: rgb(100, 210, 255);
    --blue: rgb(10, 132, 255);
    --indigo: rgb(94, 92, 230);
    --purple: rgb(191, 90, 242);
    --pink: rgb(255, 55, 95);
    --gray: rgb(142, 142, 147);
    --gray2: rgb(99, 99, 102);
    --gray3: rgb(72, 72, 74);
    --gray4: rgb(58, 58, 60);
    --gray5: rgb(44, 44, 46);
    --gray6: rgb(28, 28, 30);

    --text: rgb(255, 255, 255);
    --secondary-text: rgb(235, 235, 245);
    --placeholder-text: rgb(235, 235, 245);
    --separator: rgb(84, 84, 88);
    --opaque-separator: rgb(56, 56, 58);
    --fill: rgb(120, 120, 128);
    --secondary-fill: rgb(120, 120, 128);
    --background: rgb(14, 14, 15);
    --secondary-background: rgb(28, 28, 30);
  }

  @supports (color: color(display-p3 1 1 1)) {
    :root {
      --red: color(display-p3 1 0.4118 0.3804);
      --yellow: color(display-p3 1 0.8314 0.149);
      --green: color(display-p3 0.1882 0.8588 0.3569);
      --teal: color(display-p3 0.4392 0.8431 1);
      --blue: color(display-p3 0.251 0.6118 1);
      --indigo: color(display-p3 0.4902 0.4784 1);
      --purple: color(display-p3 0.8549 0.5608 1);
      --pink: color(display-p3 1 0.3922 0.5098);
      --gray: color(display-p3 0.6824 0.6824 0.698);
      --gray2: color(display-p3 0.4863 0.4863 0.502);
      --gray3: color(display-p3 0.3294 0.3294 0.3373);
      --gray4: color(display-p3 0.2667 0.2667 0.2745);
      --gray5: color(display-p3 0.2118 0.2118 0.2196);
      --gray6: color(display-p3 0.1412 0.1412 0.149);

      --text: color(display-p3 1 1 1);
      --secondary-text: color(display-p3 0.9216 0.9216 0.9608);
      --placeholder-text: color(display-p3 0.9216 0.9216 0.9608);
      --separator: color(display-p3 0.3294 0.3294 0.3451);
      --opaque-separator: color(display-p3 0.2196 0.2196 0.2275);
      --fill: color(display-p3 0.4706 0.4706 0.502);
      --secondary-fill: color(display-p3 0.4706 0.4706 0.502);
      --background: color(display-p3 0.0706 0.0706 0.075);
      --secondary-background: color(display-p3 0.1412 0.1412 0.149);
    }
  }

  body {
    div.highlight {
      border: 1px var(--separator) solid !important;
    }

    .language-toggle a {
      color: var(--secondary-text) !important;
    }

    .info {
      background: #333c44 !important;
    }

    .warning {
      background: #484131 !important;
    }

    .error {
      background: #592e41 !important;
    }
  }

  article,
  i {
    img[src$=".svg"] {
      filter: invert(100%);
    }
  }

  kbd {
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.2), 0 0 0 2px #222 inset;
  }
}


================================================
FILE: assets/css/media-queries/_prefers-contrast.scss
================================================
@media (prefers-contrast: high), screen and (-ms-high-contrast: active) {
  :root {
    --red: rgb(215, 0, 21);
    --yellow: rgb(179, 98, 0);
    --green: rgb(36, 138, 61);
    --teal: rgb(0, 113, 164);
    --blue: rgb(0, 64, 221);
    --indigo: rgb(54, 52, 163);
    --purple: rgb(137, 68, 171);
    --pink: rgb(211, 15, 69);
    --gray: rgb(108, 108, 112);
    --gray2: rgb(142, 142, 147);
    --gray3: rgb(174, 174, 178);
    --gray4: rgb(188, 188, 192);
    --gray5: rgb(216, 216, 220);
    --gray6: rgb(235, 235, 240);

    --text: rgb(0, 0, 0);
    --secondary-text: rgb(60, 60, 67);
    --placeholder-text: rgb(60, 60, 67);
    --separator: rgb(60, 60, 67);
    --opaque-separator: rgb(198, 198, 200);
    --fill: rgb(120, 120, 128);
    --secondary-fill: rgb(120, 120, 128);
    --background: rgb(235, 235, 240);
    --secondary-background: rgb(255, 255, 255);
  }

  @supports (color: color(display-p3 1 1 1)) {
    :root {
      --red: color(display-p3 0.8431 0 0.08235);
      --yellow: color(display-p3 0.702 0.3843 0);
      --green: color(display-p3 0.1412 0.5412 0.2392);
      --teal: color(display-p3 0 0.4431 0.6431);
      --blue: color(display-p3 0 0.251 0.8667);
      --indigo: color(display-p3 0.2118 0.2039 0.6392);
      --purple: color(display-p3 0.5373 0.2667 0.6706);
      --pink: color(display-p3 0.8275 0.05882 0.2706);
      --gray: color(display-p3 0.4235 0.4235 0.4392);
      --gray2: color(display-p3 0.5569 0.5569 0.5765);
      --gray3: color(display-p3 0.6824 0.6824 0.698);
      --gray4: color(display-p3 0.7373 0.7373 0.7529);
      --gray5: color(display-p3 0.8471 0.8471 0.8627);
      --gray6: color(display-p3 0.9216 0.9216 0.9412);

      --text: color(display-p3 0 0 0);
      --secondary-text: color(display-p3 0.2353 0.2353 0.2627);
      --placeholder-text: color(display-p3 0.2353 0.2353 0.2627);
      --separator: color(display-p3 0.2353 0.2353 0.2627);
      --opaque-separator: color(display-p3 0.7765 0.7765 0.7843);
      --fill: color(display-p3 0.4706 0.4706 0.502);
      --secondary-fill: color(display-p3 0.4706 0.4706 0.502);
      --background: color(display-p3 0.9216 0.9216 0.9412);
      --secondary-background: color(display-p3 1 1 1);
    }
  }
}


================================================
FILE: assets/css/media-queries/_prefers-reduced-motion.scss
================================================
@media (prefers-reduced-motion: reduce) {
    #logo #mustache {
        animation: none !important;
    }
}


================================================
FILE: assets/css/media-queries/_print.scss
================================================
@media print {
  @page {
    margin: 0.5in;
  }

  @page {
    @bottom-center {
      content: "Page " counter(page) " of " counter(pages);
      font-size: small;
    }

    @footnote {
      border-top: 1pt black solid;
      padding-top: 1em;
      font-size: smaller;
      padding-left: 1.5em;
    }
  }

  html {
    border-top: none;

    body {
      font-size: 12pt !important;
    }
  }

  #logo {
    height: 3em !important;

    svg {
      transform: scale(0.5);
      transform-origin: top left;
    }
  }

  img,
  p,
  blockquote,
  aside,
  ul,
  ol,
  table,
  figure,
  .highlight-group {
    page-break-inside: avoid;
  }

  .highlight-group {
    page-break-before: avoid;
  }

  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    page-break-before: avoid;
    page-break-after: avoid;
  }

  img {
    max-width: 100% !important;
  }

  p {
    a {
      word-wrap: break-word;
    }

    a[href^="#"]:after {
      display: none;
    }

    a[href^="http://"]:after,
    a[href^="https://"]:after {
      // content: " ("attr(href) ")";
      // text-decoration: underline;
      content: " (" attr(title) ") ";
      float: footnote;
      color: var(--secondary-text);
      font-size: small;
      text-decoration: none;
      text-align: left;
      page-break-inside: avoid;
      page-break-before: avoid;
    }
  }

  article [title]::after {
    content: " (" attr(title) ") ";
    float: footnote;
    font-size: small;
  }

  .highlight-group a {
    font-size: 50%;
  }

  div.highlight {
    border-radius: 4px;
    border: 2px black solid;
  }

  [role="article"] {
    .content {
      margin-bottom: 1em !important;
    }
  }

  [role="complementary"] {
    display: none;
  }

  [role="contentinfo"] {
    page-break-inside: avoid;
    font-size: small;
  }

  .admonition {
    padding: 0 0 0 1em;

    &::before {
      visibility: hidden;
    }
  }

  [hidden] {
    display: none !important;
  }
}

@media print and (color) {
  * {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
}


================================================
FILE: assets/css/media-queries/_width.scss
================================================
@media screen and (max-width: 768px) {
  [role="article"] header {
    .byline {
      .authors,
      .translators {
        &:after {
          content: " ";
          display: block;
        }
      }
    }
  }

  .container {
    padding: 1em;
  }

  #recent {
    ul {
      display: block;

      li {
        min-height: auto;
        margin-bottom: 2em;

        .title {
          display: block;
          height: auto;
          padding-bottom: 0.5rem;
        }
      }
    }
  }

  [role="article"] {
    font-size: smaller;

    .content {
      overflow: hidden;

      blockquote {
        margin: 1em 0;
      }
    }

    footer .contributor {
      width: 100%;
      margin-bottom: 1em;

      &:not(:first-child) {
        border-top: none;
      }

      .avatar {
        padding: 0;
      }

      .details {
        margin-top: 0;
      }
    }
  }

  [role="complementary"] {
    #continue,
    #related {
      width: 100%;
    }

    #related {
      margin-top: 1em;

      li {
        font-size: 1em;
      }
    }
  }

  #contributors ul li {
    flex-basis: 33%;
  }

  #recent article {
    float: none;
    display: block;
    width: 100%;

    &:last-child,
    &:nth-of-type(2n) {
      margin-right: 0;
    }
  }

  .archive dl {
    width: 100%;
    margin: 0;
    float: none;

    dt {
      margin: 2em 0 0.5em 0;
    }
  }

  #archive dd {
    min-height: 30px;
  }
}

@media screen and (max-width: 960px) {
  [role="banner"] {
    display: block;
    margin-bottom: 0;
    padding-bottom: 0;

    #logo {
      margin: 0 !important;
      height: auto;

      svg {
        width: 25vw;
        display: block;
        margin: 0 auto 1.5em auto;
      }

      padding-bottom: 0.5em;
    }

    .tagline {
      font-size: 4.4vw;
      padding-bottom: 2em;
    }
  }

  #recent {
    ul {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  .anchor {
    font-size: smaller;
  }

  #announcement {
    margin-left: 0;
    margin-right: 0;
  }

  article.author,
  article.translator {
    header {
      display: block;

      .avatar {
        margin: 0 auto 1em auto;
        display: block;
      }

      h1 {
        text-align: center;
      }
    }
  }
}

@media screen and (max-width: 768px) {
  #promotion {
    padding-top: 3em;

    small {
      position: relative;
      top: 60px;
    }

    article {
      padding-top: 80px;
    }

    .book {
      img {
        width: 350px;
        margin: -86px auto 0 280px;
        position: absolute;
      }
    }

    .buy {
      width: 100%;
    }
  }
}

@media screen and (max-width: 480px) {
  #promotion {
    padding-top: 0;

    small {
      text-align: center;
      display: block;
    }

    article {
      overflow: hidden;
    }

    h3 {
      padding-right: 3em;
    }

    .book {
      margin: -30px 0 0 0;
      img {
        width: 320px;
        margin: 0;
        padding: 0;
        position: relative;
        left: -10px;
      }

      & + div {
        clear: both;
      }
    }
  }
}


================================================
FILE: assets/css/screen.scss
================================================
@charset "UTF-8";

@import "colors";
@import "animations";
@import "typography";
@import "admonitions";
@import "layout";
@import "code";
@import "inputs";

@import "media-queries/width";
@import "media-queries/hover";
@import "media-queries/inverted-colors";
@import "media-queries/monochrome";
@import "media-queries/prefers-color-scheme";
@import "media-queries/prefers-contrast";
@import "media-queries/prefers-reduced-motion";
@import "media-queries/print";

* {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

#type-encodings tr > td:first-child,
#method-encodings tr > td:first-child {
  width: 12em;
  padding-left: 3em;
}

@media screen and (max-width: 480px) {
  #gpuimage table {
    font-size: 50%;
  }
}

#gpuimage {
  #gpuimage-benchmarks td {
    text-align: center;

    &:first-child {
      text-align: left;
    }

    &:last-child {
      text-align: right;
    }
  }

  #gpuimage-filters td {
    vertical-align: top;
    font-size: 75%;
  }

  blockquote {
    font-size: 75%;
  }
}

table {
  &.core-data-versus-nskeyedarchiver td {
    text-align: center;

    &:first-child {
      text-align: left;
      font-weight: bold;
    }
  }

  &#xcode-key-bindings-modifiers {
    width: 100%;

    td,
    th {
      width: 20%;
      text-align: center;
    }
  }
}

#cfstringtransform table {
  display: block;

  td:first-child {
    width: 60%;
  }
}

#icloud header time {
  background-color: rgba(255, 128, 0, 0.2);
}




================================================
FILE: assets/js/application.js
================================================
"use strict";

(function() {
  const delay = 300;

  const keys = {
    end: 35,
    home: 36,
    left: 37,
    up: 38,
    right: 39,
    down: 40
  };

  const direction = {
    37: -1,
    39: 1
  };

  const tablists = document.querySelectorAll('[role="tablist"]');
  tablists.forEach(tablist => {
    const tabs = tablist.querySelectorAll('[role="tab"]');
    const panels = tablist.parentElement.querySelectorAll('[role="tabpanel"]');

    const clickEventListener = event => {
      const target = event.target;

      target.dispatchEvent(
        new Event("activate", {
          bubbles: true
        })
      );
    };

    const keydownEventListener = event => {
      const { keyCode } = event;

      switch (keyCode) {
        case keys.end:
          event.preventDefault();
          tabs[tabs.length - 1].dispatchEvent(
            new Event("activate", {
              bubbles: true
            })
          );
          break;
        case keys.home:
          event.preventDefault();
          tabs[0].dispatchEvent(
            new Event("activate", {
              bubbles: true
            })
          );
          break;
        case keys.up:
        case keys.down:
          determineOrientation(event);
          break;
      }
    };

    const keyupEventListener = event => {
      const { keyCode, target } = event;

      tabs.forEach(tab => {
        tab.addEventListener("focus", focusEventListener);
      });

      if (direction[keyCode]) {
        if (target.dataset.index !== undefined) {
          if (tabs[target.dataset.index + direction[pressed]]) {
            tabs[target.dataset.index + direction[pressed]].focus();
          } else if (pressed === keys.left || pressed === keys.up) {
            tabs[tabs.length - 1].focus();
          } else if (pressed === keys.right || pressed == keys.down) {
            tabs[0].focus();
          }
        }
      }
    };

    const focusEventListener = event => {
      const { target } = event;

      const handler = target => {
        focused = document.activeElement;

        if (target === focused) {
          target.dispatchEvent(new Event("activate"));
        }
      };

      setTimeout(handler, delay, target);
    };

    const activateEventListener = event => {
      const { target, bubbles } = event;

      tabs.forEach(tab => {
        tab.setAttribute("tabindex", "-1");
        tab.setAttribute("aria-selected", "false");
        tab.removeEventListener("focus", focusEventListener);
      });

      panels.forEach(panel => {
        panel.setAttribute("hidden", "hidden");
      });

      target.removeAttribute("tabindex");
      target.setAttribute("aria-selected", "true");

      var controls = target.getAttribute("aria-controls");
      document.getElementById(controls).removeAttribute("hidden");

      if (bubbles) {
        for (const language of ["swift", "objective-c"]) {
          if (target.classList.contains(language)) {
            if (window.localStorage) {
              window.localStorage.setItem("preferred-language", language);
            }

            document
              .querySelectorAll(`[role="tab"].${language}`)
              .forEach(tab => {
                tab.dispatchEvent(new Event("activate"));
              });

            document.querySelectorAll(".highlight-group").forEach(group => {
              if (
                group.clientHeight > (parseInt(group.style.minHeight, 10) || 0)
              ) {
                group.style.minHeight = `${group.clientHeight}px`;
              }
            });
          }
        }
      }
    };

    for (let index = 0; index < tabs.length; index++) {
      const tab = tabs[index];
      tab.addEventListener("click", clickEventListener);
      tab.addEventListener("keydown", keydownEventListener);
      tab.addEventListener("keyup", keyupEventListener);
      tab.addEventListener("activate", activateEventListener);

      tab.dataset.index = index;
    }
  });

  if (window.localStorage) {
    const language = window.localStorage.getItem("preferred-language");
    if (language) {
      document.querySelectorAll(`[role="tab"].${language}`).forEach(tab => {
        tab.dispatchEvent(new Event("activate"));
      });
    }
  }

  document
    .querySelectorAll('article [role="heading"] h1.title')
    .forEach(element => {
      const resize = () => {
        const compression = 1.0;
        const minFontSize = 16.0;
        const maxFontSize = 72.0;

        element.style.fontSize =
          Math.max(
            Math.min(element.clientWidth / (compression * 10), maxFontSize),
            minFontSize
          ) + "px";
      };

      resize();

      window.addEventListener("resize", resize);
      window.addEventListener("orientationchange", resize);
    });
})();

setTimeout(function() {
  if (
    document.location.pathname === "/" &&
    matchMedia("(hover: none)").matches
  ) {
    document.querySelector("#logo svg").classList.add("animated");
  }
}, 1000);


================================================
FILE: assets/js/articles/caemitterlayer.js
================================================
// Credit: https://jsfiddle.net/subzey/52sowezj/

'use strict';

(function() {
var canvas = document.querySelector('#webgl-confetti canvas');
var gl = canvas.getContext('webgl', {alpha: true});

var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, `
precision lowp float;

attribute vec2 a_position;
attribute float a_startAngle;
attribute float a_angularVelocity;
attribute float a_rotationAxisAngle;
attribute float a_particleDistance;
attribute float a_particleAngle;
attribute float a_particleY;
uniform float u_time;

varying vec2 v_position;
varying vec3 v_color;
varying float v_overlight;

void main() {
  float angle = a_startAngle + a_angularVelocity * u_time;
  float vertPosition = 1.1 - mod(u_time * .25 + a_particleY, 2.2);
  float viewAngle = a_particleAngle + mod(u_time * .25, 6.28);

  mat4 vMatrix = mat4(1.3, 0.0, 0.0, 0.0, 0.0, 1.3, 0.0, 0.0, 0.0, 0.0, 1.0,
                      1.0, 0.0, 0.0, 0.0, 1.0);

  mat4 shiftMatrix =
      mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
           a_particleDistance * sin(viewAngle), vertPosition,
           a_particleDistance * cos(viewAngle), 1.0);

  mat4 pMatrix = mat4(cos(a_rotationAxisAngle), sin(a_rotationAxisAngle), 0.0,
                      0.0, -sin(a_rotationAxisAngle), cos(a_rotationAxisAngle),
                      0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) *
                 mat4(1.0, 0.0, 0.0, 0.0, 0.0, cos(angle), sin(angle), 0.0, 0.0,
                      -sin(angle), cos(angle), 0.0, 0.0, 0.0, 0.0, 1.0);

  gl_Position =
      vMatrix * shiftMatrix * pMatrix * vec4(a_position * 0.03, 0.0, 1.0);
  vec4 normal = vec4(0.0, 0.0, 1.0, 0.0);
  vec4 transformedNormal = normalize(pMatrix * normal);

  float dotNormal = abs(dot(normal.xyz, transformedNormal.xyz));
  float regularLighting = dotNormal / 2.0 + 0.5;
  float glanceLighting = smoothstep(0.92, 0.98, dotNormal);
  v_color = vec3(mix((0.5 - transformedNormal.z / 2.0) * regularLighting, 1.0,
                     glanceLighting),
                 mix(0.5 * regularLighting, 1.0, glanceLighting),
                 mix((0.5 + transformedNormal.z / 2.0) * regularLighting, 1.0,
                     glanceLighting));

  v_position = a_position;
  v_overlight = 0.9 + glanceLighting * 0.1;
}
`);
gl.compileShader(vertexShader);

var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, `
precision lowp float;
varying vec2 v_position;
varying vec3 v_color;
varying float v_overlight;

void main() {
  gl_FragColor =
      vec4(v_color, 1.0 - smoothstep(0.8, v_overlight, length(v_position)));
}
`);
gl.compileShader(fragmentShader);

var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);

gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());

var STRIDE = 8;
var attrs = [
  {name: 'a_position', length: 2, offset: 0},
  {name: 'a_startAngle', length: 1, offset: 2},
  {name: 'a_angularVelocity', length: 1, offset: 3},
  {name: 'a_rotationAxisAngle', length: 1, offset: 4},
  {name: 'a_particleDistance', length: 1, offset: 5},
  {name: 'a_particleAngle', length: 1, offset: 6},
  {name: 'a_particleY', length: 1, offset: 7}
];
for (var i = 0; i < attrs.length; i++) {
  var name = attrs[i].name;
  var length = attrs[i].length;
  var offset = attrs[i].offset;
  var attribLocation = gl.getAttribLocation(shaderProgram, name);
  gl.vertexAttribPointer(
      attribLocation, length, gl.FLOAT, false, STRIDE * 4, offset * 4);
  gl.enableVertexAttribArray(attribLocation);
}

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.createBuffer());

var NUM_PARTICLES = 150;
var NUM_VERTICES = 4;
var NUM_INDICES = 6;

var vertices = new Float32Array(NUM_PARTICLES * STRIDE * NUM_VERTICES);
var indices = new Uint16Array(NUM_PARTICLES * NUM_INDICES);
for (var i = 0; i < NUM_PARTICLES; i++) {
  var axisAngle = Math.random() * Math.PI * 2;
  var startAngle = Math.random() * Math.PI * 2;
  var groupPtr = i * STRIDE * NUM_VERTICES;

  var particleDistance = Math.sqrt(Math.random());
  var particleAngle = Math.random() * Math.PI * 2;
  var particleY = Math.random() * 2.2;
  var angularVelocity = Math.random() * 2 + 1;

  for (var j = 0; j < 4; j++) {
    var vertexPtr = groupPtr + j * STRIDE;
    vertices[vertexPtr + 2] = startAngle;
    vertices[vertexPtr + 3] = angularVelocity;
    vertices[vertexPtr + 4] = axisAngle;
    vertices[vertexPtr + 5] = particleDistance;
    vertices[vertexPtr + 6] = particleAngle;
    vertices[vertexPtr + 7] = particleY;
  }

  vertices[groupPtr] = vertices[groupPtr + STRIDE * 2] = -1;
  vertices[groupPtr + STRIDE] = vertices[groupPtr + STRIDE * 3] = 1;
  vertices[groupPtr + 1] = vertices[groupPtr + STRIDE + 1] = -1;
  vertices[groupPtr + STRIDE * 2 + 1] = vertices[groupPtr + STRIDE * 3 + 1] = 1;

  var indicesPtr = i * NUM_INDICES;
  var vertexPtr = i * NUM_VERTICES;
  indices[indicesPtr] = vertexPtr;
  indices[indicesPtr + 4] = indices[indicesPtr + 1] = vertexPtr + 1;
  indices[indicesPtr + 3] = indices[indicesPtr + 2] = vertexPtr + 2;
  indices[indicesPtr + 5] = vertexPtr + 3;
}

gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

var timeUniformLocation = gl.getUniformLocation(shaderProgram, 'u_time');
var startTime = (window.performance || Date).now();
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
gl.viewport(0, 0, canvas.width, canvas.height);

function frame() {
  gl.uniform1f(
      timeUniformLocation,
      ((window.performance || Date).now() - startTime) / 1000);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawElements(
      gl.TRIANGLES, NUM_INDICES * NUM_PARTICLES, gl.UNSIGNED_SHORT, 0);

  requestAnimationFrame(frame);
}

frame();
})();


================================================
FILE: assets/js/articles/mapkit-js.js
================================================
"use strict";

(function() {
  mapkit.init({
    authorizationCallback: done => {
      done(
        "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IjRUOTJZWlNXR00ifQ.eyJleHAiOjI0MTYzMjE2MDAuMjc2NjE2MSwiaXNzIjoiOUpXVkFEUjNSUSIsIm9yaWdpbiI6Imh0dHBzOlwvXC9uc2hpcHN0ZXIuY29tIiwiaWF0IjoxNTUyMzIxNjAwLjI3NjYxNzF9.DRsKD-6Y9MMVId46PnV9DK-YiobqGu0qCMbK1fYjglWOVnuJkpm4UGDdYLB0T4xJfStPlrSI1Pwbzsjn_i0Qww"
      );
    }
  });

  const center = new mapkit.Coordinate(37.3327, -122.0053),
    span = new mapkit.CoordinateSpan(0.0125, 0.0125),
    region = new mapkit.CoordinateRegion(center, span);

  let map = new mapkit.Map("map", {
    region: region,
    showsCompass: mapkit.FeatureVisibility.Hidden,
    showsZoomControl: false,
    showsMapTypeControl: false
  });

  const annotation = new mapkit.MarkerAnnotation(center, {
    title: "Apple Park Visitor Center",
    subtitle: "10600 North Tantau Avenue, Cupertino, CA 95014",
    glyphText: "",
    color: "#8e8e93",
    displayPriority: 1000
  });

  map.addAnnotation(annotation);
})();


================================================
FILE: assets/js/articles/swift-format.js
================================================
//= require vendor/resize-observer.min.js

"use strict";

function getComputedWidthInEm(element) {
  const computed = window.getComputedStyle(element);

  const regex = /(\d+(\.\d+)?)px$/;
  const fontSize = Number(computed.fontSize.match(regex)[1]);
  const width = Number(computed.width.match(regex)[1]);
  return (width / fontSize) * 2.6;
}

(function() {
  const container = document.querySelector(".variable-width");

  const candidates = Array.from(document.querySelectorAll("[data-width]")).sort(
    ({ dataset: { width: a } }, { dataset: { width: b } }) => b.localeCompare(a)
  );

  const observer = new ResizeObserver(() => {
    const targetWidth = getComputedWidthInEm(container);
    var foundMatch = false;

    candidates.forEach(element => {
      const width = Number(element.dataset.width);
      if (!width || foundMatch) {
        element.setAttribute("hidden", "hidden");
      } else if (width < targetWidth) {
        foundMatch = true;
        element.removeAttribute("hidden");
      } else {
        element.setAttribute("hidden", "hidden");
      }
    });

    if (!foundMatch) {
      candidates[candidates.length - 1].removeAttribute("hidden");
    }
  });

  observer.observe(container);
})();


================================================
FILE: assets/js/articles/wwdc-2020.js
================================================
"use strict";

(function () {
  const details = document.querySelector("details");
  if (details) {
    let listener = details.addEventListener("toggle", (event) => {
      console.log("ADSFADSAFD");
      const video = document.querySelector("video");
      video.loop = true;
      video.controls = false;
      video.play();
      details.removeEventListener("toggle", listener);
    });
  }
})();


================================================
FILE: assets/js/nsmutablehipster.js
================================================
//= require vendor/typed.min.js

"use strict";

(function() {
  document.body.contentEditable = true;
  document.querySelectorAll("a").forEach(element => {
    element.contentEditable = false;
  });

  if (document.querySelector(".tagline")) {
    new Typed(".tagline strong", {
      strings: ["NSHipster", "NSMutableHipster"],
      typeSpeed: 100,
      backSpeed: 100,
      startDelay: 1000,
      onComplete: () => {
        document.querySelector(".typed-cursor").remove();
      }
    });

    document
      .querySelector(".typed-cursor")
      .setAttribute("style", "position: absolute;");
  }
})();


================================================
FILE: assets/videos/TrickXORTreat.srt
================================================
1
00:00:02,500 --> 00:00:07,591
Every kid knows the phrase, [kid sing-songy] "Trick or treat!" But have you

2
00:00:07,691 --> 00:00:11,882
ever stopped to wonder — what kind of _"or"_ is that, exactly?

3
00:00:13,566 --> 00:00:20,150
Let's start with the obvious interpretation: Two circles—two children. Orange means

4
00:00:20,250 --> 00:00:25,063
treats, gray means tricks. This is inclusive OR: If any child

5
00:00:25,163 --> 00:00:29,976
knocks, everyone gets candy. Only an empty porch gets tricks.

6
00:00:30,076 --> 00:00:33,306
[quickly] [chuckles] Is this how Venn diagrams work? Not at all!

7
00:00:33,406 --> 00:00:36,323
But hey, it's Halloween—logic gets to wear a costume, too.

8
00:00:37,323 --> 00:00:40,651
[title] Trick AND Treat Both children must show up together, or

9
00:00:40,751 --> 00:00:44,459
nobody gets treats. [sarcastic] One lonely kid? Sorry, that's a trick.

10
00:00:45,459 --> 00:00:50,925
[title] Trick XOR Treat This house rewards exactly one visitor.

11
00:00:51,025 --> 00:00:55,077
Too few or too many, and everyone gets tricked.

12
00:00:57,377 --> 00:01:00,878
These three behaviors cover most houses on the block.

13
00:01:00,978 --> 00:01:04,140
But De Morgan's laws hint at something more... a

14
00:01:04,240 --> 00:01:08,353
theoretical complement to each. A spooky, inverted reflection.

15
00:01:08,953 --> 00:01:14,882
[spooky] What cursed operations lurk in the penumbra of reason?

16
00:01:14,982 --> 00:01:19,380
Let's face our fears and venture into the dark.

17
00:01:21,069 --> 00:01:24,576
[title] Trick NOR Treat: the Halloween hater. This neighbor

18
00:01:24,676 --> 00:01:27,938
only gives treats when nobody visits. [quick laugh] The

19
00:01:28,038 --> 00:01:29,955
only winning move is not to play.

20
00:01:30,955 --> 00:01:36,134
[title] Trick NAND Treat: NOT-AND—the reverse psychology neighbor. This

21
00:01:36,234 --> 00:01:40,521
house gives treats to everyone... except pairs. Come alone?

22
00:01:40,621 --> 00:01:44,833
Treats. Don't come at all? ...[chuckles] Also Treats. Come

23
00:01:44,933 --> 00:01:49,219
together? [mischievous] That's the only way to get tricked.

24
00:01:50,219 --> 00:01:55,675
[title] Trick XNOR Treat: the conformity enforcer—XOR inverted. This neighbor

25
00:01:55,775 --> 00:02:00,148
rewards matching behavior. Both kids visit, or both stay home?

26
00:02:00,248 --> 00:02:03,755
Treats. Just one kid? [judgmental] That's a trick.

27
00:02:06,555 --> 00:02:11,086
These bottom-row operations are... deeply strange. They're the

28
00:02:11,186 --> 00:02:15,268
kinds of houses you'd skip entirely. But mathematically?

29
00:02:15,368 --> 00:02:18,106
They're just as valid as the classics.

30
00:02:18,705 --> 00:02:20,877
So the next time a child asks [kid sing-songy]

31
00:02:20,977 --> 00:02:23,742
"trick or treat?", you now have the mathematically correct

32
00:02:23,842 --> 00:02:27,940
response: [annoying high-pitched nasal pedantic] "That depends—which logical operator

33
00:02:28,040 --> 00:02:31,249
are you implementing?" [quick laugh] ...though I wouldn't recommend

34
00:02:31,349 --> 00:02:33,521
it if you don't want your house getting egged.



================================================
FILE: collections/en/_authors/croath-liu.md
================================================
---
title: Croath Liu

name: Croath Liu
email: Croath.Liu@gmail.com
url: https://twitter.com/cr0ath
twitter: cr0ath
github: croath
image: croath-liu.jpg
---

[Croath Liu](http://croath.com) ([@cr0ath](https://twitter.com/cr0ath)) is an iOS developer and one of the [lead translators](https://nshipster.cn/translators/croath-liu/) for [nshipster.cn](https://nshipster.cn/). He lives in Beijing.


================================================
FILE: collections/en/_authors/delisa-mason.md
================================================
---
title: Delisa Mason

name: Delisa Mason
email: delisa.mason@gmail.com
url: https://twitter.com/kattrali
twitter: kattrali
github: kattrali
image: delisa-mason.jpg
---

[Delisa Mason](https://delisa.me)
([@kattrali](https://twitter.com/kattrali))
is the creator of the Xcode Package Manager,
[Alcatraz](https://alcatraz.io),
as well as a [CocoaPods](https://cocoapods.org) Core Team member.


================================================
FILE: collections/en/_authors/em-lazer-walker.md
================================================
---
title: Em Lazer-Walker

name: Em Lazer-Walker
email: hi@lazerwalker.com
url: https://twitter.com/lazerwalker
twitter: lazerwalker
github: lazerwalker
image: em-lazer-walker.jpg
---

[Em Lazer-Walker](http://lazerwalker.com) ([@lazerwalker](https://twitter.com/lazerwalker)) 
makes experimental games, interactive art, and software tools.


================================================
FILE: collections/en/_authors/jack-flintermann.md
================================================
---
title: Jack Flintermann

name: Jack Flintermann
email: jack@stripe.com
url: https://twitter.com/jflinter
twitter: jflinter
github: jflinter
image: jack-flintermann.jpg
---

[Jack Flintermann](https://twitter.com/jflinter) is a software developer at [Stripe](https://stripe.com/). He lives in New York City.


================================================
FILE: collections/en/_authors/jemmons.md
================================================
---
title: "@jemmons"
name: jemmons
url: https://figure.ink
twitter: jemmons
github: jemmons
image: jemmons.jpg
---

Josh ([@jemmons](https://twitter.com/jemmons)) has led mobile development at
graphic.ly, Reverb, and now Retail Zipline.
He lives in Chicago and writes about Swift at [figure.ink](https://figure.ink).


================================================
FILE: collections/en/_authors/jordan-morgan.md
================================================
---
title: Jordan Morgan

name: Jordan Morgan
email: info@dreaminginbinary.co
url: https://dreaminginbinary.co
twitter: JordanMorgan10
github: JordanMorgan10
image: jordan-morgan.jpg
---

Jordan Morgan is a software developer from Ozark, who created
[Dreaming In Binary](https://dreaminginbinary.co)
as a creative outlet for his side projects.
Currently, he is an iOS engineer at [Buffer](https://buffer.com).
Jordan is focused on helping the community by
doing talks about iOS and remote work and
writing books and blogs posts,
and considers himself a lifelong student for all forms of software engineering.


================================================
FILE: collections/en/_authors/matt-massicotte.md
================================================
---
title: Matt Massicotte

name: Matt Massicotte
url: https://www.massicotte.org
github: mattmassicotte
image: matt-massicotte.jpg
---

[Matt](https://www.massicotte.org/about) 
is a long-time developer for Apple platforms. 
He's into programming, the outdoors, video games, music, 
and progress towards a safe and fair world for all people.


================================================
FILE: collections/en/_authors/mattt.md
================================================
---
title: Mattt

name: Mattt
email: mattt@nshipster.com
url: https://twitter.com/mattt
twitter: mattt
github: mattt
image: mattt.jpg
---

[Mattt](https://github.com/mattt) ([@mattt](https://twitter.com/mattt))
is a writer and developer in Portland, Oregon.


================================================
FILE: collections/en/_authors/natasha-murashev.md
================================================
---
title: Natasha Murashev

name: Natasha Murashev
email: natasha@natashatherobot.com
url: https://twitter.com/NatashaTheRobot
twitter: NatashaTheRobot
github: NatashaTheRobot
image: natasha-murashev.jpg
---

Natasha (aka [@NatashaTheRobot](https://twitter.com/natashatherobot))
is an iOS developer by day and a robot by night.
She organizes the
[try! Swift Conference](https://www.tryswift.co)
around the world.
She's currently living the digital nomad life as her alter identity:
[@NatashaTheNomad](https://twitter.com/natashathenomad).


================================================
FILE: collections/en/_authors/nate-cook.md
================================================
---
title: Nate Cook

name: Nate Cook
email: nate@nshipster.com
url: https://twitter.com/nnnnnnnn
twitter: nnnnnnnn
github: natecook1000
image: nate-cook.jpg
---

[Nate Cook](http://natecook.com) ([@nnnnnnnn](https://twitter.com/nnnnnnnn)) is an independent web and application developer who [writes frequently about topics in Swift](http://natecook.com/blog/), and the creator of [SwiftDoc.org](http://swiftdoc.org).


================================================
FILE: collections/en/_authors/reda-lemeden.md
================================================
---
title: Reda Lemeden

name: Reda Lemeden
email: hello@redalemeden.com
url: https://redalemeden.com
twitter: kaishin
github: kaishin
image: reda-lemeden.jpg
---

[Reda Lemeden](https://redalemeden.com) is a UI designer and developer making software on both Apple platforms and the Web. He has a penchant for layout engines, grids, and color theory.


================================================
FILE: collections/en/_authors/zoe-smith.md
================================================
---
title: Zoë Smith

name: Zoë Smith
email: zoews@me.com
url: https://zoesmith.io/about
twitter: zoejessica
github: zoejessica
image: zoe-smith.jpg
---

[Zoë Smith](https://zoesmith.io/about)
[(@zoejessica)](https://twitter.com/zoejessica)
is a software developer for Apple platforms
and the creator of
[AccessControlKitty](https://github.com/zoejessica/accesscontrolkitty) and
[F\*\*\*ingIfCaseLetSyntax.com](http://fuckingifcaseletsyntax.com).


================================================
FILE: collections/en/_books/cfhipsterref.md
================================================
---
name: cfhipsterref
title: "CFHipsterRef: Low-Level Programming on iOS & OS X"
short_title: "CFHipsterRef"
sub_title: "Low-Level Programming on iOS & OS X"
author: Mattt
summary: "Perfect for intermediate and expert developers wanting to take a deeper dive into advanced topics, _CFHipsterRef: Low-Level Programming on iOS & OS X_ covers the core technologies powering Cocoa, Objective-C, and the operating system itself, including Grand Central Dispatch, Accelerate, and the Objective-C runtime."
image: "cfhipsterref-cover@2x.png"
availability: http://schema.org/Discontinued
price: 29.00
number_of_pages: 296
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-4-0
date: 2014-06-03
---


================================================
FILE: collections/en/_books/fake-book-objective-c.md
================================================
---
name: "fake-book-objective-c"
title: "The NSHipster Fake Book (Objective-C)"
author: Mattt
summary: "Over 200 code samples, ranging from the beginner and basic to the expert and obscure, across a variety of genres and use cases. Without any needless explanation."
image: "the-nshipster-fake-book-cover@2x.png"
availability: http://schema.org/Discontinued
book_url: https://gum.co/the-nshipster-fake-book
price: 19
number_of_pages: 115
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-1-9
date: 2014-06-03
---


================================================
FILE: collections/en/_books/flight-school-guide-to-swift-codable.md
================================================
---
name: flight-school-guide-to-swift-codable
title: Flight School Guide to Swift Codable
short_title: Flight School
sub_title: Guide to Swift Codable
author: Mattt
summary: >-
  Make better apps with less code more quickly using Swift Codable.
image: flight-school-guide-to-swift-codable.svg
availability: http://schema.org/InStock
book_url: https://flightdotschool.com/books/codable
price: 29.00
number_of_pages: 140
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-1-949080-04-9
date: 2018-04-20
---


================================================
FILE: collections/en/_books/flight-school-guide-to-swift-numbers.md
================================================
---
name: flight-school-guide-to-swift-numbers
title: Flight School Guide to Swift Numbers
short_title: Flight School
sub_title: Guide to Swift Numbers
author: Mattt
summary: >-
  Everything you need to know about working with numbers in Swift
image: flight-school-guide-to-swift-numbers.svg
availability: http://schema.org/InStock
book_url: https://flightdotschool.com/books/numbers
price: 29.00
number_of_pages: 120
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-1-949080-05-6
date: 2018-06-01
---


================================================
FILE: collections/en/_books/flight-school-guide-to-swift-strings.md
================================================
---
name: flight-school-guide-to-swift-strings
title: Flight School Guide to Swift Strings
short_title: Flight School
sub_title: Guide to Swift Strings
author: Mattt
summary: >-
  A comprehensive reference for working with text in Swift and Foundation.
image: flight-school-guide-to-swift-strings.svg
availability: http://schema.org/InStock
book_url: https://flightdotschool.com/books/strings
price: 29.00
number_of_pages: 180
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-1-949080-08-7
date: 2019-02-01
---


================================================
FILE: collections/en/_books/nshipster.md
================================================
---
name: nshipster
title: "NSHipster: Obscure Topics in Objective-C, Swift, & Cocoa"
short_title: "NSHipster"
sub_title: "Obscure Topics in Objective-C, Swift, & Cocoa"
edition: 3<sup>rd</sup> Edition
author: Mattt
summary: >-
  A hand-picked selection of articles and essays from NSHipster.com,
  bound together in a single volume for convenient reference.

image: nshipster-obscure-topics-third-edition.png
availability: http://schema.org/InStock
book_url: https://gumroad.com/l/nshipster-third-edition-digital-only
price: 9.00
number_of_pages: 389
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-1-949080-26-1
date: 2019-12-17
---


================================================
FILE: collections/es/_authors/croath-liu.md
================================================
---
title: Croath Liu

name: Croath Liu
email: Croath.Liu@gmail.com
url: https://twitter.com/cr0ath
twitter: cr0ath
github: croath
image: croath-liu.jpg
---

[Croath Liu](http://croath.com) ([@cr0ath](https://twitter.com/cr0ath)) is an iOS developer and one of the [lead translators](https://nshipster.cn/translators/croath-liu/) for [nshipster.cn](https://nshipster.cn/). He lives in Beijing.


================================================
FILE: collections/es/_authors/delisa-mason.md
================================================
---
title: Delisa Mason

name: Delisa Mason
email: delisa.mason@gmail.com
url: https://twitter.com/kattrali
twitter: kattrali
github: kattrali
image: delisa-mason.jpg
---

[Delisa Mason](https://delisa.me)
([@kattrali](https://twitter.com/kattrali))
is the creator of the Xcode Package Manager,
[Alcatraz](https://alcatraz.io),
as well as a [CocoaPods](https://cocoapods.org) Core Team member.


================================================
FILE: collections/es/_authors/jack-flintermann.md
================================================
---
title: Jack Flintermann

name: Jack Flintermann
email: jack@stripe.com
url: https://twitter.com/jflinter
twitter: jflinter
github: jflinter
image: jack-flintermann.jpg
---

[Jack Flintermann](https://twitter.com/jflinter) is a software developer at [Stripe](https://stripe.com/). He lives in New York City.


================================================
FILE: collections/es/_authors/jordan-morgan.md
================================================
---
title: Jordan Morgan

name: Jordan Morgan
email: info@dreaminginbinary.co
url: https://dreaminginbinary.co
twitter: JordanMorgan10
github: JordanMorgan10
image: jordan-morgan.jpg
---

Jordan Morgan is a software developer from Ozark, who created
[Dreaming In Binary](https://dreaminginbinary.co)
as a creative outlet for his side projects.
Currently, he is an iOS engineer at [Buffer](https://buffer.com).
Jordan is focused on helping the community by
doing talks about iOS and remote work and
writing books and blogs posts,
and considers himself a lifelong student for all forms of software engineering.


================================================
FILE: collections/es/_authors/mattt.md
================================================
---
title: Mattt

name: Mattt
email: mattt@nshipster.com
url: https://twitter.com/mattt
twitter: mattt
github: mattt
google: 106751358503565042647
image: mattt.jpg
---

[Mattt](https://github.com/mattt) ([@mattt](https://twitter.com/mattt))
is a writer and developer in Portland, Oregon.
He is the founder of NSHipster and [Flight School](https://flightdotschool.com),
and the creator of several open source libraries,
including [AFNetworking](https://github.com/afnetworking/afnetworking)
and [Alamofire](https://github.com/alamofire/alamofire).


================================================
FILE: collections/es/_authors/mike-lazer-walker.md
================================================
---
title: Mike Lazer-Walker

name: Mike Lazer-Walker
email: michael@lazerwalker.com
url: https://twitter.com/lazerwalker
twitter: lazerwalker
github: lazerwalker
image: mike-lazer-walker.jpg
---

[Mike Lazer-Walker](http://lazerwalker.com) ([@lazerwalker](https://twitter.com/lazerwalker)) is an independent app and game developer, and the creator of [F\*\*\*ing Block Syntax](http://goshdarnblocksyntax.com). He frequently writes about engineering and design on his [blog](http://blog.lazerwalker.com).


================================================
FILE: collections/es/_authors/natasha-murashev.md
================================================
---
title: Natasha Murashev

name: Natasha Murashev
email: natasha@natashatherobot.com
url: https://twitter.com/NatashaTheRobot
twitter: NatashaTheRobot
github: NatashaTheRobot
image: natasha-murashev.jpg
---

Natasha (aka [@NatashaTheRobot](https://twitter.com/natashatherobot))
is an iOS developer by day and a robot by night.
She organizes the
[try! Swift Conference](https://www.tryswift.co)
around the world.
She's currently living the digital nomad life as her alter identity:
[@NatashaTheNomad](https://twitter.com/natashathenomad).


================================================
FILE: collections/es/_authors/nate-cook.md
================================================
---
title: Nate Cook

name: Nate Cook
email: nate@nshipster.com
url: https://twitter.com/nnnnnnnn
twitter: nnnnnnnn
github: natecook1000
image: nate-cook.jpg
---

[Nate Cook](http://natecook.com) ([@nnnnnnnn](https://twitter.com/nnnnnnnn)) is an independent web and application developer who [writes frequently about topics in Swift](http://natecook.com/blog/), and the creator of [SwiftDoc.org](http://swiftdoc.org).


================================================
FILE: collections/es/_books/01-nshipster-swift.md
================================================
---
name: nshipster-swift
title: "NSHipster: Obscure Topics in Cocoa & Swift"
short_title: "NSHipster, Second Edition"
sub_title: "Obscure Topics in Cocoa & Swift"
author: Mattt & Nate Cook
summary: "Revised and extended to focus on using Swift in iOS and OS X development, NSHipster: Obscure Topics in Cocoa & Swift is an essential updated guide."
image: "nshipster-swift-cover@2x.png"
formats:
  ebook:
    isbn: 978-0-9912182-6-4
availability: in_stock
book_url: https://gum.co/nshipster-swift/
price: 29.00
number_of_pages: 288
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-6-4
date: 2015-04-18
---


================================================
FILE: collections/es/_books/02-cfhipsterref.md
================================================
---
name: cfhipsterref
title: "CFHipsterRef: Low-Level Programming on iOS & OS X"
short_title: "CFHipsterRef"
sub_title: "Low-Level Programming on iOS & OS X"
author: Mattt
summary: "Perfect for intermediate and expert developers wanting to take a deeper dive into advanced topics, _CFHipsterRef: Low-Level Programming on iOS & OS X_ covers the core technologies powering Cocoa, Objective-C, and the operating system itself, including Grand Central Dispatch, Accelerate, and the Objective-C runtime."
image: "cfhipsterref-cover@2x.png"
availability: in_stock
book_url: https://gum.co/cfhipsterref
price: 29.00
number_of_pages: 296
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-4-0
date: 2014-06-03

---


================================================
FILE: collections/es/_books/03-nshipster-fake-book-objective-c.md
================================================
---
name: "nshipster-fake-book-objective-c"
title: "The NSHipster Fake Book (Objective-C)"
author: Mattt
summary: "Over 200 code samples, ranging from the beginner and basic to the expert and obscure, across a variety of genres and use cases. Without any needless explanation."
image: "the-nshipster-fake-book-cover@2x.png"
availability: in_stock
book_url: https://gum.co/the-nshipster-fake-book
price: 19
number_of_pages: 115
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-1-9
date: 2014-06-03

---


================================================
FILE: collections/es/_translators/juan-fernandez-sagasti.md
================================================
---
title: Juan F. Sagasti
name: Juan F. Sagasti
url: https://theam.io
twitter: https://www.twitter.com/jfsagasti
github: https://github.com/jfsagasti
image: juan-fernandez-sagasti.jpg
---

[Juan F. Sagasti](https://www.twitter.com/jfsagasti) es ingeniero de software y cofundador en [Theam](https://theam.io). Colabora como traductor principal en español de NSHipster. Vive con su gata Lily en una bonita isla del Atlántico llamada Gran Canaria.


================================================
FILE: collections/fr/_authors/croath-liu.md
================================================
---
title: Croath Liu

name: Croath Liu
email: Croath.Liu@gmail.com
url: https://twitter.com/cr0ath
twitter: cr0ath
github: croath
image: croath-liu.jpg
---

[Croath Liu](http://croath.com) ([@cr0ath](https://twitter.com/cr0ath)) is an iOS developer and one of the [lead translators](https://nshipster.cn/translators/croath-liu/) for [nshipster.cn](https://nshipster.cn/). He lives in Beijing.


================================================
FILE: collections/fr/_authors/delisa-mason.md
================================================
---
title: Delisa Mason

name: Delisa Mason
email: delisa.mason@gmail.com
url: https://twitter.com/kattrali
twitter: kattrali
github: kattrali
image: delisa-mason.jpg
---

[Delisa Mason](https://delisa.me)
([@kattrali](https://twitter.com/kattrali))
is the creator of the Xcode Package Manager,
[Alcatraz](https://alcatraz.io),
as well as a [CocoaPods](https://cocoapods.org) Core Team member.


================================================
FILE: collections/fr/_authors/jack-flintermann.md
================================================
---
title: Jack Flintermann

name: Jack Flintermann
email: jack@stripe.com
url: https://twitter.com/jflinter
twitter: jflinter
github: jflinter
image: jack-flintermann.jpg
---

[Jack Flintermann](https://twitter.com/jflinter) is a software developer at [Stripe](https://stripe.com/). He lives in New York City.


================================================
FILE: collections/fr/_authors/jordan-morgan.md
================================================
---
title: Jordan Morgan

name: Jordan Morgan
email: info@dreaminginbinary.co
url: https://dreaminginbinary.co
twitter: JordanMorgan10
github: JordanMorgan10
image: jordan-morgan.jpg
---

Jordan Morgan is a software developer from Ozark, who created
[Dreaming In Binary](https://dreaminginbinary.co)
as a creative outlet for his side projects.
Currently, he is an iOS engineer at [Buffer](https://buffer.com).
Jordan is focused on helping the community by
doing talks about iOS and remote work and
writing books and blogs posts,
and considers himself a lifelong student for all forms of software engineering.


================================================
FILE: collections/fr/_authors/mattt.md
================================================
---
title: Mattt

name: Mattt
email: mattt@nshipster.com
url: https://twitter.com/mattt
twitter: mattt
github: mattt
google: 106751358503565042647
image: mattt.jpg
---

[Mattt](https://github.com/mattt) ([@mattt](https://twitter.com/mattt))
is a writer and developer in Portland, Oregon.
He is the founder of NSHipster and [Flight School](https://flightdotschool.com),
and the creator of several open source libraries,
including [AFNetworking](https://github.com/afnetworking/afnetworking)
and [Alamofire](https://github.com/alamofire/alamofire).


================================================
FILE: collections/fr/_authors/mike-lazer-walker.md
================================================
---
title: Mike Lazer-Walker

name: Mike Lazer-Walker
email: michael@lazerwalker.com
url: https://twitter.com/lazerwalker
twitter: lazerwalker
github: lazerwalker
image: mike-lazer-walker.jpg
---

[Mike Lazer-Walker](http://lazerwalker.com) ([@lazerwalker](https://twitter.com/lazerwalker)) is an independent app and game developer, and the creator of [F\*\*\*ing Block Syntax](http://goshdarnblocksyntax.com). He frequently writes about engineering and design on his [blog](http://blog.lazerwalker.com).


================================================
FILE: collections/fr/_authors/natasha-murashev.md
================================================
---
title: Natasha Murashev

name: Natasha Murashev
email: natasha@natashatherobot.com
url: https://twitter.com/NatashaTheRobot
twitter: NatashaTheRobot
github: NatashaTheRobot
image: natasha-murashev.jpg
---

Natasha (aka [@NatashaTheRobot](https://twitter.com/natashatherobot))
is an iOS developer by day and a robot by night.
She organizes the
[try! Swift Conference](https://www.tryswift.co)
around the world.
She's currently living the digital nomad life as her alter identity:
[@NatashaTheNomad](https://twitter.com/natashathenomad).


================================================
FILE: collections/fr/_authors/nate-cook.md
================================================
---
title: Nate Cook

name: Nate Cook
email: nate@nshipster.com
url: https://twitter.com/nnnnnnnn
twitter: nnnnnnnn
github: natecook1000
image: nate-cook.jpg
---

[Nate Cook](http://natecook.com) ([@nnnnnnnn](https://twitter.com/nnnnnnnn)) is an independent web and application developer who [writes frequently about topics in Swift](http://natecook.com/blog/), and the creator of [SwiftDoc.org](http://swiftdoc.org).


================================================
FILE: collections/fr/_books/01-nshipster-swift.md
================================================
---
name: nshipster-swift
title: "NSHipster: Obscure Topics in Cocoa & Swift"
short_title: "NSHipster, Second Edition"
sub_title: "Obscure Topics in Cocoa & Swift"
author: Mattt & Nate Cook
summary: "Revised and extended to focus on using Swift in iOS and OS X development, NSHipster: Obscure Topics in Cocoa & Swift is an essential updated guide."
image: "nshipster-swift-cover@2x.png"
formats:
  ebook:
    isbn: 978-0-9912182-6-4
availability: in_stock
book_url: https://gum.co/nshipster-swift/
price: 29.00
number_of_pages: 288
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-6-4
date: 2015-04-18
---


================================================
FILE: collections/fr/_books/02-cfhipsterref.md
================================================
---
name: cfhipsterref
title: "CFHipsterRef: Low-Level Programming on iOS & OS X"
short_title: "CFHipsterRef"
sub_title: "Low-Level Programming on iOS & OS X"
author: Mattt
summary: "Perfect for intermediate and expert developers wanting to take a deeper dive into advanced topics, _CFHipsterRef: Low-Level Programming on iOS & OS X_ covers the core technologies powering Cocoa, Objective-C, and the operating system itself, including Grand Central Dispatch, Accelerate, and the Objective-C runtime."
image: "cfhipsterref-cover@2x.png"
availability: in_stock
book_url: https://gum.co/cfhipsterref
price: 29.00
number_of_pages: 296
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-4-0
date: 2014-06-03

---


================================================
FILE: collections/fr/_books/03-nshipster-fake-book-objective-c.md
================================================
---
name: "nshipster-fake-book-objective-c"
title: "The NSHipster Fake Book (Objective-C)"
author: Mattt
summary: "Over 200 code samples, ranging from the beginner and basic to the expert and obscure, across a variety of genres and use cases. Without any needless explanation."
image: "the-nshipster-fake-book-cover@2x.png"
availability: in_stock
book_url: https://gum.co/the-nshipster-fake-book
price: 19
number_of_pages: 115
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-1-9
date: 2014-06-03

---


================================================
FILE: collections/fr/_translators/vincent-pradeilles.md
================================================
---
title: Vincent 
name: Vincent Pradeilles
twitter: https://www.twitter.com/v_pradeilles
github: https://github.com/vincent-pradeilles
image: vincent-pradeilles.jpg
---

[Vincent Pradeilles](https://www.twitter.com/v_pradeilles) est dévelopeur iOS chez [Worldline](https://worldline.com) à Lyon. Il collabore à NSHipster en tant que traducteur français.


================================================
FILE: collections/ko/_authors/croath-liu.md
================================================
---
title: Croath Liu

name: Croath Liu
email: Croath.Liu@gmail.com
url: https://twitter.com/cr0ath
twitter: cr0ath
github: croath
image: croath-liu.jpg
---

[Croath Liu](http://croath.com) ([@cr0ath](https://twitter.com/cr0ath)) is an iOS developer and one of the [lead translators](https://nshipster.cn/translators/croath-liu/) for [nshipster.cn](https://nshipster.cn/). He lives in Beijing.


================================================
FILE: collections/ko/_authors/delisa-mason.md
================================================
---
title: Delisa Mason

name: Delisa Mason
email: delisa.mason@gmail.com
url: https://twitter.com/kattrali
twitter: kattrali
github: kattrali
image: delisa-mason.jpg
---

[Delisa Mason](http://delisa.me) ([@kattrali](https://twitter.com/kattrali)) is the creator of the Xcode Package Manager, [Alcatraz](http://alcatraz.io), as well as a [CocoaPods](http://cocoapods.org) Core Team member.


================================================
FILE: collections/ko/_authors/jack-flintermann.md
================================================
---
title: Jack Flintermann

name: Jack Flintermann
email: jack@stripe.com
url: https://twitter.com/jflinter
twitter: jflinter
github: jflinter
image: jack-flintermann.jpg
---

[Jack Flintermann](https://twitter.com/jflinter) is a software developer at [Stripe](https://stripe.com/). He lives in New York City.


================================================
FILE: collections/ko/_authors/jemmons.md
================================================
---
title: "@jemmons"
name: jemmons
url: https://figure.ink
twitter: jemmons
github: jemmons
image: jemmons.jpg
---

Josh ([@jemmons](https://twitter.com/jemmons)) has led mobile development at
graphic.ly, Reverb, and now Retail Zipline.
He lives in Chicago and writes about Swift at [figure.ink](https://figure.ink).


================================================
FILE: collections/ko/_authors/mattt.md
================================================
---
title: Mattt

name: Mattt
email: mattt@nshipster.com
url: https://twitter.com/mattt
twitter: mattt
github: mattt
google: 106751358503565042647
image: mattt.jpg
---

[Mattt](https://github.com/mattt) ([@mattt](https://twitter.com/mattt))
is a writer and developer in Portland, Oregon.
He is the founder of NSHipster and [Flight School](https://flightdotschool.com),
and the creator of several open source libraries,
including [AFNetworking](https://github.com/afnetworking/afnetworking)
and [Alamofire](https://github.com/alamofire/alamofire).


================================================
FILE: collections/ko/_authors/mike-lazer-walker.md
================================================
---
title: Mike Lazer-Walker

name: Mike Lazer-Walker
email: michael@lazerwalker.com
url: https://twitter.com/lazerwalker
twitter: lazerwalker
github: lazerwalker
image: mike-lazer-walker.jpg
---

[Mike Lazer-Walker](http://lazerwalker.com) ([@lazerwalker](https://twitter.com/lazerwalker)) is an independent app and game developer, and the creator of [F\*\*\*ing Block Syntax](http://goshdarnblocksyntax.com). He frequently writes about engineering and design on his [blog](http://blog.lazerwalker.com).


================================================
FILE: collections/ko/_authors/natasha-murashev.md
================================================
---
title: Natasha Murashev

name: Natasha Murashev
email: natasha@natashatherobot.com
url: https://twitter.com/NatashaTheRobot
twitter: NatashaTheRobot
github: NatashaTheRobot
image: natasha-murashev.jpg
---

Natasha (aka [@NatashaTheRobot](https://twitter.com/natashatherobot))
is an iOS developer by day and a robot by night.
She organizes the
[try! Swift Conference](https://www.tryswift.co)
around the world.
She's currently living the digital nomad life as her alter identity:
[@NatashaTheNomad](https://twitter.com/natashathenomad).


================================================
FILE: collections/ko/_authors/nate-cook.md
================================================
---
title: Nate Cook

name: Nate Cook
email: nate@nshipster.com
url: https://twitter.com/nnnnnnnn
twitter: nnnnnnnn
github: natecook1000
image: nate-cook.jpg
---

[Nate Cook](http://natecook.com) ([@nnnnnnnn](https://twitter.com/nnnnnnnn)) is an independent web and application developer who [writes frequently about topics in Swift](http://natecook.com/blog/), and the creator of [SwiftDoc.org](http://swiftdoc.org).


================================================
FILE: collections/ko/_books/01-nshipster-swift.md
================================================
---
name: nshipster-swift
title: "NSHipster: Obscure Topics in Cocoa & Swift"
short_title: "NSHipster, Second Edition"
sub_title: "Obscure Topics in Cocoa & Swift"
author: Mattt & Nate Cook
summary: "Revised and extended to focus on using Swift in iOS and OS X development, NSHipster: Obscure Topics in Cocoa & Swift is an essential updated guide."
image: "nshipster-swift-cover@2x.png"
formats:
  ebook:
    isbn: 978-0-9912182-6-4
availability: in_stock
book_url: https://gum.co/nshipster-swift/
price: 29.00
number_of_pages: 288
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-6-4
date: 2015-04-18
---


================================================
FILE: collections/ko/_books/02-cfhipsterref.md
================================================
---
name: cfhipsterref
title: "CFHipsterRef: Low-Level Programming on iOS & OS X"
short_title: "CFHipsterRef"
sub_title: "Low-Level Programming on iOS & OS X"
author: Mattt
summary: "Perfect for intermediate and expert developers wanting to take a deeper dive into advanced topics, _CFHipsterRef: Low-Level Programming on iOS & OS X_ covers the core technologies powering Cocoa, Objective-C, and the operating system itself, including Grand Central Dispatch, Accelerate, and the Objective-C runtime."
image: "cfhipsterref-cover@2x.png"
availability: in_stock
book_url: https://gum.co/cfhipsterref
price: 29.00
number_of_pages: 296
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-4-0
date: 2014-06-03

---


================================================
FILE: collections/ko/_books/03-nshipster-fake-book-objective-c.md
================================================
---
name: "nshipster-fake-book-objective-c"
title: "The NSHipster Fake Book (Objective-C)"
author: Mattt
summary: "Over 200 code samples, ranging from the beginner and basic to the expert and obscure, across a variety of genres and use cases. Without any needless explanation."
image: "the-nshipster-fake-book-cover@2x.png"
availability: in_stock
book_url: https://gum.co/the-nshipster-fake-book
price: 19
number_of_pages: 115
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-1-9
date: 2014-06-03

---


================================================
FILE: collections/ko/_translators/pilgwon.md
================================================
---
title: 김필권

name: 김필권
email: rlavlfrnjs12@gmail.com
url: https://blog.pilgwon.app
github: pilgwon
twitter: pilgwon
image: pilgwon.jpg
---

[Pilgwon](https://nshipster.co.kr/translators/pilgwon)([@pilgwon](https://twitter.com/pilgwon)) is an iOS developer in Seoul, South Korea. And the creator of [GROOV](https://itunes.apple.com/us/app/groov/id1138262409?mt=8). He translates about iOS on his [blog](https://blog.pilgwon.app) more than once a week. He loves making Insanely Great services. He is lead translator for [nshipster.co.kr](https://nshipster.co.kr).


================================================
FILE: collections/ru/_authors/croath-liu.md
================================================
---
title: Croath Liu

name: Croath Liu
email: Croath.Liu@gmail.com
url: https://twitter.com/cr0ath
twitter: cr0ath
github: croath
image: croath-liu.jpg
---

[Croath Liu](http://croath.com) ([@cr0ath](https://twitter.com/cr0ath)) is an iOS developer and one of the [lead translators](https://nshipster.cn/translators/croath-liu/) for [nshipster.cn](https://nshipster.cn/). He lives in Beijing.


================================================
FILE: collections/ru/_authors/delisa-mason.md
================================================
---
title: Delisa Mason

name: Delisa Mason
email: delisa.mason@gmail.com
url: https://twitter.com/kattrali
twitter: kattrali
github: kattrali
image: delisa-mason.jpg
---

[Delisa Mason](https://delisa.me)
([@kattrali](https://twitter.com/kattrali))
is the creator of the Xcode Package Manager,
[Alcatraz](https://alcatraz.io),
as well as a [CocoaPods](https://cocoapods.org) Core Team member.


================================================
FILE: collections/ru/_authors/jack-flintermann.md
================================================
---
title: Jack Flintermann

name: Jack Flintermann
email: jack@stripe.com
url: https://twitter.com/jflinter
twitter: jflinter
github: jflinter
image: jack-flintermann.jpg
---

[Jack Flintermann](https://twitter.com/jflinter) is a software developer at [Stripe](https://stripe.com/). He lives in New York City.


================================================
FILE: collections/ru/_authors/jordan-morgan.md
================================================
---
title: Jordan Morgan

name: Jordan Morgan
email: info@dreaminginbinary.co
url: https://dreaminginbinary.co
twitter: JordanMorgan10
github: JordanMorgan10
image: jordan-morgan.jpg
---

Jordan Morgan is a software developer from Ozark, who created
[Dreaming In Binary](https://dreaminginbinary.co)
as a creative outlet for his side projects.
Currently, he is an iOS engineer at [Buffer](https://buffer.com).
Jordan is focused on helping the community by
doing talks about iOS and remote work and
writing books and blogs posts,
and considers himself a lifelong student for all forms of software engineering.


================================================
FILE: collections/ru/_authors/mattt.md
================================================
---
title: Mattt

name: Mattt
email: mattt@nshipster.com
url: https://twitter.com/mattt
twitter: mattt
github: mattt
google: 106751358503565042647
image: mattt.jpg
---

[Mattt](https://github.com/mattt) ([@mattt](https://twitter.com/mattt))
is a writer and developer in Portland, Oregon.
He is the founder of NSHipster and [Flight School](https://flightdotschool.com),
and the creator of several open source libraries,
including [AFNetworking](https://github.com/afnetworking/afnetworking)
and [Alamofire](https://github.com/alamofire/alamofire).


================================================
FILE: collections/ru/_authors/mike-lazer-walker.md
================================================
---
title: Mike Lazer-Walker

name: Mike Lazer-Walker
email: michael@lazerwalker.com
url: https://twitter.com/lazerwalker
twitter: lazerwalker
github: lazerwalker
image: mike-lazer-walker.jpg
---

[Mike Lazer-Walker](http://lazerwalker.com) ([@lazerwalker](https://twitter.com/lazerwalker)) is an independent app and game developer, and the creator of [F\*\*\*ing Block Syntax](http://goshdarnblocksyntax.com). He frequently writes about engineering and design on his [blog](http://blog.lazerwalker.com).


================================================
FILE: collections/ru/_authors/natasha-murashev.md
================================================
---
title: Natasha Murashev

name: Natasha Murashev
email: natasha@natashatherobot.com
url: https://twitter.com/NatashaTheRobot
twitter: NatashaTheRobot
github: NatashaTheRobot
image: natasha-murashev.jpg
---

Natasha (aka [@NatashaTheRobot](https://twitter.com/natashatherobot))
is an iOS developer by day and a robot by night.
She organizes the
[try! Swift Conference](https://www.tryswift.co)
around the world.
She's currently living the digital nomad life as her alter identity:
[@NatashaTheNomad](https://twitter.com/natashathenomad).


================================================
FILE: collections/ru/_authors/nate-cook.md
================================================
---
title: Nate Cook

name: Nate Cook
email: nate@nshipster.com
url: https://twitter.com/nnnnnnnn
twitter: nnnnnnnn
github: natecook1000
image: nate-cook.jpg
---

[Nate Cook](http://natecook.com) ([@nnnnnnnn](https://twitter.com/nnnnnnnn)) is an independent web and application developer who [writes frequently about topics in Swift](http://natecook.com/blog/), and the creator of [SwiftDoc.org](http://swiftdoc.org).


================================================
FILE: collections/ru/_books/01-nshipster-swift.md
================================================
---
name: nshipster-swift
title: "NSHipster: Obscure Topics in Cocoa & Swift"
short_title: "NSHipster, Second Edition"
sub_title: "Obscure Topics in Cocoa & Swift"
author: Mattt & Nate Cook
summary: "Revised and extended to focus on using Swift in iOS and OS X development, NSHipster: Obscure Topics in Cocoa & Swift is an essential updated guide."
image: "nshipster-swift-cover@2x.png"
formats:
  ebook:
    isbn: 978-0-9912182-6-4
availability: in_stock
book_url: https://gum.co/nshipster-swift/
price: 29.00
number_of_pages: 288
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-6-4
date: 2015-04-18
---


================================================
FILE: collections/ru/_books/02-cfhipsterref.md
================================================
---
name: cfhipsterref
title: "CFHipsterRef: Low-Level Programming on iOS & OS X"
short_title: "CFHipsterRef"
sub_title: "Low-Level Programming on iOS & OS X"
author: Mattt
summary: "Perfect for intermediate and expert developers wanting to take a deeper dive into advanced topics, _CFHipsterRef: Low-Level Programming on iOS & OS X_ covers the core technologies powering Cocoa, Objective-C, and the operating system itself, including Grand Central Dispatch, Accelerate, and the Objective-C runtime."
image: "cfhipsterref-cover@2x.png"
availability: in_stock
book_url: https://gum.co/cfhipsterref
price: 29.00
number_of_pages: 296
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-4-0
date: 2014-06-03

---


================================================
FILE: collections/ru/_books/03-nshipster-fake-book-objective-c.md
================================================
---
name: "nshipster-fake-book-objective-c"
title: "The NSHipster Fake Book (Objective-C)"
author: Mattt
summary: "Over 200 code samples, ranging from the beginner and basic to the expert and obscure, across a variety of genres and use cases. Without any needless explanation."
image: "the-nshipster-fake-book-cover@2x.png"
availability: in_stock
book_url: https://gum.co/the-nshipster-fake-book
price: 19
number_of_pages: 115
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-1-9
date: 2014-06-03

---


================================================
FILE: collections/zh-Hans/_authors/croath-liu.md
================================================
---
title: Croath Liu

name: "Croath Liu"
email: Croath.Liu@gmail.com
url: https://croath.com
twitter: croath
github: croath
google: 108566152424457191834
image: "croath-liu.jpg"
---

云游四海的工程师


================================================
FILE: collections/zh-Hans/_authors/delisa-mason.md
================================================
---
title: Delisa Mason

name: Delisa Mason
email: delisa.mason@gmail.com
url: https://twitter.com/kattrali
twitter: kattrali
github: kattrali
image: delisa-mason.jpg
---

[Delisa Mason](https://delisa.me)
([@kattrali](https://twitter.com/kattrali))
is the creator of the Xcode Package Manager,
[Alcatraz](https://alcatraz.io),
as well as a [CocoaPods](https://cocoapods.org) Core Team member.


================================================
FILE: collections/zh-Hans/_authors/jack-flintermann.md
================================================
---
title: Jack Flintermann

name: Jack Flintermann
email: jack@stripe.com
url: https://twitter.com/jflinter
twitter: jflinter
github: jflinter
image: jack-flintermann.jpg
---

[Jack Flintermann](https://twitter.com/jflinter) is a software developer at [Stripe](https://stripe.com/). He lives in New York City.


================================================
FILE: collections/zh-Hans/_authors/mattt.md
================================================
---
title: Mattt

name: Mattt
email: mattt@nshipster.com
url: https://twitter.com/mattt
twitter: mattt
github: mattt
google: 106751358503565042647
image: mattt.jpg
---

[Mattt](https://github.com/mattt) ([@mattt](https://twitter.com/mattt))
is a writer and developer in Portland, Oregon.
He is the founder of NSHipster and [Flight School](https://flightdotschool.com),
and the creator of several open source libraries,
including [AFNetworking](https://github.com/afnetworking/afnetworking)
and [Alamofire](https://github.com/alamofire/alamofire).


================================================
FILE: collections/zh-Hans/_authors/mike-lazer-walker.md
================================================
---
title: Mike Lazer-Walker

name: Mike Lazer-Walker
email: michael@lazerwalker.com
url: https://twitter.com/lazerwalker
twitter: lazerwalker
github: lazerwalker
image: mike-lazer-walker.jpg
---

[Mike Lazer-Walker](http://lazerwalker.com) ([@lazerwalker](https://twitter.com/lazerwalker)) is an independent app and game developer, and the creator of [F\*\*\*ing Block Syntax](http://goshdarnblocksyntax.com). He frequently writes about engineering and design on his [blog](http://blog.lazerwalker.com).


================================================
FILE: collections/zh-Hans/_authors/natasha-murashev.md
================================================
---
title: Natasha Murashev

name: Natasha Murashev
email: natasha@natashatherobot.com
url: https://twitter.com/NatashaTheRobot
twitter: NatashaTheRobot
github: NatashaTheRobot
image: natasha-murashev.jpg
---

Natasha (aka [@NatashaTheRobot](https://twitter.com/natashatherobot))
is an iOS developer by day and a robot by night.
She organizes the
[try! Swift Conference](https://www.tryswift.co)
around the world.
She's currently living the digital nomad life as her alter identity:
[@NatashaTheNomad](https://twitter.com/natashathenomad).


================================================
FILE: collections/zh-Hans/_authors/nate-cook.md
================================================
---
title: Nate Cook

name: Nate Cook
email: nate@nshipster.com
url: https://twitter.com/nnnnnnnn
twitter: nnnnnnnn
github: natecook1000
image: nate-cook.jpg
---

[Nate Cook](http://natecook.com) ([@nnnnnnnn](https://twitter.com/nnnnnnnn)) is an independent web and application developer who [writes frequently about topics in Swift](http://natecook.com/blog/), and the creator of [SwiftDoc.org](http://swiftdoc.org).


================================================
FILE: collections/zh-Hans/_books/01-nshipster-swift.md
================================================
---
name: nshipster-swift
title: "NSHipster: Obscure Topics in Cocoa & Swift"
short_title: "NSHipster, Second Edition"
sub_title: "Obscure Topics in Cocoa & Swift"
author: Mattt & Nate Cook
summary: "Revised and extended to focus on using Swift in iOS and OS X development, NSHipster: Obscure Topics in Cocoa & Swift is an essential updated guide."
image: "nshipster-swift-cover@2x.png"
formats:
  ebook:
    isbn: 978-0-9912182-6-4
availability: in_stock
book_url: https://gum.co/nshipster-swift/
price: 29
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-6-4
---


================================================
FILE: collections/zh-Hans/_books/02-cfhipsterref.md
================================================
---
name: cfhipsterref
title: "CFHipsterRef: Low-Level Programming on iOS & OS X"
short_title: "CFHipsterRef"
sub_title: "Low-Level Programming on iOS & OS X"
author: Mattt
summary: "Perfect for intermediate and expert developers wanting to take a deeper dive into advanced topics, _CFHipsterRef: Low-Level Programming on iOS & OS X_ covers the core technologies powering Cocoa, Objective-C, and the operating system itself, including Grand Central Dispatch, Accelerate, and the Objective-C runtime."
image: "cfhipsterref-cover@2x.png"
availability: in_stock
book_url: https://gum.co/cfhipsterref
price: 29.99
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-4-0
---


================================================
FILE: collections/zh-Hans/_books/03-nshipster-fake-book-objective-c.md
================================================
---
name: "nshipster-fake-book-objective-c"
title: "The NSHipster Fake Book (Objective-C)"
author: Mattt
summary: "Over 200 code samples, ranging from the beginner and basic to the expert and obscure, across a variety of genres and use cases. Without any needless explanation."
image: "the-nshipster-fake-book-cover@2x.png"
formats:
  pdf:
    price: 19.99
    isbn: ...
availability: in_stock
book_url: https://gum.co/the-nshipster-fake-book
price: 19.99
category: Media > Books > Non-Fiction > Technology Books
isbn: 978-0-9912182-1-9
---


================================================
FILE: collections/zh-Hans/_translators/Candyan.md
================================================
---
title: Candyan

name: "Candyan"
email: liuyanhp@gmail.com
url: https://candyan.com
github: candyan
---

[Candyan](https://candyan.com) 专业 iOS,业余 Android,偶尔捣鼓下Server的工程师。


================================================
FILE: collections/zh-Hans/_translators/andrew-yang.md
================================================
---
title: Andrew Yang

name: "Andrew Yang"
email: younthu@gmail.com
url: http://blog.ilibrary.me
github: younthu
---

iOS 开发者,11 年之前做过很长时间 windows 后台程序的开发。很喜欢移动应用开发,发布过一些小应用,有一个[个人网站](http://blog.ilibrary.me),你可以尝试和网站上的机器人聊天,希望你不要失望。


================================================
FILE: collections/zh-Hans/_translators/april-peng.md
================================================
---
title: April Peng

name: "April Peng"
email: april.pyl@gmail.com
url: http://aprilme.com
github: aprilnov
---

做 iOS / Mac / Web 开发的大白羊妹子~


================================================
FILE: collections/zh-Hans/_translators/chester-liu.md
================================================
---
title: Chester Liu

name: "Chester Liu"
email: skyline75489@outlook.com
gravatar: 64edfde4a55cef57f9d47d42acbcaf48
github: skyline75489
twitter: ChesterLiu2
---

iOS 工程师,一直想成为更好的自己。我的 [Github](https://github.com/skyline75489) 和 [StackOverflow](https://stackoverflow.com/users/3562486/skyline75489)。


================================================
FILE: collections/zh-Hans/_translators/croath-liu.md
================================================
---
title: Croath Liu

name: "Croath Liu"
email: Croath.Liu@gmail.com
url: https://croath.com
twitter: croath
github: croath
google: 108566152424457191834
gravatar: 720e8ba099f10eca25dd87ef5afe4aa7
---

云游四海的工程师


================================================
FILE: collections/zh-Hans/_translators/david-liu.md
================================================
---
title: David Liu

name: "David Liu"
email: xingruo.liu@gmail.com
twitter: davydliu
github: davydliu
gravatar: 7085efed913ec6d5186e7c57352acfbd
---

混迹于美帝的工程师,户外运动爱好者。


================================================
FILE: collections/zh-Hans/_translators/henry-lee.md
================================================
---
title: Henry Lee

name: "Henry Lee"
email: leelejia@gmail.com
url: http://lejia.li
github: lilejia
gravatar: 97b4cc7deef9a17bef19a13dc2a033a4
---

爱好广泛的 iOS 工程师。


================================================
FILE: collections/zh-Hans/_translators/ricky-tan.md
================================================
---
title: Ricky Tan

name: "Ricky Tan"
email: ricky.tan.xin@gmail.com
url: https://xcoder.tips
gravatar: 71f0bbfbb3b0bc7e6e9aa2187814196a
github: rickytan
google: +rickytanx
---

Ricky Tan 是一位来自杭州的 iOS 开发者,毕业于浙江大学,早期参与开发浙大校园应用 [iZJU](https://itunes.apple.com/cn/app/izju/id573810521?mt=8) iOS 版。另外开源了一个反响不错的 Xcode 插件 [RTImageAssets](https://github.com/rickytan/RTImageAssets),及一个导航器 [RTRootNavigationController](https://github.com/rickytan/RTRootNavigationController) 。更多其他内容请[点我](https://github.com/rickytan?tab=repositories)。


================================================
FILE: collections/zh-Hans/_translators/steven-wang.md
================================================
---
title: Steven Wang

name: "Steven Wang"
email: mobilefellow@outlook.com
github: mobilefellow
gravatar: d05f1e723ced114014820ed9d9aa42ba
---

iOS 开发者,热爱移动开发,喜欢 Swift 语言。曾经四处漂流,现定居杭州。


================================================
FILE: collections/zh-Hans/_translators/tiny-tian.md
================================================
---
title: change2hao
name: "Tiny Tian"
email: lwtiandev@gmail.com
url: http://devtian.me
gravatar: 5b77b0456447e9040bc35a001b9f3611
twitter: change2hao
github: change2hao
---

iOS开发工程师,爱技术,爱生活。

================================================
FILE: contribute.json
================================================
{
  "name": "NSHipster.com",
  "description": "A journal of the overlooked bits in Objective-C, Swift, and Cocoa. Updated weekly.",
  "repository": {
    "url": "https://github.com/nshipster/nshipster.com",
    "license": "MIT"
  },
  "keywords": ["Ruby", "Jekyll"]
}


================================================
FILE: feed.xml
================================================
---
layout: null
---

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="{{ site.lang }}">
    <link href="{{ page.url | absolute_url }}" rel="self" type="application/atom+xml" />
    <link href="{{ '/' | absolute_url }}" rel="alternate" type="text/html" hreflang="{{ site.lang }}"/>
    <updated>{{ site.time | date_to_xmlschema }}</updated>
    <id>{{ page.url | absolute_url | xml_escape }}</id>

    <title>{{ site.title | strip_html | xml_escape | strip }}</title>
    <subtitle>{{ site.description | markdownify | strip_html }}</subtitle>

    {% if site.author %}
    <author>
        <name>{{ site.author.name | default: site.author | xml_escape }}</name>
        {% if site.author.email %}
        <email>{{ site.author.email | xml_escape }}</email>
        {% endif %}
        {% if site.author.url %}
        <uri>{{ site.author.url | absolute_url | xml_escape }}</uri>
        {% endif %}
    </author>
    {% endif %}

    {% assign sorted_posts = site.posts | sort: 'updated_on' | reverse %}
    {% for post in sorted_posts limit: 10 %}
    <entry>
        <title type="html">{{ post.title | smartify | strip_html | normalize_whitespace | xml_escape }}</title>
        <link href="{{ post.url | absolute_url }}" rel="alternate" type="text/html" title="{{ post.title | xml_escape }}" />
        <published>{{ post.date | date_to_xmlschema }}</published>
        <updated>{{ post.last_revised_on | default: post.date | date_to_xmlschema }}</updated>
        <id>{{ post.id | absolute_url | xml_escape }}</id>
        <content type="html" xml:base="{{ post.url | absolute_url | xml_escape }}">
            {{ post.content | strip | xml_escape }}
        </content>

        {% assign author = site.authors | where:"name", post.author | first | default: site.author %}
        <author>
            <name>{{ author.name | default: "" | xml_escape }}</name>
            {% if author.email %}
            <email>{{ author.email | xml_escape }}</email>
            {% endif %}
            {% if author.url %}
            <uri>{{ author.url | absolute_url | xml_escape }}</uri>
            {% endif %}
        </author>

        {% if post.category and post.category != empty %}
        <category term="{{ post.category | xml_escape }}" />
        {% endif %}

        {% for tag in post.tags %}
        <category term="{{ tag | xml_escape }}" />
        {% endfor %}

        {% if post.excerpt and post.excerpt != empty %}
        <summary type="html">{{ post.excerpt | markdownify | normalize_whitespace | xml_escape }}</summary>
        {% endif %}
    </entry>
    {% endfor %}
</feed>


================================================
FILE: flight-school.md
================================================
---
layout: post
date: 2019-02-01
title: Flight School
author: Mattt
category: ""
excerpt: >-
  A new book series for advanced Swift developers
  from the creators of NSHipster,
  with comprehensive guides for Codable, Numbers, and Strings.
  Now updated for Swift 5 and available in print.
status:
  swift: n/a
---

[Flight School](https://flightdotschool.com)
is a book series for advanced Swift developers
that explores essential topics in iOS and macOS development
through concise, focused guides.

Today, I'm excited to announce updates to our guides to
[Swift Codable](https://flightdotschool.com/books/codable) and
[Numbers](https://flightdotschool.com/books/numbers),
as well as a brand new
[Guide to Swift Strings](https://flightdotschool.com/books/strings).
Everything is up-to-date with the latest from Swift 5 and Xcode 10.2,
and now --- _for the first time_ --- available in print!

If you like NSHipster and are looking for something a bit longer,
I think you're gonna love what Flight School has to offer.

---

{% if site.lang == "en-US" %}
{::nomarkdown type="html"}

<section id="publications">
  <div class="books">
  {% include book.html book="flight-school-guide-to-swift-codable" %}
  {% include book.html book="flight-school-guide-to-swift-numbers" %}
  {% include book.html book="flight-school-guide-to-swift-strings" %}
  </div>
</section>

{:/}
{% endif %}

## Why I'm Writing Flight School

As software developers,
our jobs require us to learn a variety of different
platforms, programming languages, frameworks, and tools.
In spite of their differences,
most technologies share a common foundation in concepts
like floating-point arithmetic, data interchange, and string encoding ---
the kinds of things you might find in a typical
Computer Science curriculum.

But for those of us who came into programming from unconventional backgrounds,
(for instance, I studied philosophy and linguistics as an undergraduate),
the weight of all of this can feel overwhelming at times.
And even if you did study CS in college,
it may be hard to relate the theory of your coursework
(what you can remember of it, anyway)
to the realities of your day job.

I'm writing [Flight School](https://flightdotschool.com)
to explore important concepts in software development
in a way that's informative, accessible, and entertaining.

Each book is short enough to be read over a weekend
(or perhaps coffee breaks over the course of a work week).
Each chapter is filled with practical information that's backed by examples
that you can experiment with for yourself in Xcode Playgrounds.

The forthcoming [_Guide to Strings_](https://flightdotschool.com/books/strings)
is our newest and most ambitious release yet,
covering everything from the Unicode® standard and Swift 5 `String` internals
to binary-to-text encoding, parser generators, and natural language processing.
If you've ever felt like you wanted to get a handle on text _once and for all_,
this is the book for you.

It'll be available to download next Friday, February 8th,
and you can pre-order a copy for yourself and download a sample chapter now.

---

The response from Flight School readers since launching earlier last year
has been overwhelming,
and I couldn't be more excited to share this with everyone.

I look forward to continuing to share new and interesting things
on NSHipster and Flight School,
and thank you for your continued support. 🧡


================================================
FILE: index.html
================================================
---
title: NSHipster
permalink: /
---

{% assign sorted_posts = site.posts | sort: 'updated_on' | reverse %}
{% assign latest_post = sorted_posts.first %}
<section id="latest">
  <article>
    <header>
      <h1 class="title">
        <a href="{{ latest_post.url }}">{{ latest_post.title | strip_html | escape | camel_break }}</a>
      </h1>
    </header>

    {{ latest_post.excerpt | markdownify }}

    <a class="readmore" href="{{ latest_post.url }}">{% t continue_reading %}</a>
  </article>
</section>

{% if sorted_posts.size > 3 %}
<section id="recent">
  <h1>{% t recent_articles %}</h1>

  <ul>
    {% for post in sorted_posts offset:1 limit: 6 %}
      <li>
        <a class="title" href="{{ post.url }}">{{ post.title | strip_html | escape | camel_break }}</a>

        {{ post.excerpt | markdownify }}
      </li>
    {% endfor %}
  </ul>
</section>
{% endif %}

<section id="archive" class="archive" role="navigation">
  {% for group in site.groups %}
    {% for category in site.categories %}
      {% assign c
Download .txt
gitextract_5m6loz3c/

├── .gitignore
├── .gitmodules
├── .ruby-version
├── .tool-versions
├── .well-known/
│   ├── brave-payments-verification.txt
│   ├── browserconfig.xml
│   ├── humans.txt
│   ├── robots.txt
│   └── site.webmanifest
├── 404.md
├── Gemfile
├── LICENSE.md
├── README.md
├── _bibliography/
│   └── references.bib
├── _config/
│   ├── default.yml
│   ├── nshipster.cn.yml
│   ├── nshipster.co.kr.yml
│   ├── nshipster.com.ru.yml
│   ├── nshipster.com.yml
│   ├── nshipster.es.yml
│   ├── nshipster.fr.yml
│   └── nsmutablehipster.com.yml
├── _functions/
│   └── search/
│       ├── package.json
│       └── search.js
├── _i18n/
│   ├── en-US.yml
│   ├── es-ES.yml
│   ├── fr-FR.yml
│   ├── ko-KR.yml
│   ├── ru-RU.yml
│   └── zh-Hans.yml
├── _includes/
│   ├── book.html
│   ├── contributor.html
│   ├── json-ld/
│   │   ├── article.html
│   │   ├── book.html
│   │   ├── breadcrumblist.html
│   │   ├── organization.html
│   │   └── website.html
│   └── promo.html
├── _layouts/
│   ├── author.html
│   ├── default.html
│   ├── error.html
│   ├── page.html
│   ├── post.html
│   └── translator.html
├── _plugins/
│   ├── admonition-block.rb
│   ├── camel-case-thin-space-break-filter.rb
│   ├── extended-date-filter.rb
│   ├── jwt-lexer.rb
│   ├── localization-filter.rb
│   ├── markdown-converter.rb
│   ├── page-translation-hook.rb
│   ├── post-commit-history-hook.rb
│   ├── post-revisions-hook.rb
│   ├── post-translation-hook.rb
│   ├── search-index-generator.rb
│   ├── shuffle-filter.rb
│   ├── translate-tag.rb
│   ├── unwrap-filter.rb
│   ├── url-filter.rb
│   └── well-known-hook.rb
├── assets/
│   ├── css/
│   │   ├── _admonitions.scss
│   │   ├── _animations.scss
│   │   ├── _code.scss
│   │   ├── _colors.scss
│   │   ├── _functions.scss
│   │   ├── _inputs.scss
│   │   ├── _layout.scss
│   │   ├── _typography.scss
│   │   ├── articles/
│   │   │   ├── 1password-cli.scss
│   │   │   ├── as-we-may-code.scss
│   │   │   ├── availability.scss
│   │   │   ├── caemitterlayer.scss
│   │   │   ├── callable.scss
│   │   │   ├── characterset.scss
│   │   │   ├── dark-mode.scss
│   │   │   ├── formatter.scss
│   │   │   ├── ios-13.scss
│   │   │   ├── keyvaluepairs.scss
│   │   │   ├── mapkit-js.scss
│   │   │   ├── message-id.scss
│   │   │   ├── metrickit.scss
│   │   │   ├── model-context-protocol.scss
│   │   │   ├── swift-format.scss
│   │   │   ├── swift-log.scss
│   │   │   ├── swift-package-registry.scss
│   │   │   └── swiftui-previews.scss
│   │   ├── fonts/
│   │   │   ├── _batang.scss
│   │   │   ├── _cc.scss
│   │   │   └── _merriweather.scss
│   │   ├── media-queries/
│   │   │   ├── _hover.scss
│   │   │   ├── _inverted-colors.scss
│   │   │   ├── _monochrome.scss
│   │   │   ├── _prefers-color-scheme.scss
│   │   │   ├── _prefers-contrast.scss
│   │   │   ├── _prefers-reduced-motion.scss
│   │   │   ├── _print.scss
│   │   │   └── _width.scss
│   │   └── screen.scss
│   ├── images/
│   │   └── NSShowMe.tiff
│   ├── js/
│   │   ├── application.js
│   │   ├── articles/
│   │   │   ├── caemitterlayer.js
│   │   │   ├── mapkit-js.js
│   │   │   ├── swift-format.js
│   │   │   └── wwdc-2020.js
│   │   └── nsmutablehipster.js
│   └── videos/
│       ├── TrickXORTreat.srt
│       └── caemitterlayer-final-product.m4v
├── collections/
│   ├── en/
│   │   ├── _authors/
│   │   │   ├── croath-liu.md
│   │   │   ├── delisa-mason.md
│   │   │   ├── em-lazer-walker.md
│   │   │   ├── jack-flintermann.md
│   │   │   ├── jemmons.md
│   │   │   ├── jordan-morgan.md
│   │   │   ├── matt-massicotte.md
│   │   │   ├── mattt.md
│   │   │   ├── natasha-murashev.md
│   │   │   ├── nate-cook.md
│   │   │   ├── reda-lemeden.md
│   │   │   └── zoe-smith.md
│   │   └── _books/
│   │       ├── cfhipsterref.md
│   │       ├── fake-book-objective-c.md
│   │       ├── flight-school-guide-to-swift-codable.md
│   │       ├── flight-school-guide-to-swift-numbers.md
│   │       ├── flight-school-guide-to-swift-strings.md
│   │       └── nshipster.md
│   ├── es/
│   │   ├── _authors/
│   │   │   ├── croath-liu.md
│   │   │   ├── delisa-mason.md
│   │   │   ├── jack-flintermann.md
│   │   │   ├── jordan-morgan.md
│   │   │   ├── mattt.md
│   │   │   ├── mike-lazer-walker.md
│   │   │   ├── natasha-murashev.md
│   │   │   └── nate-cook.md
│   │   ├── _books/
│   │   │   ├── 01-nshipster-swift.md
│   │   │   ├── 02-cfhipsterref.md
│   │   │   └── 03-nshipster-fake-book-objective-c.md
│   │   └── _translators/
│   │       └── juan-fernandez-sagasti.md
│   ├── fr/
│   │   ├── _authors/
│   │   │   ├── croath-liu.md
│   │   │   ├── delisa-mason.md
│   │   │   ├── jack-flintermann.md
│   │   │   ├── jordan-morgan.md
│   │   │   ├── mattt.md
│   │   │   ├── mike-lazer-walker.md
│   │   │   ├── natasha-murashev.md
│   │   │   └── nate-cook.md
│   │   ├── _books/
│   │   │   ├── 01-nshipster-swift.md
│   │   │   ├── 02-cfhipsterref.md
│   │   │   └── 03-nshipster-fake-book-objective-c.md
│   │   └── _translators/
│   │       └── vincent-pradeilles.md
│   ├── ko/
│   │   ├── _authors/
│   │   │   ├── croath-liu.md
│   │   │   ├── delisa-mason.md
│   │   │   ├── jack-flintermann.md
│   │   │   ├── jemmons.md
│   │   │   ├── mattt.md
│   │   │   ├── mike-lazer-walker.md
│   │   │   ├── natasha-murashev.md
│   │   │   └── nate-cook.md
│   │   ├── _books/
│   │   │   ├── 01-nshipster-swift.md
│   │   │   ├── 02-cfhipsterref.md
│   │   │   └── 03-nshipster-fake-book-objective-c.md
│   │   └── _translators/
│   │       └── pilgwon.md
│   ├── ru/
│   │   ├── _authors/
│   │   │   ├── croath-liu.md
│   │   │   ├── delisa-mason.md
│   │   │   ├── jack-flintermann.md
│   │   │   ├── jordan-morgan.md
│   │   │   ├── mattt.md
│   │   │   ├── mike-lazer-walker.md
│   │   │   ├── natasha-murashev.md
│   │   │   └── nate-cook.md
│   │   └── _books/
│   │       ├── 01-nshipster-swift.md
│   │       ├── 02-cfhipsterref.md
│   │       └── 03-nshipster-fake-book-objective-c.md
│   └── zh-Hans/
│       ├── _authors/
│       │   ├── croath-liu.md
│       │   ├── delisa-mason.md
│       │   ├── jack-flintermann.md
│       │   ├── mattt.md
│       │   ├── mike-lazer-walker.md
│       │   ├── natasha-murashev.md
│       │   └── nate-cook.md
│       ├── _books/
│       │   ├── 01-nshipster-swift.md
│       │   ├── 02-cfhipsterref.md
│       │   └── 03-nshipster-fake-book-objective-c.md
│       └── _translators/
│           ├── Candyan.md
│           ├── andrew-yang.md
│           ├── april-peng.md
│           ├── chester-liu.md
│           ├── croath-liu.md
│           ├── david-liu.md
│           ├── henry-lee.md
│           ├── ricky-tan.md
│           ├── steven-wang.md
│           └── tiny-tian.md
├── contribute.json
├── feed.xml
├── flight-school.md
├── index.html
├── return.md
├── sitemap.xml
├── status.md
└── vendor/
    └── cache/
        ├── activesupport-6.1.4.1.gem
        ├── addressable-2.8.0.gem
        ├── bibtex-ruby-6.0.0.gem
        ├── camertron-eprun-1.1.1.gem
        ├── citeproc-1.0.10.gem
        ├── citeproc-ruby-1.1.14.gem
        ├── cldr-plurals-runtime-rb-1.1.0.gem
        ├── colorator-1.1.0.gem
        ├── concurrent-ruby-1.1.9.gem
        ├── csl-1.6.0.gem
        ├── csl-styles-1.0.1.11.gem
        ├── em-websocket-0.5.2.gem
        ├── eventmachine-1.2.7.gem
        ├── execjs-2.8.1.gem
        ├── extras-0.3.0.gem
        ├── fastimage-2.2.5.gem
        ├── ffi-1.16.3.gem
        ├── foreman-0.87.2.gem
        ├── forwardable-extended-2.6.0.gem
        ├── htmlbeautifier-1.3.1.gem
        ├── htmlcompressor-0.4.0.gem
        ├── http_parser.rb-0.6.0.gem
        ├── i18n-1.8.10.gem
        ├── jekyll-4.2.1.gem
        ├── jekyll-include-cache-0.2.1.gem
        ├── jekyll-sanity-1.6.0.gem
        ├── jekyll-sass-converter-2.1.0.gem
        ├── jekyll-scholar-7.0.0.gem
        ├── jekyll-tidy-0.2.2.gem
        ├── jekyll-watch-2.2.1.gem
        ├── kramdown-2.3.1.gem
        ├── kramdown-parser-gfm-1.1.0.gem
        ├── latex-decode-0.3.2.gem
        ├── liquid-4.0.3.gem
        ├── liquid-tag-parser-2.0.2.gem
        ├── listen-3.7.0.gem
        ├── mercenary-0.4.0.gem
        ├── mini_portile2-2.8.7.gem
        ├── minitest-5.14.4.gem
        ├── namae-1.1.1.gem
        ├── nokogiri-1.15.6-arm64-darwin.gem
        ├── pathutil-0.16.2.gem
        ├── public_suffix-4.0.6.gem
        ├── racc-1.8.1.gem
        ├── rack-2.2.3.gem
        ├── rake-13.0.6.gem
        ├── rb-fsevent-0.11.0.gem
        ├── rb-inotify-0.10.1.gem
        ├── rexml-3.2.5.gem
        ├── safe_yaml-1.0.5.gem
        ├── sassc-2.4.0.gem
        ├── sprockets-4.0.2.gem
        ├── terminal-table-2.0.0.gem
        ├── twitter_cldr-6.7.0.gem
        ├── tzinfo-2.0.4.gem
        ├── uglifier-4.2.0.gem
        ├── unicode-display_width-1.8.0.gem
        └── zeitwerk-2.4.2.gem
Download .txt
SYMBOL INDEX (59 symbols across 13 files)

FILE: _plugins/admonition-block.rb
  type Jekyll (line 3) | module Jekyll
    class AdmonitionBlock (line 4) | class AdmonitionBlock < Liquid::Block
      method initialize (line 5) | def initialize(tag_name, arguments, tokens)
      method render (line 11) | def render(context)

FILE: _plugins/camel-case-thin-space-break-filter.rb
  type Jekyll (line 3) | module Jekyll
    type CamelCaseThinSpaceBreakFilter (line 4) | module CamelCaseThinSpaceBreakFilter
      function camel_break (line 7) | def camel_break(string)

FILE: _plugins/extended-date-filter.rb
  type Jekyll (line 5) | module Jekyll
    type ExtendedDateFilter (line 6) | module ExtendedDateFilter
      function date (line 40) | def date(input, format)
      function ordinal (line 49) | def ordinal(number)
      function datetime (line 60) | def datetime(date)

FILE: _plugins/jwt-lexer.rb
  type Rouge (line 5) | module Rouge
    type Lexers (line 6) | module Lexers
      class JWT (line 7) | class JWT < RegexLexer

FILE: _plugins/localization-filter.rb
  type Jekyll (line 5) | module Jekyll
    type LocalizationFilter (line 6) | module LocalizationFilter
      function as_language_code (line 7) | def as_language_code(input, locale = nil)
      function to_sentence (line 14) | def to_sentence(list)
      function current_locale (line 21) | def current_locale

FILE: _plugins/markdown-converter.rb
  type Jekyll (line 9) | module Jekyll
    type Converters (line 10) | module Converters
      class Markdown (line 11) | class Markdown
        class NSHipsterProcessor (line 13) | class NSHipsterProcessor
          method initialize (line 14) | def initialize(config)
          method convert (line 18) | def convert(content)
          method cache (line 42) | def cache
          method remove_proprietary_attributes! (line 46) | def remove_proprietary_attributes!(doc)
          method transform_code_symbols! (line 52) | def transform_code_symbols!(doc)
          method transform_apple_trademarks! (line 59) | def transform_apple_trademarks!(doc)
          method secure_links_to_cross_origin_destinations! (line 65) | def secure_links_to_cross_origin_destinations!(doc)
          method transform_placeholder_tokens! (line 74) | def transform_placeholder_tokens!(doc)
          method add_heading_anchors! (line 80) | def add_heading_anchors!(doc)
          method unnest_code_listing_markup! (line 92) | def unnest_code_listing_markup!(doc)
          method consolidate_consecutive_code_listings! (line 130) | def consolidate_consecutive_code_listings!(doc)
          method improve_accessibility! (line 177) | def improve_accessibility!(doc)
          method style_optional_placeholders! (line 187) | def style_optional_placeholders!(doc)
          method delineate_flim_flam! (line 197) | def delineate_flim_flam!(doc)

FILE: _plugins/search-index-generator.rb
  type Jekyll (line 3) | module Jekyll
    class SearchIndexGenerator (line 4) | class SearchIndexGenerator < Generator
      method generate (line 7) | def generate(site)

FILE: _plugins/shuffle-filter.rb
  type Jekyll (line 3) | module Jekyll
    type ShuffleFilter (line 4) | module ShuffleFilter
      function shuffle (line 5) | def shuffle(input = [])

FILE: _plugins/translate-tag.rb
  type Jekyll (line 3) | module Jekyll
    class Site (line 4) | class Site
    class TranslateTag (line 8) | class TranslateTag < Liquid::Tag
      method initialize (line 9) | def initialize(tag_name, key, tokens)
      method render (line 14) | def render(context)
      method key (line 27) | def key(context)
      method translations (line 40) | def translations(context)

FILE: _plugins/unwrap-filter.rb
  type Jekyll (line 5) | module Jekyll
    type UnwrapFilter (line 6) | module UnwrapFilter
      function unwrap (line 7) | def unwrap(input)

FILE: _plugins/url-filter.rb
  type Jekyll (line 5) | module Jekyll
    type URLFilter (line 6) | module URLFilter
      function host (line 7) | def host(input)

FILE: assets/js/articles/caemitterlayer.js
  function frame (line 157) | function frame() {

FILE: assets/js/articles/swift-format.js
  function getComputedWidthInEm (line 5) | function getComputedWidthInEm(element) {
Condensed preview — 257 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (210K chars).
[
  {
    "path": ".gitignore",
    "chars": 195,
    "preview": ".s3cfg\n_site\n_drafts\nbuild\nnshipster.com/articles\nnshipster.com/books\nnshipster.com/training\n.sass-cache\n.vscode\n.jekyll"
  },
  {
    "path": ".gitmodules",
    "chars": 837,
    "preview": "[submodule \"collections/en/_posts\"]\n\tpath = collections/en/_posts\n\turl = https://github.com/NSHipster/articles.git\n\tbran"
  },
  {
    "path": ".ruby-version",
    "chars": 6,
    "preview": "2.7.5\n"
  },
  {
    "path": ".tool-versions",
    "chars": 11,
    "preview": "ruby 2.7.5\n"
  },
  {
    "path": ".well-known/brave-payments-verification.txt",
    "chars": 149,
    "preview": "This is a Brave Payments publisher verification file.\n\nDomain: nshipster.com\nToken: 9427d793d5eb646c66ff42e31086f6e792c3"
  },
  {
    "path": ".well-known/browserconfig.xml",
    "chars": 246,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n    <msapplication>\n        <tile>\n            <square150x150logo"
  },
  {
    "path": ".well-known/humans.txt",
    "chars": 370,
    "preview": "---\nlayout: null\npermalink: /humans.txt\n---\n\n/* TEAM */\n\nManaging Editor: Mattt\nSite: https://mat.tt\nContact: mattt [at]"
  },
  {
    "path": ".well-known/robots.txt",
    "chars": 105,
    "preview": "---\nlayout: null\npermalink: /robots.txt\n---\n\nUser-agent: *\nAllow: /\n\nSitemap: {{ site.url }}/sitemap.xml\n"
  },
  {
    "path": ".well-known/site.webmanifest",
    "chars": 435,
    "preview": "{\n    \"name\": \"NSHipster\",\n    \"short_name\": \"NSHipster\",\n    \"icons\": [{\n            \"src\": \"/android-chrome-192x192.pn"
  },
  {
    "path": "404.md",
    "chars": 879,
    "preview": "---\nlayout: error\ntitle: NSError 404 - NSHipster\npermalink: 404.html\n---\n\n```swift\nlet domain = \"{{ site.url | host }}\"\n"
  },
  {
    "path": "Gemfile",
    "chars": 742,
    "preview": "# frozen_string_literal: true\n\nsource 'https://rubygems.org'\n\ngem 'jekyll'\ngem 'rack', '>= 2.0.6'\n\ngem 'sprockets', '~> "
  },
  {
    "path": "LICENSE.md",
    "chars": 1080,
    "preview": "Copyright 2012 – 2025 NSHipster (https://nshipster.com)\n\nPermission is hereby granted, free of charge, to any person obt"
  },
  {
    "path": "README.md",
    "chars": 2389,
    "preview": "# NSHipster.com\n\n[NSHipster](https://nshipster.com) is a journal of the overlooked bits in\nSwift, Objective-C and Cocoa."
  },
  {
    "path": "_bibliography/references.bib",
    "chars": 5971,
    "preview": "---\n---\n\n@article{de_montjoye_2013,\n    title = {Unique in the {Crowd}: {The} privacy bounds of human mobility},\n    vol"
  },
  {
    "path": "_config/default.yml",
    "chars": 1184,
    "preview": "title: NSHipster\npermalink: /:title/\n\ntwitter: 629523445\nfacebook: 418545184954768\nissn: 2373-9800\n\ndomains:\n  en: https"
  },
  {
    "path": "_config/nshipster.cn.yml",
    "chars": 338,
    "preview": "url: https://nshipster.cn\nlang: zh-Hans\n\ndescription: >-\n  **NSHipster** 关注被忽略的 Objective-C、Swift 和 Cocoa 特性。\ntimezone: "
  },
  {
    "path": "_config/nshipster.co.kr.yml",
    "chars": 343,
    "preview": "url: https://nshipster.co.kr\nlang: ko-KR\n\ndescription: >-\n  **NSHipster**는 간과 된 비트의 저널입니다\n  Objective-C, Swift 및 Cocoa에서"
  },
  {
    "path": "_config/nshipster.com.ru.yml",
    "chars": 357,
    "preview": "url: https://nshipster.com.ru\nlang: ru-RU\n\ndescription: >-\n  **NSHipster** это журнал пропущенных бит в\n  Objective-C, S"
  },
  {
    "path": "_config/nshipster.com.yml",
    "chars": 306,
    "preview": "url: https://nshipster.com\nlang: en-US\n\ndescription: >-\n  **NSHipster** is a journal of the overlooked bits\n  in Objecti"
  },
  {
    "path": "_config/nshipster.es.yml",
    "chars": 375,
    "preview": "url: https://nshipster.es\nlang: es-ES\n\ndescription: >-\n  **NSHipster** es una publicación de los bits pasados por alto\n "
  },
  {
    "path": "_config/nshipster.fr.yml",
    "chars": 392,
    "preview": "url: https://nshipster.fr\nlang: fr-FR\n\ndescription: >-\n  **NSHipster** est une publication qui s'intéresse aux\n  parties"
  },
  {
    "path": "_config/nsmutablehipster.com.yml",
    "chars": 337,
    "preview": "title: NSMutableHipster\nurl: https://nsmutablehipster.com\nlang: en-US\n\ndescription: >-\n  **NSHipster** is a journal of t"
  },
  {
    "path": "_functions/search/package.json",
    "chars": 288,
    "preview": "{\n  \"name\": \"nshipster-netlify-functions\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"search.js\",\n  \"scripts\""
  },
  {
    "path": "_functions/search/search.js",
    "chars": 751,
    "preview": "const fs = require(\"fs\");\nconst lunr = require(\"lunr\");\n\nconst json = JSON.parse(fs.readFileSync(require.resolve(\"./inde"
  },
  {
    "path": "_i18n/en-US.yml",
    "chars": 752,
    "preview": "format:\n  date: \"%B %-d<sup>%o</sup>, %Y\"\n\nthis_week: This Week...\ncontinue_reading: Continue Reading\nrecent_articles: R"
  },
  {
    "path": "_i18n/es-ES.yml",
    "chars": 743,
    "preview": "format:\n  date: \"%-d/%-m/%Y\"\n\nthis_week: Esta semana...\ncontinue_reading: Sigue leyendo\nrecent_articles: Artículos recie"
  },
  {
    "path": "_i18n/fr-FR.yml",
    "chars": 768,
    "preview": "format:\n  date: \"%-d/%-m/%Y\"\n\nthis_week: Cette semaine...\ncontinue_reading: Lire la suite\nrecent_articles: Articles réce"
  },
  {
    "path": "_i18n/ko-KR.yml",
    "chars": 625,
    "preview": "format:\n  date: \"%Y년 %-m월 %-d일\"\n\nthis_week: 이번 주\ncontinue_reading: 더 읽기\nrecent_articles: 최근 기사\npublications: 책\npopular_a"
  },
  {
    "path": "_i18n/ru-RU.yml",
    "chars": 715,
    "preview": "format:\n  date: \"%-d.%-m.%Y\"\n\nthis_week: На этой неделе...\ncontinue_reading: Продолжить чтение\nrecent_articles: Последни"
  },
  {
    "path": "_i18n/zh-Hans.yml",
    "chars": 433,
    "preview": "format:\n  date: \"%Y年%-m月%-d日\"\n\nthis_week: 本周发布\ncontinue_reading: 继续阅读\nrecent_articles: 最近的文章\npublications: 书籍\npopular_ar"
  },
  {
    "path": "_includes/book.html",
    "chars": 358,
    "preview": "{% assign book = site.books | where:\"name\", include.book | first %}\n\n<div id=\"{{ book.name }}\" class=\"book\">\n    <a href"
  },
  {
    "path": "_includes/contributor.html",
    "chars": 1013,
    "preview": "{% case include.role %}\n{% when 'author' %}\n  {% assign contributor = site.authors | where:\"name\", page.author | first %"
  },
  {
    "path": "_includes/json-ld/article.html",
    "chars": 892,
    "preview": "<script type=\"application/ld+json\">\n{\n  \"@context\": \"https://schema.org\",\n  \"@type\": \"Article\",\n  \"headline\": \"{{ page.t"
  },
  {
    "path": "_includes/json-ld/book.html",
    "chars": 804,
    "preview": "<script type=\"application/ld+json\">\n{\n  \"@context\": \"https://schema.org\",\n  \"@type\": \"Book\",\n  \"author\": {\n    \"@type\": "
  },
  {
    "path": "_includes/json-ld/breadcrumblist.html",
    "chars": 462,
    "preview": "<script type=\"application/ld+json\">\n{\n  \"@context\": \"https://schema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElemen"
  },
  {
    "path": "_includes/json-ld/organization.html",
    "chars": 486,
    "preview": "<script type=\"application/ld+json\">\n{\n  \"@context\": \"https://schema.org\",\n  \"@type\": \"Organization\",\n  \"name\": \"NSHipste"
  },
  {
    "path": "_includes/json-ld/website.html",
    "chars": 499,
    "preview": "<script type=\"application/ld+json\">\n{\n  \"@context\": \"https://schema.org\",\n  \"@type\": \"WebSite\",\n  \"url\": \"{{ site.url }}"
  },
  {
    "path": "_includes/promo.html",
    "chars": 591,
    "preview": "{% assign book = site.books | where:\"name\", include.book | first %}\n\n<section id=\"promotion\"{% if include.home %} class="
  },
  {
    "path": "_layouts/author.html",
    "chars": 1067,
    "preview": "---\nlayout: default\n---\n\n{% assign author = page %}\n{% capture date_format %}{% t format.date %}{% endcapture %}\n\n<artic"
  },
  {
    "path": "_layouts/default.html",
    "chars": 6244,
    "preview": "<!DOCTYPE html>\n<html lang=\"{{ site.lang }}\">\n<head>\n  <meta charset=\"utf-8\"/>\n  {% if page.id %}\n    <title>{{ page.tit"
  },
  {
    "path": "_layouts/error.html",
    "chars": 146,
    "preview": "---\nlayout: default\n---\n\n<article role=\"article\">\n  <h1 class=\"title\">NSError</h1>\n\n  <div class=\"content\">\n    {{ conte"
  },
  {
    "path": "_layouts/page.html",
    "chars": 259,
    "preview": "---\nlayout: default\n---\n\n<article role=\"article\">\n  <header role=\"heading\">\n    <h1 class=\"title\">\n      <a href=\"{{ pag"
  },
  {
    "path": "_layouts/post.html",
    "chars": 4726,
    "preview": "---\nlayout: default\n---\n\n{% assign author = site.authors | where:\"name\", page.author | first %}\n{% assign translator = s"
  },
  {
    "path": "_layouts/translator.html",
    "chars": 1116,
    "preview": "---\nlayout: default\n---\n\n{% assign translator = page %}\n{% capture date_format %}{% t format.date %}{% endcapture %}\n\n<a"
  },
  {
    "path": "_plugins/admonition-block.rb",
    "chars": 477,
    "preview": "# frozen_string_literal: true\n\nmodule Jekyll\n  class AdmonitionBlock < Liquid::Block\n    def initialize(tag_name, argume"
  },
  {
    "path": "_plugins/camel-case-thin-space-break-filter.rb",
    "chars": 340,
    "preview": "# frozen_string_literal: true\n\nmodule Jekyll\n  module CamelCaseThinSpaceBreakFilter\n    REGEX = /(?:([a-z]{2,})([A-Z]+))"
  },
  {
    "path": "_plugins/extended-date-filter.rb",
    "chars": 2302,
    "preview": "# frozen_string_literal: true\n\nrequire 'time'\n\nmodule Jekyll\n  module ExtendedDateFilter\n    # Reformat a date using Rub"
  },
  {
    "path": "_plugins/jwt-lexer.rb",
    "chars": 636,
    "preview": "# frozen_string_literal: true\n\nrequire 'rouge'\n\nmodule Rouge\n  module Lexers\n    class JWT < RegexLexer\n      tag 'jwt'\n"
  },
  {
    "path": "_plugins/localization-filter.rb",
    "chars": 792,
    "preview": "# frozen_string_literal: true\n\nrequire 'twitter_cldr'\n\nmodule Jekyll\n  module LocalizationFilter\n    def as_language_cod"
  },
  {
    "path": "_plugins/markdown-converter.rb",
    "chars": 6920,
    "preview": "# frozen_string_literal: true\n\nrequire 'yaml'\n\nrequire 'jekyll'\nrequire 'nokogiri'\nrequire 'active_support/inflector'\n\nm"
  },
  {
    "path": "_plugins/page-translation-hook.rb",
    "chars": 166,
    "preview": "# frozen_string_literal: true\n\nJekyll::Hooks.register :pages, :pre_render do |page|\n  page.data['translations'] = page.s"
  },
  {
    "path": "_plugins/post-commit-history-hook.rb",
    "chars": 847,
    "preview": "# frozen_string_literal: true\n\nrequire 'uri'\n\nJekyll::Hooks.register :posts, :pre_render do |post|\n  language = post.sit"
  },
  {
    "path": "_plugins/post-revisions-hook.rb",
    "chars": 506,
    "preview": "# frozen_string_literal: true\n\nrequire 'date'\n\nJekyll::Hooks.register :posts, :pre_render do |post|\n  if post.data['revi"
  },
  {
    "path": "_plugins/post-translation-hook.rb",
    "chars": 512,
    "preview": "# frozen_string_literal: true\n\nJekyll::Hooks.register :posts, :pre_render do |post|\n  directory = File.expand_path('../."
  },
  {
    "path": "_plugins/search-index-generator.rb",
    "chars": 572,
    "preview": "# frozen_string_literal: true\n\nmodule Jekyll\n  class SearchIndexGenerator < Generator\n    priority :low\n\n    def generat"
  },
  {
    "path": "_plugins/shuffle-filter.rb",
    "chars": 237,
    "preview": "# frozen_string_literal: true\n\nmodule Jekyll\n  module ShuffleFilter\n    def shuffle(input = [])\n      input.sort_by { ra"
  },
  {
    "path": "_plugins/translate-tag.rb",
    "chars": 1277,
    "preview": "# frozen_string_literal: true\n\nmodule Jekyll\n  class Site\n    attr_accessor :translations\n  end\n\n  class TranslateTag < "
  },
  {
    "path": "_plugins/unwrap-filter.rb",
    "chars": 345,
    "preview": "# frozen_string_literal: true\n\nrequire 'nokogiri'\n\nmodule Jekyll\n  module UnwrapFilter\n    def unwrap(input)\n      retur"
  },
  {
    "path": "_plugins/url-filter.rb",
    "chars": 229,
    "preview": "# frozen_string_literal: true\n\nrequire 'uri'\n\nmodule Jekyll\n  module URLFilter\n    def host(input)\n      return input un"
  },
  {
    "path": "_plugins/well-known-hook.rb",
    "chars": 241,
    "preview": "# frozen_string_literal: true\n\nrequire 'fileutils'\n\nJekyll::Hooks.register :site, :post_write do |site|\n  site.static_fi"
  },
  {
    "path": "assets/css/_admonitions.scss",
    "chars": 1466,
    "preview": "@mixin border-icon($name) {\n  content: \" \";\n  background-image: asset_url($name + \".svg\");\n  background-size: 24px 24px;"
  },
  {
    "path": "assets/css/_animations.scss",
    "chars": 371,
    "preview": "@keyframes twirl {\n    0% {\n        transform: scale(1) rotate(0);\n    }\n\n    10%,\n    20% {\n        transform: scale(0."
  },
  {
    "path": "assets/css/_code.scss",
    "chars": 2433,
    "preview": "pre.highlight {\n  background: var(--secondary-background);\n  border: 1px var(--separator-opaque) solid;\n  border-radius:"
  },
  {
    "path": "assets/css/_colors.scss",
    "chars": 2360,
    "preview": ":root {\n  --red: rgb(255, 59, 48);\n  --orange: rgb(255, 128, 0);\n  --yellow: rgb(255, 204, 0);\n  --green: rgb(52, 199, 8"
  },
  {
    "path": "assets/css/_functions.scss",
    "chars": 443,
    "preview": "@mixin clearfix {\n  &:after {\n    content: \" \";\n    display: block;\n    clear: both;\n  }\n}\n\n@mixin disable-selection {\n "
  },
  {
    "path": "assets/css/_inputs.scss",
    "chars": 600,
    "preview": "button,\ninput[type=\"submit\"] {\n  -moz-appearance: none;\n  -ms-appearance: none;\n  -o-appearance: none;\n  -webkit-appeara"
  },
  {
    "path": "assets/css/_layout.scss",
    "chars": 12081,
    "preview": "@import \"functions\";\n\nhtml,\nbody {\n  margin: 0;\n}\n\nbody {\n  padding: env(safe-area-inset-top) env(safe-area-inset-right)"
  },
  {
    "path": "assets/css/_typography.scss",
    "chars": 5240,
    "preview": "@import \"fonts/merriweather\";\n@import \"fonts/batang\";\n@import \"fonts/cc\";\n@import \"colors\";\n\n$serif-font-stack: \"Merriwe"
  },
  {
    "path": "assets/css/articles/1password-cli.scss",
    "chars": 914,
    "preview": "figure#create-vault-dialog {\n    display: block;\n    width: 360px !important;\n    border-radius: 10px;\n    box-shadow: 0"
  },
  {
    "path": "assets/css/articles/as-we-may-code.scss",
    "chars": 177,
    "preview": ".nohighlight * {\n  color: var(--gray) !important;\n}\n\np > code {\n  .kd {\n    color: var(--teal);\n  }\n\n  .nf {\n    color: "
  },
  {
    "path": "assets/css/articles/availability.scss",
    "chars": 301,
    "preview": "figure#wavailability {\n  table {\n    table-layout: auto;\n    font-size: smaller;\n\n    td[colspan=\"7\"] {\n      text-align"
  },
  {
    "path": "assets/css/articles/caemitterlayer.scss",
    "chars": 540,
    "preview": "#webgl-confetti {\n    position: relative;\n    width: 500px;\n    margin: 1em auto;\n    display: block;\n    canvas {\n     "
  },
  {
    "path": "assets/css/articles/callable.scss",
    "chars": 205,
    "preview": "dl {\n  display: grid;\n  grid-template-columns: min-content auto;\n  gap: 0.5em 1em;\n}\n\ndt {\n  grid-column-start: 1;\n  mar"
  },
  {
    "path": "assets/css/articles/characterset.scss",
    "chars": 457,
    "preview": "@import \"colors\";\n@import \"functions\";\n\n.conversation {\n  @include clearfix;\n\n  margin: 1em auto;\n  max-width: 650px;\n\n "
  },
  {
    "path": "assets/css/articles/dark-mode.scss",
    "chars": 1148,
    "preview": ".color {\n  background: var(--color);\n  display: inline-block;\n}\n\np .color {\n  width: 0.8em;\n  height: 0.8em;\n  border-ra"
  },
  {
    "path": "assets/css/articles/formatter.scss",
    "chars": 476,
    "preview": "dl {\n    width: auto;\n    font-family: initial;\n    display: grid;\n    grid-template-columns: auto max-content;\n    gap:"
  },
  {
    "path": "assets/css/articles/ios-13.scss",
    "chars": 732,
    "preview": ".conversation {\n    max-width: 50ch;\n    display: block;\n    margin: 0 auto;\n    padding: 1em 0;\n    p {\n        margin:"
  },
  {
    "path": "assets/css/articles/keyvaluepairs.scss",
    "chars": 173,
    "preview": "#bagua {\n  td {\n    text-align: center;\n  }\n}\n\n#bagua + p ruby:last-of-type {\n  -webkit-ruby-position: under;\n  ruby-pos"
  },
  {
    "path": "assets/css/articles/mapkit-js.scss",
    "chars": 1264,
    "preview": "#jwt-debug {\n  h3 {\n    margin: 0;\n\n    small {\n      display: block;\n      font-weight: normal;\n      font-size: smalle"
  },
  {
    "path": "assets/css/articles/message-id.scss",
    "chars": 339,
    "preview": "@import \"../functions\";\n\n@media screen and (min-width: 768px) {\n  aside {\n    @include clearfix;\n\n    figure {\n      flo"
  },
  {
    "path": "assets/css/articles/metrickit.scss",
    "chars": 147,
    "preview": "h2 {\n  clear: both;\n}\n\n@media screen and (min-width: 768px) {\n  #battery-usage {\n    float: right;\n    width: 300px;\n   "
  },
  {
    "path": "assets/css/articles/model-context-protocol.scss",
    "chars": 1331,
    "preview": "ol {\n    list-style-type: decimal !important;\n}\n\n@media (min-width: 768px) {\n    dl {\n        margin-left: auto;\n       "
  },
  {
    "path": "assets/css/articles/swift-format.scss",
    "chars": 265,
    "preview": "div.variable-width {\n  resize: horizontal;\n  overflow: hidden;\n  min-width: 30ch;\n  width: 30ch;\n  max-width: 100%;\n  ma"
  },
  {
    "path": "assets/css/articles/swift-log.scss",
    "chars": 549,
    "preview": "#log-levels {\n  table-layout: auto;\n  tbody td:first-of-type {\n    background-color: var(--color);\n    code {\n      back"
  },
  {
    "path": "assets/css/articles/swift-package-registry.scss",
    "chars": 1208,
    "preview": "table {\n  table-layout: auto !important;\n\n  td {\n    text-align: right !important;\n  }\n}\n\n.dialogue {\n  text-align: left"
  },
  {
    "path": "assets/css/articles/swiftui-previews.scss",
    "chars": 373,
    "preview": ".code-with-automatic-preview {\n  display: flex;\n  align-items: stretch;\n  background-color: var(--secondary-background);"
  },
  {
    "path": "assets/css/fonts/_batang.scss",
    "chars": 310,
    "preview": "@font-face {\n    font-family: 'Batang';\n    src: url(font_path(\"Batang.woff2\")) format(\"woff2\"),\n        url(font_path(\""
  },
  {
    "path": "assets/css/fonts/_cc.scss",
    "chars": 287,
    "preview": "@font-face {\n  font-family: \"Creative Commons Symbols\";\n  src: url(font_path(\"CreativeCommonsSymbols.woff2\")) format(\"wo"
  },
  {
    "path": "assets/css/fonts/_merriweather.scss",
    "chars": 2646,
    "preview": "@font-face {\n    font-family: \"Merriweather\";\n    src: local(\"Merriweather Regular\"), local(\"Merriweather-Regular\"),\n   "
  },
  {
    "path": "assets/css/media-queries/_hover.scss",
    "chars": 91,
    "preview": "@media (hover: none) {\n    #logo #mustache {\n        animation-iteration-count: 1;\n    }\n}\n"
  },
  {
    "path": "assets/css/media-queries/_inverted-colors.scss",
    "chars": 165,
    "preview": "@media (inverted-colors) {\n    * {\n        text-shadow: none !important;\n        box-shadow: none !important;\n    }\n\n   "
  },
  {
    "path": "assets/css/media-queries/_monochrome.scss",
    "chars": 1266,
    "preview": "@media (monochrome),\n  print and (not(color)),\n  (prefers-contrast: high),\n  screen and (-ms-high-contrast: active) {\n  "
  },
  {
    "path": "assets/css/media-queries/_prefers-color-scheme.scss",
    "chars": 2683,
    "preview": "@media (prefers-color-scheme: dark) {\n  :root {\n    --red: rgb(255, 69, 58);\n    --yellow: rgb(255, 214, 10);\n    --gree"
  },
  {
    "path": "assets/css/media-queries/_prefers-contrast.scss",
    "chars": 2218,
    "preview": "@media (prefers-contrast: high), screen and (-ms-high-contrast: active) {\n  :root {\n    --red: rgb(215, 0, 21);\n    --ye"
  },
  {
    "path": "assets/css/media-queries/_prefers-reduced-motion.scss",
    "chars": 108,
    "preview": "@media (prefers-reduced-motion: reduce) {\n    #logo #mustache {\n        animation: none !important;\n    }\n}\n"
  },
  {
    "path": "assets/css/media-queries/_print.scss",
    "chars": 2039,
    "preview": "@media print {\n  @page {\n    margin: 0.5in;\n  }\n\n  @page {\n    @bottom-center {\n      content: \"Page \" counter(page) \" o"
  },
  {
    "path": "assets/css/media-queries/_width.scss",
    "chars": 3022,
    "preview": "@media screen and (max-width: 768px) {\n  [role=\"article\"] header {\n    .byline {\n      .authors,\n      .translators {\n  "
  },
  {
    "path": "assets/css/screen.scss",
    "chars": 1492,
    "preview": "@charset \"UTF-8\";\n\n@import \"colors\";\n@import \"animations\";\n@import \"typography\";\n@import \"admonitions\";\n@import \"layout\""
  },
  {
    "path": "assets/js/application.js",
    "chars": 4999,
    "preview": "\"use strict\";\n\n(function() {\n  const delay = 300;\n\n  const keys = {\n    end: 35,\n    home: 36,\n    left: 37,\n    up: 38,"
  },
  {
    "path": "assets/js/articles/caemitterlayer.js",
    "chars": 5851,
    "preview": "// Credit: https://jsfiddle.net/subzey/52sowezj/\n\n'use strict';\n\n(function() {\nvar canvas = document.querySelector('#web"
  },
  {
    "path": "assets/js/articles/mapkit-js.js",
    "chars": 1039,
    "preview": "\"use strict\";\n\n(function() {\n  mapkit.init({\n    authorizationCallback: done => {\n      done(\n        \"eyJ0eXAiOiJKV1QiL"
  },
  {
    "path": "assets/js/articles/swift-format.js",
    "chars": 1226,
    "preview": "//= require vendor/resize-observer.min.js\n\n\"use strict\";\n\nfunction getComputedWidthInEm(element) {\n  const computed = wi"
  },
  {
    "path": "assets/js/articles/wwdc-2020.js",
    "chars": 401,
    "preview": "\"use strict\";\n\n(function () {\n  const details = document.querySelector(\"details\");\n  if (details) {\n    let listener = d"
  },
  {
    "path": "assets/js/nsmutablehipster.js",
    "chars": 612,
    "preview": "//= require vendor/typed.min.js\n\n\"use strict\";\n\n(function() {\n  document.body.contentEditable = true;\n  document.querySe"
  },
  {
    "path": "assets/videos/TrickXORTreat.srt",
    "chars": 3202,
    "preview": "1\n00:00:02,500 --> 00:00:07,591\nEvery kid knows the phrase, [kid sing-songy] \"Trick or treat!\" But have you\n\n2\n00:00:07,"
  },
  {
    "path": "collections/en/_authors/croath-liu.md",
    "chars": 394,
    "preview": "---\ntitle: Croath Liu\n\nname: Croath Liu\nemail: Croath.Liu@gmail.com\nurl: https://twitter.com/cr0ath\ntwitter: cr0ath\ngith"
  },
  {
    "path": "collections/en/_authors/delisa-mason.md",
    "chars": 394,
    "preview": "---\ntitle: Delisa Mason\n\nname: Delisa Mason\nemail: delisa.mason@gmail.com\nurl: https://twitter.com/kattrali\ntwitter: kat"
  },
  {
    "path": "collections/en/_authors/em-lazer-walker.md",
    "chars": 342,
    "preview": "---\ntitle: Em Lazer-Walker\n\nname: Em Lazer-Walker\nemail: hi@lazerwalker.com\nurl: https://twitter.com/lazerwalker\ntwitter"
  },
  {
    "path": "collections/en/_authors/jack-flintermann.md",
    "chars": 311,
    "preview": "---\ntitle: Jack Flintermann\n\nname: Jack Flintermann\nemail: jack@stripe.com\nurl: https://twitter.com/jflinter\ntwitter: jf"
  },
  {
    "path": "collections/en/_authors/jemmons.md",
    "chars": 318,
    "preview": "---\ntitle: \"@jemmons\"\nname: jemmons\nurl: https://figure.ink\ntwitter: jemmons\ngithub: jemmons\nimage: jemmons.jpg\n---\n\nJos"
  },
  {
    "path": "collections/en/_authors/jordan-morgan.md",
    "chars": 609,
    "preview": "---\ntitle: Jordan Morgan\n\nname: Jordan Morgan\nemail: info@dreaminginbinary.co\nurl: https://dreaminginbinary.co\ntwitter: "
  },
  {
    "path": "collections/en/_authors/matt-massicotte.md",
    "chars": 343,
    "preview": "---\ntitle: Matt Massicotte\n\nname: Matt Massicotte\nurl: https://www.massicotte.org\ngithub: mattmassicotte\nimage: matt-mas"
  },
  {
    "path": "collections/en/_authors/mattt.md",
    "chars": 258,
    "preview": "---\ntitle: Mattt\n\nname: Mattt\nemail: mattt@nshipster.com\nurl: https://twitter.com/mattt\ntwitter: mattt\ngithub: mattt\nima"
  },
  {
    "path": "collections/en/_authors/natasha-murashev.md",
    "chars": 540,
    "preview": "---\ntitle: Natasha Murashev\n\nname: Natasha Murashev\nemail: natasha@natashatherobot.com\nurl: https://twitter.com/NatashaT"
  },
  {
    "path": "collections/en/_authors/nate-cook.md",
    "chars": 418,
    "preview": "---\ntitle: Nate Cook\n\nname: Nate Cook\nemail: nate@nshipster.com\nurl: https://twitter.com/nnnnnnnn\ntwitter: nnnnnnnn\ngith"
  },
  {
    "path": "collections/en/_authors/reda-lemeden.md",
    "chars": 351,
    "preview": "---\ntitle: Reda Lemeden\n\nname: Reda Lemeden\nemail: hello@redalemeden.com\nurl: https://redalemeden.com\ntwitter: kaishin\ng"
  },
  {
    "path": "collections/en/_authors/zoe-smith.md",
    "chars": 447,
    "preview": "---\ntitle: Zoë Smith\n\nname: Zoë Smith\nemail: zoews@me.com\nurl: https://zoesmith.io/about\ntwitter: zoejessica\ngithub: zoe"
  },
  {
    "path": "collections/en/_books/cfhipsterref.md",
    "chars": 717,
    "preview": "---\nname: cfhipsterref\ntitle: \"CFHipsterRef: Low-Level Programming on iOS & OS X\"\nshort_title: \"CFHipsterRef\"\nsub_title:"
  },
  {
    "path": "collections/en/_books/fake-book-objective-c.md",
    "chars": 541,
    "preview": "---\nname: \"fake-book-objective-c\"\ntitle: \"The NSHipster Fake Book (Objective-C)\"\nauthor: Mattt\nsummary: \"Over 200 code s"
  },
  {
    "path": "collections/en/_books/flight-school-guide-to-swift-codable.md",
    "chars": 522,
    "preview": "---\nname: flight-school-guide-to-swift-codable\ntitle: Flight School Guide to Swift Codable\nshort_title: Flight School\nsu"
  },
  {
    "path": "collections/en/_books/flight-school-guide-to-swift-numbers.md",
    "chars": 520,
    "preview": "---\nname: flight-school-guide-to-swift-numbers\ntitle: Flight School Guide to Swift Numbers\nshort_title: Flight School\nsu"
  },
  {
    "path": "collections/en/_books/flight-school-guide-to-swift-strings.md",
    "chars": 529,
    "preview": "---\nname: flight-school-guide-to-swift-strings\ntitle: Flight School Guide to Swift Strings\nshort_title: Flight School\nsu"
  },
  {
    "path": "collections/en/_books/nshipster.md",
    "chars": 654,
    "preview": "---\nname: nshipster\ntitle: \"NSHipster: Obscure Topics in Objective-C, Swift, & Cocoa\"\nshort_title: \"NSHipster\"\nsub_title"
  },
  {
    "path": "collections/es/_authors/croath-liu.md",
    "chars": 394,
    "preview": "---\ntitle: Croath Liu\n\nname: Croath Liu\nemail: Croath.Liu@gmail.com\nurl: https://twitter.com/cr0ath\ntwitter: cr0ath\ngith"
  },
  {
    "path": "collections/es/_authors/delisa-mason.md",
    "chars": 394,
    "preview": "---\ntitle: Delisa Mason\n\nname: Delisa Mason\nemail: delisa.mason@gmail.com\nurl: https://twitter.com/kattrali\ntwitter: kat"
  },
  {
    "path": "collections/es/_authors/jack-flintermann.md",
    "chars": 311,
    "preview": "---\ntitle: Jack Flintermann\n\nname: Jack Flintermann\nemail: jack@stripe.com\nurl: https://twitter.com/jflinter\ntwitter: jf"
  },
  {
    "path": "collections/es/_authors/jordan-morgan.md",
    "chars": 609,
    "preview": "---\ntitle: Jordan Morgan\n\nname: Jordan Morgan\nemail: info@dreaminginbinary.co\nurl: https://dreaminginbinary.co\ntwitter: "
  },
  {
    "path": "collections/es/_authors/mattt.md",
    "chars": 547,
    "preview": "---\ntitle: Mattt\n\nname: Mattt\nemail: mattt@nshipster.com\nurl: https://twitter.com/mattt\ntwitter: mattt\ngithub: mattt\ngoo"
  },
  {
    "path": "collections/es/_authors/mike-lazer-walker.md",
    "chars": 505,
    "preview": "---\ntitle: Mike Lazer-Walker\n\nname: Mike Lazer-Walker\nemail: michael@lazerwalker.com\nurl: https://twitter.com/lazerwalke"
  },
  {
    "path": "collections/es/_authors/natasha-murashev.md",
    "chars": 540,
    "preview": "---\ntitle: Natasha Murashev\n\nname: Natasha Murashev\nemail: natasha@natashatherobot.com\nurl: https://twitter.com/NatashaT"
  },
  {
    "path": "collections/es/_authors/nate-cook.md",
    "chars": 418,
    "preview": "---\ntitle: Nate Cook\n\nname: Nate Cook\nemail: nate@nshipster.com\nurl: https://twitter.com/nnnnnnnn\ntwitter: nnnnnnnn\ngith"
  },
  {
    "path": "collections/es/_books/01-nshipster-swift.md",
    "chars": 634,
    "preview": "---\nname: nshipster-swift\ntitle: \"NSHipster: Obscure Topics in Cocoa & Swift\"\nshort_title: \"NSHipster, Second Edition\"\ns"
  },
  {
    "path": "collections/es/_books/02-cfhipsterref.md",
    "chars": 734,
    "preview": "---\nname: cfhipsterref\ntitle: \"CFHipsterRef: Low-Level Programming on iOS & OS X\"\nshort_title: \"CFHipsterRef\"\nsub_title:"
  },
  {
    "path": "collections/es/_books/03-nshipster-fake-book-objective-c.md",
    "chars": 530,
    "preview": "---\nname: \"nshipster-fake-book-objective-c\"\ntitle: \"The NSHipster Fake Book (Objective-C)\"\nauthor: Mattt\nsummary: \"Over "
  },
  {
    "path": "collections/es/_translators/juan-fernandez-sagasti.md",
    "chars": 447,
    "preview": "---\ntitle: Juan F. Sagasti\nname: Juan F. Sagasti\nurl: https://theam.io\ntwitter: https://www.twitter.com/jfsagasti\ngithub"
  },
  {
    "path": "collections/fr/_authors/croath-liu.md",
    "chars": 394,
    "preview": "---\ntitle: Croath Liu\n\nname: Croath Liu\nemail: Croath.Liu@gmail.com\nurl: https://twitter.com/cr0ath\ntwitter: cr0ath\ngith"
  },
  {
    "path": "collections/fr/_authors/delisa-mason.md",
    "chars": 394,
    "preview": "---\ntitle: Delisa Mason\n\nname: Delisa Mason\nemail: delisa.mason@gmail.com\nurl: https://twitter.com/kattrali\ntwitter: kat"
  },
  {
    "path": "collections/fr/_authors/jack-flintermann.md",
    "chars": 311,
    "preview": "---\ntitle: Jack Flintermann\n\nname: Jack Flintermann\nemail: jack@stripe.com\nurl: https://twitter.com/jflinter\ntwitter: jf"
  },
  {
    "path": "collections/fr/_authors/jordan-morgan.md",
    "chars": 609,
    "preview": "---\ntitle: Jordan Morgan\n\nname: Jordan Morgan\nemail: info@dreaminginbinary.co\nurl: https://dreaminginbinary.co\ntwitter: "
  },
  {
    "path": "collections/fr/_authors/mattt.md",
    "chars": 547,
    "preview": "---\ntitle: Mattt\n\nname: Mattt\nemail: mattt@nshipster.com\nurl: https://twitter.com/mattt\ntwitter: mattt\ngithub: mattt\ngoo"
  },
  {
    "path": "collections/fr/_authors/mike-lazer-walker.md",
    "chars": 505,
    "preview": "---\ntitle: Mike Lazer-Walker\n\nname: Mike Lazer-Walker\nemail: michael@lazerwalker.com\nurl: https://twitter.com/lazerwalke"
  },
  {
    "path": "collections/fr/_authors/natasha-murashev.md",
    "chars": 540,
    "preview": "---\ntitle: Natasha Murashev\n\nname: Natasha Murashev\nemail: natasha@natashatherobot.com\nurl: https://twitter.com/NatashaT"
  },
  {
    "path": "collections/fr/_authors/nate-cook.md",
    "chars": 418,
    "preview": "---\ntitle: Nate Cook\n\nname: Nate Cook\nemail: nate@nshipster.com\nurl: https://twitter.com/nnnnnnnn\ntwitter: nnnnnnnn\ngith"
  },
  {
    "path": "collections/fr/_books/01-nshipster-swift.md",
    "chars": 634,
    "preview": "---\nname: nshipster-swift\ntitle: \"NSHipster: Obscure Topics in Cocoa & Swift\"\nshort_title: \"NSHipster, Second Edition\"\ns"
  },
  {
    "path": "collections/fr/_books/02-cfhipsterref.md",
    "chars": 734,
    "preview": "---\nname: cfhipsterref\ntitle: \"CFHipsterRef: Low-Level Programming on iOS & OS X\"\nshort_title: \"CFHipsterRef\"\nsub_title:"
  },
  {
    "path": "collections/fr/_books/03-nshipster-fake-book-objective-c.md",
    "chars": 530,
    "preview": "---\nname: \"nshipster-fake-book-objective-c\"\ntitle: \"The NSHipster Fake Book (Objective-C)\"\nauthor: Mattt\nsummary: \"Over "
  },
  {
    "path": "collections/fr/_translators/vincent-pradeilles.md",
    "chars": 356,
    "preview": "---\ntitle: Vincent \nname: Vincent Pradeilles\ntwitter: https://www.twitter.com/v_pradeilles\ngithub: https://github.com/vi"
  },
  {
    "path": "collections/ko/_authors/croath-liu.md",
    "chars": 394,
    "preview": "---\ntitle: Croath Liu\n\nname: Croath Liu\nemail: Croath.Liu@gmail.com\nurl: https://twitter.com/cr0ath\ntwitter: cr0ath\ngith"
  },
  {
    "path": "collections/ko/_authors/delisa-mason.md",
    "chars": 391,
    "preview": "---\ntitle: Delisa Mason\n\nname: Delisa Mason\nemail: delisa.mason@gmail.com\nurl: https://twitter.com/kattrali\ntwitter: kat"
  },
  {
    "path": "collections/ko/_authors/jack-flintermann.md",
    "chars": 311,
    "preview": "---\ntitle: Jack Flintermann\n\nname: Jack Flintermann\nemail: jack@stripe.com\nurl: https://twitter.com/jflinter\ntwitter: jf"
  },
  {
    "path": "collections/ko/_authors/jemmons.md",
    "chars": 318,
    "preview": "---\ntitle: \"@jemmons\"\nname: jemmons\nurl: https://figure.ink\ntwitter: jemmons\ngithub: jemmons\nimage: jemmons.jpg\n---\n\nJos"
  },
  {
    "path": "collections/ko/_authors/mattt.md",
    "chars": 547,
    "preview": "---\ntitle: Mattt\n\nname: Mattt\nemail: mattt@nshipster.com\nurl: https://twitter.com/mattt\ntwitter: mattt\ngithub: mattt\ngoo"
  },
  {
    "path": "collections/ko/_authors/mike-lazer-walker.md",
    "chars": 505,
    "preview": "---\ntitle: Mike Lazer-Walker\n\nname: Mike Lazer-Walker\nemail: michael@lazerwalker.com\nurl: https://twitter.com/lazerwalke"
  },
  {
    "path": "collections/ko/_authors/natasha-murashev.md",
    "chars": 540,
    "preview": "---\ntitle: Natasha Murashev\n\nname: Natasha Murashev\nemail: natasha@natashatherobot.com\nurl: https://twitter.com/NatashaT"
  },
  {
    "path": "collections/ko/_authors/nate-cook.md",
    "chars": 418,
    "preview": "---\ntitle: Nate Cook\n\nname: Nate Cook\nemail: nate@nshipster.com\nurl: https://twitter.com/nnnnnnnn\ntwitter: nnnnnnnn\ngith"
  },
  {
    "path": "collections/ko/_books/01-nshipster-swift.md",
    "chars": 634,
    "preview": "---\nname: nshipster-swift\ntitle: \"NSHipster: Obscure Topics in Cocoa & Swift\"\nshort_title: \"NSHipster, Second Edition\"\ns"
  },
  {
    "path": "collections/ko/_books/02-cfhipsterref.md",
    "chars": 734,
    "preview": "---\nname: cfhipsterref\ntitle: \"CFHipsterRef: Low-Level Programming on iOS & OS X\"\nshort_title: \"CFHipsterRef\"\nsub_title:"
  },
  {
    "path": "collections/ko/_books/03-nshipster-fake-book-objective-c.md",
    "chars": 530,
    "preview": "---\nname: \"nshipster-fake-book-objective-c\"\ntitle: \"The NSHipster Fake Book (Objective-C)\"\nauthor: Mattt\nsummary: \"Over "
  },
  {
    "path": "collections/ko/_translators/pilgwon.md",
    "chars": 565,
    "preview": "---\ntitle: 김필권\n\nname: 김필권\nemail: rlavlfrnjs12@gmail.com\nurl: https://blog.pilgwon.app\ngithub: pilgwon\ntwitter: pilgwon\ni"
  },
  {
    "path": "collections/ru/_authors/croath-liu.md",
    "chars": 394,
    "preview": "---\ntitle: Croath Liu\n\nname: Croath Liu\nemail: Croath.Liu@gmail.com\nurl: https://twitter.com/cr0ath\ntwitter: cr0ath\ngith"
  },
  {
    "path": "collections/ru/_authors/delisa-mason.md",
    "chars": 394,
    "preview": "---\ntitle: Delisa Mason\n\nname: Delisa Mason\nemail: delisa.mason@gmail.com\nurl: https://twitter.com/kattrali\ntwitter: kat"
  },
  {
    "path": "collections/ru/_authors/jack-flintermann.md",
    "chars": 311,
    "preview": "---\ntitle: Jack Flintermann\n\nname: Jack Flintermann\nemail: jack@stripe.com\nurl: https://twitter.com/jflinter\ntwitter: jf"
  },
  {
    "path": "collections/ru/_authors/jordan-morgan.md",
    "chars": 609,
    "preview": "---\ntitle: Jordan Morgan\n\nname: Jordan Morgan\nemail: info@dreaminginbinary.co\nurl: https://dreaminginbinary.co\ntwitter: "
  },
  {
    "path": "collections/ru/_authors/mattt.md",
    "chars": 547,
    "preview": "---\ntitle: Mattt\n\nname: Mattt\nemail: mattt@nshipster.com\nurl: https://twitter.com/mattt\ntwitter: mattt\ngithub: mattt\ngoo"
  },
  {
    "path": "collections/ru/_authors/mike-lazer-walker.md",
    "chars": 505,
    "preview": "---\ntitle: Mike Lazer-Walker\n\nname: Mike Lazer-Walker\nemail: michael@lazerwalker.com\nurl: https://twitter.com/lazerwalke"
  },
  {
    "path": "collections/ru/_authors/natasha-murashev.md",
    "chars": 540,
    "preview": "---\ntitle: Natasha Murashev\n\nname: Natasha Murashev\nemail: natasha@natashatherobot.com\nurl: https://twitter.com/NatashaT"
  },
  {
    "path": "collections/ru/_authors/nate-cook.md",
    "chars": 418,
    "preview": "---\ntitle: Nate Cook\n\nname: Nate Cook\nemail: nate@nshipster.com\nurl: https://twitter.com/nnnnnnnn\ntwitter: nnnnnnnn\ngith"
  },
  {
    "path": "collections/ru/_books/01-nshipster-swift.md",
    "chars": 634,
    "preview": "---\nname: nshipster-swift\ntitle: \"NSHipster: Obscure Topics in Cocoa & Swift\"\nshort_title: \"NSHipster, Second Edition\"\ns"
  },
  {
    "path": "collections/ru/_books/02-cfhipsterref.md",
    "chars": 734,
    "preview": "---\nname: cfhipsterref\ntitle: \"CFHipsterRef: Low-Level Programming on iOS & OS X\"\nshort_title: \"CFHipsterRef\"\nsub_title:"
  },
  {
    "path": "collections/ru/_books/03-nshipster-fake-book-objective-c.md",
    "chars": 530,
    "preview": "---\nname: \"nshipster-fake-book-objective-c\"\ntitle: \"The NSHipster Fake Book (Objective-C)\"\nauthor: Mattt\nsummary: \"Over "
  },
  {
    "path": "collections/zh-Hans/_authors/croath-liu.md",
    "chars": 193,
    "preview": "---\ntitle: Croath Liu\n\nname: \"Croath Liu\"\nemail: Croath.Liu@gmail.com\nurl: https://croath.com\ntwitter: croath\ngithub: cr"
  },
  {
    "path": "collections/zh-Hans/_authors/delisa-mason.md",
    "chars": 394,
    "preview": "---\ntitle: Delisa Mason\n\nname: Delisa Mason\nemail: delisa.mason@gmail.com\nurl: https://twitter.com/kattrali\ntwitter: kat"
  },
  {
    "path": "collections/zh-Hans/_authors/jack-flintermann.md",
    "chars": 311,
    "preview": "---\ntitle: Jack Flintermann\n\nname: Jack Flintermann\nemail: jack@stripe.com\nurl: https://twitter.com/jflinter\ntwitter: jf"
  },
  {
    "path": "collections/zh-Hans/_authors/mattt.md",
    "chars": 547,
    "preview": "---\ntitle: Mattt\n\nname: Mattt\nemail: mattt@nshipster.com\nurl: https://twitter.com/mattt\ntwitter: mattt\ngithub: mattt\ngoo"
  },
  {
    "path": "collections/zh-Hans/_authors/mike-lazer-walker.md",
    "chars": 505,
    "preview": "---\ntitle: Mike Lazer-Walker\n\nname: Mike Lazer-Walker\nemail: michael@lazerwalker.com\nurl: https://twitter.com/lazerwalke"
  },
  {
    "path": "collections/zh-Hans/_authors/natasha-murashev.md",
    "chars": 540,
    "preview": "---\ntitle: Natasha Murashev\n\nname: Natasha Murashev\nemail: natasha@natashatherobot.com\nurl: https://twitter.com/NatashaT"
  },
  {
    "path": "collections/zh-Hans/_authors/nate-cook.md",
    "chars": 418,
    "preview": "---\ntitle: Nate Cook\n\nname: Nate Cook\nemail: nate@nshipster.com\nurl: https://twitter.com/nnnnnnnn\ntwitter: nnnnnnnn\ngith"
  },
  {
    "path": "collections/zh-Hans/_books/01-nshipster-swift.md",
    "chars": 593,
    "preview": "---\nname: nshipster-swift\ntitle: \"NSHipster: Obscure Topics in Cocoa & Swift\"\nshort_title: \"NSHipster, Second Edition\"\ns"
  },
  {
    "path": "collections/zh-Hans/_books/02-cfhipsterref.md",
    "chars": 695,
    "preview": "---\nname: cfhipsterref\ntitle: \"CFHipsterRef: Low-Level Programming on iOS & OS X\"\nshort_title: \"CFHipsterRef\"\nsub_title:"
  },
  {
    "path": "collections/zh-Hans/_books/03-nshipster-fake-book-objective-c.md",
    "chars": 541,
    "preview": "---\nname: \"nshipster-fake-book-objective-c\"\ntitle: \"The NSHipster Fake Book (Objective-C)\"\nauthor: Mattt\nsummary: \"Over "
  },
  {
    "path": "collections/zh-Hans/_translators/Candyan.md",
    "chars": 174,
    "preview": "---\ntitle: Candyan\n\nname: \"Candyan\"\nemail: liuyanhp@gmail.com\nurl: https://candyan.com\ngithub: candyan\n---\n\n[Candyan](ht"
  },
  {
    "path": "collections/zh-Hans/_translators/andrew-yang.md",
    "chars": 235,
    "preview": "---\ntitle: Andrew Yang\n\nname: \"Andrew Yang\"\nemail: younthu@gmail.com\nurl: http://blog.ilibrary.me\ngithub: younthu\n---\n\ni"
  },
  {
    "path": "collections/zh-Hans/_translators/april-peng.md",
    "chars": 143,
    "preview": "---\ntitle: April Peng\n\nname: \"April Peng\"\nemail: april.pyl@gmail.com\nurl: http://aprilme.com\ngithub: aprilnov\n---\n\n做 iOS"
  },
  {
    "path": "collections/zh-Hans/_translators/chester-liu.md",
    "chars": 303,
    "preview": "---\ntitle: Chester Liu\n\nname: \"Chester Liu\"\nemail: skyline75489@outlook.com\ngravatar: 64edfde4a55cef57f9d47d42acbcaf48\ng"
  },
  {
    "path": "collections/zh-Hans/_translators/croath-liu.md",
    "chars": 212,
    "preview": "---\ntitle: Croath Liu\n\nname: \"Croath Liu\"\nemail: Croath.Liu@gmail.com\nurl: https://croath.com\ntwitter: croath\ngithub: cr"
  },
  {
    "path": "collections/zh-Hans/_translators/david-liu.md",
    "chars": 171,
    "preview": "---\ntitle: David Liu\n\nname: \"David Liu\"\nemail: xingruo.liu@gmail.com\ntwitter: davydliu\ngithub: davydliu\ngravatar: 7085ef"
  },
  {
    "path": "collections/zh-Hans/_translators/henry-lee.md",
    "chars": 166,
    "preview": "---\ntitle: Henry Lee\n\nname: \"Henry Lee\"\nemail: leelejia@gmail.com\nurl: http://lejia.li\ngithub: lilejia\ngravatar: 97b4cc7"
  },
  {
    "path": "collections/zh-Hans/_translators/ricky-tan.md",
    "chars": 529,
    "preview": "---\ntitle: Ricky Tan\n\nname: \"Ricky Tan\"\nemail: ricky.tan.xin@gmail.com\nurl: https://xcoder.tips\ngravatar: 71f0bbfbb3b0bc"
  },
  {
    "path": "collections/zh-Hans/_translators/steven-wang.md",
    "chars": 186,
    "preview": "---\ntitle: Steven Wang\n\nname: \"Steven Wang\"\nemail: mobilefellow@outlook.com\ngithub: mobilefellow\ngravatar: d05f1e723ced1"
  },
  {
    "path": "collections/zh-Hans/_translators/tiny-tian.md",
    "chars": 194,
    "preview": "---\ntitle: change2hao\nname: \"Tiny Tian\"\nemail: lwtiandev@gmail.com\nurl: http://devtian.me\ngravatar: 5b77b0456447e9040bc3"
  },
  {
    "path": "contribute.json",
    "chars": 268,
    "preview": "{\n  \"name\": \"NSHipster.com\",\n  \"description\": \"A journal of the overlooked bits in Objective-C, Swift, and Cocoa. Update"
  },
  {
    "path": "feed.xml",
    "chars": 2636,
    "preview": "---\nlayout: null\n---\n\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\" xml:lang=\"{{ site"
  },
  {
    "path": "flight-school.md",
    "chars": 3424,
    "preview": "---\nlayout: post\ndate: 2019-02-01\ntitle: Flight School\nauthor: Mattt\ncategory: \"\"\nexcerpt: >-\n  A new book series for ad"
  },
  {
    "path": "index.html",
    "chars": 1624,
    "preview": "---\ntitle: NSHipster\npermalink: /\n---\n\n{% assign sorted_posts = site.posts | sort: 'updated_on' | reverse %}\n{% assign l"
  },
  {
    "path": "return.md",
    "chars": 10087,
    "preview": "---\nlayout: post\ndate: 2018-07-09\ntitle: Returning to Our Regularly Scheduled Programming\nauthor: Mattt\ncategory: \"\"\nret"
  },
  {
    "path": "sitemap.xml",
    "chars": 1080,
    "preview": "---\nlayout: null\n---\n\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instanc"
  },
  {
    "path": "status.md",
    "chars": 2064,
    "preview": "---\nlayout: page\ntitle: Article Status\npermalink: /status\nretired: true\n---\n\nThe common swift (_Apus apus_) can travel a"
  }
]

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

About this extraction

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

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

Copied to clipboard!