├── .github ├── CODEOWNERS ├── pull_request_template.md └── workflows │ ├── development.yml │ └── github-pages.yml ├── .gitignore ├── 404.html ├── CONTRIBUTING.md ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── _assets ├── fonts │ ├── FontAwesome.otf │ ├── JetBrainsMono-Regular.woff2 │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── images │ ├── benchee_html_graph_sample.png │ ├── chat-message-not-visible.png │ ├── debugger_1.png │ ├── debugger_2.png │ ├── debugger_3.png │ ├── debugger_4.png │ ├── default.jpg │ ├── documentation_1.png │ ├── documentation_2.png │ ├── favicons │ │ ├── android-chrome-144x144.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── mstile-150x150.png │ │ └── splash-512x512.png │ ├── game-ratings-bar-chart-selected.png │ ├── game-ratings-chart.png │ ├── kafka-flow-example.png │ ├── ld-ets-detail.png │ ├── ld-home.png │ ├── ld-metrics.png │ ├── ld-port-4000-detail.png │ ├── ld-port-detail.png │ ├── ld-ports.png │ ├── ld-process-detail.png │ ├── ld-processes.png │ ├── ld-request-logger.png │ ├── live-component-search-form-query-params.png │ ├── live-view-1.png │ ├── live-view-broadcasts-event.png │ ├── live-view-channel-join.png │ ├── live-view-channel-push.png │ ├── live-view-channel-register.png │ ├── live-view-connect-channel.png │ ├── live-view-front-end-update.png │ ├── live-view-handle-event.png │ ├── live-view-lookup-send-to-channel.png │ ├── live-view-messages-index.png │ ├── live-view-mount-render.png │ ├── live-view-mount-session-uuid.png │ ├── live-view-presence-1.png │ ├── live-view-presence-2.png │ ├── live-view-send-self.png │ ├── live-view-socket-connect.png │ ├── live-view-table.png │ ├── live_view.png │ ├── live_view_pub_sub.png │ └── og_image.jpg ├── javascripts │ ├── clipboard.min.js │ ├── copy.js │ ├── ie │ │ ├── html5shiv.js │ │ └── respond.min.js │ ├── jquery.min.js │ ├── main.js │ ├── skel.min.js │ ├── stickyfill.min.js │ ├── toc.js │ └── util.js └── stylesheets │ ├── base │ ├── _page.scss │ ├── _syntax.scss │ └── _typography.scss │ ├── components │ ├── _box.scss │ ├── _button.scss │ ├── _errors.scss │ ├── _features.scss │ ├── _form.scss │ ├── _icon.scss │ ├── _image.scss │ ├── _list.scss │ ├── _mini-posts.scss │ ├── _posts.scss │ ├── _section.scss │ └── _table.scss │ ├── dark.scss │ ├── ie8.scss │ ├── ie9.scss │ ├── layout │ ├── _banner.scss │ ├── _footer.scss │ ├── _header.scss │ ├── _main.scss │ ├── _menu.scss │ ├── _sidebar.scss │ └── _wrapper.scss │ ├── libs │ ├── _functions.scss │ ├── _mixins.scss │ ├── _skel.scss │ ├── _vars.scss │ └── font-awesome │ │ ├── _animated.scss │ │ ├── _bordered-pulled.scss │ │ ├── _core.scss │ │ ├── _fixed-width.scss │ │ ├── _icons.scss │ │ ├── _larger.scss │ │ ├── _list.scss │ │ ├── _mixins.scss │ │ ├── _path.scss │ │ ├── _rotated-flipped.scss │ │ ├── _screen-reader.scss │ │ ├── _stacked.scss │ │ ├── _variables.scss │ │ └── font-awesome.scss │ └── main.scss ├── _config.yml ├── _config_dev.yml ├── _data ├── blog-meta.yml ├── contents.yml ├── contributors.yml ├── locales │ ├── en.yml │ ├── fr.yml │ └── ru.yml └── redirects.yml ├── _includes ├── _head.html ├── _sidebar.html ├── article-preview.html ├── contributor-profile.html ├── function-displayAuthor ├── function-getArticle.html ├── function-getCategoryMeta ├── function-getContributor ├── function-getTagMeta ├── report.html ├── section-author.html ├── section-home-banner.html ├── section-home-blog-posts.html ├── section-home-helloworld.html ├── section-pagination.html ├── section-prevnext.html ├── section-related.html ├── section-sidebar-contact.html ├── section-sidebar-langs.html ├── section-sidebar-menu.html ├── section-sidebar-search.html ├── share-icons.html ├── social.html ├── toc.html └── version.html ├── _layouts ├── archive.html ├── blog.html ├── default.html ├── home.html ├── page.html └── post.html ├── _plugins └── haskell_school │ ├── generator.rb │ ├── redirects.rb │ └── translation_report.rb ├── app.json ├── blog-archive-categories.html ├── blog-archive-tags.html ├── blog-archive-years.html ├── blog.html ├── config.ru ├── contributors.html ├── en ├── index.md └── lessons │ ├── basics │ ├── basics.md │ ├── containers.md │ ├── control-structures.md │ ├── functions.md │ ├── modules.md │ ├── operators.md │ └── pattern-matching.md │ └── typeclasses │ ├── comparison.md │ ├── enumeration.md │ ├── functors.md │ ├── iteration.md │ ├── monoids.md │ ├── numbers.md │ ├── string-representation.md │ └── what-are-typeclasses.md ├── feed.xml ├── fr └── index.md ├── manifest.json ├── robots.txt ├── ru └── index.md ├── script └── build.sh ├── serviceworker.js ├── shell.nix └── style ├── code.md ├── en_guide.md └── glossary.md /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Order alphabetically. 2 | # Order is important. The last matching pattern takes the most precedence. 3 | 4 | # Default owners for everything in the repo. 5 | # * @elixirschool/developers 6 | 7 | # en/ @elixirschool/english 8 | 9 | # es/ @elixirschool/spanish 10 | 11 | # fr/ @elixirschool/french 12 | 13 | # ru/ @elixirschool/russian 14 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Submitter checklist 2 | 3 | - [ ] My PR is related to \ 4 | - [ ] My PR follows the [code style](https://github.com/haskellfoundation/HaskellSchool/blob/development/style/code.md) 5 | - [ ] My PR follows the [style guide for my language](https://github.com/haskellfoundation/HaskellSchool/tree/development/style) 6 | - [ ] I have read and understood the [CONTRIBUTING guide](https://github.com/haskellfoundation/HaskellSchool/blob/development/CONTRIBUTING.md) 7 | -------------------------------------------------------------------------------- /.github/workflows/development.yml: -------------------------------------------------------------------------------- 1 | name: Haskell School Deployment 2 | on: 3 | pull_request: 4 | branches: 5 | - development 6 | push: 7 | branches: 8 | - development 9 | jobs: 10 | Build-With-Jekyll: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: helaili/jekyll-action@v2 15 | with: 16 | build_only: true 17 | -------------------------------------------------------------------------------- /.github/workflows/github-pages.yml: -------------------------------------------------------------------------------- 1 | name: Haskell School Deployment 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | github-pages: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: helaili/jekyll-action@v2 12 | with: 13 | token: ${{ secrets.GITHUB_TOKEN }} 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/ruby,jekyll,sass,vim,osx 2 | 3 | ### Ruby ### 4 | *.gem 5 | *.rbc 6 | /.config 7 | /coverage/ 8 | /InstalledFiles 9 | /pkg/ 10 | /spec/reports/ 11 | /spec/examples.txt 12 | /test/tmp/ 13 | /test/version_tmp/ 14 | /tmp/ 15 | 16 | ## Specific to RubyMotion: 17 | .dat* 18 | .repl_history 19 | build/ 20 | 21 | ## Documentation cache and generated files: 22 | /.yardoc/ 23 | /_yardoc/ 24 | /doc/ 25 | /rdoc/ 26 | 27 | ## Environment normalisation: 28 | /.bundle/ 29 | /vendor/bundle 30 | /lib/bundler/man/ 31 | 32 | # for a library or gem, you might want to ignore these files since the code is 33 | # intended to run in multiple environments; otherwise, check them in: 34 | # Gemfile.lock 35 | .ruby-version 36 | # .ruby-gemset 37 | 38 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 39 | .rvmrc 40 | 41 | 42 | ### Jekyll ### 43 | _site/ 44 | .sass-cache/ 45 | .jekyll-metadata 46 | .jekyll-cache/ 47 | 48 | ### Sass ### 49 | .sass-cache/ 50 | *.css.map 51 | .asset-cache/ 52 | 53 | ### Vim ### 54 | [._]*.s[a-w][a-z] 55 | [._]s[a-w][a-z] 56 | *.un~ 57 | Session.vim 58 | .netrwhist 59 | *~ 60 | 61 | 62 | ### OSX ### 63 | .DS_Store 64 | .AppleDouble 65 | .LSOverride 66 | 67 | # Icon must end with two \r 68 | Icon 69 | 70 | 71 | # Thumbnails 72 | ._* 73 | 74 | # Files that might appear in the root of a volume 75 | .DocumentRevisions-V100 76 | .fseventsd 77 | .Spotlight-V100 78 | .TemporaryItems 79 | .Trashes 80 | .VolumeIcon.icns 81 | 82 | # Directories potentially created on remote AFP share 83 | .AppleDB 84 | .AppleDesktop 85 | Network\ Trash\ Folder 86 | Temporary Items 87 | .apdisk 88 | 89 | # intelliJ idea And other editors 90 | .idea 91 | *.iml 92 | -------------------------------------------------------------------------------- /404.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Not found 3 | layout: default 4 | disable_transform: true 5 | lang: en 6 | permalink: 404.html 7 | --- 8 |
9 |
404
10 |
Looks like you are lost
11 |
12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | ## General 4 | Please ensure your pull request adheres to the following guidelines: 5 | 6 | * New lessons or improvements to existing lessons are welcome. 7 | * Please check your spelling and grammar. 8 | * Please adhere to our [style guides](./style) 9 | 10 | ## A Note on Lesson Versions 11 | 12 | All lessons should include the following front matter: 13 | 14 | ```markdown 15 | --- 16 | version: 2.0.0 17 | title: Basics 18 | --- 19 | ``` 20 | 21 | Change the `version` attribute according to the following rules: 22 | 23 | * MAJOR — You (re)wrote the whole thing. Your new content will need some translation. 24 | * MINOR — Added or removed some content, few sentences, etc. 25 | * PATCH — Spelling, typos. Probably not translated stuff. 26 | 27 | Fun fact! The version changes are necessary because we use that to programmatically determine and inform translators of new content that requires translation. 28 | 29 | Each language has a generated [Translation Report](https://school.haskell.org/fr/report/) 30 | 31 | ## Adding a New Lesson 32 | To add a new lesson, create the file under the appropriate directory in `en/lessons` (or `/lessons`) if you are not writing your new lesson in English). 33 | 34 | Then, update `_data/content.yml` with the name of your new lesson under the appropriate section. 35 | 36 | If you've added a new section (i.e. a new directory under `/lessons`), add the section name under the `sections` key of `_data/locales/en.yml` or `_data/locales/.yml` if the section + lesson you added are not in English. 37 | 38 | Thank you for your contributions! 39 | 40 | 41 | ## Adding a new Language 42 | 43 | 1. Create a folder using the ISO language code (e.g. ja, zh-hans, es, et al) with lesson subfolders. 44 | Not sure which language code to use? 45 | Check [here](https://www.loc.gov/standards/iso639-2/php/English_list.php) for the official list. 46 | 47 | ```shell 48 | $ cd haskellschool 49 | $ mkdir -p ja/lessons/{basics,advanced,specifics,libraries} 50 | $ touch ja/lessons/{basics,advanced,specifics,libraries}/.gitkeep 51 | ``` 52 | 53 | 1. Add your language code to `interlang` in `_data/locales/en.yml`: 54 | 55 | ```yaml 56 | interlang: 57 | ja: Japanese 58 | ``` 59 | 60 | 1. Create a locale file for your new language using `_data/locales/en.yml` as a guide: 61 | 62 | ```shell 63 | $ touch _data/locales/ja.yml 64 | ``` 65 | 66 | 1. If the new language is RTL (right-to-left) it should be added to the `rtl_languages` list in `config.yml`: 67 | 68 | ```yaml 69 | script_direction: rtl 70 | ``` 71 | 72 | ## Gotcha 73 | 74 | Look out for Liquid templating weirdness! 75 | 76 | If you have a code snippet that includes the following syntax: `{%{message: "error message"}, :error}`, i.e. if you have a tuple where the first element is a map, WATCH OUT! That set of characters, `{%` is the start of a liquid tag! Instead, wrap your backticked code block in `{% raw % }` `{% endraw %}` 77 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | ruby '>= 2.7.3', '< 3.0' 3 | 4 | gem 'autoprefixer-rails' 5 | gem 'jekyll' 6 | gem 'jekyll-assets' 7 | gem 'jekyll-redirect-from' 8 | gem 'jekyll-sitemap' 9 | gem 'kramdown' 10 | gem 'kramdown-parser-gfm' 11 | gem 'puma' 12 | gem 'rack-jekyll' 13 | gem 'rake' 14 | gem 'sprockets', '~> 3.7' 15 | gem 'sprockets-es6' 16 | gem 'uglifier' 17 | gem 'jekyll-archives' 18 | gem 'mini_racer' 19 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (5.2.6) 5 | concurrent-ruby (~> 1.0, >= 1.0.2) 6 | i18n (>= 0.7, < 2) 7 | minitest (~> 5.1) 8 | tzinfo (~> 1.1) 9 | addressable (2.8.0) 10 | public_suffix (>= 2.0.2, < 5.0) 11 | autoprefixer-rails (10.3.1.0) 12 | execjs (~> 2) 13 | babel-source (5.8.35) 14 | babel-transpiler (0.7.0) 15 | babel-source (>= 4.0, < 6) 16 | execjs (~> 2.0) 17 | colorator (1.1.0) 18 | concurrent-ruby (1.1.9) 19 | em-websocket (0.5.2) 20 | eventmachine (>= 0.12.9) 21 | http_parser.rb (~> 0.6.0) 22 | eventmachine (1.2.7) 23 | execjs (2.8.1) 24 | extras (0.3.0) 25 | forwardable-extended (~> 2.5) 26 | fastimage (2.2.5) 27 | ffi (1.15.3) 28 | forwardable-extended (2.6.0) 29 | http_parser.rb (0.6.0) 30 | i18n (0.9.5) 31 | concurrent-ruby (~> 1.0) 32 | jekyll (3.9.1) 33 | addressable (~> 2.4) 34 | colorator (~> 1.0) 35 | em-websocket (~> 0.5) 36 | i18n (~> 0.7) 37 | jekyll-sass-converter (~> 1.0) 38 | jekyll-watch (~> 2.0) 39 | kramdown (>= 1.17, < 3) 40 | liquid (~> 4.0) 41 | mercenary (~> 0.3.3) 42 | pathutil (~> 0.9) 43 | rouge (>= 1.7, < 4) 44 | safe_yaml (~> 1.0) 45 | jekyll-archives (2.2.1) 46 | jekyll (>= 3.6, < 5.0) 47 | jekyll-assets (3.0.12) 48 | activesupport (~> 5.0) 49 | execjs (~> 2.7) 50 | extras (~> 0.2) 51 | fastimage (~> 2.0, >= 1.8) 52 | jekyll (>= 3.5, < 4.0) 53 | jekyll-sanity (~> 1.2) 54 | liquid-tag-parser (~> 1.0) 55 | nokogiri (~> 1.8) 56 | pathutil (~> 0.16) 57 | sprockets (>= 3.3, < 4.1.beta) 58 | jekyll-redirect-from (0.16.0) 59 | jekyll (>= 3.3, < 5.0) 60 | jekyll-sanity (1.6.0) 61 | jekyll (>= 3.1, < 5.0) 62 | pathutil (~> 0.16) 63 | jekyll-sass-converter (1.5.2) 64 | sass (~> 3.4) 65 | jekyll-sitemap (1.4.0) 66 | jekyll (>= 3.7, < 5.0) 67 | jekyll-watch (2.2.1) 68 | listen (~> 3.0) 69 | kramdown (2.3.1) 70 | rexml 71 | kramdown-parser-gfm (1.1.0) 72 | kramdown (~> 2.0) 73 | libv8-node (15.14.0.1-x86_64-linux) 74 | liquid (4.0.3) 75 | liquid-tag-parser (1.9.0) 76 | extras (~> 0.3) 77 | liquid (>= 3.0, < 5.0) 78 | listen (3.6.0) 79 | rb-fsevent (~> 0.10, >= 0.10.3) 80 | rb-inotify (~> 0.9, >= 0.9.10) 81 | mercenary (0.3.6) 82 | mini_racer (0.4.0) 83 | libv8-node (~> 15.14.0.0) 84 | minitest (5.14.4) 85 | nio4r (2.5.8) 86 | nokogiri (1.12.3-x86_64-linux) 87 | racc (~> 1.4) 88 | pathutil (0.16.2) 89 | forwardable-extended (~> 2.6) 90 | public_suffix (4.0.6) 91 | puma (5.4.0) 92 | nio4r (~> 2.0) 93 | racc (1.5.2) 94 | rack (1.6.13) 95 | rack-jekyll (0.5.0) 96 | jekyll (>= 1.3) 97 | listen (>= 1.3) 98 | rack (~> 1.5) 99 | rake (13.0.6) 100 | rb-fsevent (0.11.0) 101 | rb-inotify (0.10.1) 102 | ffi (~> 1.0) 103 | rexml (3.2.5) 104 | rouge (3.26.0) 105 | safe_yaml (1.0.5) 106 | sass (3.7.4) 107 | sass-listen (~> 4.0.0) 108 | sass-listen (4.0.0) 109 | rb-fsevent (~> 0.9, >= 0.9.4) 110 | rb-inotify (~> 0.9, >= 0.9.7) 111 | sprockets (3.7.2) 112 | concurrent-ruby (~> 1.0) 113 | rack (> 1, < 3) 114 | sprockets-es6 (0.9.2) 115 | babel-source (>= 5.8.11) 116 | babel-transpiler 117 | sprockets (>= 3.0.0) 118 | thread_safe (0.3.6) 119 | tzinfo (1.2.9) 120 | thread_safe (~> 0.1) 121 | uglifier (4.2.0) 122 | execjs (>= 0.3.0, < 3) 123 | 124 | PLATFORMS 125 | x86_64-linux 126 | 127 | DEPENDENCIES 128 | autoprefixer-rails 129 | jekyll 130 | jekyll-archives 131 | jekyll-assets 132 | jekyll-redirect-from 133 | jekyll-sitemap 134 | kramdown 135 | kramdown-parser-gfm 136 | mini_racer 137 | puma 138 | rack-jekyll 139 | rake 140 | sprockets (~> 3.7) 141 | sprockets-es6 142 | uglifier 143 | 144 | RUBY VERSION 145 | ruby 2.7.4p191 146 | 147 | BUNDLED WITH 148 | 2.2.24 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Haskell School 2 | 3 | > Haskell school was built on the model and using the code of elixir school. 4 | > You can find elixir school at [ElixirSchool.com](https://elixirschool.com). 5 | 6 | _Feedback and participation are strongly encouraged! Please see [Contributing](CONTRIBUTING.md) for more details on how to get involved._ 7 | 8 | ### Running locally 9 | 10 | Haskell School is generated using [Jekyll](https://github.com/jekyll/jekyll). 11 | To run it locally, you need both Ruby and Bundler installed. 12 | 13 | 1. Install dependencies: 14 | 15 | ```shell 16 | $ bundle install 17 | ``` 18 | 19 | 2. Run Jekyll: 20 | 21 | ```shell 22 | $ bundle exec jekyll s 23 | ``` 24 | 25 | 3. Access it at [http://localhost:4000](http://localhost:4000) 26 | 27 | ### Translating a lesson 28 | 29 | 1. Each of the languages has a folder in root of this repo. To start translating you need to copy a file from the English language to the corresponding 30 | folder in your language and start translating it. 31 | 32 | 2. Check the [translation report](https://school.haskell.org/fr/report/) for pages that haven't been translated yet, or for pages which need to have their translations updated in the corresponding language you want to work with. 33 | 34 | 3. Translated lessons must include page metadata. 35 | * `title` should be a translation of the original lesson's `title`. 36 | * `version` should be set to the original English `version`. 37 | 38 | For example `/ja/lessons/basics/basics.md`: 39 | 40 | ```yaml 41 | --- 42 | title: 基本 43 | version: 1.0.0 44 | --- 45 | ``` 46 | 47 | 4. Submit a PR with the new translated lesson and join [https://school.haskell.org/contributors/](_data/contributors.yml). 48 | 49 | ### Posting an article 50 | 51 | In its current iteration Haskell School is powered by Jekyll, a powerful static blog generator. If you're familiar with Jekyll then you're ready to go, if you aren't don't fret we're here to help! 52 | 53 | 1. We need to create the file for our article. Blog posts live in the `_posts/` directory. Our filename will need to confirm to the `YYYY-MM-DD-name-separated-with-hyphens.md` pattern. 54 | 55 | 2. After opening the new file in our favorite editor we need to add some metadata to the top of it: 56 | 57 | ```markdown 58 | --- 59 | author: Author Name 60 | author_link: https://github.com/author_github_account (or website) 61 | categories: article_category (find them or add a new one in _data/blog_meta.yml) 62 | tags: ['phoenix'] (find them or create a new one in _data/blog_meta.yml) 63 | date: YYYY-MM-DD for the post date 64 | layout: post 65 | title: Full Article Title 66 | excerpt: > 67 | Article short preview text 68 | --- 69 | ``` 70 | 71 | 3. Once we've completed writing our post we should add/update `_data/contributors.yml` with our details. 72 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | namespace :assets do 2 | task :precompile do 3 | system 'bundle exec jekyll build' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /_assets/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /_assets/fonts/JetBrainsMono-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/fonts/JetBrainsMono-Regular.woff2 -------------------------------------------------------------------------------- /_assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /_assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /_assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /_assets/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /_assets/images/benchee_html_graph_sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/benchee_html_graph_sample.png -------------------------------------------------------------------------------- /_assets/images/chat-message-not-visible.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/chat-message-not-visible.png -------------------------------------------------------------------------------- /_assets/images/debugger_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/debugger_1.png -------------------------------------------------------------------------------- /_assets/images/debugger_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/debugger_2.png -------------------------------------------------------------------------------- /_assets/images/debugger_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/debugger_3.png -------------------------------------------------------------------------------- /_assets/images/debugger_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/debugger_4.png -------------------------------------------------------------------------------- /_assets/images/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/default.jpg -------------------------------------------------------------------------------- /_assets/images/documentation_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/documentation_1.png -------------------------------------------------------------------------------- /_assets/images/documentation_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/documentation_2.png -------------------------------------------------------------------------------- /_assets/images/favicons/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/favicons/android-chrome-144x144.png -------------------------------------------------------------------------------- /_assets/images/favicons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/favicons/apple-touch-icon.png -------------------------------------------------------------------------------- /_assets/images/favicons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #00aba9 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /_assets/images/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /_assets/images/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /_assets/images/favicons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/favicons/favicon.ico -------------------------------------------------------------------------------- /_assets/images/favicons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/favicons/mstile-150x150.png -------------------------------------------------------------------------------- /_assets/images/favicons/splash-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/favicons/splash-512x512.png -------------------------------------------------------------------------------- /_assets/images/game-ratings-bar-chart-selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/game-ratings-bar-chart-selected.png -------------------------------------------------------------------------------- /_assets/images/game-ratings-chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/game-ratings-chart.png -------------------------------------------------------------------------------- /_assets/images/kafka-flow-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/kafka-flow-example.png -------------------------------------------------------------------------------- /_assets/images/ld-ets-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/ld-ets-detail.png -------------------------------------------------------------------------------- /_assets/images/ld-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/ld-home.png -------------------------------------------------------------------------------- /_assets/images/ld-metrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/ld-metrics.png -------------------------------------------------------------------------------- /_assets/images/ld-port-4000-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/ld-port-4000-detail.png -------------------------------------------------------------------------------- /_assets/images/ld-port-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/ld-port-detail.png -------------------------------------------------------------------------------- /_assets/images/ld-ports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/ld-ports.png -------------------------------------------------------------------------------- /_assets/images/ld-process-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/ld-process-detail.png -------------------------------------------------------------------------------- /_assets/images/ld-processes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/ld-processes.png -------------------------------------------------------------------------------- /_assets/images/ld-request-logger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/ld-request-logger.png -------------------------------------------------------------------------------- /_assets/images/live-component-search-form-query-params.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-component-search-form-query-params.png -------------------------------------------------------------------------------- /_assets/images/live-view-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-1.png -------------------------------------------------------------------------------- /_assets/images/live-view-broadcasts-event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-broadcasts-event.png -------------------------------------------------------------------------------- /_assets/images/live-view-channel-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-channel-join.png -------------------------------------------------------------------------------- /_assets/images/live-view-channel-push.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-channel-push.png -------------------------------------------------------------------------------- /_assets/images/live-view-channel-register.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-channel-register.png -------------------------------------------------------------------------------- /_assets/images/live-view-connect-channel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-connect-channel.png -------------------------------------------------------------------------------- /_assets/images/live-view-front-end-update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-front-end-update.png -------------------------------------------------------------------------------- /_assets/images/live-view-handle-event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-handle-event.png -------------------------------------------------------------------------------- /_assets/images/live-view-lookup-send-to-channel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-lookup-send-to-channel.png -------------------------------------------------------------------------------- /_assets/images/live-view-messages-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-messages-index.png -------------------------------------------------------------------------------- /_assets/images/live-view-mount-render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-mount-render.png -------------------------------------------------------------------------------- /_assets/images/live-view-mount-session-uuid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-mount-session-uuid.png -------------------------------------------------------------------------------- /_assets/images/live-view-presence-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-presence-1.png -------------------------------------------------------------------------------- /_assets/images/live-view-presence-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-presence-2.png -------------------------------------------------------------------------------- /_assets/images/live-view-send-self.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-send-self.png -------------------------------------------------------------------------------- /_assets/images/live-view-socket-connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-socket-connect.png -------------------------------------------------------------------------------- /_assets/images/live-view-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live-view-table.png -------------------------------------------------------------------------------- /_assets/images/live_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live_view.png -------------------------------------------------------------------------------- /_assets/images/live_view_pub_sub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/live_view_pub_sub.png -------------------------------------------------------------------------------- /_assets/images/og_image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haskellfoundation/HaskellSchool/0a128af3f01bb116d9f164fe42963fd400c73f5b/_assets/images/og_image.jpg -------------------------------------------------------------------------------- /_assets/javascripts/copy.js: -------------------------------------------------------------------------------- 1 | // See https://github.com/marcoaugustoandrade/jekyll-clipboardjs/blob/master/copy.js 2 | let codes = document.querySelectorAll(".highlight > pre > code"); 3 | let countID = 0; 4 | codes.forEach((code) => { 5 | code.setAttribute("id", "code" + countID); 6 | 7 | let btn = document.createElement("button"); 8 | btn.innerHTML = "Copy"; 9 | btn.className = "btn-copy"; 10 | btn.setAttribute("data-clipboard-action", "copy"); 11 | btn.setAttribute("data-clipboard-target", "#code" + countID); 12 | 13 | let div = document.createElement("div"); 14 | div.appendChild(btn); 15 | 16 | code.before(div); 17 | 18 | countID++; 19 | }); 20 | 21 | let clipboard = new ClipboardJS(".btn-copy"); 22 | -------------------------------------------------------------------------------- /_assets/javascripts/ie/html5shiv.js: -------------------------------------------------------------------------------- 1 | /* 2 | HTML5 Shiv v3.6.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | (function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag(); 5 | a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x"; 6 | c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode|| 7 | "undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video",version:"3.6.2",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment(); 8 | for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d #mq-test-1 { width: 42px; }',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){v(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q=30,r=k.getElementsByTagName("head")[0]||l,s=k.getElementsByTagName("base")[0],t=r.getElementsByTagName("link"),u=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},v=function(b){var c="clientWidth",d=l[c],e="CSS1Compat"===k.compatMode&&d||k.body[c]||d,f={},g=t[t.length-1],p=(new Date).getTime();if(b&&h&&q>p-h)return a.clearTimeout(i),i=a.setTimeout(v,q),void 0;h=p;for(var s in m)if(m.hasOwnProperty(s)){var w=m[s],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?j||u():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?j||u():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(n[w.rules]))}for(var C in o)o.hasOwnProperty(C)&&o[C]&&o[C].parentNode===r&&r.removeChild(o[C]);o.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=k.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,r.insertBefore(E,g.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(k.createTextNode(F)),o.push(E)}},w=function(a,b,d){var e=a.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},i=!f&&d;b.length&&(b+="/"),i&&(f=1);for(var j=0;f>j;j++){var k,l,o,p;i?(k=d,n.push(h(a))):(k=e[j].match(c.regex.findStyles)&&RegExp.$1,n.push(RegExp.$2&&h(RegExp.$2))),o=k.split(","),p=o.length;for(var q=0;p>q;q++)l=o[q],g(l)||m.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}v()},x=function(){if(d.length){var b=d.shift();f(b.href,function(c){w(c,b.href,b.media),p[b.href]=!0,a.setTimeout(function(){x()},0)})}},y=function(){for(var b=0;b tag is added to the DOM. 41 | // That means it will be `undefined` if cookie does not exist. 42 | if (!$theme) $theme = 'light'; 43 | 44 | if ($theme === 'dark') { 45 | toggleThemeIcon($elToggleTheme); 46 | } 47 | 48 | // Disable animations/transitions ... 49 | 50 | // ... when resizing. 51 | var resizeTimeout; 52 | 53 | $window.on('resize', function () { 54 | 55 | // Mark as resizing. 56 | $body.addClass('is-resizing'); 57 | 58 | // Unmark after delay. 59 | clearTimeout(resizeTimeout); 60 | 61 | resizeTimeout = setTimeout(function () { 62 | $body.removeClass('is-resizing'); 63 | }, 100); 64 | 65 | }); 66 | 67 | // Fix: Placeholder polyfill. 68 | $('form').placeholder(); 69 | 70 | // Prioritize "important" elements on medium. 71 | skel.on('+medium -medium', function () { 72 | $.prioritize( 73 | '.important\\28 medium\\29', 74 | skel.breakpoint('medium').active 75 | ); 76 | }); 77 | 78 | // Fixes. 79 | 80 | // Object fit images. 81 | if (!skel.canUse('object-fit') 82 | || skel.vars.browser == 'safari') 83 | $('.image.object').each(function () { 84 | 85 | var $this = $(this), 86 | $img = $this.children('img'); 87 | 88 | // Hide original image. 89 | $img.css('opacity', '0'); 90 | 91 | // Set background. 92 | $this 93 | .css('background-image', 'url("' + $img.attr('src') + '")') 94 | .css('background-size', $img.css('object-fit') ? $img.css('object-fit') : 'cover') 95 | .css('background-position', $img.css('object-position') ? $img.css('object-position') : 'center'); 96 | 97 | }); 98 | 99 | // Sidebar. 100 | var $sidebar = $('#sidebar'), 101 | $sidebar_inner = $sidebar.children('.inner'); 102 | 103 | // Inactive by default on <= large. 104 | skel 105 | .on('+large', function () { 106 | $sidebar.addClass('inactive'); 107 | $sidebar.css('visibility', 'visible'); 108 | }) 109 | .on('-large !large', function () { 110 | $sidebar.removeClass('inactive'); 111 | $sidebar.css('visibility', 'visible'); 112 | }); 113 | 114 | // Hack: Workaround for Chrome/Android scrollbar position bug. 115 | if (skel.vars.os == 'android' 116 | && skel.vars.browser == 'chrome') 117 | $('') 118 | .appendTo($head); 119 | 120 | // Toggle. 121 | if (skel.vars.IEVersion > 9) { 122 | 123 | $('Toggle') 124 | .appendTo($sidebar) 125 | .on('click', function (event) { 126 | 127 | // Prevent default. 128 | event.preventDefault(); 129 | event.stopPropagation(); 130 | 131 | // Toggle. 132 | $sidebar.toggleClass('inactive'); 133 | 134 | }); 135 | 136 | } 137 | 138 | // Events. 139 | 140 | // Link clicks. 141 | $sidebar.on('click', 'a', function (event) { 142 | 143 | // >large? Bail. 144 | if (!skel.breakpoint('large').active) 145 | return; 146 | 147 | // Vars. 148 | var $a = $(this), 149 | href = $a.attr('href'), 150 | target = $a.attr('target'); 151 | 152 | // Prevent default. 153 | event.preventDefault(); 154 | event.stopPropagation(); 155 | 156 | // Check URL. 157 | if (!href || href == '#' || href == '') 158 | return; 159 | 160 | // Hide sidebar. 161 | $sidebar.addClass('inactive'); 162 | 163 | // Redirect to href. 164 | setTimeout(function () { 165 | if (target == '_blank') 166 | window.open(href); 167 | else 168 | window.location.href = href; 169 | 170 | }, 500); 171 | 172 | }); 173 | 174 | // Prevent certain events inside the panel from bubbling. 175 | $sidebar.on('click touchend touchstart touchmove', function (event) { 176 | 177 | // >large? Bail. 178 | if (!skel.breakpoint('large').active) 179 | return; 180 | 181 | // Prevent propagation. 182 | event.stopPropagation(); 183 | 184 | }); 185 | 186 | // Hide panel on body click/tap. 187 | $body.on('click touchend', function (event) { 188 | 189 | // >large? Bail. 190 | if (!skel.breakpoint('large').active) 191 | return; 192 | 193 | // Deactivate. 194 | $sidebar.addClass('inactive'); 195 | 196 | }); 197 | 198 | // Menu. 199 | var $menu = $('#menu'), 200 | $menu_openers = $menu.children('ul').find('.opener'); 201 | 202 | // Openers. 203 | $menu_openers.each(function () { 204 | 205 | var $this = $(this); 206 | 207 | $this.on('click', function (event) { 208 | 209 | // Prevent default. 210 | event.preventDefault(); 211 | 212 | // Toggle. 213 | $menu_openers.not($this).removeClass('active'); 214 | $this.toggleClass('active'); 215 | 216 | // Trigger resize (sidebar lock). 217 | $window.triggerHandler('resize.sidebar-lock'); 218 | 219 | }); 220 | 221 | }); 222 | 223 | // Theme 224 | $elToggleTheme.on('click', function (event) { 225 | event.preventDefault(); 226 | event.stopPropagation(); 227 | 228 | var isDark = $body.attr('class') === 'dark'; 229 | $theme = isDark ? 'light' : 'dark'; 230 | localStorage.setItem('theme', $theme); 231 | $body.toggleClass('dark'); 232 | toggleThemeIcon($elToggleTheme); 233 | }); 234 | 235 | // Polyfill for sidebar 236 | Stickyfill.add($('#sidebar > .inner')); 237 | 238 | }); 239 | 240 | })(jQuery); 241 | -------------------------------------------------------------------------------- /_assets/javascripts/stickyfill.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Stickyfill – `position: sticky` polyfill 3 | * v. 2.1.0 | https://github.com/wilddeer/stickyfill 4 | * MIT License 5 | */ 6 | !function(a,b){"use strict";function c(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}function d(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])}function e(a){return parseFloat(a)||0}function f(a){for(var b=0;a;)b+=a.offsetTop,a=a.offsetParent;return b}function g(){function c(){a.pageXOffset!=m.left?(m.top=a.pageYOffset,m.left=a.pageXOffset,p.refreshAll()):a.pageYOffset!=m.top&&(m.top=a.pageYOffset,m.left=a.pageXOffset,n.forEach(function(a){return a._recalcPosition()}))}function d(){f=setInterval(function(){n.forEach(function(a){return a._fastCheck()})},500)}function e(){clearInterval(f)}if(!k){k=!0,c(),a.addEventListener("scroll",c),a.addEventListener("resize",p.refreshAll),a.addEventListener("orientationchange",p.refreshAll);var f=void 0,g=void 0,h=void 0;"hidden"in b?(g="hidden",h="visibilitychange"):"webkitHidden"in b&&(g="webkitHidden",h="webkitvisibilitychange"),h?(b[g]||d(),b.addEventListener(h,function(){b[g]?e():d()})):d()}}var h=function(){function a(a,b){for(var c=0;c=this._limits.end?"end":"middle";if(this._stickyMode!=a){switch(a){case"start":d(this._node.style,{position:"absolute",left:this._offsetToParent.left+"px",right:this._offsetToParent.right+"px",top:this._offsetToParent.top+"px",bottom:"auto",width:"auto",marginLeft:0,marginRight:0,marginTop:0});break;case"middle":d(this._node.style,{position:"fixed",left:this._offsetToWindow.left+"px",right:this._offsetToWindow.right+"px",top:this._styles.top,bottom:"auto",width:"auto",marginLeft:0,marginRight:0,marginTop:0});break;case"end":d(this._node.style,{position:"absolute",left:this._offsetToParent.left+"px",right:this._offsetToParent.right+"px",top:"auto",bottom:0,width:"auto",marginLeft:0,marginRight:0})}this._stickyMode=a}}}},{key:"_fastCheck",value:function(){this._active&&!this._removed&&(Math.abs(f(this._clone.node)-this._clone.docOffsetTop)>1||Math.abs(this._parent.node.offsetHeight-this._parent.offsetHeight)>1)&&this.refresh()}},{key:"_deactivate",value:function(){var a=this;this._active&&!this._removed&&(this._clone.node.parentNode.removeChild(this._clone.node),delete this._clone,d(this._node.style,this._styles),delete this._styles,n.some(function(b){return b!==a&&b._parent&&b._parent.node===a._parent.node})||d(this._parent.node.style,this._parent.styles),delete this._parent,this._stickyMode=null,this._active=!1,delete this._offsetToWindow,delete this._offsetToParent,delete this._limits)}},{key:"remove",value:function(){var a=this;this._deactivate(),n.some(function(b,c){if(b._node===a._node)return n.splice(c,1),!0}),this._removed=!0}}]),g}(),p={stickies:n,Sticky:o,forceSticky:function(){i=!1,g(),this.refreshAll()},addOne:function(a){if(!(a instanceof HTMLElement)){if(!a.length||!a[0])return;a=a[0]}for(var b=0;bJump to...', 7 | minimumHeaders: 3, 8 | headers: 'h1, h2, h3, h4, h5, h6', 9 | listType: 'ol', // values: [ol|ul] 10 | showEffect: 'show', // values: [show|slideDown|fadeIn|none] 11 | showSpeed: 'slow', // set to 0 to deactivate effect 12 | classes: { 13 | list: '', 14 | item: '' 15 | }, 16 | backToTopClasses: 'opener icon-chevron-up2 back-to-top' 17 | }, 18 | settings = $.extend(defaults, options); 19 | 20 | function fixedEncodeURIComponent (str) { 21 | return encodeURIComponent(str).replace(/[!'()*]/g, function(c) { 22 | return '%' + c.charCodeAt(0).toString(16); 23 | }); 24 | } 25 | 26 | function createLink (header) { 27 | var innerText = (header.textContent === undefined) ? header.innerText : header.textContent; 28 | return "" + innerText + ""; 29 | } 30 | 31 | var headers = $(settings.headers).filter(function() { 32 | // get all headers with an ID 33 | var previousSiblingName = $(this).prev().attr( "name" ); 34 | if (!this.id && previousSiblingName) { 35 | this.id = $(this).attr( "id", previousSiblingName.replace(/\./g, "-") ); 36 | } 37 | return this.id; 38 | }), output = $(this); 39 | if (!headers.length || headers.length < settings.minimumHeaders || !output.length) { 40 | $(this).hide(); 41 | return; 42 | } 43 | 44 | if (0 === settings.showSpeed) { 45 | settings.showEffect = 'none'; 46 | } 47 | 48 | var render = { 49 | show: function() { output.hide().html(html).show(settings.showSpeed); }, 50 | slideDown: function() { output.hide().html(html).slideDown(settings.showSpeed); }, 51 | fadeIn: function() { output.hide().html(html).fadeIn(settings.showSpeed); }, 52 | none: function() { output.html(html); } 53 | }; 54 | 55 | var get_level = function(ele) { return parseInt(ele.nodeName.replace("H", ""), 10); }; 56 | var return_to_top = ' '; 57 | 58 | var level = get_level(headers[0]), 59 | this_level, 60 | html = settings.title + " <" +settings.listType + " class=\"" + settings.classes.list +"\">"; 61 | headers.on('click', function() { 62 | if (!settings.noBackToTopLinks) { 63 | window.location.hash = this.id; 64 | } 65 | }) 66 | .addClass('clickable-header') 67 | .each(function(_, header) { 68 | this_level = get_level(header); 69 | if (!settings.noBackToTopLinks) { 70 | $(header).after(return_to_top); 71 | } 72 | if (this_level === level) // same level as before; same indenting 73 | html += "
  • " + createLink(header); 74 | else if (this_level <= level){ // higher level than before; end parent ol 75 | for(var i = this_level; i < level; i++) { 76 | html += "
  • " 77 | } 78 | html += "
  • " + createLink(header); 79 | } 80 | else if (this_level > level) { // lower level than before; expand the previous to contain a ol 81 | for(i = this_level; i > level; i--) { 82 | html += "<" + settings.listType + " class=\"" + settings.classes.list +"\">" + 83 | "
  • " 84 | } 85 | html += createLink(header); 86 | } 87 | level = this_level; // update for the next one 88 | }); 89 | html += ""; 90 | if (!settings.noBackToTopLinks) { 91 | $(document).on('click', '.back-to-top', function() { 92 | $(window).scrollTop(0); 93 | window.location.hash = ''; 94 | }); 95 | } 96 | 97 | render[settings.showEffect](); 98 | }; 99 | $('#toc').toc({ 100 | listType: 'ul', 101 | title: '', 102 | headers: 'h1, h2, h3:not([id="social"]), h4, h5, h6', 103 | noBackToTopLinks: false, 104 | minimumHeaders: 0, 105 | backToTopClasses: 'icon fa-chevron-up back-to-top' 106 | }); 107 | })(jQuery); 108 | -------------------------------------------------------------------------------- /_assets/stylesheets/base/_page.scss: -------------------------------------------------------------------------------- 1 | /* Basic */ 2 | 3 | // MSIE: Required for IEMobile. 4 | @-ms-viewport { 5 | width: device-width; 6 | } 7 | 8 | // MSIE: Prevents scrollbar from overlapping content. 9 | body { 10 | -ms-overflow-style: scrollbar; 11 | } 12 | 13 | // Ensures page width is always >=320px. 14 | @include breakpoint(xsmall) { 15 | html, body { 16 | min-width: 320px; 17 | } 18 | } 19 | 20 | body { 21 | background: _palette(bg); 22 | 23 | // Prevents animation/transition "flicker". 24 | // Automatically added/removed by js/main.js. 25 | &.is-loading, 26 | &.is-resizing { 27 | *, *:before, *:after { 28 | @include vendor('animation', 'none !important'); 29 | @include vendor('transition', 'none !important'); 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /_assets/stylesheets/base/_syntax.scss: -------------------------------------------------------------------------------- 1 | .highlight table td { padding: 2px; } 2 | .highlight table pre { margin: 0; } 3 | .highlight .cm { 4 | color: #999988; 5 | font-style: italic; 6 | } 7 | .highlight .cp { 8 | color: #999999; 9 | font-weight: bold; 10 | } 11 | .highlight .c1 { 12 | color: #999988; 13 | font-style: italic; 14 | } 15 | .highlight .cs { 16 | color: #999999; 17 | font-weight: bold; 18 | font-style: italic; 19 | } 20 | .highlight .c, .highlight .cd { 21 | color: #999988; 22 | font-style: italic; 23 | } 24 | .highlight .err { 25 | color: #a61717; 26 | background-color: #e3d2d2; 27 | } 28 | .highlight .gd { 29 | color: #000000; 30 | background-color: #ffdddd; 31 | } 32 | .highlight .ge { 33 | color: #000000; 34 | font-style: italic; 35 | } 36 | .highlight .gr { 37 | color: #aa0000; 38 | } 39 | .highlight .gh { 40 | color: #999999; 41 | } 42 | .highlight .gi { 43 | color: #000000; 44 | background-color: #ddffdd; 45 | } 46 | .highlight .go { 47 | color: #888888; 48 | } 49 | .highlight .gp { 50 | color: #555555; 51 | } 52 | .highlight .gs { 53 | font-weight: bold; 54 | } 55 | .highlight .gu { 56 | color: #aaaaaa; 57 | } 58 | .highlight .gt { 59 | color: #aa0000; 60 | } 61 | .highlight .kc { 62 | color: #000000; 63 | font-weight: bold; 64 | } 65 | .highlight .kd { 66 | color: #000000; 67 | font-weight: bold; 68 | } 69 | .highlight .kn { 70 | color: #000000; 71 | font-weight: bold; 72 | } 73 | .highlight .kp { 74 | color: #000000; 75 | font-weight: bold; 76 | } 77 | .highlight .kr { 78 | color: #000000; 79 | font-weight: bold; 80 | } 81 | .highlight .kt { 82 | color: #445588; 83 | font-weight: bold; 84 | } 85 | .highlight .k, .highlight .kv { 86 | color: #000000; 87 | font-weight: bold; 88 | } 89 | .highlight .mf { 90 | color: #009999; 91 | } 92 | .highlight .mh { 93 | color: #009999; 94 | } 95 | .highlight .il { 96 | color: #009999; 97 | } 98 | .highlight .mi { 99 | color: #009999; 100 | } 101 | .highlight .mo { 102 | color: #009999; 103 | } 104 | .highlight .m, .highlight .mb, .highlight .mx { 105 | color: #009999; 106 | } 107 | .highlight .sb { 108 | color: #d14; 109 | } 110 | .highlight .sc { 111 | color: #d14; 112 | } 113 | .highlight .sd { 114 | color: #d14; 115 | } 116 | .highlight .s2 { 117 | color: #d14; 118 | } 119 | .highlight .se { 120 | color: #d14; 121 | } 122 | .highlight .sh { 123 | color: #d14; 124 | } 125 | .highlight .si { 126 | color: #d14; 127 | } 128 | .highlight .sx { 129 | color: #d14; 130 | } 131 | .highlight .sr { 132 | color: #009926; 133 | } 134 | .highlight .s1 { 135 | color: #d14; 136 | } 137 | .highlight .ss { 138 | color: #990073; 139 | } 140 | .highlight .s { 141 | color: #d14; 142 | } 143 | .highlight .na { 144 | color: #008080; 145 | } 146 | .highlight .bp { 147 | color: #999999; 148 | } 149 | .highlight .nb { 150 | color: #0086B3; 151 | } 152 | .highlight .nc { 153 | color: #445588; 154 | font-weight: bold; 155 | } 156 | .highlight .no { 157 | color: #008080; 158 | } 159 | .highlight .nd { 160 | color: #3c5d5d; 161 | font-weight: bold; 162 | } 163 | .highlight .ni { 164 | color: #800080; 165 | } 166 | .highlight .ne { 167 | color: #990000; 168 | font-weight: bold; 169 | } 170 | .highlight .nf { 171 | color: #990000; 172 | font-weight: bold; 173 | } 174 | .highlight .nl { 175 | color: #990000; 176 | font-weight: bold; 177 | } 178 | .highlight .nn { 179 | color: #555555; 180 | } 181 | .highlight .nt { 182 | color: #000080; 183 | } 184 | .highlight .vc { 185 | color: #008080; 186 | } 187 | .highlight .vg { 188 | color: #008080; 189 | } 190 | .highlight .vi { 191 | color: #008080; 192 | } 193 | .highlight .nv { 194 | color: #008080; 195 | } 196 | .highlight .ow { 197 | color: #000000; 198 | font-weight: bold; 199 | } 200 | .highlight .o { 201 | color: #000000; 202 | font-weight: bold; 203 | } 204 | .highlight .w { 205 | color: #bbbbbb; 206 | } 207 | .highlight { 208 | background-color: #f8f8f8; 209 | } 210 | -------------------------------------------------------------------------------- /_assets/stylesheets/base/_typography.scss: -------------------------------------------------------------------------------- 1 | /* Type */ 2 | 3 | body, input, select, textarea { 4 | color: _palette(fg); 5 | font-family: _font(family); 6 | font-size: 13pt; 7 | font-weight: _font(weight); 8 | line-height: 1.65; 9 | 10 | @include breakpoint(xlarge) { 11 | font-size: 11pt; 12 | } 13 | 14 | @include breakpoint(large) { 15 | font-size: 10pt; 16 | } 17 | 18 | @include breakpoint(xxsmall) { 19 | font-size: 9pt; 20 | } 21 | } 22 | 23 | a { 24 | @include vendor('transition', ( 25 | 'color #{_duration(transition)} ease-in-out', 26 | 'border-bottom-color #{_duration(transition)} ease-in-out' 27 | )); 28 | border-bottom: dotted 1px _purple(fg); 29 | color: _purple(fg-hov); 30 | text-decoration: none; 31 | 32 | &:hover { 33 | border-bottom-color: lighten(_purple(fg), 25%); 34 | color: _purple(fg-alt) !important; 35 | 36 | strong { 37 | color: inherit; 38 | } 39 | } 40 | } 41 | 42 | strong, b { 43 | color: _palette(fg-bold); 44 | font-weight: _font(weight-bold); 45 | } 46 | 47 | em, i { 48 | font-style: italic; 49 | } 50 | 51 | p { 52 | margin: 0 0 _size(element-margin) 0; 53 | } 54 | 55 | h1, h2, h3, h4, h5, h6 { 56 | color: _palette(fg-bold); 57 | font-family: _font(family-heading); 58 | font-weight: _font(weight-heading); 59 | line-height: 1.5; 60 | margin: 0 0 (_size(element-margin) * 0.5) 0; 61 | 62 | a { 63 | color: inherit; 64 | text-decoration: none; 65 | } 66 | } 67 | 68 | h1 { 69 | font-size: 4em; 70 | margin: 0 0 (_size(element-margin) * 0.25) 0; 71 | line-height: 1.3; 72 | } 73 | 74 | h2 { 75 | font-size: 1.75em; 76 | } 77 | 78 | h3 { 79 | font-size: 1.25em; 80 | } 81 | 82 | h4 { 83 | font-size: 1.1em; 84 | } 85 | 86 | h5 { 87 | font-size: 0.9em; 88 | } 89 | 90 | h6 { 91 | font-size: 0.7em; 92 | } 93 | 94 | @include breakpoint(xlarge) { 95 | h1 { 96 | font-size: 3.5em; 97 | } 98 | } 99 | 100 | @include breakpoint(medium) { 101 | h1 { 102 | font-size: 3.25em; 103 | } 104 | } 105 | 106 | @include breakpoint(small) { 107 | h1 { 108 | font-size: 2em; 109 | line-height: 1.4; 110 | } 111 | 112 | h2 { 113 | font-size: 1.5em; 114 | } 115 | } 116 | 117 | sub { 118 | font-size: 0.8em; 119 | position: relative; 120 | top: 0.5em; 121 | } 122 | 123 | sup { 124 | font-size: 0.8em; 125 | position: relative; 126 | top: -0.5em; 127 | } 128 | 129 | blockquote { 130 | border-left: solid 3px _palette(border); 131 | font-style: italic; 132 | margin: 0 0 _size(element-margin) 0; 133 | padding: (_size(element-margin) / 4) 0 (_size(element-margin) / 4) _size(element-margin); 134 | } 135 | 136 | code { 137 | background: _palette(border-bg); 138 | border-radius: _size(border-radius); 139 | border: solid 1px _palette(border); 140 | font-family: _font(family-fixed); 141 | font-size: 1.15em; 142 | margin: 0 0.25em; 143 | padding: 0.25em 0.65em; 144 | 145 | &.highlighter-rouge { 146 | padding: 0.2em 0.4em; 147 | font-size: 80%; 148 | } 149 | } 150 | 151 | pre { 152 | -webkit-overflow-scrolling: touch; 153 | font-family: _font(family-fixed); 154 | font-size: 0.9em; 155 | margin: 0 0 _size(element-margin) 0; 156 | 157 | code { 158 | display: block; 159 | line-height: 1.15; 160 | padding: 1em 1.5em; 161 | overflow-x: auto; 162 | } 163 | } 164 | 165 | hr { 166 | border: 0; 167 | border-bottom: solid 1px _palette(border); 168 | margin: _size(element-margin) 0; 169 | 170 | &.major { 171 | margin: (_size(element-margin) * 1.5) 0; 172 | } 173 | } 174 | 175 | .align-left { 176 | text-align: left; 177 | } 178 | 179 | .align-center { 180 | text-align: center; 181 | } 182 | 183 | .align-right { 184 | text-align: right; 185 | } 186 | 187 | .highlighter-rouge { 188 | &:last-of-type .highlight { 189 | margin: 0; 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /_assets/stylesheets/components/_box.scss: -------------------------------------------------------------------------------- 1 | /* Box */ 2 | 3 | .box { 4 | border-radius: _size(border-radius); 5 | border: solid 1px _palette(border); 6 | margin-bottom: _size(element-margin); 7 | padding: 1.5em; 8 | 9 | > :last-child, 10 | > :last-child > :last-child, 11 | > :last-child > :last-child > :last-child { 12 | margin-bottom: 0; 13 | } 14 | 15 | &.alt { 16 | border: 0; 17 | border-radius: 0; 18 | padding: 0; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /_assets/stylesheets/components/_button.scss: -------------------------------------------------------------------------------- 1 | /* Button */ 2 | 3 | input[type="submit"], 4 | input[type="reset"], 5 | input[type="button"], 6 | button, 7 | .button { 8 | @include vendor('appearance', 'none'); 9 | @include vendor('transition', ( 10 | 'background-color #{_duration(transition)} ease-in-out', 11 | 'color #{_duration(transition)} ease-in-out' 12 | )); 13 | background-color: transparent; 14 | border-radius: _size(border-radius); 15 | border: 0; 16 | box-shadow: inset 0 0 0 2px _purple(fg); 17 | color: _purple(fg) !important; 18 | cursor: pointer; 19 | display: inline-block; 20 | font-family: _font(family-heading); 21 | font-size: 0.8em; 22 | font-weight: _font(weight-heading); 23 | height: 3.5em; 24 | letter-spacing: _font(kerning-heading); 25 | line-height: 3.5em; 26 | padding: 0 2.25em; 27 | text-align: center; 28 | text-decoration: none; 29 | white-space: nowrap; 30 | &.up{ 31 | text-transform: uppercase; 32 | } 33 | &:hover { 34 | background-color: transparentize(_purple(fg), 0.95); 35 | } 36 | 37 | &:active { 38 | background-color: transparentize(_purple(fg), 0.85); 39 | } 40 | 41 | &.icon { 42 | &:before { 43 | margin-right: 0.5em; 44 | } 45 | } 46 | 47 | &.fit { 48 | display: block; 49 | margin: 0 0 (_size(element-margin) * 0.5) 0; 50 | width: 100%; 51 | } 52 | 53 | &.small { 54 | font-size: 0.6em; 55 | } 56 | 57 | &.big { 58 | font-size: 1em; 59 | height: 3.65em; 60 | line-height: 3.65em; 61 | } 62 | 63 | &.special { 64 | background-color: _purple(fg); 65 | box-shadow: none; 66 | color: _palette(bg) !important; 67 | 68 | &:hover { 69 | background-color: lighten(_purple(fg), 3); 70 | } 71 | 72 | &:active { 73 | background-color: darken(_purple(fg), 3); 74 | } 75 | } 76 | 77 | &.disabled, 78 | &:disabled { 79 | @include vendor('pointer-events', 'none'); 80 | opacity: 0.25; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /_assets/stylesheets/components/_errors.scss: -------------------------------------------------------------------------------- 1 | .not_found { 2 | text-align: center; 3 | color: _purple(fg-hov); 4 | 5 | &-code { 6 | font-size: 12em; 7 | font-weight: bold; 8 | line-height: 1.25; 9 | } 10 | 11 | &-text { 12 | font-size: 2em; 13 | line-height: 1.25; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /_assets/stylesheets/components/_features.scss: -------------------------------------------------------------------------------- 1 | /* Features */ 2 | 3 | .features { 4 | $gutter: _size(gutter); 5 | 6 | @include vendor('display', 'flex'); 7 | @include vendor('flex-wrap', 'wrap'); 8 | margin: 0 0 _size(element-margin) ($gutter * -1); 9 | width: calc(100% + #{$gutter}); 10 | 11 | article { 12 | @include vendor('align-items', 'center'); 13 | @include vendor('display', 'flex'); 14 | margin: 0 0 $gutter $gutter; 15 | position: relative; 16 | width: calc(50% - #{$gutter}); 17 | 18 | &:nth-child(2n - 1) { 19 | margin-right: ($gutter * 0.5); 20 | } 21 | 22 | &:nth-child(2n) { 23 | margin-left: ($gutter * 0.5); 24 | } 25 | 26 | &:nth-last-child(1), 27 | &:nth-last-child(2) { 28 | margin-bottom: 0; 29 | } 30 | 31 | .icon { 32 | @include vendor('flex-grow', '0'); 33 | @include vendor('flex-shrink', '0'); 34 | display: block; 35 | height: 10em; 36 | line-height: 10em; 37 | margin: 0 _size(element-margin) 0 0; 38 | text-align: center; 39 | width: 10em; 40 | 41 | &:before { 42 | color: _purple(fg); 43 | font-size: 2.75rem; 44 | position: relative; 45 | top: 0.05em; 46 | } 47 | 48 | &:after { 49 | @include vendor('transform', 'rotate(45deg)'); 50 | border-radius: 0.25rem; 51 | border: solid 2px _purple(bg); 52 | content: ''; 53 | display: block; 54 | height: 7em; 55 | left: 50%; 56 | margin: -3.5em 0 0 -3.5em; 57 | position: absolute; 58 | top: 50%; 59 | width: 7em; 60 | } 61 | } 62 | 63 | .content { 64 | @include vendor('flex-grow', '1'); 65 | @include vendor('flex-shrink', '1'); 66 | width: 100%; 67 | 68 | > :last-child { 69 | margin-bottom: 0; 70 | } 71 | } 72 | } 73 | 74 | @include breakpoint(medium) { 75 | margin: 0 0 _size(element-margin) 0; 76 | width: 100%; 77 | 78 | article { 79 | margin: 0 0 $gutter 0; 80 | width: 100%; 81 | 82 | &:nth-child(2n - 1) { 83 | margin-right: 0; 84 | } 85 | 86 | &:nth-child(2n) { 87 | margin-left: 0; 88 | } 89 | 90 | &:nth-last-child(1), 91 | &:nth-last-child(2) { 92 | margin-bottom: $gutter; 93 | } 94 | 95 | &:last-child { 96 | margin-bottom: 0; 97 | } 98 | 99 | .icon { 100 | height: 8em; 101 | line-height: 8em; 102 | width: 8em; 103 | 104 | &:before { 105 | font-size: 2.25rem; 106 | } 107 | 108 | &:after { 109 | height: 6em; 110 | margin: -3em 0 0 -3em; 111 | width: 6em; 112 | } 113 | } 114 | } 115 | } 116 | 117 | @include breakpoint(xsmall) { 118 | article { 119 | @include vendor('flex-direction', 'column'); 120 | @include vendor('align-items', 'flex-start'); 121 | 122 | .icon { 123 | height: 6em; 124 | line-height: 6em; 125 | margin: 0 0 (_size(element-margin) * 0.75) 0; 126 | width: 6em; 127 | 128 | &:before { 129 | font-size: 1.5rem; 130 | } 131 | 132 | &:after { 133 | height: 4em; 134 | margin: -2em 0 0 -2em; 135 | width: 4em; 136 | } 137 | } 138 | } 139 | } 140 | 141 | @include breakpoint(xsmall) { 142 | article { 143 | .icon { 144 | &:before { 145 | font-size: 1.25rem; 146 | } 147 | } 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /_assets/stylesheets/components/_form.scss: -------------------------------------------------------------------------------- 1 | /* Form */ 2 | 3 | form { 4 | margin: 0 0 _size(element-margin) 0; 5 | } 6 | 7 | label { 8 | color: _palette(fg-bold); 9 | display: block; 10 | font-size: 0.9em; 11 | font-weight: _font(weight-bold); 12 | margin: 0 0 (_size(element-margin) * 0.5) 0; 13 | } 14 | 15 | input[type="text"], 16 | input[type="password"], 17 | input[type="email"], 18 | input[type="tel"], 19 | input[type="search"], 20 | input[type="url"], 21 | select, 22 | textarea { 23 | @include vendor('appearance', 'none'); 24 | background: _palette(bg); 25 | border-radius: _size(border-radius); 26 | border: none; 27 | border: solid 1px _palette(border); 28 | color: inherit; 29 | display: block; 30 | outline: 0; 31 | padding: 0 1em; 32 | text-decoration: none; 33 | width: 100%; 34 | 35 | &:invalid { 36 | box-shadow: none; 37 | } 38 | 39 | &:focus { 40 | border-color: _purple(fg); 41 | box-shadow: 0 0 0 1px _purple(fg); 42 | } 43 | } 44 | 45 | .select-wrapper { 46 | @include icon; 47 | display: block; 48 | position: relative; 49 | 50 | &:before { 51 | color: _palette(border); 52 | content: '\f078'; 53 | display: block; 54 | height: _size(element-height); 55 | line-height: _size(element-height); 56 | pointer-events: none; 57 | position: absolute; 58 | right: 0; 59 | text-align: center; 60 | top: 0; 61 | width: _size(element-height); 62 | } 63 | 64 | select::-ms-expand { 65 | display: none; 66 | } 67 | } 68 | 69 | input[type="text"], 70 | input[type="password"], 71 | input[type="email"], 72 | input[type="tel"], 73 | input[type="search"], 74 | input[type="url"], 75 | select { 76 | height: _size(element-height); 77 | } 78 | 79 | textarea { 80 | padding: 0.75em 1em; 81 | } 82 | 83 | input[type="checkbox"], 84 | input[type="radio"], { 85 | @include vendor('appearance', 'none'); 86 | display: block; 87 | float: left; 88 | margin-right: -2em; 89 | opacity: 0; 90 | width: 1em; 91 | z-index: -1; 92 | 93 | & + label { 94 | @include icon; 95 | color: _palette(fg); 96 | cursor: pointer; 97 | display: inline-block; 98 | font-size: 1em; 99 | font-weight: _font(weight); 100 | padding-left: (_size(element-height) * 0.6) + 0.75em; 101 | padding-right: 0.75em; 102 | position: relative; 103 | 104 | &:before { 105 | background: _palette(bg); 106 | border-radius: _size(border-radius); 107 | border: solid 1px _palette(border); 108 | content: ''; 109 | display: inline-block; 110 | height: (_size(element-height) * 0.6); 111 | left: 0; 112 | line-height: (_size(element-height) * 0.575); 113 | position: absolute; 114 | text-align: center; 115 | top: 0; 116 | width: (_size(element-height) * 0.6); 117 | } 118 | } 119 | 120 | &:checked + label { 121 | &:before { 122 | background: _palette(fg-bold); 123 | border-color: _palette(fg-bold); 124 | color: _palette(bg); 125 | content: '\f00c'; 126 | } 127 | } 128 | 129 | &:focus + label { 130 | &:before { 131 | border-color: _purple(fg); 132 | box-shadow: 0 0 0 1px _purple(fg); 133 | } 134 | } 135 | } 136 | 137 | input[type="checkbox"] { 138 | & + label { 139 | &:before { 140 | border-radius: _size(border-radius); 141 | } 142 | } 143 | } 144 | 145 | input[type="radio"] { 146 | & + label { 147 | &:before { 148 | border-radius: 100%; 149 | } 150 | } 151 | } 152 | 153 | ::-webkit-input-placeholder { 154 | color: _palette(fg-light) !important; 155 | opacity: 1.0; 156 | } 157 | 158 | :-moz-placeholder { 159 | color: _palette(fg-light) !important; 160 | opacity: 1.0; 161 | } 162 | 163 | ::-moz-placeholder { 164 | color: _palette(fg-light) !important; 165 | opacity: 1.0; 166 | } 167 | 168 | :-ms-input-placeholder { 169 | color: _palette(fg-light) !important; 170 | opacity: 1.0; 171 | } 172 | 173 | .formerize-placeholder { 174 | color: _palette(fg-light) !important; 175 | opacity: 1.0; 176 | } 177 | -------------------------------------------------------------------------------- /_assets/stylesheets/components/_icon.scss: -------------------------------------------------------------------------------- 1 | /* Icon */ 2 | 3 | .icon { 4 | @include icon; 5 | border-bottom: none; 6 | position: relative; 7 | 8 | > .label { 9 | display: none; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /_assets/stylesheets/components/_image.scss: -------------------------------------------------------------------------------- 1 | /* Image */ 2 | 3 | .image { 4 | border-radius: _size(border-radius); 5 | border: 0; 6 | display: inline-block; 7 | position: relative; 8 | 9 | img { 10 | border-radius: _size(border-radius); 11 | display: block; 12 | } 13 | 14 | &.left, 15 | &.right { 16 | max-width: 40%; 17 | 18 | img { 19 | width: 100%; 20 | } 21 | } 22 | 23 | &.left { 24 | float: left; 25 | padding: 0 1.5em 1em 0; 26 | top: 0.25em; 27 | } 28 | 29 | &.right { 30 | float: right; 31 | padding: 0 0 1em 1.5em; 32 | top: 0.25em; 33 | } 34 | 35 | &.fit { 36 | display: block; 37 | margin: 0 0 _size(element-margin) 0; 38 | width: 100%; 39 | 40 | img { 41 | width: 100%; 42 | } 43 | } 44 | 45 | &.main { 46 | display: block; 47 | margin: 0 0 (_size(element-margin) * 1.5) 0; 48 | width: 100%; 49 | 50 | img { 51 | width: 100%; 52 | } 53 | } 54 | } 55 | 56 | a.image { 57 | overflow: hidden; 58 | 59 | img { 60 | @include vendor('transition', 'transform #{_duration(transition)} ease'); 61 | } 62 | 63 | &:hover { 64 | img { 65 | @include vendor('transform', 'scale(1.075)'); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /_assets/stylesheets/components/_list.scss: -------------------------------------------------------------------------------- 1 | /* List */ 2 | 3 | ol { 4 | list-style: decimal; 5 | margin: 0 0 _size(element-margin) 0; 6 | padding-left: 1.25em; 7 | 8 | li { 9 | padding-left: 0.25em; 10 | } 11 | } 12 | 13 | ul { 14 | list-style: disc; 15 | margin: 0 0 _size(element-margin) 0; 16 | padding-left: _size(element-margin); 17 | 18 | ul { 19 | margin: 0; 20 | } 21 | 22 | &.showcase { 23 | list-style: none; 24 | padding-left: 0; 25 | li { 26 | padding: .5em 0; 27 | 28 | &:first-child { 29 | padding-top: 0; 30 | } 31 | } 32 | } 33 | 34 | &.alt { 35 | list-style: none; 36 | padding-left: 0; 37 | 38 | li { 39 | border-top: solid 1px _palette(border); 40 | padding: 0.5em 0; 41 | 42 | &:first-child { 43 | border-top: 0; 44 | padding-top: 0; 45 | } 46 | } 47 | } 48 | 49 | &.icons { 50 | cursor: default; 51 | list-style: none; 52 | padding-left: 0; 53 | 54 | li { 55 | display: inline-block; 56 | padding: 0 1em 0 0; 57 | 58 | &:last-child { 59 | padding-right: 0; 60 | } 61 | 62 | .icon { 63 | color: inherit; 64 | 65 | &:before { 66 | font-size: 1.25em; 67 | } 68 | } 69 | } 70 | } 71 | 72 | &.contact { 73 | list-style: none; 74 | padding: 0; 75 | 76 | li { 77 | @include icon; 78 | border-top: solid 1px _palette(border); 79 | margin: 1.5em 0 0 0; 80 | padding: 1.5em 0 0 3em; 81 | position: relative; 82 | 83 | &:before { 84 | color: _purple(fg); 85 | display: inline-block; 86 | font-size: 1.5em; 87 | height: 1.125em; 88 | left: 0; 89 | line-height: 1.125em; 90 | position: absolute; 91 | text-align: center; 92 | top: (1.5em / 1.5); 93 | width: 1.5em; 94 | } 95 | 96 | &:first-child { 97 | border-top: 0; 98 | margin-top: 0; 99 | padding-top: 0; 100 | 101 | &:before { 102 | top: 0; 103 | } 104 | } 105 | 106 | a { 107 | color: inherit; 108 | } 109 | } 110 | } 111 | 112 | &.actions { 113 | cursor: default; 114 | list-style: none; 115 | padding-left: 0; 116 | 117 | li { 118 | display: inline-block; 119 | padding: 0 (_size(element-margin) * 0.5) 0 0; 120 | vertical-align: middle; 121 | 122 | &:last-child { 123 | padding-right: 0; 124 | } 125 | } 126 | 127 | &.small { 128 | li { 129 | padding: 0 (_size(element-margin) * 0.25) 0 0; 130 | } 131 | } 132 | 133 | &.vertical { 134 | li { 135 | display: block; 136 | padding: (_size(element-margin) * 0.5) 0 0 0; 137 | 138 | &:first-child { 139 | padding-top: 0; 140 | } 141 | 142 | > * { 143 | margin-bottom: 0; 144 | } 145 | } 146 | 147 | &.small { 148 | li { 149 | padding: (_size(element-margin) * 0.25) 0 0 0; 150 | 151 | &:first-child { 152 | padding-top: 0; 153 | } 154 | } 155 | } 156 | } 157 | 158 | &.fit { 159 | display: table; 160 | margin-left: (_size(element-margin) * -0.5); 161 | padding: 0; 162 | table-layout: fixed; 163 | width: calc(100% + #{(_size(element-margin) * 0.5)}); 164 | 165 | li { 166 | display: table-cell; 167 | padding: 0 0 0 (_size(element-margin) * 0.5); 168 | 169 | > * { 170 | margin-bottom: 0; 171 | } 172 | } 173 | 174 | &.small { 175 | margin-left: (_size(element-margin) * -0.25); 176 | width: calc(100% + #{(_size(element-margin) * 0.25)}); 177 | 178 | li { 179 | padding: 0 0 0 (_size(element-margin) * 0.25); 180 | } 181 | } 182 | } 183 | } 184 | 185 | &.pagination { 186 | cursor: default; 187 | list-style: none; 188 | padding-left: 0; 189 | 190 | li { 191 | display: inline-block; 192 | padding-left: 0; 193 | vertical-align: middle; 194 | 195 | > .page { 196 | @include vendor('transition', ( 197 | 'background-color #{_duration(transition)} ease-in-out', 198 | 'color #{_duration(transition)} ease-in-out' 199 | )); 200 | border-bottom: 0; 201 | border-radius: _size(border-radius); 202 | display: inline-block; 203 | font-size: 0.8em; 204 | font-weight: _font(weight-bold); 205 | height: 2em; 206 | line-height: 2em; 207 | margin: 0 0.125em; 208 | min-width: 2em; 209 | padding: 0 0.5em; 210 | text-align: center; 211 | 212 | &.active { 213 | background-color: _purple(fg); 214 | color: _palette(bg) !important; 215 | 216 | &:hover { 217 | background-color: lighten(_purple(fg), 3); 218 | } 219 | 220 | &:active { 221 | background-color: darken(_purple(fg), 3); 222 | } 223 | } 224 | } 225 | 226 | &:first-child { 227 | padding-right: 0.75em; 228 | } 229 | 230 | &:last-child { 231 | padding-left: 0.75em; 232 | } 233 | } 234 | 235 | @include breakpoint(xsmall) { 236 | li { 237 | &:nth-child(n+2):nth-last-child(n+2) { 238 | display: none; 239 | } 240 | 241 | &:first-child { 242 | padding-right: 0; 243 | } 244 | } 245 | } 246 | } 247 | } 248 | 249 | dl { 250 | margin: 0 0 _size(element-margin) 0; 251 | 252 | dt { 253 | display: block; 254 | font-weight: _font(weight-bold); 255 | margin: 0 0 (_size(element-margin) * 0.5) 0; 256 | } 257 | 258 | dd { 259 | margin-left: _size(element-margin); 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /_assets/stylesheets/components/_mini-posts.scss: -------------------------------------------------------------------------------- 1 | /* Mini Posts */ 2 | 3 | .mini-posts { 4 | article { 5 | border-top: solid 1px _palette(border); 6 | margin-top: _size(element-margin); 7 | padding-top: _size(element-margin); 8 | 9 | .image { 10 | display: block; 11 | margin: 0 0 (_size(element-margin) * 0.75) 0; 12 | 13 | img { 14 | display: block; 15 | width: 100%; 16 | } 17 | } 18 | 19 | &:first-child { 20 | border-top: 0; 21 | margin-top: 0; 22 | padding-top: 0; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /_assets/stylesheets/components/_posts.scss: -------------------------------------------------------------------------------- 1 | /* Posts */ 2 | 3 | .posts { 4 | $gutter: (_size(gutter) * 2); 5 | 6 | @include vendor('display', 'flex'); 7 | @include vendor('flex-wrap', 'wrap'); 8 | margin: 0 0 _size(element-margin) ($gutter * -1); 9 | width: calc(100% + #{$gutter}); 10 | 11 | article { 12 | @include vendor('flex-grow', '0'); 13 | @include vendor('flex-shrink', '1'); 14 | margin: 0 0 $gutter $gutter; 15 | position: relative; 16 | width: calc(#{(100% / 3)} - #{$gutter}); 17 | 18 | &:before { 19 | background: _purple(bg); 20 | content: ''; 21 | display: block; 22 | height: calc(100% + #{$gutter}); 23 | left: ($gutter * -0.5); 24 | position: absolute; 25 | top: 0; 26 | width: 1px; 27 | } 28 | 29 | &:after { 30 | background: _purple(bg); 31 | bottom: ($gutter * -0.5); 32 | content: ''; 33 | display: block; 34 | height: 1px; 35 | position: absolute; 36 | right: 0; 37 | width: calc(100% + #{$gutter}); 38 | } 39 | 40 | > :last-child { 41 | margin-bottom: 0; 42 | } 43 | 44 | .image { 45 | display: block; 46 | margin: 0 0 _size(element-margin) 0; 47 | 48 | img { 49 | display: block; 50 | width: 100%; 51 | } 52 | } 53 | } 54 | 55 | @include breakpoint(xlarge-to-max) { 56 | article { 57 | &:nth-child(3n + 1) { 58 | &:before { 59 | display: none; 60 | } 61 | 62 | &:after { 63 | width: 100%; 64 | } 65 | } 66 | 67 | &:nth-last-child(1), 68 | &:nth-last-child(2), 69 | &:nth-last-child(3) { 70 | margin-bottom: 0; 71 | 72 | &:before { 73 | height: 100%; 74 | } 75 | 76 | &:after { 77 | display: none; 78 | } 79 | } 80 | } 81 | } 82 | 83 | @include breakpoint(xlarge) { 84 | article { 85 | width: calc(50% - #{$gutter}); 86 | 87 | &:nth-last-child(3) { 88 | margin-bottom: $gutter; 89 | } 90 | } 91 | } 92 | 93 | @include breakpoint(small-to-xlarge) { 94 | article { 95 | &:nth-child(2n + 1) { 96 | &:before { 97 | display: none; 98 | } 99 | 100 | &:after { 101 | width: 100%; 102 | } 103 | } 104 | 105 | &:nth-last-child(1), 106 | &:nth-last-child(2) { 107 | margin-bottom: 0; 108 | 109 | &:before { 110 | height: 100%; 111 | } 112 | 113 | &:after { 114 | display: none; 115 | } 116 | } 117 | } 118 | } 119 | 120 | @include breakpoint(small) { 121 | $gutter: _size(gutter) * 1.5; 122 | 123 | margin: 0 0 _size(element-margin) ($gutter * -1); 124 | width: calc(100% + #{$gutter}); 125 | 126 | article { 127 | margin: 0 0 $gutter $gutter; 128 | width: calc(50% - #{$gutter}); 129 | 130 | &:before { 131 | height: calc(100% + #{$gutter}); 132 | left: ($gutter * -0.5); 133 | } 134 | 135 | &:after { 136 | bottom: ($gutter * -0.5); 137 | width: calc(100% + #{$gutter}); 138 | } 139 | 140 | &:nth-last-child(3) { 141 | margin-bottom: $gutter; 142 | } 143 | } 144 | } 145 | 146 | @include breakpoint(xsmall) { 147 | $gutter: _size(gutter) * 1.5; 148 | 149 | margin: 0 0 _size(element-margin) 0; 150 | width: 100%; 151 | 152 | article { 153 | margin: 0 0 $gutter 0; 154 | width: 100%; 155 | 156 | &:before { 157 | display: none; 158 | } 159 | 160 | &:after { 161 | width: 100%; 162 | } 163 | 164 | &:last-child { 165 | margin-bottom: 0; 166 | 167 | &:after { 168 | display: none; 169 | } 170 | } 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /_assets/stylesheets/components/_section.scss: -------------------------------------------------------------------------------- 1 | /* Section/Article */ 2 | 3 | section, article { 4 | &.special { 5 | text-align: center; 6 | } 7 | } 8 | 9 | header { 10 | p { 11 | font-family: _font(family-heading); 12 | font-size: 1em; 13 | font-weight: _font(weight-heading-alt); 14 | letter-spacing: _font(kerning-heading); 15 | margin-top: -0.5em; 16 | 17 | } 18 | 19 | &.major { 20 | > :last-child { 21 | border-bottom: solid 3px _purple(fg-hov); 22 | display: inline-block; 23 | margin: 0 0 _size(element-margin) 0; 24 | padding: 0 0.75em 0.5em 0; 25 | } 26 | } 27 | 28 | &.main { 29 | > :last-child { 30 | margin: 0 0 (_size(element-margin) * 0.5) 0; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /_assets/stylesheets/components/_table.scss: -------------------------------------------------------------------------------- 1 | /* Table */ 2 | 3 | .table-wrapper { 4 | -webkit-overflow-scrolling: touch; 5 | overflow-x: auto; 6 | } 7 | 8 | table { 9 | margin: 0 0 _size(element-margin) 0; 10 | width: 100%; 11 | 12 | tbody { 13 | tr { 14 | border: solid 1px _palette(border); 15 | border-left: 0; 16 | border-right: 0; 17 | 18 | &:nth-child(2n + 1) { 19 | background-color: _palette(border-bg); 20 | } 21 | } 22 | } 23 | 24 | td { 25 | padding: 0.75em 0.75em; 26 | } 27 | 28 | th { 29 | color: _palette(fg-bold); 30 | font-size: 0.9em; 31 | font-weight: _font(weight-bold); 32 | padding: 0 0.75em 0.75em 0.75em; 33 | text-align: left; 34 | } 35 | 36 | thead { 37 | border-bottom: solid 2px _palette(border); 38 | } 39 | 40 | tfoot { 41 | border-top: solid 2px _palette(border); 42 | } 43 | 44 | &.alt { 45 | border-collapse: separate; 46 | 47 | tbody { 48 | tr { 49 | td { 50 | border: solid 1px _palette(border); 51 | border-left-width: 0; 52 | border-top-width: 0; 53 | 54 | &:first-child { 55 | border-left-width: 1px; 56 | } 57 | } 58 | 59 | &:first-child { 60 | td { 61 | border-top-width: 1px; 62 | } 63 | } 64 | } 65 | } 66 | 67 | thead { 68 | border-bottom: 0; 69 | } 70 | 71 | tfoot { 72 | border-top: 0; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /_assets/stylesheets/dark.scss: -------------------------------------------------------------------------------- 1 | body.dark { 2 | background-color: _dark(bg); 3 | color: _dark(fg); 4 | 5 | // Typography 6 | input, select, textarea { 7 | color: _dark(fg); 8 | } 9 | 10 | h1, h2, h3, h4, h5, h6, th { 11 | color: _dark(fg-bold); 12 | } 13 | 14 | a { 15 | color: _purple(bg); 16 | &:hover { 17 | color: lighten(#4A365F, 55%) !important; // fixed 18 | } 19 | } 20 | button, .button { 21 | color: lighten(_purple(fg), 20%) !important; 22 | } 23 | strong, b { 24 | color: _dark(fg-bold); 25 | } 26 | 27 | hr { 28 | border-bottom: solid 1px _dark(border); 29 | } 30 | 31 | blockquote { 32 | border-left: solid 3px _dark(border); 33 | } 34 | 35 | code { 36 | color: _dark(fg); 37 | background: _dark(bg-alt); 38 | border: solid 1px _dark(border); 39 | } 40 | 41 | .tag { 42 | background-color: _dark(border); 43 | } 44 | 45 | .highlight { 46 | background: _dark(bg); 47 | 48 | .gd, .ge, .gi, .gu, .k, .kd, .kn, .kp, .kr, .kv, .o, .ow { 49 | color: #fff; // 000 50 | } 51 | 52 | .gi { 53 | background-color: darken(#ddffdd, 10%); 54 | } 55 | 56 | .gp, .nn { 57 | color: #555; 58 | } 59 | 60 | .go { 61 | color: #888; 62 | } 63 | 64 | .bp, .cp, .cs, .gh { 65 | color: #999; 66 | } 67 | 68 | .gu { 69 | color: #aaa; 70 | } 71 | 72 | .w { 73 | color: #bbb; 74 | } 75 | 76 | .gr, .gt { 77 | color: #aa0000; 78 | } 79 | 80 | .c, .c1, .cm, .cd { 81 | color: #999988; 82 | } 83 | 84 | .kt, .nc { 85 | color: #445588; 86 | } 87 | 88 | .ni { 89 | color: #800080; 90 | } 91 | 92 | .na, .no, .nv, .vc, .vg, .vi { 93 | color: lighten(#008080, 20%); 94 | } 95 | 96 | .nb { 97 | color: lighten(#0086B3, 20%); 98 | } 99 | 100 | .nt { 101 | color: lighten(#000080, 50%); 102 | } 103 | 104 | .nd { 105 | color: #3c5d5d; 106 | } 107 | .ne, .nf, .nl { 108 | color: #990000; 109 | } 110 | .mf, .mh, .il, .mi, .mo, .m, .mb, .mx { 111 | color: lighten(#009999, 20%); 112 | } 113 | 114 | .err { 115 | background-color: #a61717; 116 | color: #fff; 117 | } 118 | 119 | .ss { 120 | color: lighten(#990073, 50%); 121 | } 122 | .sr { 123 | color: #009926; 124 | } 125 | .s, .s1, .s2, .sb, .sc, .sd, .se, .sh, .si, .sx { 126 | color: lighten(#d14, 20%); 127 | } 128 | } 129 | 130 | #footer.copyright { 131 | color: _dark(fg-light); 132 | } 133 | 134 | #sidebar { 135 | background-color: _dark(bg-alt); 136 | 137 | > .inner { 138 | 139 | > .alt { 140 | background-color: darken(#3d4449, 2); // fixed 141 | } 142 | } 143 | 144 | .toggle { 145 | -webkit-tap-highlight-color: rgba(255,255,255,50); 146 | 147 | } 148 | @include breakpoint(small) { 149 | .toggle { 150 | &:before { 151 | color: _dark(fg); 152 | } 153 | &:after { 154 | background: transparentize(lighten(_dark(fg), 35), 0.25); 155 | 156 | } 157 | } 158 | } 159 | } 160 | 161 | #menu { 162 | ul { 163 | color: _dark(fg-bold); 164 | a, span { 165 | &.opener { 166 | -webkit-tap-highlight-color: rgba(255,255,255,50); 167 | &:before { 168 | color: lighten(_dark(fg-light), 5%); 169 | } 170 | &:hover { 171 | &:before { 172 | color: _purple(bg); 173 | } 174 | } 175 | } 176 | } 177 | } 178 | > ul { 179 | > li { 180 | border-color: _dark(border); 181 | > ul { 182 | color: _dark(fg); 183 | a, span { 184 | color: _dark(fg-light); 185 | &.active { 186 | color: _purple(bg); 187 | } 188 | } 189 | } 190 | } 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /_assets/stylesheets/ie8.scss: -------------------------------------------------------------------------------- 1 | @import 'libs/vars'; 2 | @import 'libs/functions'; 3 | @import 'libs/mixins'; 4 | @import 'libs/skel'; 5 | 6 | /* Button */ 7 | 8 | input[type="submit"], 9 | input[type="reset"], 10 | input[type="button"], 11 | button, 12 | .button { 13 | border: solid 2px _purple(fg); 14 | } 15 | 16 | /* Posts */ 17 | 18 | .posts { 19 | article { 20 | width: 40%; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /_assets/stylesheets/ie9.scss: -------------------------------------------------------------------------------- 1 | @import 'libs/vars'; 2 | @import 'libs/functions'; 3 | @import 'libs/mixins'; 4 | @import 'libs/skel'; 5 | 6 | /* Features */ 7 | 8 | .features { 9 | &:after { 10 | clear: both; 11 | content: ''; 12 | display: block; 13 | } 14 | 15 | article { 16 | float: left; 17 | 18 | &:after { 19 | clear: both; 20 | content: ''; 21 | display: block; 22 | } 23 | 24 | .icon { 25 | float: left; 26 | } 27 | } 28 | } 29 | 30 | /* Posts */ 31 | 32 | .posts { 33 | &:after { 34 | clear: both; 35 | content: ''; 36 | display: block; 37 | } 38 | 39 | article { 40 | float: left; 41 | } 42 | } 43 | 44 | /* Main */ 45 | 46 | #main { 47 | padding-left: _size(sidebar-width-alt); 48 | } 49 | 50 | /* Sidebar */ 51 | 52 | #sidebar { 53 | position: absolute; 54 | top: 0; 55 | left: 0; 56 | min-height: 100%; 57 | width: _size(sidebar-width-alt); 58 | } 59 | 60 | /* Banner */ 61 | 62 | #banner { 63 | &:after { 64 | clear: both; 65 | content: ''; 66 | display: block; 67 | } 68 | 69 | .content { 70 | float: left; 71 | padding-right: (_size(element-margin) * 2); 72 | } 73 | 74 | .image { 75 | float: left; 76 | margin-left: 0; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /_assets/stylesheets/layout/_banner.scss: -------------------------------------------------------------------------------- 1 | /* Banner */ 2 | 3 | #banner { 4 | @include padding(6em, 0); 5 | @include vendor('display', 'flex'); 6 | 7 | h1 { 8 | margin-top: -0.125em; 9 | } 10 | 11 | .content { 12 | @include vendor('flex-grow', '1'); 13 | @include vendor('flex-shrink', '1'); 14 | width: 50%; 15 | } 16 | 17 | .image { 18 | @include vendor('flex-grow', '0'); 19 | @include vendor('flex-shrink', '0'); 20 | display: block; 21 | margin: 0 0 _size(element-margin) (_size(element-margin) * 2); 22 | width: 50%; 23 | 24 | img { 25 | height: 100%; 26 | -moz-object-fit: cover; 27 | -webkit-object-fit: cover; 28 | -ms-object-fit: cover; 29 | object-fit: cover; 30 | -moz-object-position: center; 31 | -webkit-object-position: center; 32 | -ms-object-position: center; 33 | object-position: center; 34 | width: 100%; 35 | } 36 | } 37 | 38 | @include orientation(portrait) { 39 | @include vendor('flex-direction', 'column-reverse'); 40 | 41 | h1 { 42 | br { 43 | display: none; 44 | } 45 | } 46 | 47 | .content { 48 | @include vendor('flex-grow', '0'); 49 | @include vendor('flex-shrink', '0'); 50 | width: 100%; 51 | } 52 | 53 | .image { 54 | @include vendor('flex-grow', '0'); 55 | @include vendor('flex-shrink', '0'); 56 | margin: 0 0 (_size(element-margin) * 2) 0; 57 | height: 25em; 58 | max-height: 50vh; 59 | min-height: 18em; 60 | width: 100%; 61 | } 62 | 63 | @include breakpoint(xsmall) { 64 | .image { 65 | max-height: 35vh; 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /_assets/stylesheets/layout/_footer.scss: -------------------------------------------------------------------------------- 1 | /* Footer */ 2 | 3 | #footer { 4 | .copyright { 5 | color: _palette(fg-light); 6 | font-size: 0.9em; 7 | 8 | a { 9 | color: inherit; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /_assets/stylesheets/layout/_header.scss: -------------------------------------------------------------------------------- 1 | /* Header */ 2 | 3 | #header { 4 | @include vendor('display', 'flex'); 5 | border-bottom: solid 5px _purple(fg-hov); 6 | padding: 6em 0 1em 0; 7 | position: relative; 8 | 9 | > * { 10 | @include vendor('flex', '1'); 11 | margin-bottom: 0; 12 | } 13 | 14 | .logo { 15 | border-bottom: 0; 16 | color: inherit; 17 | font-family: _font(family-heading); 18 | font-size: 1.125em; 19 | } 20 | 21 | .icons { 22 | text-align: right; 23 | } 24 | 25 | @include breakpoint(xlarge) { 26 | padding-top: 5em; 27 | } 28 | 29 | @include breakpoint(small) { 30 | padding-top: 6.5em; 31 | 32 | .logo { 33 | font-size: 1.25em; 34 | margin: 0; 35 | } 36 | 37 | .icons { 38 | height: (6.25em / 1.25); 39 | line-height: (6.25em / 1.25); 40 | position: absolute; 41 | right: (-0.625em / 1.25); 42 | top: 0; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /_assets/stylesheets/layout/_main.scss: -------------------------------------------------------------------------------- 1 | /* Main */ 2 | 3 | #main { 4 | @include vendor('flex-grow', '1'); 5 | @include vendor('flex-shrink', '1'); 6 | width: calc(100vw - #{_size(sidebar-width)}); 7 | 8 | > .inner { 9 | @include padding(0, 6em); 10 | margin: 0 auto; 11 | max-width: 110em; 12 | 13 | > section { 14 | @include padding(6em, 0); 15 | border-top: solid 2px _purple(bg); 16 | 17 | &:first-of-type { 18 | border-top: 0 !important; 19 | } 20 | } 21 | } 22 | 23 | @include breakpoint(xlarge) { 24 | width: calc(100vw - #{_size(sidebar-width-alt)}); 25 | 26 | > .inner { 27 | @include padding(0, 5em); 28 | 29 | > section { 30 | @include padding(5em, 0); 31 | } 32 | } 33 | } 34 | 35 | @include breakpoint(large) { 36 | > .inner { 37 | @include padding(0, 4em); 38 | 39 | > section { 40 | @include padding(4em, 0); 41 | } 42 | } 43 | } 44 | 45 | @include breakpoint(small) { 46 | > .inner { 47 | @include padding(0, 2em); 48 | 49 | > section { 50 | @include padding(3em, 0); 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /_assets/stylesheets/layout/_menu.scss: -------------------------------------------------------------------------------- 1 | /* Menu */ 2 | 3 | #menu { 4 | ul { 5 | @include vendor('user-select', 'none'); 6 | color: _palette(fg-bold); 7 | font-family: _font(family-heading); 8 | font-family: _font(weight-heading-alt); 9 | letter-spacing: _font(kerning-heading); 10 | list-style: none; 11 | margin-bottom: 0; 12 | padding: 0; 13 | 14 | a, span { 15 | border-bottom: 0; 16 | color: inherit; 17 | cursor: pointer; 18 | display: block; 19 | font-size: 1em; 20 | font-weight: 700; 21 | padding: 0.25em 0; 22 | 23 | &.up{ 24 | text-transform: uppercase; 25 | } 26 | 27 | &.active{ 28 | color: _purple(fg-hov); 29 | } 30 | 31 | &:hover { 32 | color: _purple(fg-hov); 33 | } 34 | 35 | &.opener { 36 | @include vendor('transition', 'color #{_duration(transition)} ease-in-out'); 37 | @include icon; 38 | -webkit-tap-highlight-color: rgba(255,255,255,0); 39 | position: relative; 40 | font-size: 1.1em; 41 | 42 | &:before { 43 | @include vendor('transition', ( 44 | 'color #{_duration(transition)} ease-in-out', 45 | 'transform #{_duration(transition)} ease-in-out' 46 | )); 47 | color: darken(_palette(fg-light), 5%); 48 | content: '\f078'; 49 | position: absolute; 50 | right: 0; 51 | } 52 | 53 | &:hover { 54 | &:before { 55 | color: _purple(fg-hov); 56 | } 57 | } 58 | 59 | &.active { 60 | & + ul { 61 | display: block; 62 | } 63 | 64 | &:before { 65 | @include vendor('transform', 'rotate(-180deg)'); 66 | } 67 | } 68 | } 69 | } 70 | } 71 | 72 | > ul { 73 | > li { 74 | border-top: solid 1px _palette(border); 75 | margin: 0.5em 0 0 0; 76 | padding: 0.5em 0 0 0; 77 | 78 | > ul { 79 | color: _palette(fg-light); 80 | display: none; 81 | margin: 0.5em 0 1.5em 0; 82 | padding-left: 1em; 83 | 84 | a, span { 85 | color: darken(_palette(fg-light), 15%); 86 | font-size: 1em; 87 | font-weight: 400; 88 | } 89 | 90 | > li { 91 | margin: 0.125em 0 0 0; 92 | padding: 0.125em 0 0 0; 93 | } 94 | } 95 | 96 | &:first-child { 97 | border-top: 0; 98 | margin-top: 0; 99 | padding-top: 0; 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /_assets/stylesheets/layout/_sidebar.scss: -------------------------------------------------------------------------------- 1 | /* Sidebar */ 2 | 3 | #search { 4 | margin-bottom: _size(element-margin) !important; 5 | 6 | form { 7 | @include icon; 8 | position: relative; 9 | 10 | &:before { 11 | @include vendor('transform', 'scaleX(-1)'); 12 | color: _palette(fg); 13 | content: '\f002'; 14 | cursor: default; 15 | display: block; 16 | font-size: 1.5em; 17 | height: _size(element-height) / 1.375; 18 | line-height: _size(element-height) / 1.375; 19 | opacity: 0.325; 20 | position: absolute; 21 | right: 0; 22 | text-align: center; 23 | top: 0; 24 | width: _size(element-height) / 1.375; 25 | } 26 | 27 | input[type="text"] { 28 | padding-right: _size(element-height); 29 | } 30 | } 31 | } 32 | 33 | #sidebar { 34 | $sidebar-pad: 1.5em / 0.9; 35 | $xlarge-sidebar-pad: 1em / 0.9; 36 | 37 | @include vendor('flex-grow', '0'); 38 | @include vendor('flex-shrink', '0'); 39 | @include vendor('transition', ( 40 | 'margin-left 0.5s ease', 41 | 'box-shadow 0.5s ease' 42 | )); 43 | background-color: _palette(bg-alt); 44 | // Hide until skel detects screen size 45 | visibility: hidden; 46 | font-size: 1em; 47 | position: relative; 48 | width: _size(sidebar-width); 49 | 50 | h2 { 51 | font-size: (1.25em / 0.9); 52 | } 53 | 54 | > .inner { 55 | @include padding($sidebar-pad, $sidebar-pad, (0, 0, $sidebar-pad, 0)); 56 | position: relative; 57 | width: _size(sidebar-width); 58 | position: sticky !important; 59 | top: -1px !important; 60 | overflow: scroll; 61 | max-height: 100vh; 62 | 63 | // To hide scrollbar in Firefox 64 | scrollbar-width: none; 65 | // To hide scrollbar in Chrome 66 | &::-webkit-scrollbar { 67 | width: 0 !important; 68 | } 69 | 70 | > * { 71 | margin: 0 0 (_size(element-margin)/2) 0; 72 | padding: 0 0 (_size(element-margin)/2) 0; 73 | 74 | > :last-child { 75 | margin-bottom: 0; 76 | } 77 | 78 | &:last-child { 79 | border-bottom: 0; 80 | margin-bottom: 0; 81 | padding-bottom: 0; 82 | } 83 | } 84 | 85 | > .alt { 86 | background-color: darken(_palette(bg-alt), 2); 87 | border-bottom: 0; 88 | margin: ($sidebar-pad * -1) 0 ($sidebar-pad) ($sidebar-pad * -1); 89 | padding: $sidebar-pad; 90 | width: calc(100% + #{$sidebar-pad * 2}); 91 | } 92 | 93 | .major { 94 | margin-bottom: $sidebar-pad; 95 | > :last-child { 96 | margin: 0 0 0 0; 97 | } 98 | } 99 | 100 | .stack-info { 101 | display: flex; 102 | margin-bottom: $sidebar-pad; 103 | 104 | &.ghc-version { 105 | font-size: 12px; 106 | font-family: _font(family-fixed); 107 | font-weight: bold; 108 | } 109 | 110 | @include breakpoint(xlarge) { 111 | margin-bottom: $xlarge-sidebar-pad; 112 | } 113 | } 114 | } 115 | 116 | .toggle { 117 | @include icon; 118 | @include vendor('transition', 'left 0.5s ease'); 119 | -webkit-tap-highlight-color: rgba(255,255,255,0); 120 | border: 0; 121 | display: block; 122 | height: 7.5em; 123 | left: _size(sidebar-width); 124 | line-height: 7.5em; 125 | outline: 0; 126 | overflow: hidden; 127 | position: absolute; 128 | text-align: center; 129 | text-indent: -200%; 130 | top: 0; 131 | width: 6em; 132 | z-index: _misc(z-index-base); 133 | 134 | &:before { 135 | content: '\f0c9'; 136 | font-size: 2rem; 137 | height: inherit; 138 | left: 0; 139 | line-height: inherit; 140 | position: absolute; 141 | text-indent: 0; 142 | top: 0; 143 | width: inherit; 144 | } 145 | } 146 | 147 | &.inactive { 148 | margin-left: (_size(sidebar-width) * -1); 149 | } 150 | 151 | .toggle-theme-wrapper { 152 | position: absolute; 153 | top: 6em; 154 | left: _size(sidebar-width); 155 | .icon { 156 | display: block; 157 | width: 6em; 158 | text-align: center; 159 | &:before { 160 | display: block; 161 | width: 100%; 162 | font-size: 2rem; 163 | } 164 | } 165 | } 166 | 167 | @include breakpoint(xlarge) { 168 | width: _size(sidebar-width-alt); 169 | 170 | > .inner { 171 | @include padding($xlarge-sidebar-pad, $xlarge-sidebar-pad, (0, 0, $xlarge-sidebar-pad, 0)); 172 | width: _size(sidebar-width-alt); 173 | 174 | > .alt { 175 | margin: ($xlarge-sidebar-pad * -1) 0 ($xlarge-sidebar-pad) ($xlarge-sidebar-pad * -1); 176 | padding: $xlarge-sidebar-pad; 177 | width: calc(100% + #{$xlarge-sidebar-pad * 2}); 178 | } 179 | } 180 | 181 | .toggle { 182 | height: 6.25em; 183 | left: _size(sidebar-width-alt); 184 | line-height: 6.25em; 185 | width: 5em; 186 | 187 | &:before { 188 | font-size: 1.5rem; 189 | } 190 | } 191 | 192 | .toggle-theme-wrapper { 193 | top: 6em; 194 | left: _size(sidebar-width-alt); 195 | .icon { 196 | width: 5em; 197 | &:before { 198 | font-size: 1.5rem; 199 | } 200 | } 201 | } 202 | 203 | &.inactive { 204 | margin-left: (_size(sidebar-width-alt) * -1); 205 | } 206 | } 207 | 208 | @include breakpoint(large) { 209 | box-shadow: 0 0 5em 0 rgba(0, 0, 0, 0.175); 210 | height: 100%; 211 | left: 0; 212 | position: fixed; 213 | top: 0; 214 | z-index: _misc(z-index-base); 215 | 216 | &.inactive { 217 | box-shadow: none; 218 | } 219 | 220 | > .inner { 221 | -webkit-overflow-scrolling: touch; 222 | height: 100%; 223 | left: 0; 224 | overflow-x: hidden; 225 | overflow-y: auto; 226 | position: absolute; 227 | top: 0; 228 | 229 | &:after { 230 | content: ''; 231 | display: block; 232 | height: 4em; 233 | width: 100%; 234 | } 235 | } 236 | 237 | .toggle { 238 | width: 6em; 239 | 240 | &:before { 241 | font-size: 1.5rem; 242 | margin-left: (-0.875em / 2); 243 | } 244 | } 245 | 246 | .toggle-theme-wrapper { 247 | .icon { 248 | width: 6em; 249 | &:before { 250 | font-size: 1.5rem; 251 | margin-left: (-0.875em / 2); 252 | } 253 | } 254 | } 255 | 256 | body.is-loading & { 257 | display: none; 258 | } 259 | } 260 | 261 | @include breakpoint(small) { 262 | .toggle { 263 | width: 7.25em; 264 | 265 | &:before { 266 | color: _palette(fg); 267 | margin-left: (-0.125em / 2); 268 | margin-top: (-0.5em / 2); 269 | font-size: 1.1rem; 270 | z-index: 1; 271 | } 272 | 273 | &:after { 274 | background: transparentize(lighten(_palette(fg), 35), 0.25); 275 | border-radius: _size(border-radius); 276 | content: ''; 277 | height: 3.5em; 278 | left: 1em; 279 | position: absolute; 280 | top: 1em; 281 | width: 5em; 282 | } 283 | } 284 | 285 | .toggle-theme-wrapper { 286 | width: 4.25em; 287 | top: 1.3em; 288 | left: _size(sidebar-width) + 3em; 289 | .icon { 290 | width: 6em; 291 | &:before { 292 | font-size: 1.5rem; 293 | margin-left: (-0.875em / 2); 294 | } 295 | } 296 | } 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /_assets/stylesheets/layout/_wrapper.scss: -------------------------------------------------------------------------------- 1 | /* Wrapper */ 2 | 3 | #wrapper { 4 | @include vendor('display', 'flex'); 5 | @include vendor('flex-direction', 'row-reverse'); 6 | min-height: 100vh; 7 | } 8 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/_functions.scss: -------------------------------------------------------------------------------- 1 | /// Gets a duration value. 2 | /// @param {string} $keys Key(s). 3 | /// @return {string} Value. 4 | @function _duration($keys...) { 5 | @return val($duration, $keys...); 6 | } 7 | 8 | /// Gets a font value. 9 | /// @param {string} $keys Key(s). 10 | /// @return {string} Value. 11 | @function _font($keys...) { 12 | @return val($font, $keys...); 13 | } 14 | 15 | /// Gets a misc value. 16 | /// @param {string} $keys Key(s). 17 | /// @return {string} Value. 18 | @function _misc($keys...) { 19 | @return val($misc, $keys...); 20 | } 21 | 22 | /// Gets a palette value. 23 | /// @param {string} $keys Key(s). 24 | /// @return {string} Value. 25 | @function _palette($keys...) { 26 | @return val($palette, $keys...); 27 | } 28 | 29 | @function _purple($keys...) { 30 | @return val($purple, $keys...); 31 | } 32 | 33 | /// Gets a dark palette value. 34 | /// @param {string} $keys Key(s). 35 | /// @return {string} Value. 36 | @function _dark($keys...) { 37 | @return val($dark, $keys...); 38 | } 39 | 40 | /// Gets a size value. 41 | /// @param {string} $keys Key(s). 42 | /// @return {string} Value. 43 | @function _size($keys...) { 44 | @return val($size, $keys...); 45 | } 46 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/_vars.scss: -------------------------------------------------------------------------------- 1 | // Misc. 2 | $misc: ( 3 | z-index-base: 10000 4 | ); 5 | 6 | // Duration. 7 | $duration: ( 8 | nav: 0.5s, 9 | transition: 0.2s 10 | ); 11 | 12 | // Size. 13 | $size: ( 14 | border-radius: 0.375em, 15 | element-height: 2.75em, 16 | element-margin: 2em, 17 | sidebar-width: 26em, 18 | sidebar-width-alt: 24em, 19 | gutter: 3em 20 | ); 21 | 22 | // Font. 23 | $font: ( 24 | family: ('Open Sans', sans-serif), 25 | family-heading: ('Roboto Slab', serif), 26 | family-fixed: ('JetBrains Mono', monospace), 27 | weight: 400, 28 | weight-bold: 600, 29 | weight-heading: 700, 30 | weight-heading-alt: 400, 31 | kerning-heading: 0.075em 32 | ); 33 | 34 | // Palette. 35 | $palette: ( 36 | bg: #ffffff, 37 | bg-alt: #f5f6f7, 38 | fg: darken(#7f888f, 15%), 39 | fg-bold: #3d4449, 40 | fg-light: #9fa3a6, 41 | border: rgba(210,215,217,0.75), 42 | border-bg: transparentize(#e6ebed, 0.75), 43 | accent: #f56a6a 44 | ); 45 | 46 | // Dark Palette. 47 | $dark: ( 48 | bg: #3d4449, 49 | bg-alt: darken(#3d4449, 5%), 50 | fg: #f5f6f7, 51 | fg-bold: #ffffff, 52 | fg-light: lighten(#f5f6f7, 5%), 53 | border: rgba(210,215,217,0.25), 54 | border-bg: transparentize(#e6ebed, 0.75), 55 | accent: #f56a6a 56 | ); 57 | 58 | // Elixir School 59 | $purple: ( 60 | bg: lighten(#4A365F, 45%), 61 | fg: lighten(#4A365F, 10%), 62 | fg-bold: darken(#4A365F, 5%), 63 | fg-alt: lighten(#4A365F, 20%), 64 | fg-hov: lighten(#4A365F, 30%), 65 | accent: #F07E6B 66 | ); 67 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/font-awesome/_animated.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .#{$fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/font-awesome/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .#{$fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/font-awesome/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/font-awesome/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/font-awesome/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/font-awesome/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/font-awesome/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | @mixin fa-icon-rotate($degrees, $rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; 16 | -webkit-transform: rotate($degrees); 17 | -ms-transform: rotate($degrees); 18 | transform: rotate($degrees); 19 | } 20 | 21 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; 23 | -webkit-transform: scale($horiz, $vert); 24 | -ms-transform: scale($horiz, $vert); 25 | transform: scale($horiz, $vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | @mixin sr-only { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | @mixin sr-only-focusable { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/font-awesome/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url(asset_path('fontawesome-webfont.eot?v=#{$fa-version}')); 7 | src: url(asset_path('font-awesome-webfont.eot?#iefix&v=#{$fa-version}')) format('embedded-opentype'), 8 | url(asset_path('fontawesome-webfont.woff2?v=#{$fa-version}')) format('woff2'), 9 | url(asset_path('fontawesome-webfont.woff?v=#{$fa-version}')) format('woff'), 10 | url(asset_path('fontawesome-webfont.ttf?v=#{$fa-version}')) format('truetype'), 11 | url(asset_path('fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular')) format('svg'); 12 | font-weight: normal; 13 | font-style: normal; 14 | font-display: swap; 15 | } 16 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/font-awesome/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/font-awesome/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/font-awesome/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /_assets/stylesheets/libs/font-awesome/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "animated"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | @import "screen-reader"; 19 | -------------------------------------------------------------------------------- /_assets/stylesheets/main.scss: -------------------------------------------------------------------------------- 1 | @import 'libs/vars'; 2 | @import 'libs/functions'; 3 | @import 'libs/mixins'; 4 | @import 'libs/skel'; 5 | 6 | 7 | // Skel 8 | @include skel-breakpoints((xlarge: '(max-width: 1680px)', 9 | large: '(max-width: 1280px)', 10 | medium: '(max-width: 980px)', 11 | small: '(max-width: 736px)', 12 | xsmall: '(max-width: 480px)', 13 | xxsmall: '(max-width: 360px)', 14 | xlarge-to-max: '(min-width: 1681px)', 15 | small-to-xlarge: '(min-width: 481px) and (max-width: 1680px)' 16 | )); 17 | 18 | @include skel-layout((reset: 'full', 19 | boxModel: 'border', 20 | grid: (gutters: 1.5em))); 21 | 22 | // Base. 23 | 24 | @import 'base/page'; 25 | @import 'base/typography'; 26 | @import 'base/syntax'; 27 | 28 | // Component. 29 | @import 'components/section'; 30 | @import 'components/form'; 31 | @import 'components/box'; 32 | @import 'components/icon'; 33 | @import 'components/image'; 34 | @import 'components/list'; 35 | @import 'components/table'; 36 | @import 'components/button'; 37 | @import 'components/mini-posts'; 38 | @import 'components/features'; 39 | @import 'components/posts'; 40 | @import 'components/errors'; 41 | 42 | // Layout. 43 | 44 | @import 'layout/wrapper'; 45 | @import 'layout/main'; 46 | @import 'layout/sidebar'; 47 | @import 'layout/header'; 48 | @import 'layout/banner'; 49 | @import 'layout/footer'; 50 | @import 'layout/menu'; 51 | 52 | // Theme. 53 | @import 'dark'; 54 | 55 | @import url('https://fonts.googleapis.com/css?family=Open+Sans:400,600,400italic,600italic|Roboto+Slab:400,700'); 56 | @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@500&display=swap'); 57 | 58 | .breadcrumb { 59 | ul { 60 | align-items: flex-start; 61 | display: flex; 62 | flex-wrap: wrap; 63 | justify-content: flex-start; 64 | list-style: none; 65 | padding-left: 0; 66 | margin-top: -4em; 67 | margin-bottom: 3em; 68 | 69 | li { 70 | align-items: center; 71 | margin-right: .75em; 72 | 73 | &:before { 74 | content: "\0002f"; // / 75 | padding-right: .75em; 76 | } 77 | 78 | &:first-child { 79 | &:before { 80 | content: "" !important; 81 | padding: 0 !important; 82 | } 83 | } 84 | 85 | &.is-active { 86 | &:before { 87 | color: _purple(fg-alt); 88 | } 89 | } 90 | 91 | &:last-child { 92 | margin: 0; 93 | } 94 | } 95 | } 96 | } 97 | 98 | .tags { 99 | display: inline-flex; 100 | align-items: center; 101 | flex-wrap: wrap; 102 | justify-content: flex-start; 103 | 104 | .title { 105 | margin: 0 1em 0 0; 106 | } 107 | 108 | .tag { 109 | display: inline-flex; 110 | align-items: center; 111 | justify-content: center; 112 | border-radius: _size(border-radius); 113 | background-color: _palette(border); 114 | color: #000; 115 | line-height: 1.5; 116 | font-size: .75rem; 117 | height: 2em; 118 | padding: 0 .75em; 119 | white-space: nowrap; 120 | margin-right: .75em; 121 | 122 | &:last-child { 123 | margin-right: 0px; 124 | } 125 | 126 | a { 127 | border: 0; 128 | text-decoration: none; 129 | 130 | &:hover { 131 | text-decoration: underline 132 | } 133 | } 134 | } 135 | } 136 | 137 | .profile { 138 | h2 { 139 | margin: 0 0 .5em 0; 140 | } 141 | 142 | .content { 143 | margin: 0 0 .5em 0; 144 | } 145 | 146 | img { 147 | border-radius: _size(border-radius); 148 | border: 0; 149 | } 150 | 151 | @include breakpoint(small) { 152 | h2 { 153 | text-align: center; 154 | } 155 | 156 | .icons { 157 | text-align: center; 158 | 159 | li { 160 | display: inline-block; 161 | float: none; 162 | } 163 | } 164 | 165 | img { 166 | display: block; 167 | margin-left: auto; 168 | margin-right: auto; 169 | } 170 | } 171 | } 172 | 173 | section .content { 174 | h2 { 175 | border-bottom: solid 3px _purple(fg-hov); 176 | display: inline-block; 177 | margin: 0 0 _size(element-margin) 0; 178 | padding: 0 0.75em 0.5em 0; 179 | } 180 | 181 | .edit-lesson { 182 | margin: 4em 0 0 0; 183 | 184 | @include breakpoint(xlarge) { 185 | margin: 3em 0 0 0; 186 | } 187 | 188 | @include breakpoint(large) { 189 | margin: 2em 0 0 0; 190 | } 191 | 192 | @include breakpoint(small) { 193 | margin: 1em 0 0 0; 194 | } 195 | } 196 | } 197 | 198 | pre { 199 | white-space: pre-wrap; 200 | word-wrap: break-word; 201 | } 202 | 203 | .post-info { 204 | margin: -0.5em 0 1em 0; 205 | font-size: 0.8rem; 206 | 207 | .bold { 208 | font-weight: 600; 209 | } 210 | } 211 | 212 | .section-prevnext { 213 | @include breakpoint(small) { 214 | h4 { 215 | font-size: 0.75em; 216 | } 217 | } 218 | } 219 | 220 | #section-page { 221 | 222 | /** 223 | * Right-to-left languages 224 | */ 225 | &.rtl { 226 | direction: rtl; 227 | unicode-bidi: embed; 228 | } 229 | 230 | &.rtl ul>li { 231 | margin-right: 10px; 232 | } 233 | 234 | &.rtl pre { 235 | direction: ltr; 236 | text-align: left; 237 | } 238 | 239 | &.rtl .content { 240 | margin-right: auto; 241 | } 242 | 243 | .clickable-header { 244 | display: inline-block; 245 | cursor: pointer; 246 | } 247 | 248 | .back-to-top { 249 | display: inline; 250 | cursor: pointer; 251 | padding: 0px 1em; 252 | color: #ddd; 253 | 254 | &::after { 255 | content: '\A'; 256 | white-space: pre; 257 | } 258 | } 259 | 260 | img { 261 | max-width: 100%; 262 | } 263 | 264 | 265 | /** 266 | * Versioning 267 | */ 268 | 269 | .page-title { 270 | display: inline-flex; 271 | align-items: center; 272 | } 273 | 274 | .version-difference-indicator { 275 | width: 0.5em; 276 | height: 0.5em; 277 | margin: 0 0.25em; 278 | border-radius: 50%; 279 | } 280 | 281 | .version-info { 282 | width: 100%; 283 | font-size: 0.75em; 284 | margin-bottom: 0.75em; 285 | padding: 0.5em; 286 | border: 1px solid transparent; 287 | cursor: pointer; 288 | } 289 | 290 | $version_color_map: ("major": "#f00", 291 | "minor": "#f60", 292 | "patch": "#fc3", 293 | "none": "#9f0", 294 | "error": "#f00", 295 | "missing": "#f00", 296 | ); 297 | 298 | @each $severity, 299 | $color in $version_color_map { 300 | 301 | .version-info-#{$severity} { 302 | border-color: #{$color}; 303 | } 304 | 305 | .version-difference-#{$severity} { 306 | background-color: #{$color}; 307 | } 308 | } 309 | 310 | .translation-report { 311 | 312 | .version-difference-indicator { 313 | width: 1em; 314 | height: 1em; 315 | margin: auto; 316 | } 317 | 318 | .version-cell { 319 | vertical-align: middle; 320 | cursor: help; 321 | } 322 | } 323 | } 324 | 325 | .responsive-embed { 326 | position: relative; 327 | overflow: hidden; 328 | padding-top: 56.25%; 329 | 330 | iframe { 331 | position: absolute; 332 | top: 0; 333 | left: 0; 334 | width: 100%; 335 | height: 100%; 336 | border: 0; 337 | } 338 | } 339 | 340 | /* modification for button copy */ 341 | .highlight>pre>div { 342 | display: flex; 343 | flex-direction: row-reverse; 344 | } 345 | 346 | .btn-copy { 347 | border: 0; 348 | cursor: pointer; 349 | position: absolute; 350 | margin-right: 0.5em; 351 | } 352 | 353 | .btn-copy:hover { 354 | background-color: _purple(fg-hov); 355 | } 356 | 357 | /* modification for button copy */ 358 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Setup 2 | name: Haskell School 3 | url: https://haskellfoundation.github.io/ 4 | permalink: /blog/:title/ 5 | default_lang: en 6 | exclude_from_localization: [] 7 | encoding: utf-8 8 | 9 | plugins: 10 | - jekyll-assets 11 | # - jekyll-redirect-from 12 | - jekyll-sitemap 13 | - kramdown 14 | - uglifier 15 | - jekyll-archives 16 | 17 | # Markdown Config 18 | markdown: kramdown 19 | kramdown: 20 | input: GFM 21 | syntax_highlighter: rouge 22 | 23 | # Assets 24 | exclude: ['config.ru', 'CONTRIBUTING.md', 'Gemfile', 'Gemfile.lock', 'GLOSSARY', 'Rakefile', 'README.md', 'vendor', 'LICENSE'] 25 | assets: 26 | compress: 27 | css: sass 28 | js: uglifier 29 | digest: true 30 | sources: 31 | - _assets/images 32 | - _assets/javascripts 33 | - _assets/stylesheets 34 | - _assets/fonts 35 | 36 | 37 | ghc_version: 9.0 38 | 39 | sitemap: 40 | file: '/sitemap.xml' 41 | include_posts: 42 | - '/index.html' 43 | change_frequency_name: 'change_frequency' 44 | priority_name: 'priority' 45 | 46 | jekyll-archives: 47 | enabled: ['categories', 'tags', 'year'] 48 | layout: archive 49 | permalinks: 50 | year: '/blog/years/:year/' 51 | category: '/blog/categories/:name/' 52 | tag: '/blog/tags/:name/' 53 | 54 | defaults: 55 | - 56 | scope: 57 | path: "" # an empty string here means all files in the project 58 | values: 59 | layout: "default" 60 | - 61 | scope: 62 | type: "pages" 63 | values: 64 | layout: "page" 65 | - 66 | scope: 67 | type: "posts" 68 | values: 69 | layout: "post" 70 | 71 | # Helpers 72 | empty_array: [] 73 | -------------------------------------------------------------------------------- /_config_dev.yml: -------------------------------------------------------------------------------- 1 | port: 4001 2 | url: http://localhost 3 | baseurl: / 4 | 5 | # assets: 6 | # compress: 7 | # css: false 8 | # js: false 9 | -------------------------------------------------------------------------------- /_data/blog-meta.yml: -------------------------------------------------------------------------------- 1 | categories: 2 | - name: announcement 3 | caption: Announcements 4 | description: "Haskell School announcements." 5 | - name: general 6 | caption: General 7 | description: "General topics about the Haskell language." 8 | - name: til 9 | caption: Today I Learned 10 | description: "Useful pro-tips that you can use on your own." 11 | -------------------------------------------------------------------------------- /_data/contents.yml: -------------------------------------------------------------------------------- 1 | home: 2 | - home 3 | - report 4 | basics: 5 | - basics 6 | - functions 7 | - types 8 | - algebraic-data-types 9 | - lists-tuples 10 | - control-structures 11 | - pattern-matching 12 | - containers 13 | typeclasses: 14 | - what-are-typeclasses 15 | - comparison 16 | - enumeration 17 | - string-representation 18 | - monoids 19 | - iteration 20 | - functors 21 | - numbers 22 | -------------------------------------------------------------------------------- /_data/contributors.yml: -------------------------------------------------------------------------------- 1 | # INSTRUCTIONS 2 | # add your github profile, and contributions. See details below. 3 | # 4 | # github: (required), name:, twitter:, homepage:, intro: 5 | # contributions: lesson, blog, translation, developer (required) 6 | # languages: list of ISO language codes to which you contributed 7 | # lessons: list contributed lesson names (required if applicable) 8 | # articles: list of titles from contributed blog articles (required if applicable) 9 | # translations: list of locales translated (required if applicable) 10 | 11 | ## Example: 12 | # - github: doomspork 13 | # name: Sean Callan 14 | # intro: 15 | # Sean has been passionately involved with Elixir since the very beginning. 16 | # After experiencing the joys of working with Elixir he created Elixir School and has become a core contributor to numerous libraries. 17 | # During the day, Sean helps companies transition teams and codebases to Elixir. 18 | # twitter: doomspork 19 | # homepage: https://seancallan.com 20 | # contributions: 21 | # - lesson 22 | # - developer 23 | # - blog 24 | # languages: 25 | # - en 26 | # lessons: ['Project creator'] 27 | # articles: 28 | # - A look at Elixir 1.6 29 | # - Just the beginning 30 | # - Configuration Demystified 31 | # - Ecto query composition 32 | # - 'Umbrellas: only when it rains?' 33 | - github: JonathanLorimer 34 | name: Jonathan Lorimer 35 | intro: 36 | Jonathan Lorimer was a philosophy student who couldn't turn it into a 37 | career so he sold out and learned how to do web development. Along the way 38 | he discovered haskell, and found it to be an edifying endeavour in the same 39 | ways that philosophy was. 40 | twitter: jonathanlorime1 41 | homepage: https://jonathanlorimer.dev 42 | contributions: 43 | - lesson 44 | languages: 45 | - en 46 | lessons: ['collections'] 47 | -------------------------------------------------------------------------------- /_data/locales/en.yml: -------------------------------------------------------------------------------- 1 | script_direction: ltr 2 | menu: Menu 3 | project: 4 | title: Haskell School 5 | description: The reference destination for learning and mastering Haskell 6 | table_of_contents: Table of Contents 7 | share: Share This Page 8 | sections: 9 | home: Home 10 | basics: Basics 11 | typeclasses: Typeclasses 12 | blog: Blog 13 | contributors: Contributors 14 | translation_report: Translation Report 15 | 16 | version_messages: 17 | outdated: "Some contents of this translation may be outdated." 18 | major: "Several major changes were applied to the original lesson since the last update." 19 | minor: "Several minor changes were applied to the original lesson since the last update." 20 | patch: "Several patches were applied to the original lesson since the last update." 21 | none: "This translation is up to date." 22 | error: "There is an error in the version definition of this chapter." 23 | 24 | translation_report: 25 | section: Section 26 | original_title: Original Title 27 | translation_title: Translation Title 28 | original_version: Original Version 29 | translation_version: Translation Version 30 | version_severity: Version Severity 31 | last_commit: Last Commit 32 | 33 | interlang: 34 | en: English 35 | fr: French 36 | ru: Russian 37 | -------------------------------------------------------------------------------- /_data/locales/fr.yml: -------------------------------------------------------------------------------- 1 | script_direction: ltr 2 | menu: Menu 3 | project: 4 | title: Haskell School 5 | description: La première destination pour apprendre et maîtriser Haskell. 6 | table_of_contents: Table des matières 7 | share: Partager cette page 8 | sections: 9 | home: Accueil 10 | basics: Bases 11 | advanced: Avancé 12 | specifics: Spécificités 13 | ecto: Ecto 14 | libraries: Bibliothèques 15 | blog: Blog 16 | contributors: Contributeurs 17 | translation_report: Rapport de Traductions 18 | 19 | version_messages: 20 | outdated: "Certains contenus de cette traduction peuvent ne pas être à jour." 21 | major: "La leçon originale a reçu plusieurs changements majeurs depuis la dernière mise à jour." 22 | minor: "La leçon originale a reçu plusieurs changements mineurs depuis la dernière mise à jour." 23 | patch: "La leçon originale a reçu plusieurs patchs depuis la dernière mise à jour." 24 | none: "Cette traduction est à jour." 25 | error: "Il y a une erreur dans la définition de version de ce chapitre." 26 | 27 | translation_report: 28 | section: Section 29 | original_title: Titre Original 30 | translation_title: Titre Traduit 31 | original_version: Version Originale 32 | translation_version: Version Traduite 33 | version_severity: Sévérité de Version 34 | last_commit: Dernier Commit 35 | 36 | interlang: 37 | ar: Arabe 38 | bg: Bulgare 39 | bn: Bengali 40 | de: Allemand 41 | en: Anglais 42 | es: Espagnol 43 | fr: Francais 44 | gr: Grec 45 | id: Indonesien 46 | it: Italien 47 | ja: Japonais 48 | ko: Coréen 49 | ms: Malaysien 50 | "no": Norvegien 51 | pl: Polonais 52 | pt: Portuguais 53 | ru: Russe 54 | sk: Slovaque 55 | ta: Tamoul 56 | th: Thailandais 57 | tr: Turc 58 | uk: Ukrainien 59 | vi: Vietnamien 60 | zh-hans: Chinois 61 | zh-hant: Chinois Traditionnel 62 | -------------------------------------------------------------------------------- /_data/locales/ru.yml: -------------------------------------------------------------------------------- 1 | script_direction: ltr 2 | menu: Меню 3 | project: 4 | title: Haskell School 5 | description: Уроки программирования на языке Haskell 6 | table_of_contents: Содержание 7 | share: Поделиться 8 | sections: 9 | home: Домашняя страница 10 | basics: Основы 11 | advanced: Продвинутый 12 | specifics: Специфика 13 | ecto: Ecto 14 | libraries: Библиотеки 15 | blog: Блог 16 | contributors: Участники 17 | translation_report: Состояние перевода 18 | 19 | version_messages: 20 | outdated: "Некоторое содержимое этого урока может оказаться устаревшим." 21 | major: "С момента последнего обновления перевода в оригинальный урок были внесены серьёзные изменения." 22 | minor: "С момента последнего обновления перевода в оригинальный урок были внесены небольшие изменения." 23 | patch: "С момента последнего обновления перевода в оригинальный урок были внесены небольшие правки." 24 | none: "Это перевод актуальной версии оригинального урока." 25 | error: "Обнаружена ошибка в объявлении этого урока." 26 | 27 | translation_report: 28 | section: Раздел 29 | original_title: Заголовок оригинала 30 | translation_title: Заголовок перевода 31 | original_version: Версия оригинала 32 | translation_version: Версия перевода 33 | version_severity: Разница в версиях 34 | last_commit: Последний коммит 35 | 36 | interlang: 37 | ar: Арабский 38 | bg: Болгарский 39 | bn: Бенгальский 40 | de: Немецкий 41 | en: Английский 42 | es: Испанский 43 | fr: Французский 44 | gr: Греческий 45 | id: Индонезийский 46 | it: Итальянский 47 | ja: Японский 48 | ko: Корейский 49 | ms: Малайский 50 | "no": Норвежский 51 | pl: Польский 52 | pt: Португальский 53 | ru: Русский 54 | sk: Словацкий 55 | ta: Тамильский 56 | th: Тайский 57 | tr: Турецкий 58 | uk: Украинский 59 | vi: Вьетнамский 60 | zh-hans: Китайский 61 | zh-hant: Китайский традиционный 62 | -------------------------------------------------------------------------------- /_data/redirects.yml: -------------------------------------------------------------------------------- 1 | # "": "en" 2 | # cn: "zh-hans" 3 | # jp: "ja" 4 | # my: "ms" 5 | # tw: "zh-hant" 6 | -------------------------------------------------------------------------------- /_includes/_head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% for _interlang_chapter in site.tree[page.lang][page.section][page.chapter]['interlang'] %} 18 | {% assign _lang = _interlang_chapter[0] %} 19 | {% assign _url = _interlang_chapter[1]['url'] %} 20 | 21 | {% if _lang == "en" %} 22 | 23 | 24 | {% elsif _lang == "gr" %} 25 | 26 | {% else %} 27 | 28 | {% endif %} 29 | {% endfor %} 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | {% assign title = locale.project.title %} 42 | {% unless page.title == locale.project.title or page.title == nil %} 43 | {% assign title = page.title | append: " · " | append: title %} 44 | {% else %} 45 | 46 | {% endunless %} 47 | {{ title }} 48 | 49 | 50 | {% asset main.css %} 51 | 52 | 53 | 54 | 65 | 66 | -------------------------------------------------------------------------------- /_includes/_sidebar.html: -------------------------------------------------------------------------------- 1 | 2 | 14 | -------------------------------------------------------------------------------- /_includes/article-preview.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_includes/contributor-profile.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |

    5 | {% if include.contributor.name %} 6 | {{include.contributor.name}} 7 | {% else %} 8 | @{{include.contributor.github}} 9 | {% endif %} 10 |

    11 |

    {{ include.contributor.intro }}

    12 |
      13 | {% if include.contributor.homepage %} 14 |
    • Homepage
    • 15 | {% endif %} 16 | {% if include.contributor.twitter %} 17 |
    • Twitter
    • 18 | {% endif %} 19 |
    • Github
    • 20 |
    21 |
    22 |
    23 | -------------------------------------------------------------------------------- /_includes/function-displayAuthor: -------------------------------------------------------------------------------- 1 | {%- if include.contributor -%} 2 | {%- if include.contributor.homepage -%} 3 | {{include.contributor.name}} 4 | {%- else -%} 5 | {{include.contributor.name}} 6 | {%- endif -%} 7 | {%- endif -%} 8 | -------------------------------------------------------------------------------- /_includes/function-getArticle.html: -------------------------------------------------------------------------------- 1 | {% for article in site.posts %} 2 | {% if article.title == include.article %} 3 | {% assign post = article %} 4 | {% endif %} 5 | {% endfor %} 6 | -------------------------------------------------------------------------------- /_includes/function-getCategoryMeta: -------------------------------------------------------------------------------- 1 | {% for check in site.data.blog-meta.categories %} 2 | {%- if include.name == check.name -%} 3 | {%- assign category-meta = check -%} 4 | {%- endif -%} 5 | {% endfor %} -------------------------------------------------------------------------------- /_includes/function-getContributor: -------------------------------------------------------------------------------- 1 | {% for user in site.data.contributors %} 2 | {% if include.type == "name" %} 3 | {% if include.search == user.name %} 4 | {% assign contributor = user %} 5 | {% endif %} 6 | {% endif %} 7 | {% if include.type == "github" %} 8 | {% if include.search == user.github %} 9 | {% assign contributor = user %} 10 | {% endif %} 11 | {% endif %} 12 | {% endfor %} 13 | -------------------------------------------------------------------------------- /_includes/function-getTagMeta: -------------------------------------------------------------------------------- 1 | {% for check in site.data.blog-meta.tags %} 2 | {%- if include.name == check.name -%} 3 | {%- assign tag-meta = check -%} 4 | {%- endif -%} 5 | {% endfor %} -------------------------------------------------------------------------------- /_includes/report.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    {{ site.data['locales'][page['lang']]['sections']['translation_report'] }} - {{ page['translation_report']['percentage'] }}%

    4 |
    5 | 6 | 7 | 8 | {% assign headers = page['translation_report']['headers'] %} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% for section in page['translation_report']['sections'] %} 19 | {% assign title = section[0] %} 20 | {% for lesson in section[1] %} 21 | 22 | 23 | 24 | 29 | 30 | 31 | 34 | 35 | {% endfor %} 36 | {% endfor %} 37 | 38 |
    {{ headers['section'] }}{{ headers['original_title'] }}{{ headers['translation_title'] }}{{ headers['original_version'] }}{{ headers['translation_version'] }}{{ headers['version_severity'] }}
    {{ site.data['locales'][page['lang']]['sections'][title] }}{{ lesson[1]['lesson'] }} 25 | {% unless lesson[1]['translated_severity'] == 'missing' %} 26 | {{ lesson[1]['translated_title'] }} 27 | {% endunless %} 28 | {{ lesson[1]['original_version'] }}{{ lesson[1]['translated_version'] }} 32 |
    33 |
    39 |
    40 | -------------------------------------------------------------------------------- /_includes/section-author.html: -------------------------------------------------------------------------------- 1 | {% if contributor %} 2 | 3 | {% include contributor-profile.html contributor=contributor %} 4 | 5 | {% endif %} -------------------------------------------------------------------------------- /_includes/section-home-banner.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /_includes/section-home-blog-posts.html: -------------------------------------------------------------------------------- 1 | 2 |
    3 |
    4 |

    Blog

    5 |
    6 |
    7 | {% for post in site.posts limit:6 %} 8 | {% include article-preview.html article=post %} 9 | {% endfor %} 10 |
    11 |
    12 | -------------------------------------------------------------------------------- /_includes/section-home-helloworld.html: -------------------------------------------------------------------------------- 1 | {% capture getting_started %} 2 | ```haskell 3 | module Greetings where 4 | 5 | data Lang = EN | DE | ES | RU 6 | 7 | hello EN = "Hello World" 8 | hello DE = "Hallo Welt" 9 | hello ES = "Hola Mundo" 10 | hello RU = "Привет мир" 11 | 12 | -- Now let's try it 13 | 14 | $ ghci Greetings.hs 15 | ghci> hello EN 16 | "Hello World" 17 | ghci> hello ES 18 | "Hola Mundo" 19 | ghci> hello RU 20 | "Привет мир" 21 | ``` 22 | {% endcapture %} 23 | 24 | {{ getting_started | markdownify }} 25 | 26 | -------------------------------------------------------------------------------- /_includes/section-pagination.html: -------------------------------------------------------------------------------- 1 | {% assign pagination = page.leaf %} 2 | {% unless pagination.previous == nil and pagination.next == nil %} 3 |
    4 | 5 |
    6 | {% unless pagination.previous == nil %} 7 | {% assign previous = site.tree[page.lang][pagination.previous.section][pagination.previous.chapter] %} 8 | {% if pagination.previous.section == 'home' %} 9 | {% assign title = site.data.locales[page.lang].sections.home %} 10 | {% else %} 11 | {% assign title = previous.title %} 12 | {% endif %} 13 |
    14 | ← {{ title }} 15 |
    16 | {% endunless %} 17 | {% unless pagination.next == nil %} 18 | {% assign next = site.tree[page.lang][pagination.next.section][pagination.next.chapter] %} 19 | 22 | {% endunless %} 23 |
    24 |
    25 | 26 | {% endunless %} 27 | -------------------------------------------------------------------------------- /_includes/section-prevnext.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 | {% if page.previous %} 5 |

    Previous article

    6 | 7 | {% else %} 8 |

    Current article

    9 | {{page.title}} 10 | {% endif %} 11 |
    12 |
    13 | {% if page.next %} 14 |

    Next article

    15 | 16 | {% else %} 17 |

    Current article

    18 | {{page.title}} 19 | {% endif %} 20 |
    21 |
    22 |
    23 | -------------------------------------------------------------------------------- /_includes/section-related.html: -------------------------------------------------------------------------------- 1 | {% if page.related_posts %} 2 | 17 | {% endif %} 18 | -------------------------------------------------------------------------------- /_includes/section-sidebar-contact.html: -------------------------------------------------------------------------------- 1 | 2 |
    3 |
    4 |

    Get in touch

    5 |
    6 |

    Sed varius enim lorem ullamcorper dolore aliquam aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin sed aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

    7 | 13 |
    14 | -------------------------------------------------------------------------------- /_includes/section-sidebar-langs.html: -------------------------------------------------------------------------------- 1 | {% if page.lang %} 2 | 3 | 19 | {% endif %} 20 | -------------------------------------------------------------------------------- /_includes/section-sidebar-menu.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 61 | -------------------------------------------------------------------------------- /_includes/section-sidebar-search.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /_includes/share-icons.html: -------------------------------------------------------------------------------- 1 |
      2 | {% if page.title == page.locale.project.title or page.title == "Haskell School" %} 3 | {% assign title = page.locale.project.description %} 4 | {% else %} 5 | {% assign title = page.title %} 6 | {% endif %} 7 |
    • 8 |
    • RSS
    • 9 |
    • Linkedin
    • 10 |
    • Twitter
    • 12 |
    • Facebook
    • 13 |
    • Pinterest
    • 15 |
    • VK
    • 17 |
    • Email
    • 18 |
    • Print
    • 19 |
    20 | -------------------------------------------------------------------------------- /_includes/social.html: -------------------------------------------------------------------------------- 1 | {% if page.title == page.locale.project.title or page.title == "Elixir School" %} 2 | {% assign title = page.locale.project.description %} 3 | {% else %} 4 | {% assign title = page.title %} 5 | {% endif %} 6 |
    7 |

    8 | {{ page.locale.share }} 9 |

    10 | -------------------------------------------------------------------------------- /_includes/toc.html: -------------------------------------------------------------------------------- 1 |

    {{ page.locale.table_of_contents }}

    2 |
    -------------------------------------------------------------------------------- /_includes/version.html: -------------------------------------------------------------------------------- 1 |

    2 | 3 | {{ page.title }} 4 |

    5 |
    6 | 7 | {% if page.version_severity == 'error' %} 8 | {{ page.locale.version_messages.error | default: site.default_locale.version_messages.error }}
    9 | {{ site.tree[site.default_lang][page.section][page.chapter].version | inspect }} vs {{ page.version | inspect }}
    10 | {% elsif page.version_severity != 'none' %} 11 | {{ page.locale.version_messages.outdated }}
    12 | {% endif %} 13 | 14 | {{ page.locale.version_messages[page.version_severity] }} 15 |
    16 |
    17 | -------------------------------------------------------------------------------- /_layouts/archive.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: blog 3 | --- 4 | {%- if page.type == "category" -%} 5 | {% include function-getCategoryMeta name=page.title %} 6 | {%- endif -%} 7 | 8 | {%- if page.type == "tag" -%} 9 | {% include function-getTagMeta name=page.title %} 10 | {%- endif -%} 11 | 12 | {%- capture caption -%} 13 | {%- case page.type -%} 14 | {%- when "year" -%} 15 | Published in {{ page.date | date: "%Y" }} 16 | {%- when "category" -%} 17 | {% if category-meta %}{{ category-meta.caption }}{% else %}{{ page.title }}{% endif %} 18 | {%- when "tag" -%} 19 | {{ page.title }} 20 | {%- endcase -%} 21 | {%- endcapture -%} 22 | 23 | {%- capture type_uri -%} 24 | {%- case page.type -%} 25 | {%- when "year" -%} 26 | Years 27 | {%- when "category" -%} 28 | Categories 29 | {%- when "tag" -%} 30 | Tags 31 | {%- endcase -%} 32 | {%- endcapture -%} 33 | 34 | {%- capture archive_uri -%} 35 | {%- case page.type -%} 36 | {%- when "year" -%} 37 | {{ site.jekyll-archives.permalinks.year | replace: ":year/", "" }} 38 | {%- when "category" -%} 39 | {{ site.jekyll-archives.permalinks.category | replace: ":name/", "" }} 40 | {%- when "tag" -%} 41 | {{ site.jekyll-archives.permalinks.tag | replace: ":name/", "" }} 42 | {%- endcase -%} 43 | {%- endcapture -%} 44 | 45 | {%- capture active_caption -%} 46 | {%- if page.type == "year" -%} 47 | {{ page.date | date: "%Y" }} 48 | {%- else -%} 49 | {{ page.title }} 50 | {%- endif -%} 51 | {%- endcapture -%} 52 | 53 | 61 | 62 |
    63 |

    {{ caption }}

    64 | {% if category-meta %}{{ category-meta.description | markdownify }}{% endif %} 65 | {% if tag-meta %}{{ tag-meta.description | markdownify }}{% endif %} 66 |
    67 |
    68 |
    69 | {% for post in page.posts %} 70 | {% include article-preview.html article=post %} 71 | {% endfor %} 72 |
    -------------------------------------------------------------------------------- /_layouts/blog.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
    5 | 6 | {{ content }} 7 | 8 |
    9 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | {% assign language = site.default_lang %} 3 | {% if page.lang %} 4 | {% assign language = page.lang %} 5 | {% endif %} 6 | {% assign locale = site.data['locales'][language] %} 7 | 8 | {% include _head.html %} 9 | 10 | 14 | 15 |
    16 | 17 | 27 | {% include _sidebar.html %} 28 |
    29 | 30 | 31 | {% asset main.js async %} 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /_layouts/home.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | {% include section-home-banner.html %} 5 | {% include section-home-blog-posts.html %} 6 | {% include section-pagination.html %} 7 | -------------------------------------------------------------------------------- /_layouts/page.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 |
    6 |
    7 | {% if page.version_severity == nil or page.lang == site.default_lang or page.section == 'home' %} 8 |

    {{ page.title }}

    9 | {% else %} 10 | {% include version.html %} 11 | {% endif %} 12 |
    13 |
    14 | {{ content }} 15 | 16 |
    17 | Caught a mistake or want to contribute to the lesson? 18 | 19 | Edit this page on GitHub! 20 | 21 |
    22 |
    23 |
    24 | 25 | {% include section-pagination.html %} 26 | -------------------------------------------------------------------------------- /_layouts/post.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | {%- if page.authors -%} 5 | {%- capture links -%} 6 | {%- for author in page.authors -%} 7 | {% include function-getContributor type="name" search=author %} 8 | {% include function-displayAuthor contributor=contributor %}\ 9 | {%- endfor -%} 10 | {%- endcapture -%} 11 | {% assign authors = links | split: "\" | array_to_sentence_string %} 12 | {%- else -%} 13 | {%- capture authors -%} 14 | {% include function-getContributor type="name" search=page.author %} 15 | {% include function-displayAuthor contributor=contributor %} 16 | {%- endcapture -%} 17 | {%- endif -%} 18 | {%- include function-getCategoryMeta name=page.categories.first %} 19 | {% assign post_date = page.date | date: "%Y" %} 20 |
    21 |
    22 |

    {{ page.title }}

    23 |

    {{ page.date | date_to_string }} · by {{ authors }}{% if category-meta.size %} in {{ category-meta.caption }}{%endif%}

    24 |
    25 |
    26 | {{ content }} 27 | {% if page.tags.size > 0 %} 28 |
    29 |

    Article tags

    30 | {% for tag in page.tags %} 31 | {{ tag }} 32 | {% endfor %} 33 |
    34 |

    35 | {% endif %} 36 | 37 |
    38 | Caught a mistake or want to contribute to the article? 39 | 40 | Edit this page on GitHub! 41 | 42 |
    43 |
    44 |
    45 | {% include section-prevnext.html %} 46 |
    47 | {%- if page.authors -%} 48 | {%- for author in page.authors -%} 49 | {% include function-getContributor type="name" search=author %} 50 | {% include section-author.html %} 51 |
    52 | {%- endfor -%} 53 | {%- else -%} 54 | {% include function-getContributor type="name" search=page.author %} 55 | {% include section-author.html %} 56 | {%- endif -%} 57 |
    58 | -------------------------------------------------------------------------------- /_plugins/haskell_school/redirects.rb: -------------------------------------------------------------------------------- 1 | # module HaskellSchool 2 | # class Redirects < Jekyll::Generator 3 | # priority :high 4 | 5 | # def generate(site) 6 | # site.data['redirects'].each do |from, to| 7 | # site.data['contents'].each do |category, pages| 8 | # pages.each do |page| 9 | # if (category == 'home') 10 | # page = page == 'home' ? '' : page 11 | # from_page = File.join(from, page) 12 | # to_page = File.join(to, page) 13 | # else 14 | # from_page = File.join(from, 'lessons', category, page) 15 | # to_page = File.join(to, 'lessons', category, page) 16 | # end 17 | 18 | # site.pages << JekyllRedirectFrom::RedirectPage.from_paths(site, from_page, to_page) 19 | # end 20 | # end 21 | # end 22 | # end 23 | # end 24 | # end 25 | -------------------------------------------------------------------------------- /_plugins/haskell_school/translation_report.rb: -------------------------------------------------------------------------------- 1 | module HaskellSchool 2 | class TranslationReport < Jekyll::Generator 3 | priority :low 4 | 5 | def generate(site) 6 | locales = site.data['locales'].keys.sort.delete_if { |lang| lang == site.config['default_lang'] } 7 | 8 | locales.each do |lang| 9 | site.pages << build_report(site, lang, locales) 10 | end 11 | end 12 | 13 | private 14 | 15 | def build_report(site, lang, locales) 16 | page = Jekyll::PageWithoutAFile.new(site, site.source, lang, 'report.md') 17 | page.data['section'] = 'report' 18 | page.data['chapter'] = 'report' 19 | page.data['lang'] = lang 20 | page.data['translation_report'] = build_translation_report(site, lang) 21 | 22 | build_interlang(site, lang, locales) 23 | 24 | page.content = '{% include report.html %}' 25 | 26 | page 27 | end 28 | 29 | def build_interlang(site, lang, locales) 30 | interlang = Hash.new { |h, k| h[k] = {} } 31 | 32 | locales.each do |locale| 33 | interlang[locale] = { 34 | 'title' => site.data['locales'][locale]['sections']['translation_report'], 35 | 'url' => "/#{locale}/report" 36 | } 37 | end 38 | 39 | site.config['tree'][lang]['report'] = {'report' => {'interlang' => interlang}} 40 | end 41 | 42 | def build_translation_report(site, lang) 43 | report = Hash.new { |hash, key| hash[key] = Hash.new { |h, k| h[k] = {} }} 44 | points = 0 45 | total_lessons = 0 46 | 47 | site.config['tree'][site.config['default_lang']].each do |section, section_content| 48 | section_content.each do |lesson, lesson_content| 49 | severity = translated_value(site, lang, section, lesson, 'version_severity') 50 | translated_severity = site.data['locales'][lang]['version_messages'][severity] || site.data['locales'][site.config['default_lang']]['version_messages'][severity] 51 | points += translation_points(severity) 52 | total_lessons += 1 53 | 54 | report[section][lesson] = { 55 | 'lesson' => lesson_content['title'], 56 | 'chapter' => lesson_content['chapter'], 57 | 'url' => lesson_content['url'], 58 | 'original_version' => prettify_version(lesson_content['version']), 59 | 'translated_url' => translated_value(site, lang, section, lesson, 'url'), 60 | 'translated_title' => translated_value(site, lang, section, lesson, 'title'), 61 | 'translated_version' => prettify_version(translated_value(site, lang, section, lesson, 'version')), 62 | 'version_severity' => severity, 63 | 'translated_severity' => translated_severity, 64 | 'last_commit' => severe?(severity) ? find_last_commit(severity, lesson_content) : '' 65 | } 66 | end 67 | end 68 | 69 | { 70 | 'headers' => site.data['locales'][lang]['translation_report'] || site.data['locales'][site.config['default_lang']]['translation_report'], 71 | 'sections' => report, 72 | 'percentage' => points_to_percentage(points, total_lessons) 73 | } 74 | end 75 | 76 | def find_last_commit(severity, lesson_content) 77 | file = lesson_content["url"].gsub('"', '').gsub(/\/$/, '.md') 78 | if file == '/en.md' 79 | file = '/en/index.md' 80 | end 81 | git = `git blame -L 2,2 -- #{Dir.pwd}/#{file}` 82 | "https://github.com/HaskellFoundation/HaskellSchool/commit/#{git[0..7]}" 83 | end 84 | 85 | def severe?(severity) 86 | severity != "none" && severity != "error" 87 | end 88 | 89 | def prettify_version(version) 90 | version.is_a?(Array) ? version.join('.') : '' 91 | end 92 | 93 | def points_to_percentage(points, total_lessons) 94 | sprintf("%0.2f", (points / total_lessons) * 100) 95 | end 96 | 97 | def translated_value(site, lang, section, lesson, key) 98 | site.config['tree'][lang][section][lesson][key] 99 | rescue 100 | if key == 'version_severity' 101 | 'missing' 102 | end 103 | end 104 | 105 | def translation_points(version_severity) 106 | case version_severity 107 | when 'none' 108 | 1.0 109 | when 'patch' 110 | 0.9 111 | when 'minor' 112 | 0.7 113 | when 'major' 114 | 0.5 115 | else 116 | 0 117 | end 118 | end 119 | end 120 | end 121 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Haskell School", 3 | "description": "Haskell School — Lessons in the Haskell programming language.", 4 | "repository": "https://github.com/HaskellFoundation/HaskellSchool", 5 | "website": "https://school.haskell.org", 6 | "keywords": ["haskell", "functional programming", "haskell school", "learning", "open-source"] 7 | } 8 | -------------------------------------------------------------------------------- /blog-archive-categories.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Categories 3 | layout: blog 4 | disable_transform: true 5 | exclude_from_chapters: true 6 | permalink: /blog/categories/ 7 | --- 8 | 15 | 16 |
    17 |

    Categories

    18 | 25 |
    26 | {% for topic in site.categories %} 27 | {% assign category_name=topic[0] %} 28 | {% include function-getCategoryMeta name=category_name %} 29 |

    {{ category-meta.caption }}

    30 | {{ category-meta.description | markdownify }} 31 |
      32 | {% assign pages_list = topic[1] %} 33 | {% for post in pages_list %} 34 | {% if post.title != null %} 35 |
    • {{ post.title }}
    • 36 | {% endif %} 37 | {% endfor %} 38 | {% assign pages_list = nil %} 39 | {% assign category_name=nil %} 40 |
    41 | {% endfor %} 42 |
    43 | -------------------------------------------------------------------------------- /blog-archive-tags.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tags 3 | layout: blog 4 | disable_transform: true 5 | exclude_from_chapters: true 6 | permalink: /blog/tags/ 7 | --- 8 | 15 | 16 |
    17 |

    Tags

    18 | 23 |
    24 | {%- for topic in site.tags -%} 25 | {% assign tag_name = topic[0] %} 26 | {% include function-getTagMeta name=tag_name %} 27 |

    {{ topic[0] }}

    28 | {{ tag-meta.description | markdownify }} 29 |
      30 | {% assign pages_list = topic[1] %} 31 | {% for post in pages_list %} 32 | {% if post.title != null %} 33 |
    • {{ post.title }}
    • 34 | {% endif %} 35 | {% endfor %} 36 |
    37 | {% assign pages_list = nil %} 38 | {% assign tag_name = nil %} 39 | {%- endfor -%} 40 |
    41 | -------------------------------------------------------------------------------- /blog-archive-years.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Yearly Round up 3 | layout: blog 4 | disable_transform: true 5 | exclude_from_chapters: true 6 | permalink: /blog/years/ 7 | --- 8 | 15 | 16 |
    17 |

    Yearly Round-up

    18 | {% for post in site.posts %} 19 | {% assign post_dates = post.date | date: "%Y" | prepend: post_dates | append: "," %} 20 | {% endfor %} 21 | {% assign years = post_dates | split: "," | uniq %} 22 |
      23 | {% for year in years %} 24 |
    • {{ year }}
    • 25 | {% endfor %} 26 |
    27 |
    28 | {% for year in years %} 29 |

    {{ year }}

    30 |
      31 | {% for post in site.posts %} 32 | {% assign post_year = post.date | date: "%Y" %} 33 | {% if year == post_year %} 34 |
    • {{ post.title }}
    • 35 | {% endif %} 36 | {% endfor %} 37 |
    38 | {% endfor %} 39 |
    40 | -------------------------------------------------------------------------------- /blog.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Blog 3 | layout: blog 4 | disable_transform: true 5 | exclude_from_chapters: true 6 | --- 7 |
    8 | {% for post in site.posts %} 9 | {% include article-preview.html article=post %} 10 | {% endfor %} 11 |
    12 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require 'rack/jekyll' 2 | require 'yaml' 3 | run Rack::Jekyll.new 4 | -------------------------------------------------------------------------------- /contributors.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contributors 3 | layout: default 4 | disable_transform: true 5 | exclude_from_chapters: true 6 | --- 7 | 12 |
    13 |
    14 |

    Contributors

    15 |
    16 |

    Calling all contributors: if you've been missed, now's your chance to get the recognition you 17 | deserve. Add your Github profile to the list of contributors.

    18 | {% for contributor in site.data.contributors %} 19 |
    20 | {% include contributor-profile.html contributor=contributor %} 21 | {% for contribution in contributor.contributions %} 22 | {% unless contribution == "developer" %} 23 |
    24 | {% if contribution == "lesson" %} 25 |

    Lessons

    26 |
      27 | {% for lesson in contributor.lessons %}
    • {{ lesson }}
    • {% endfor %} 28 |
    29 | {% endif %} 30 | {% if contribution == "blog" %} 31 |

    Articles

    32 |
      33 | {% for article in contributor.articles %}
    • {% include function-getArticle.html article=article %}{{ post.title }}
    • {% endfor %} 34 |
    35 | {% endif %} 36 | {% if contribution == "translator" %} 37 |

    Translations

    38 | 41 | {% endif %} 42 |
    43 | {% endunless %} 44 | {% endfor %} 45 |
    46 | {% endfor %} 47 | 48 |
    49 | -------------------------------------------------------------------------------- /en/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Haskell School 3 | layout: home 4 | version: 1.0.0 5 | --- 6 | 7 | Haskell School is the reference destination to learn the Haskell programming language, with short and clear lessons. 8 | 9 | Whether you're a seasoned veteran or this is your first time, you'll find what you need in lessons and auxiliary resources. 10 | 11 | The content is currently being translated to [French][fr] and [Russian][ru]. 12 | Join us to bring Haskell School to your language! 13 | 14 | [fr]: /fr/ 15 | [ru]: /ru 16 | -------------------------------------------------------------------------------- /en/lessons/basics/basics.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1.0.0 3 | title: Basics 4 | --- 5 | 6 | Getting started, basic data types, and basic operations. 7 | 8 | {% include toc.html %} 9 | 10 | ## Getting Started 11 | 12 | ### Installing Haskell 13 | 14 | The recommended installation instructions for each OS can be found at 15 | [ghcup](https://www.haskell.org/ghcup/). 16 | 17 | You can check the version of the Haskell compiler installed by running 18 | `ghc --version`: 19 | ```shell 20 | $ ghc --version 21 | The Glorious Glasgow Haskell Compilation System, version {{ site.ghc.version }} 22 | ``` 23 | ### Trying Interactive Mode 24 | 25 | Your installation should come with `ghci`, an interactive shell that allows you 26 | to try out code in real time. 27 | 28 | Follow this tutorial by running `ghci`: 29 | ```console?lang=haskell&prompt=ghci>,ghci| 30 | GHCi, version {{ site.ghc.version }}: https://www.haskell.org/ghc/ :? for help 31 | ghci> 32 | ``` 33 | To use the `Text` type in this tutorial, type in: 34 | 35 | ```console?lang=haskell&prompt=ghci>,ghci| 36 | ghci> :set -XOverloadedStrings 37 | ghci> import qualified Data.Text as T 38 | ghci> import qualified Data.Text.IO as T 39 | ``` 40 | __Note__: qualified imports are used here to prevent name conflicts. 41 | Imports also allow you to choose the module namespace. 42 | 43 | You can try out Haskell by typing in a few simple expressions: 44 | 45 | ```console?lang=haskell&prompt=ghci>,ghci| 46 | ghci> 2 + 3 47 | 5 48 | ghci> 2 + 3 == 5 49 | True 50 | ghci> T.length "The quick brown fox jumps over the lazy dog" 51 | 43 52 | ``` 53 | 54 | Perhaps you are able to figure out what some of these expressions mean. 55 | 56 | ## Basic Data Types 57 | 58 | ### Integers 59 | 60 | Haskell has a bounded integer type called `Int`: 61 | 62 | ```console?lang=haskell&prompt=ghci>,ghci| 63 | ghci> 196883 :: Int 64 | 196883 65 | ``` 66 | __Note__: `::` specifies the type being used. 67 | 68 | Haskell also supports arbitrary precision integers with `Integer`: 69 | 70 | ```console?lang=haskell&prompt=ghci>,ghci| 71 | ghci> 123456789101112131415 72 | 123456789101112131415 73 | ``` 74 | __Note__: `ghci` automatically defaults to `Integer` here. 75 | 76 | ### Floats 77 | 78 | Haskell supports `Double`, a double-precision floating-point number. 79 | At least one digit must come before the decimal point and Haskell supports 80 | scientific `e` notation. 81 | 82 | ```console?lang=haskell&prompt=ghci>,ghci| 83 | ghci> 3.14 84 | 3.14 85 | ghci> .14 86 | 87 | :2:1: error: parse error on input ‘.’ 88 | ghci> 5e-10 89 | 5.0e-10 90 | ghci> 2.7e10 91 | 2.7e10 92 | ``` 93 | 94 | ### Booleans 95 | 96 | Booleans in Haskell are represented with `True` and `False`: 97 | 98 | ```console?lang=haskell&prompt=ghci>,ghci| 99 | ghci> True 100 | True 101 | ghci> False 102 | False 103 | ``` 104 | 105 | ### Text 106 | 107 | Haskell supports Unicode text. Text is wrapped in double quotes, 108 | and can be printed with the function `T.putStrLn` that you imported 109 | from `Data.Text.IO`: 110 | 111 | ```console?lang=haskell&prompt=ghci>,ghci| 112 | ghci> T.putStrLn "Hello" 113 | Hello 114 | ghci> T.putStrLn "jalapeño" 115 | jalapeño 116 | ``` 117 | 118 | Special characters can be represented with numeric escapes or escape codes: 119 | 120 | ```console?lang=haskell&prompt=ghci>,ghci| 121 | ghci> T.putStrLn "'hi\"" 122 | 'hi" 123 | ghci> T.putStrLn "dis\njointed" 124 | dis 125 | jointed 126 | ghci> T.putStrLn "\42" 127 | * 128 | ``` 129 | 130 | You'll learn more about data types in [collections](../collections/) and 131 | [functions](../functions/). 132 | 133 | ## Basic Operations 134 | 135 | ### Arithmetic 136 | 137 | Haskell supports the basic operators: `+`, `-`, `*`, `/`, `**` and `^`. 138 | Note that `/` and `**` never operate on integers, 139 | whereas `^` only accepts positive integer powers. 140 | 141 | ```console?lang=haskell&prompt=ghci>,ghci| 142 | ghci> 2 + 2 143 | 4 144 | ghci> 2 - 1 145 | 1 146 | ghci> 2 * 5 147 | 10 148 | ghci> 10 / 5 149 | 2.0 150 | ghci> 2 ** (-0.5) 151 | 0.7071067811865476 152 | ghci> 1.5 ^ 2 153 | 2.25 154 | ghci> 5 ^ 2 155 | 25 156 | ``` 157 | 158 | For integer division and integer modulus, use `div` and `mod`: 159 | 160 | ```console?lang=haskell&prompt=ghci>,ghci| 161 | ghci> -8 `div` 3 162 | -2 163 | ghci> 243 `mod` 5 164 | 3 165 | ghci> 2 * (5 `div` 2) + (5 `mod` 2) 166 | 5 167 | ``` 168 | 169 | ### Boolean 170 | 171 | Haskell provides the boolean operators `||`, `&&`, and `not` that operate on 172 | `Bool`. These operators do not evaluate the second term if possible. 173 | 174 | ```console?lang=haskell&prompt=ghci>,ghci| 175 | ghci> False || False 176 | False 177 | ghci> True || False 178 | True 179 | 180 | ghci> False && True 181 | False 182 | ghci> True && True 183 | True 184 | 185 | ghci> not True 186 | False 187 | ghci> not False 188 | True 189 | ``` 190 | 191 | ### Comparison 192 | 193 | Haskell comes with comparison operators for ordering: `<=`, `>=`, `<`, and `>`. 194 | Moreover, the operator `==` checks for equality whilst `/=` checks for inequality. 195 | Values compared using these operators must have the same type. 196 | 197 | ```console?lang=haskell&prompt=ghci>,ghci| 198 | ghci> 1 > 2 199 | False 200 | ghci> 2 < 2 201 | False 202 | ghci> 5 >= 5 203 | True 204 | 205 | ghci> True == True 206 | True 207 | ghci> False /= True 208 | True 209 | ``` 210 | 211 | ### String Concatenation 212 | 213 | String concatenation uses the `<>` operator: 214 | 215 | ```console?lang=haskell&prompt=ghci>,ghci| 216 | ghci> T.putStrLn ("abra" <> "cadabra") 217 | abracadabra 218 | ``` 219 | -------------------------------------------------------------------------------- /en/lessons/basics/functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1.0.0 3 | title: Functions 4 | --- 5 | 6 | Functions are at the heart of every Haskell program, and are first-class in the language. 7 | They can be passed as parameters to other functions, and returned as computation results. 8 | You'll see some examples of functions below. 9 | 10 | {% include toc.html %} 11 | 12 | ## Anonymous Functions 13 | 14 | Anonymous functions, or Lambdas, are one of the building blocks of Haskell. They have the following syntax: 15 | 16 | **Structure of a lambda** 17 | 18 | ``` 19 | ╭─ Input of the function 20 | │ 21 | │ ╭─ Separator between input and output 22 | │ │ 23 | │ │ ╭─ Output of the function 24 | \x -> x 25 | ``` 26 | 27 | And incidentally, the example above is one of the most primordial functions: the identity function, or `id`. 28 | This function is very simple, as it returns precisely the argument that you pass to it. 29 | 30 | In Lambdas, the input parameter can be any name, and the output can be any expression. 31 | 32 | ### Syntactic Sugar: currying 33 | 34 | In Haskell, all your functions have one argument. Inspired by the Lambda Calculus, this design is however extended in 35 | the language through syntactic sugar that allows you to express yourself better: 36 | 37 | ```haskell 38 | -- Syntactic sugar 39 | \x y -> x + y 40 | 41 | -- Currified version 42 | \x -> \y -> x + y 43 | ``` 44 | 45 | The term is currification: your function of two arguments has been transformed behind the scenes into a function 46 | of one argument containing another function of one argument, containing itself the operation. 47 | In Javascript, this would be expressed like this: 48 | 49 | ```javascript 50 | // Syntactic sugar 51 | function (x, y) { 52 | return x + y; 53 | } 54 | 55 | // Currified version 56 | function (x) { 57 | return function (y) { 58 | return x + y; 59 | }; 60 | } 61 | 62 | > let a = function (x) { return function (y) { return x + y }; } 63 | > a(1) 64 | [Function (anonymous)] 65 | > a(1)(2) 66 | 3 67 | ``` 68 | 69 | 70 | ### Function Application 71 | 72 | The function application syntax is the following: 73 | 74 | ```console?lang=haskell&prompt=ghci>,ghci| 75 | ghci> (\x y -> x + y) 2 3 76 | 5 77 | ``` 78 | 79 | Here, the function between parentheses has been fully applied. But remember that these 80 | are actually two functions on top of each-other, which means that, 81 | much like in the above JavaScript example, it will return a function if you only pass it one argument: 82 | 83 | ``` 84 | (\x y -> x + y) 2 85 | │ 86 | ╰─ (\y -> 2 + y) 5 87 | │ 88 | ╰─ 2 + 5 89 | ``` 90 | 91 | This ability to do partial application unlocks many abilities. You can build computations whose 92 | parameters are not all available at the same time during the program's lifetime. 93 | 94 | ## Named functions 95 | 96 | However, one can only go so far with anonymous functions. This is why you can give names to your functions: 97 | 98 | ```console?lang=haskell&prompt=ghci>,ghci| 99 | ghci> addOne x = x + 1 100 | ghci> addOne 2 101 | 3 102 | ``` 103 | 104 | ## Higher-order functions 105 | 106 | Functions that take another function as their argument are called "higher-order functions". 107 | Because functions are first-class components of Haskell, they are no more magical than anonymous or named functions. 108 | 109 | They become particularly useful when you need to control the application of a function over a parameter: 110 | 111 | ```console?lang=haskell&prompt=ghci>,ghci| 112 | ghci> applyTwice f x = f (f x) 113 | ghci> applyTwice addOne 2 114 | 4 115 | ``` 116 | 117 | Some of the most well-known higher-order functions out there are `map` and `filter` 118 | 119 | ```console?lang=haskell&prompt=ghci>,ghci| 120 | ghci> map (\x -> x + 2) [1,2,3,4] 121 | [3,4,5,6] 122 | 123 | ghci> filter odd [1,2,3,4,5,6] 124 | [1,3,5] 125 | ``` 126 | 127 | ## Local definitions: `where` & `let … in` 128 | 129 | You can introduce bindings, such as local definitions or intermediate results, through two different syntaxes: 130 | the `where` keyword, and the `let … in` construct. 131 | 132 | ### `where` 133 | 134 | Here is an example of a function using `where` to store local functions: 135 | 136 | ```haskell 137 | processInt x = timesTwo (addTwo x) 138 | where 139 | addTwo y = y + 2 140 | timesTwo z = z * 2 141 | ``` 142 | 143 | __Note__: the binding `x` is reusable throughout the rest of the block 144 | 145 | Other functions will be **not** be able to use `addTwo` and `timesTwo` since they belong to the scope of `processInt`. 146 | 147 | ### `let … in` 148 | 149 | You can use its sibling, `let`, to produce the same result: 150 | 151 | ```haskell 152 | processInt2 x = 153 | let addTwo y = y + 2 154 | timesTwo z = z * 2 155 | in timesTwo (addTwo x) 156 | ``` 157 | 158 | These two syntaxes exist to better let you write down your mental process. Even though it is good form to stick with one 159 | when in a collaborative setting (at work, for example), you are absolutely free to pick the one that makes you happy to 160 | write Haskell. :) 161 | 162 | ## Function Composition 163 | 164 | Function composition is one of the most primordial aspects of functional programming, and Haskell offers builtin operators 165 | to enable it. 166 | 167 | The `(.)` operator that is used for function composition is a legacy of the mathematical notation: 168 | 169 | Let two functions 170 | ``` 171 | f : X |-> Y 172 | g : Y |-> Z 173 | ``` 174 | 175 | To go from X to Z, these two functions are composed like this: 176 | 177 | `g(f(x))` -- read "g of f" 178 | 179 | To simplify the notation, this composition is also written: 180 | 181 | `g ∘ f : X |-> Z` 182 | 183 | Which can be applied to an argument like this: 184 | 185 | `(g ∘ f)(x)` 186 | 187 | And this notation is so convenient that Haskell has kept it. 188 | 189 | As such, when you have a function whose output type is the input type of another function, they are composable. 190 | Remember the `processInt` function from earlier? It can now be written like this: 191 | 192 | 193 | ```console?lang=haskell&prompt=ghci>,ghci| 194 | ghci> addOne y = y + 1 195 | ghci> timesTwo z = z * 2 196 | ghci> processInt3 x = (addOne . timesTwo) x 197 | ghci> processInt3 2 198 | 5 199 | 200 | -- And you can have some fun 201 | ghci> processInt4 x = (addOne . timesTwo . addOne . timesTwo) x 202 | ghci> processInt4 5 203 | 23 204 | ``` 205 | 206 | ## Bonus: tacit, or "point-free" style 207 | 208 | Tacit style allows you to omit the arguments (or "points") of a function when declaring or applying it. 209 | While it can be quicker and help with equational reasoning, the loss of readability that it incurs needs to be a factor 210 | in your decision to use it. 211 | 212 | For example, a wrapper function that does not change its arguments may as well not define them in the function declaration: 213 | 214 | ```Haskell 215 | fun2 x y = fun1 x y 216 | ``` 217 | 218 | can perfectly be translated to 219 | 220 | ```Haskell 221 | fun2 = fun1 222 | ``` 223 | 224 | Another example is the function that searches for a number in a list, 225 | 226 | ```haskell 227 | (\list -> elem 2 list) 228 | ``` 229 | 230 | can be reduced to 231 | 232 | ```Haskell 233 | elem 2 234 | ``` 235 | 236 | And these functions are equivalent. 237 | 238 | --- 239 | 240 | And that is it for the basics about functions! In the next lesson, you will see that functions not only have a body, but also a type. 241 | You will see how to leverage types and make them a tool rather than a constraint. 242 | -------------------------------------------------------------------------------- /en/lessons/basics/operators.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1.0.0 3 | title: Operators 4 | --- 5 | 6 | Haskell provides constructs for using infix binary functions, called operators. In 7 | this lesson you will learn how to define operators and control the parsing of 8 | operators, and how infix and prefix syntax can be interchanged. 9 | 10 | {% include toc.html %} 11 | 12 | 13 | ## Using Operators 14 | 15 | Operators in Haskell are functions that can be placed between two arguments. 16 | There are two cases where you can use a function as an operator: when the function name 17 | only consists of symbols or when you surround the function name in backticks. 18 | Using infix notation makes it easier to write expressions containing many common functions, 19 | and this article will help you in understanding and writing such expressions: 20 | 21 | ```console?lang=haskell&prompt=ghci>,ghci| 22 | ghci> abs . subtract 119 $ 2 + 2 23 | 115 24 | ghci> (`mod` 930233356) . negate $ 4 25 | 930233352 26 | ghci> - (7 + 57843) 27 | -57850 28 | ``` 29 | 30 | You may have seen operators such as `+`, `*`, and `.` before. The `$` operator is 31 | useful for removing parentheses in function application: `abs . subtract 1 $ 2 + 2` is 32 | equivalent to `(abs . subtract 1) (2 + 2)`. You can find more examples of operators on 33 | [FPComplete's Operator Glossary](https://www.fpcomplete.com/haskell/tutorial/operators/). 34 | 35 | ### Interchanging Operators and Functions 36 | 37 | To use an operator symbol as if it were a regular function, surround it in parentheses. 38 | Furthermore, you can create partially applied operators, called sections, by putting 39 | an expression on only one side of the operator: 40 | 41 | ```console?lang=haskell&prompt=ghci>,ghci| 42 | ghci> (+) 2 3 43 | 5 44 | ghci> (5 <=) . (* 2) $ 3 45 | True 46 | ``` 47 | __Note__: negate (`-`) is the only unary operator in Haskell. This can make sectioning 48 | the subtraction operator, which uses the same symbol, difficult. 49 | 50 | The parenthesised operators in the above example can be treated as equivalent to the following 51 | anonymous functions: 52 | ```console?lang=haskell&prompt=ghci>,ghci| 53 | ghci> (\a b -> a + b) 2 3 54 | 5 55 | ghci> (\a -> 5 <= a) . (\a -> a * 2) $ 8 56 | True 57 | ``` 58 | 59 | Conversely, to make a regular function identifier an operator, surround it in backticks: 60 | 61 | ```console?lang=haskell&prompt=ghci>,ghci| 62 | ghci> mod 2010 1998 63 | 12 64 | ghci> 2010 `mod` 1998 65 | 12 66 | ghci> (`div` 3) . (* 1471) $ 5 67 | 2451 68 | ``` 69 | 70 | 71 | ### Operator Precedence and Associativity 72 | 73 | An operator's precedence and associativity combined is called its fixity, and it 74 | controls how the operator is parsed in an expression. To find out the fixity of an 75 | operator, look through `ghci`'s `:info` or the documentation for the operator: 76 | if fixity information isn't displayed, it defaults to `infixl 9`. The same applies to 77 | regular functions used in infix mode. 78 | ```console?lang=haskell&prompt=ghci>,ghci| 79 | ghci> :info (+) 80 | infixl 6 + 81 | ghci> :i ($) 82 | infixr 0 $ 83 | ghci> :i (==) 84 | infix 4 == 85 | ghci> :i elem 86 | infix 4 `elem` 87 | ``` 88 | 89 | In Haskell, operators have a precedence level between 0 and 9: this precedence level 90 | is the number in the operator's fixity. To see how a group of expressions 91 | separated by operators would be parenthesised, surround the highest precedence operator 92 | and the expressions next to it in parentheses, and repeat this process until there 93 | is only one operator left at the highest level of the expression. Here's an example of 94 | applying this process: 95 | ``` 96 | 16425973 + 17149685 * (106 + 235) == 3530784511 97 | | │ ╰─ Precedence level 4 98 | | ╰─ Precedence level 7 99 | ╰─ Precedence level 6 100 | 16425973 + (17149685 * (106 + 235)) == 3530784511 101 | (16425973 + (17149685 * (106 + 235))) == 3530784511 102 | ``` 103 | 104 | Knowing operator precedence is helpful in writing code without unnecessary parentheses: 105 | 106 | ```console?lang=haskell&prompt=ghci>,ghci| 107 | ghci> (^ (3 - 1)) . subtract 3818 $ 4 108 | 14546596 109 | ghci> (1729 + 1) * 1 `div` 2 110 | 865 111 | ghci> 1 + 6 <= 7952317874 + 6 && 0 == 0 112 | True 113 | ``` 114 | 115 | However, this process may be ambiguous: multiple operators of the highest precedence 116 | could exist. Operator associativity solves this problem. An operator has either left 117 | (`infixl`), right (`infixr`), or neutral (`infix`) associativity. If either all the 118 | operators of the highest precedence in an expression have left associativity, or they 119 | all have right associativity, you can parenthesise the expression by selecting 120 | the leftmost or rightmost operator of highest precedence accordingly. For example, 121 | given that both `+` and `-` have left associativity, you could do the following 122 | process to parenthesise an expression: 123 | ``` 124 | 196418 - 514229 + 317811 - 5605 125 | (196418 - 514229) + 317811 - 5605 126 | ((196418 - 514229) + 317811) - 5605 127 | ``` 128 | 129 | Otherwise, if multiple operators of the highest precedence exist, and either one has 130 | neutral associativity or they differ in associativity, Haskell will throw an error: 131 | ```console?lang=haskell&prompt=ghci>,ghci| 132 | ghci> 29 + 61 == 3 == True 133 | :1:1: error: 134 | Precedence parsing error 135 | cannot mix ‘==’ [infix 4] and ‘==’ [infix 4] in the same infix expression 136 | ghci> 0 <> 1 + (-1) 137 | :2:1: error: 138 | Precedence parsing error 139 | cannot mix ‘<>’ [infixr 6] and ‘+’ [infixl 6] in the same infix expression 140 | ``` 141 | 142 | Operator associativity is not chosen arbitrarily: for example, `1 - 6 - 2` equals `-7`, 143 | whereas `1 - (6 - 2)` equals `-3`. Similarly, the expression `not $ not $ True` returns `True`, but 144 | `(not $ not) $ True` doesn't even type-check. On a more advanced note, using certain associativities 145 | is sometimes faster: because appending to regular lists in Haskell is slow, the list concatenation 146 | operator is right associative, which prevents the repeated appending of long lists. 147 | 148 | ## Defining Operators 149 | 150 | An operator is just a function placed between two expressions, so they are defined 151 | exactly the same way that functions are. Try to use operators mainly for the most 152 | common functions in your code, and provide non-operator aliases, because 153 | function names give stronger indications of what a function does. 154 | 155 | ```console?lang=haskell&prompt=ghci>,ghci| 156 | ghci> m |--> v = 0.5 * m * v^2 157 | ghci> (f ... g) x = f (g x) 158 | ghci> (f `on` g) a b = f (g a) (g b) 159 | ghci> (&++) a b = a + b + 2 160 | ghci> on' f g a b = f (g a) (g b) 161 | ``` 162 | __Note__: operator symbols beginning with `:` form binary constructors: you'll learn about this in [types](../types). 163 | 164 | To define the fixity of an operator, put a fixity declaration next to the function 165 | declaration; you can also define an operator's type signature in this manner. A fixity declaration 166 | lacking a precedence level defaults to precedence level 9. Don't expect those reading your code to 167 | remember the fixity of rare operators: most people only memorise fixity for operators they use very 168 | frequently, and code that depends on the fixity of rare operators, such as operators defined 169 | within the codebase, might be unreadable. 170 | 171 | 172 | ```console?lang=haskell&prompt=ghci>,ghci| 173 | ghci> :{ 174 | ghci| infixl 5 ^*^ 175 | ghci| a ^*^ b = a * b 176 | ghci| :} 177 | ghci> 1342 + 2 ^*^ 5 178 | 6720 179 | ghci> :{ 180 | ghci| infixr >-< 181 | ghci| (>-<) :: Integer -> Integer -> Integer 182 | ghci| a >-< b = b - a 183 | ghci| :} 184 | ghci> 99 >-< 81 >-< 90 185 | -90 186 | ghci> :{ 187 | ghci| infix 4 `roundsTo` 188 | ghci| a `roundsTo` b = round a == b 189 | ghci> :} 190 | ghci> pi `roundsTo` 3 191 | True 192 | ``` 193 | 194 | __Note__: in `ghci`, `:{` and `:}` allow you to type definitions spanning multiple lines. 195 | -------------------------------------------------------------------------------- /en/lessons/typeclasses/functors.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: "0.0.1" 3 | title: "Functor, Applicative, and Monad" 4 | --- 5 | -------------------------------------------------------------------------------- /en/lessons/typeclasses/iteration.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: "0.0.1" 3 | title: "Iteration over lists: Foldable and Traversable" 4 | --- 5 | -------------------------------------------------------------------------------- /en/lessons/typeclasses/monoids.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: "0.0.1" 3 | title: "Semigroup and Monoid" 4 | --- 5 | -------------------------------------------------------------------------------- /en/lessons/typeclasses/numbers.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: "0.0.1" 3 | title: "Numbers: Num, Integral, Fractional, and more" 4 | --- 5 | -------------------------------------------------------------------------------- /en/lessons/typeclasses/what-are-typeclasses.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: "0.0.1" 3 | title: "What are typeclasses?" 4 | --- 5 | -------------------------------------------------------------------------------- /feed.xml: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | --- 4 | 5 | {% assign project = site.data['locales'][site.default_lang]['project'] %} 6 | 8 | 9 | {{ project.title }} 10 | {{ project.description }} 11 | {{ site.url }} 12 | 13 | {% for post in site.posts %} 14 | 15 | {{ post.title | xml_escape }} 16 | {{ post.content | strip_html | xml_escape | truncatewords:75 }} 17 | {{ post.date | date: "%a, %d %b %Y %H:%M:%S %z" }} 18 | {{ site.url }}{{ post.url }} 19 | {{ site.url }}{{ post.url }} 20 | 21 | {% endfor %} 22 | 23 | 24 | -------------------------------------------------------------------------------- /fr/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Haskell School 3 | layout: home 4 | version: 1.0.0 5 | --- 6 | 7 | [ru]: /ru/ 8 | [fr]: /fr/ 9 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | --- 4 | 5 | { 6 | "name": "{{ site.name }}", 7 | "short_name": "{{ site.name }}", 8 | "icons": [ 9 | { 10 | "src": "{% asset favicons/android-chrome-144x144.png @path %}", 11 | "sizes": "144x144", 12 | "type": "image/png", 13 | "purpose": "any maskable" 14 | }, 15 | { 16 | "src": "{% asset favicons/splash-512x512.png @path %}", 17 | "sizes": "512x512", 18 | "type": "image/png" 19 | } 20 | ], 21 | "theme_color": "#967ab4", 22 | "background_color": "#967ab4", 23 | "start_url": "{{ site.url }}", 24 | "display": "standalone", 25 | "orientation": "natural" 26 | } 27 | -------------------------------------------------------------------------------- /robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Sitemap: https://school.haskell.org/sitemap.xml 3 | -------------------------------------------------------------------------------- /ru/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Haskell School 3 | layout: home 4 | version: 1.0.0 5 | --- 6 | 7 | [ru]: /ru/ 8 | [fr]: /fr/ 9 | -------------------------------------------------------------------------------- /script/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | jekyll build 3 | -------------------------------------------------------------------------------- /serviceworker.js: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | --- 4 | 5 | const preCachedResources = [ 6 | '/', 7 | '{{ site.default_lang }}/', 8 | '{% asset main.css @path %}', 9 | '{% asset main.js @path %}' 10 | ]; 11 | 12 | const CACHE_NAME = '{{ site.name | slugify }}-v1'; 13 | 14 | self.addEventListener('install', event => { 15 | event.waitUntil(caches.open(CACHE_NAME) 16 | .then(cache => cache.addAll(preCachedResources)) 17 | .catch(error => console.log('Service worker installation has failed', error))); 18 | }); 19 | 20 | self.addEventListener('fetch', function(event) { 21 | event.respondWith( 22 | caches.open(CACHE_NAME) 23 | .then(cache => { 24 | return cache.match(event.request).then(response => { 25 | return response || fetch(event.request).then(response => { 26 | cache.put(event.request, response.clone()); 27 | return response; 28 | }); 29 | }); 30 | }) 31 | ); 32 | }); 33 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | let 2 | githubTarball = owner: repo: rev: 3 | builtins.fetchTarball { url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; }; 4 | 5 | nixpkgsSrc = commit: 6 | githubTarball "NixOS" "nixpkgs" commit; 7 | 8 | # NixOS 22.05 as of 2022-06-09 9 | pkgs = import (nixpkgsSrc "4348fc64bffc9687572125889ec15a47f3a7edca") { }; 10 | 11 | in with pkgs; 12 | mkShell { 13 | LOCALE_ARCHIVE_2_27 = "${glibcLocales}/lib/locale/locale-archive"; 14 | buildInputs = [ 15 | git 16 | ruby 17 | nodejs 18 | bundler 19 | zlib 20 | xz.dev 21 | ]; 22 | } 23 | -------------------------------------------------------------------------------- /style/code.md: -------------------------------------------------------------------------------- 1 | # Code style guide 2 | 3 | ## High Level Philosophy 4 | 5 | The impetus of this project is to get readers up to speed and using haskell in real world contexts. This means shedding some of the established patterns in haskell pedagogy (using `String` instead of `Text`, sticking to `Prelude`, neglecting data structures like `Vector` and `Map` in favour of the familiar `List`). We have a few justifications for this approach: 6 | 1. We are filling a gap in the market, we are providing diversity of learning materials. 7 | 2. We believe that this approach will provide a swifter education. 8 | 3. We would like to give the learner the benefit of the doubt. 9 | 10 | Therefore the guiding principle for writing lessons should be: "Teach the reader to use what you would use, not what you think they are capable of understanding" 11 | 12 | ## Technical Specifics 13 | 14 | * The default prompt is `ghci>`. Do not add the imported modules in scope. 15 | * Use _haskell_ code blocks for Haskell code 16 | * Use _console?lang=haskell&prompt=ghci>,ghci|_ code blocks for ghci examples 17 | * Explicitly mention the names of modules and language extensions 18 | used at the beginning of each tutorial 19 | * Ensure that name conflicts, even if unseen in the tutorial, do not occur. 20 | Import data types unqualified unless in cases of name conflict. 21 | For example, to import `Data.Vector`, write: 22 | ```haskell 23 | import Data.Vector (Vector) 24 | import qualified Data.Vector as V 25 | ``` 26 | * For terminal commands, _shell_ code blocks must be used, and the prompt should be `$` 27 | * Keep examples simple when possible 28 | * Every `deriving` clause should use an explicit deriving strategy (the `DerivingStrategies` language extension), e.g. `deriving stock (Eq, Show)` instead of `deriving (Eq, Show)`. 29 | 30 | ## Typeclasses 31 | 32 | Checklist for writing about a typeclass: 33 | 34 | * What types belong to the class? What types do not? 35 | * Give an example of using at least one of the class methods directly. 36 | * In addition to the class methods themselves, what are some other examples of library functions that include this class as a constraint? Demonstrating a task that is made easier by having this abstraction is often a critical part explaining the value of the typeclass. For example, `Ord`'s `compare` gives rise to `sort`, and `Semigroup`'s associative `(<>)` is what makes `stimes` possible. 37 | * How are instances of this class typically obtained? Written by hand, or derived? If derived, by what strategy? Include examples for strategies that are commonplace. 38 | 39 | Exercise ideas for lessons about a typeclass: 40 | 41 | * Give a type signature and definition that is missing a constraint; ask why it does not compile and how to fix it. The reader can check their answer by attempting to compile the code, since the error message gives the missing constraints. 42 | * Give a monomomorphic type signature for a library function and ask how it can be generalized into a polymorphic function using the class. The reader can check the answer by looking at the library documentation. 43 | * Give an example expression that includes use of a polymorphic function; ask what the function's most general polymorphic type is, and also what the function's monomorphic type is in this context. 44 | -------------------------------------------------------------------------------- /style/en_guide.md: -------------------------------------------------------------------------------- 1 | # Style Guide (en) 2 | 3 | This document is a living, incremental style guide targeted at contributors to the English version of the Haskell School website. 4 | 5 | This guide is not a language guide on the English language. 6 | The writer should refer to the New Oxford Style Manual, the Chicago Manual of Style, or any other professional reference 7 | for any concerns pertaining to writing in the English language. 8 | 9 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and 10 | "OPTIONAL" in this document are to be interpreted as described in RFC 2119¹. 11 | 12 | ## Spelling 13 | 14 | British spelling should be favoured in documents. 15 | 16 | --- 17 | 18 | ¹RFC 2119: https://www.ietf.org/rfc/rfc2119.txt 19 | -------------------------------------------------------------------------------- /style/glossary.md: -------------------------------------------------------------------------------- 1 | ## What is this? 2 | 3 | This file is targeted at the translators and serves as a basic tutorial for translating this project. It includes two lists of terms: 4 | - terms which do not get translated at all 5 | - terminology translations (glossary) 6 | 7 | ### What does not get translated? 8 | 9 | Class names and proper nouns do not get translated. 10 | 11 | ### Glossary - Russian 12 | 13 | This Translation table is adapted from the [Russian Haskell community wiki](https://github.com/ruHaskell/ruhaskell/wiki/Translation). 14 | 15 | #### Термины 16 | 17 | | Иностранное | Русское | 18 | |---|---| 19 | | ad hoc (polymorphism) | специализированный [Брон14] | 20 | | aldebraic data type, ADT | алгебраический тип данных, АТД | 21 | | alias | псевдоним | 22 | | applicative | аппликативный | 23 | | arrow | стрелка | 24 | | bifunctor | бифунктор | 25 | | bind | (монадическое) связывание | 26 | | boxed | упакованный | 27 | | category | категория | 28 | | class | класс [Виль15] | 29 | | closure | замыкание [Виль15] | 30 | | coerce | приводить | 31 | | coercible | приводимый | 32 | | coercion | приведение | 33 | | concurrency | конкурентность [Браг13М] | 34 | | constraint | ограничение | 35 | | contravariant | контравариантный | 36 | | cost center | центр затрат [Виль15] | 37 | | covariant | ковариантный | 38 | | currying | каррирование | 39 | | default definition | определение по умолчанию | 40 | | data type | тип данных | 41 | | derive (an instance) | вывести (экземпляр) | 42 | | dual | дуальный | 43 | | equational reasoning | эквациональное рассуждение [Браг13, Виль15] | 44 | | fixed point | неподвижная точка | 45 | | fold, unfold | свёртка, развёртка [Виль15] | 46 | | foldable | свёртываемый [Виль15] | 47 | | force a thunk | интерпретировать задумку [Браг16]; вычислить переходник [Виль15]; вынудить [Доб06] | 48 | | force an evaluation | форсировать вычисление | 49 | | foreign | внешний, заграничный | 50 | | free monad | свободная монада | 51 | | freer monad | монада посвободнее | 52 | | function application | применение функции | 53 | | functor | функтор | 54 | | generalized algebraic data type, GADT | обобщённый алгебраический тип данных, ОАТД | 55 | | guard (in a pattern match) | страж | 56 | | identity (element) | нейтральный элемент | 57 | | identity function, morphism | тождественное преобразование | 58 | | inhabit | населять | 59 | | instance | экземпляр [Виль15] | 60 | | instantiated (`fmap` instantiated for `Maybe`) | реализованный | 61 | | inverse (element) | обратный элемент | 62 | | isomorphism | изоморфизм | 63 | | kind | вид [лекции Брагилевского]; род; сорт | 64 | | lazy evaluation | ленивое вычисление | 65 | | lens | линза | 66 | | list comprehension and specifiers | формирователь списка и спецификаторы [Виль15] | 67 | | map | проекция [Виль15]; отображение | 68 | | monad | монада | 69 | | monad transformer | монадный трансформер | 70 | | monoid | моноид | 71 | | morphism | морфизм | 72 | | mutable, immutable | изменяемый, неизменяемый | 73 | | natural mapping | естественное отображение | 74 | | natural number | натуральное число | 75 | | natural transformation | естественное преобразование | 76 | | optic | оптика, оптический | 77 | | package | пакет | 78 | | parallelism | распараллеливание [Браг13М] | 79 | | parametric polymorphism | параметрический полиморфизм [Виль15] | 80 | | partial | частичный | 81 | | pattern matching | сопоставление с образцом [Виль15] | 82 | | point-free style | бесточечный стиль [Виль15] | 83 | | polymorphism | полиморфизм | 84 | | prelude | прелюдия | 85 | | prism | призма | 86 | | product type | тип-произведение | 87 | | profunctor | профунктор | 88 | | promotion (of a type) | продвижение (типа) [Виль15] | 89 | | qualified import | импорт с квалификацией [Виль15] | 90 | | record | запись [Виль15] | 91 | | record puns | уплотнение записей [Виль15] | 92 | | referential transparency | ссылочная прозрачность | 93 | | refutable, irrefutable pattern | ???, бесспорный образец [Виль15] | 94 | | resolver | решатель | 95 | | row (polymorphism) | строчный [Брон14]; рядный | 96 | | section (частичное применение оператора) | сечение | 97 | | semigroup | полугруппа | 98 | | smart constructor | умный конструктор | 99 | | strict/eager (evaluation) | строгое; энергичное [Зеф09] (вычисление) | 100 | | strong typing | сильная типизация | 101 | | subtyping | подтипизация | 102 | | sum type | тип-сумма | 103 | | tagged union | помеченное объединение | 104 | | thunk | задумка [Браг16]; санк [Доб06] | 105 | | total function | тотальная; всюду определённая функция | 106 | | total order | полный порядок | 107 | | traversable | проходимый | 108 | | traversal | обход; проход | 109 | | traverse | проходить | 110 | | type class | класс типов [Виль15] | 111 | | type family | семейство типов [Виль15] | 112 | | type synonym | синоним типа | 113 | | unification | унификация | 114 | | view pattern | отображаемый образец [Виль15] | 115 | 116 | #### Персоналии 117 | 118 | | Иностранное | Русское | 119 | |---|---| 120 | | Alejandro Serrano Mena | Алехандро Серано Мена [Виль15] | 121 | | Bartosz Milewski | Бартош Милевски | 122 | | Edward Kmett | Эдвард Кметт | 123 | | Gabriel Gonzalez | Габриэль Гонсалес | 124 | | Haskell Curry | Хаскелл Карри | 125 | | Haskell | Хаскель [Душ12] | 126 | | Michael Snoyman | Майкл Снойман | 127 | | Miran Lipovača | Миран Липовача [Душ12] | 128 | | Moses Schönfinkel | Моисей Эльевич Шейнфинкель | 129 | | Per Martin-Löf | Пер Мартин-Лёф | 130 | | Richard Eisenberg | Ричард Айзенберг | 131 | | Simon Marlow | Саймон Марлоу [Браг13М] | 132 | | William Alvin Howard | Уильям Ховард | 133 | 134 | #### Источники 135 | 136 | * **Доб06**: «Структура и интерпретация компьютерных программ». 137 | Харольд Абельсон, Джеральд Сассман. 138 | Перевод издательства «Добросвет» 139 | * **Зеф09**: «Лень бояться». Сергей Зефиров. 140 | «Практика функионального программирования», 2009, выпуск 1. 141 | http://fprog.ru/2009/issue1/serguey-zefirov-lazy-to-fear/ 142 | * **Душ12**: Изучай Haskell во имя добра! Миран Липовача. 143 | Редакторы перевода: Роман Викторович Душкин, Виталий Николаевич Брагилевский. 144 | * **Браг13**: Жемчужины проектирования алгоритмов: функциональный подход. 145 | Ричард Бёрд. 146 | Перевод: Виталий Николаевич Брагилевский, Артём Михайлович Пеленицын. 147 | * **Браг13М**: Параллельное и конкурентное программирование на языке Haskell. 148 | Саймон Марлоу. Перевод: Виталий Николаевич Брагилевский. 149 | * **Брон14**: Типы в языках программирования. Бенджамин Пирс. 150 | Перевод: Георгий Бронников, Алекс Отт. 151 | * **Виль15**: Изучаем Haskell. Алехандро Серано Мена. Перевод: Н. Вильчинский. 152 | * **Браг16**: Введение в теорию языков программирования. 153 | Жиль Довек, Жан-Жак Леви. 154 | Перевод: Виталий Николаевич Брагилевский, Артём Михайлович Пеленицын. 155 | * **Куз19**: Степан Львович Кузнецов. 156 | Программа дисциплины «Функциональное программирование». 157 | https://www.hse.ru/ba/ami/courses/292683695.html 158 | --------------------------------------------------------------------------------