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 ================================================ #f8f7f5 ================================================ 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%o, %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? @NSHipster or on GitHub. license: NSHipster.com is released under a Creative Commons BY-NC License. ================================================ 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? @NSHipster y on GitHub. license: NSHipster.com tiene licencia de Creative Commons BY-NC License. ================================================ 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 ? @NSHipster et sur GitHub. license: NSHipster est publié sous licence Creative Commons BY-NC License. ================================================ 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: 궁금하거나 잘못된 내용이 있나요? @NSHipster 또는 GitHub 에 알려주세요. license: NSHipster는 Creative Commons BY-NC에 따라 라이센스가 부여됩니다. ================================================ 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: Вопросов? Поправки? @NSHipster или на GitHub. license: NSHipster выпущен под лицензией Лицензия Creative Commons BY-NC. ================================================ 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: 除非另有声明、本网站采用知识共享「署名-非商业性使用 3.0 中国大陆」许可协议授权。 ================================================ FILE: _includes/book.html ================================================ {% assign book = site.books | where:"name", include.book | first %}
{{ book.title }} {% include json-ld/book.html %}
================================================ 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 %}
{% case include.role %} {% when 'author' %} {% t written_by %} {% when 'translator' %} {% t translated_by %} {% endcase %} {% if contributor %} {% if contributor.image %} {{ contributor.name }} {% else %} {% endif %}
{{ contributor.name }} {{ contributor.content | markdownify }}
{% endif %}
================================================ FILE: _includes/json-ld/article.html ================================================ ================================================ FILE: _includes/json-ld/book.html ================================================ ================================================ FILE: _includes/json-ld/breadcrumblist.html ================================================ ================================================ FILE: _includes/json-ld/organization.html ================================================ ================================================ FILE: _includes/json-ld/website.html ================================================ ================================================ FILE: _includes/promo.html ================================================ {% assign book = site.books | where:"name", include.book | first %}
Now Available
{% include book.html book=book.name %}
$9+

{{ book.sub_title }}

{{ book.edition }}

{{ book.summary | markdownify }} Buy Now on Gumroad
================================================ FILE: _layouts/author.html ================================================ --- layout: default --- {% assign author = page %} {% capture date_format %}{% t format.date %}{% endcapture %}
{% if author.image %} {{ author.name }} {% elsif author.gravatar %} {% endif %}

{{ author.name }}

{{ author.content | markdownify }}

{% t articles %}

    {% for post in site.posts %} {% if post.author == author.name or post.authors contains author.name %}
  1. {{ post.title }} {{ post.excerpt | markdownify }}
  2. {% endif %} {% endfor %}
================================================ FILE: _layouts/default.html ================================================ {% if page.id %} {{ page.title | strip_html | escape | strip }} - {{ site.title }} {% else %} {{ page.title | strip_html | escape | strip }} {% endif %} {% asset "screen.css" @inline %} {% if author and author.twitter %} {% endif %} {% if page.id %} {% else %} {% endif %} {% if page.id %} {% else %} {% endif %} {% for translation in page.translations %} {% assign translation_url = site.domains[translation] %} {% if translation_url %} {% endif %} {% endfor %} {% if page.url == '/' %} {% endif %} {% if page.next %} {% endif %} {% if page.previous %} {% endif %} {% if page.retired %} {% endif %} {% if site.url == "https://nsmutablehipster.com" %} {% endif %}
{% if page.url == "/" %}

{{ site.description | markdownify | unwrap }}

{% endif %}
{{ content }}
{% 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 %} ================================================ FILE: _layouts/error.html ================================================ --- layout: default ---

NSError

{{ content }}
================================================ FILE: _layouts/page.html ================================================ --- layout: default ---

{{ page.title | escape | camel_break }}

{{ content }}
================================================ 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 %}

{{ page.title | strip_html | escape | camel_break }}

{{ content }}
{% include json-ld/breadcrumblist.html %} ================================================ FILE: _layouts/translator.html ================================================ --- layout: default --- {% assign translator = page %} {% capture date_format %}{% t format.date %}{% endcapture %}
{% if translator.image %} {{ translator.name }} {% elsif translator.gravatar %} {% endif %}

{{ translator.name }}

{{ translator.content | markdownify }}

{% t articles %}

    {% for post in site.posts %} {% if post.translator == translator.name or post.translators contains translator.name %}
  1. {{ post.title }} {{ post.excerpt | markdownify }}
  2. {% endif %} {% endfor %}
================================================ 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 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", '') 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\\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\\1') 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(/<#\s*(.*?)\s*#>/, '\\1') 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(%()) 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(%(
)).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('
') 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(%( )) 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(%()) 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; } } ode-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: 3rd 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 --- {{ site.time | date_to_xmlschema }} {{ page.url | absolute_url | xml_escape }} {{ site.title | strip_html | xml_escape | strip }} {{ site.description | markdownify | strip_html }} {% if site.author %} {{ site.author.name | default: site.author | xml_escape }} {% if site.author.email %} {{ site.author.email | xml_escape }} {% endif %} {% if site.author.url %} {{ site.author.url | absolute_url | xml_escape }} {% endif %} {% endif %} {% assign sorted_posts = site.posts | sort: 'updated_on' | reverse %} {% for post in sorted_posts limit: 10 %} {{ post.title | smartify | strip_html | normalize_whitespace | xml_escape }} {{ post.date | date_to_xmlschema }} {{ post.last_revised_on | default: post.date | date_to_xmlschema }} {{ post.id | absolute_url | xml_escape }} {{ post.content | strip | xml_escape }} {% assign author = site.authors | where:"name", post.author | first | default: site.author %} {{ author.name | default: "" | xml_escape }} {% if author.email %} {{ author.email | xml_escape }} {% endif %} {% if author.url %} {{ author.url | absolute_url | xml_escape }} {% endif %} {% if post.category and post.category != empty %} {% endif %} {% for tag in post.tags %} {% endfor %} {% if post.excerpt and post.excerpt != empty %} {{ post.excerpt | markdownify | normalize_whitespace | xml_escape }} {% endif %} {% endfor %} ================================================ 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"}
{% 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" %}
{:/} {% 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 %}
{% if sorted_posts.size > 3 %}

{% t recent_articles %}

{% endif %} ================================================ FILE: return.md ================================================ --- layout: post date: 2018-07-09 title: Returning to Our Regularly Scheduled Programming author: Mattt category: "" retired: true excerpt: NSHipster returns to weekly publication, with new articles every Monday, updates every Wednesday, and new trivia questions every Friday. status: swift: n/a --- When the iPhone SDK first came out, there was a disconnect between how futuristic the iPhone was and how, well... _not_ Objective-C was. For many new developers, Objective-C was seen as an ugly, obscure language --- something you merely put up with in exchange for the privilege of developing on this amazing new platform. That was certainly the case for me when I wrote my first app. But over time, I learned to appreciate the beauty of the language and its frameworks. I started NSHipster in July 2012 as a way to share my newfound passion. At the time, the term "hipster" was tossed around frequently as a casual pejorative for people who ironically enjoyed obscure or bad things. What better term for someone excited about Objective-C, right? Rather than being ashamed or annoyed by the language we used in our day-to-day, it felt good to turn it around and say "Oh, this? It's an obscure API. You've probably never heard of it." --- Today marks six years since I first launched NSHipster (which is a big milestone for all of you out there counting in [base-6](https://www.seximal.net)). To mark the occasion, I'm very excited to announce my return as the managing editor of NSHipster. I'm extremely thankful to [Nate Cook](https://nshipster.com/authors/nate-cook/) for his stewardship of NSHipster. During my tenure at Apple from 2015 to 2018, I was unable to contribute to the site; it's entirely thanks to him that NSHipster exists today. His contributions to Swift are extraordinary and immeasurable, and we all benefit immensely as a community from his work. ## What to Expect **NSHipster is a celebration of small details that come from big ideas.** It stands at that fabled intersection of liberal arts and technology, where we can collectively geek out about thoughtful abstractions and clever optimizations. Our focus will continue to be Objective-C and Swift, and Apple platforms like macOS and iOS. And we'll also look at any other languages or technologies that can help us make insanely great software. But most importantly, we'll be returning to a regular publishing schedule. Here's what that will look like: ### New Articles Every Monday Every Monday, I want you to be able to visit the site (or refresh your feed reader) and learn something new. It could be topical and directly applicable to what you're working on right now. It might be something you hadn't heard of before, and decide to research further. Or maybe its a different way of thinking about a problem. We'll start this week with an article that ostensibly falls into any of those three categories: [Swift GYB](https://nshipster.com/swift-gyb/) > This time around, > I'd like to open things up more for external contributors. > If you have a topic that you'd like to write about on NSHipster, > please submit a quick, 3–5 sentence, pitch to > [mattt@nshipster.com](mailto:mattt@nshipster.com). ### Updated Articles Every Wednesday With nearly 150 articles dating as far back as 2012, there's a lot of material on NSHipster that needs to be revisited. Out of date, sample code (mostly Swift), changes in behavior that impact the documentation, entirely new APIs that need to be addressed... We'll have updates every Wednesday until we run out of outdated material (😂). ### Trivia Questions Every Friday The annual NSHipster pub quizzes at WWDC was one of our favorite events of the year. Hundreds of developers came out and formed small teams (with hilarious team names) to answer trivia questions about APIs, language features, and Apple lore. For example, here's one of the tougher question from the [last quiz we did](https://nshipster.com/nshipster-quiz-8/): --- **Question**: After Chris Lattner, who was the second contributor to Swift? {::nomarkdown}
Answer

Doug Gregor

{:/} --- We're excited to make these kinds of trivia questions a regular feature and share them with everyone. [Follow us on Twitter](https://twitter.com/nshipster) to take our weekly NSHipster quiz. ## What's Different Right Now You might have noticed a few changes since your last visit. Here's a recap of what we've been working on for today's announcement: ### Upgraded Site Infrastructure A lot's changed about the internet since NSHipster first launched. The web is significantly faster and more secure, thanks to new standards like HTTP/2 and the widespread adoption of SSL. In the weeks leading up to today's relaunch, I quietly got to work upgrading NSHipster's tech stack: - Both [NSHipster.com](https://nshipster.com) and [NSHipster.cn](https://nshipster.cn) are now hosted by [Netlify](https://www.netlify.com), which has been an absolute joy to use. Everything is served from a global CDN (using HTTP/2 if your browser supports it) to ensure that the site loads fast, no matter where you are. - NSHipster is now served exclusively using HTTPS thanks to [Let's Encrypt](https://letsencrypt.org). - Server responses now include fancy new security headers like [Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) and [Strict-Transport-Security](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security). - All of the image assets were re-optimized with the latest version of [ImageOptim](https://imageoptim.com/mac), which reduced file size by ~30% across the board. - Critical CSS is now inlined to optimize the site's [Critical Rendering Path](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/). - And most important of all, the site now [supports the iPhone X notch](https://webkit.org/blog/7929/designing-websites-for-iphone-x/). If you notice anything amiss, like a missing image or a page that isn't rendering as you expected, please [let us know](https://github.com/nshipster/nshipster.com)! ### Removed Site Search In the process of upgrading the site's infrastructure, I ended up removing the search widget provided by [Swiftype](https://swiftype.com). I'm looking into a couple alternatives, but don't currently have any specific plans for bringing site search back. ### Retired Content Technology evolves quickly. And while I've tried to write mostly evergreen content on NSHipster, there are some articles that have become obsolete. For example, our article about [BackRow](https://nshipster.com/backrow/) is irrelevant now that the tvOS is available. These articles will live on in perpetuity at their original URLs, but they'll include a deprecation notice at the top and won't be displayed in the main site navigation. ## More Things to Look Forward To But that's not all --- in addition to new weekly articles, we have a lot of exciting things in the works: ### CFHipsterRef Update and Print Edition [CFHipsterRef](https://gum.co/cfhipsterref) was released on the eve of Swift's announcement at WWDC 2014. Although this new language gets most of our attention these days (what, with its cool name and fast bird logo), Objective-C and low-level technologies are still just as important as ever. Coming this fall, we'll be releasing a second edition CFHipsterRef with new and updated content. This will be a free update to everyone who ordered the first edition. (I also look forward to finally making good on a promise I made to release a print edition of the book) ### New Books I can't say too much yet, but I'm planning to have a something out by the end of the year. Stay tuned! > In the meantime, > check out [Flight School](https://flightdotschool.com). > It's a new, ongoing book series I'm working on > that's all about Swift. > Each book offers an in-depth look at essential topics > for intermediate and advanced developers. > > The first two books, > [Guide to Swift Codable](https://gumroad.com/l/codable) > and [Guide to Swift Numbers](https://gumroad.com/l/swift-numbers), > are both available for download, > with more on the way soon. ### More Tools and Experiments NSHipster is more than writing blog posts and books. It's also an opportunity to make fun and useful things for the community. One such project is [ASCIIwwdc](https://asciiwwdc.com), a site that offers searchable transcripts of WWDC sessions going back to 2010. It was recently updated with all of the sessions from 2017 and most from 2018, so if you haven't gotten around to watching this year's talks, you might find this to be a nice way to get up to speed quickly. Another example is [SwiftDoc](https://swiftdoc.org). Nate created this around the time that he took the reigns of NSHipster, and it's been an invaluable tool for understanding the complex type relationships in the Swift standard library. I've updated the site for Swift 4.2, and look forward to keeping it in sync going forward. Look out for more of these in the future! ### Conferences and Meetups Near You This fall, I'll have the honor of presenting at some of the best developer conferences of the year, in New York City, Logroño, Madrid, and Paris: - [try! Swift NYC](https://www.tryswift.co/events/2018/nyc/) • New York City, USA • September 4th & 5th - [NSSpain](https://2018.nsspain.com) • Logroño, Spain • September 12th – 14th - NSCoders Night • Madrid, Spain • September 11th - [FrenchKit](https://frenchkit.fr) • Paris, France • September 20th & 21st If you plan on attending any of these or will be in any of these cities when I'm there, [please get in touch](https://twitter.com/mattt) (my DMs are open). --- Thank you to everyone who's supported NSHipster over the past 6 years. We couldn't be more excited about what's to come. Until next time: May your code continue to compile and inspire. ================================================ FILE: sitemap.xml ================================================ --- layout: null --- {{ site.url }} {{ site.posts.first.date | date_to_xmlschema }} daily 1.0 {% for post in site.posts %} {% unless post.retired %} {{ post.url | absolute_url }} {{ post.updated_on | date_to_xmlschema }} yearly 0.9 {% endunless %} {% endfor %} {% for author in site.authors %} {{ author.url | absolute_url }} {% endfor %} {% for translator in site.translators %} {{ translator.url | absolute_url }} {% endfor %} ================================================ FILE: status.md ================================================ --- layout: page title: Article Status permalink: /status retired: true --- The common swift (_Apus apus_) can travel at speeds over 100km/h. The Swift programming language --- true to its name and namesake --- is similarly fast-moving, frequently introducing new language features and syntax rules. As a result, some of our articles may become incorrect or outdated over time. We do our best to keep things fresh, with new updates to existing articles made every week, and invite you to help us find and correct any mistakes you find by [opening a new issue on our GitHub repository](https://github.com/NSHipster/articles/issues/new). In the meantime, please consult the table below for guidance on when each of our articles was last updated, and which version of Swift it's targeting: {% assign sorted = site.posts | sort: 'title' %} {% for post in sorted %} {% endfor %}
"t.b.c." indicates that an article has not yet been translated to Swift
"n/a" notes that a Swift translation would not be useful or appropriate.
Article Swift Version Last Review
{{ post.title | camel_break }} {% if post.status.swift == "n/a" %} n/a {% elsif post.status.swift == "t.b.c." %} t.b.c. {% else %} {{ post.status.swift }} {% endif %} {% assign last_review = post.status.reviewed | default: post.date %} {% capture date_format %}{% t format.date %}{% endcapture %} {{ last_review | date: date_format }}
================================================ FILE: vendor/cache/twitter_cldr-6.7.0.gem ================================================ [File too large to display: 15.8 MB]