diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/.gitignore b/.gitignore index 06c8bc5..555db7f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,30 @@ -/_build -/deps -/docs +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). *.ez -.elixir_ls/ + +# Ignore package tarball (built via "mix hex.build"). +plug_rails_cookie_session_store-*.tar + +# Temporary files, for example, from tests. +/tmp/ + +# Misc. .idea/ *.iml diff --git a/LICENSE.md b/LICENSE.md index 9209f68..0ada4ef 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -The MIT License (MIT) +# The MIT License (MIT) Copyright (c) 2014 Chris Constantin diff --git a/README.md b/README.md index 620325a..465c64d 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,28 @@ -PlugRailsCookieSessionStore -=========================== +# PlugRailsCookieSessionStore + +[![Module Version](https://img.shields.io/hexpm/v/plug_rails_cookie_session_store.svg)](https://hex.pm/packages/plug_rails_cookie_session_store) +[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/plug_rails_cookie_session_store/) +[![Total Download](https://img.shields.io/hexpm/dt/plug_rails_cookie_session_store.svg)](https://hex.pm/packages/plug_rails_cookie_session_store) +[![License](https://img.shields.io/hexpm/l/plug_rails_cookie_session_store.svg)](https://github.com/cconstantin/plug_rails_cookie_session_store/blob/master/LICENSE) +[![Last Updated](https://img.shields.io/github/last-commit/cconstantin/plug_rails_cookie_session_store.svg)](https://github.com/cconstantin/plug_rails_cookie_session_store/commits/master) Rails compatible Plug session store. This allows you to share session information between Rails and a Plug-based framework like Phoenix. -Version Information -=================== +## Version Information Version 2.0 and higher require OTP 22 or higher. ## Installation -Add PlugRailsCookieSessionStore as a dependency to your `mix.exs` file: +Add `:plug_rails_cookie_session_store` as a dependency to your `mix.exs` file: ```elixir def deps do - [{:plug_rails_cookie_session_store, "~> 2.0"}] + [ + {:plug_rails_cookie_session_store, "~> 2.0"} + ] end ``` @@ -84,7 +90,7 @@ Plug & Rails must use the same strategy for serializing cookie data. end ``` - You can confirm that your app uses JSON by searching for + You can confirm that your app uses JSON by searching for: ```ruby Rails.application.config.action_dispatch.cookies_serializer = :json @@ -143,3 +149,10 @@ And print it on Phoenix in whatever Controller you want: ```elixir Logger.debug get_session(conn, "foo") ``` + +## Copyright and License + +Copyright (c) 2014 Chris Constantin + +Released under the MIT License, which can be found in the repository in +[LICENSE.md](./LICENSE.md). diff --git a/doc/.build b/doc/.build deleted file mode 100644 index 35490d7..0000000 --- a/doc/.build +++ /dev/null @@ -1,15 +0,0 @@ -404.html -PlugRailsCookieSessionStore.MessageEncryptor.html -PlugRailsCookieSessionStore.MessageVerifier.html -PlugRailsCookieSessionStore.html -api-reference.html -dist/app-f27ff079945e43879c46.js -dist/elixir-a172fe91e725dcb259e2.css -dist/html/fonts/icomoon.eot -dist/html/fonts/icomoon.svg -dist/html/fonts/icomoon.ttf -dist/html/fonts/icomoon.woff -dist/search_items-863ec2fe87.js -dist/sidebar_items-45722afe85.js -index.html -search.html diff --git a/doc/404.html b/doc/404.html deleted file mode 100644 index 2a9e59f..0000000 --- a/doc/404.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - - - - - 404 — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

Page not found

- -

Sorry, but the page you were trying to get to, does not exist. You -may want to try searching this site using the sidebar - - or using our API Reference page - -to find what you were looking for.

- -
-
-
-
- - - - diff --git a/doc/PlugRailsCookieSessionStore-function-delete.html b/doc/PlugRailsCookieSessionStore-function-delete.html deleted file mode 100644 index d3768dc..0000000 --- a/doc/PlugRailsCookieSessionStore-function-delete.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - - PlugRailsCookieSessionStore.delete — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

PlugRailsCookieSessionStore.delete

- -
- You're seeing just the function delete, go back to PlugRailsCookieSessionStore module for more information. -
- -
- -
- - - Link to this function - -

delete(conn, sid, opts)

- - -
- -
- -

Callback implementation for Plug.Session.Store.delete/3.

-
-
- - - -
-
-
-
- - - - diff --git a/doc/PlugRailsCookieSessionStore-function-get.html b/doc/PlugRailsCookieSessionStore-function-get.html deleted file mode 100644 index 7719af9..0000000 --- a/doc/PlugRailsCookieSessionStore-function-get.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - - PlugRailsCookieSessionStore.get — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

PlugRailsCookieSessionStore.get

- -
- You're seeing just the function get, go back to PlugRailsCookieSessionStore module for more information. -
- -
- -
- - - Link to this function - -

get(conn, cookie, opts)

- - -
- -
- -

Callback implementation for Plug.Session.Store.get/3.

-
-
- - - -
-
-
-
- - - - diff --git a/doc/PlugRailsCookieSessionStore-function-init.html b/doc/PlugRailsCookieSessionStore-function-init.html deleted file mode 100644 index be7ded2..0000000 --- a/doc/PlugRailsCookieSessionStore-function-init.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - - PlugRailsCookieSessionStore.init — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

PlugRailsCookieSessionStore.init

- -
- You're seeing just the function init, go back to PlugRailsCookieSessionStore module for more information. -
- -
- -
- - - Link to this function - -

init(opts)

- - -
- -
- -

Callback implementation for Plug.Session.Store.init/1.

-
-
- - - -
-
-
-
- - - - diff --git a/doc/PlugRailsCookieSessionStore-function-put.html b/doc/PlugRailsCookieSessionStore-function-put.html deleted file mode 100644 index b7d4803..0000000 --- a/doc/PlugRailsCookieSessionStore-function-put.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - - PlugRailsCookieSessionStore.put — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

PlugRailsCookieSessionStore.put

- -
- You're seeing just the function put, go back to PlugRailsCookieSessionStore module for more information. -
- -
- -
- - - Link to this function - -

put(conn, sid, term, opts)

- - -
- -
- -

Callback implementation for Plug.Session.Store.put/4.

-
-
- - - -
-
-
-
- - - - diff --git a/doc/PlugRailsCookieSessionStore.MessageEncryptor-function-encrypt_and_sign.html b/doc/PlugRailsCookieSessionStore.MessageEncryptor-function-encrypt_and_sign.html deleted file mode 100644 index 50a2d6e..0000000 --- a/doc/PlugRailsCookieSessionStore.MessageEncryptor-function-encrypt_and_sign.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - - - - PlugRailsCookieSessionStore.MessageEncryptor.encrypt_and_sign — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

PlugRailsCookieSessionStore.MessageEncryptor.encrypt_and_sign

- -
- You're seeing just the function encrypt_and_sign, go back to PlugRailsCookieSessionStore.MessageEncryptor module for more information. -
- -
- - - -
- - - Link to this function - -

encrypt_and_sign(message, secret, sign_secret, cipher \\ :aes_256_cbc)

- - -
- -
- -

Encrypts and signs a message.

-
-
- - - -
-
-
-
- - - - diff --git a/doc/PlugRailsCookieSessionStore.MessageEncryptor-function-verify_and_decrypt.html b/doc/PlugRailsCookieSessionStore.MessageEncryptor-function-verify_and_decrypt.html deleted file mode 100644 index ca08aff..0000000 --- a/doc/PlugRailsCookieSessionStore.MessageEncryptor-function-verify_and_decrypt.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - PlugRailsCookieSessionStore.MessageEncryptor.verify_and_decrypt — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

PlugRailsCookieSessionStore.MessageEncryptor.verify_and_decrypt

- -
- You're seeing just the function verify_and_decrypt, go back to PlugRailsCookieSessionStore.MessageEncryptor module for more information. -
- -
- - - -
- - - Link to this function - -

verify_and_decrypt(encrypted, secret, sign_secret, cipher \\ :aes_256_cbc)

- - -
- -
- -

Decrypts and verifies a message. -We need to verify the message in order to avoid padding attacks. -Reference: http://www.limited-entropy.com/padding-oracle-attacks

-
-
- - - -
-
-
-
- - - - diff --git a/doc/PlugRailsCookieSessionStore.MessageEncryptor.html b/doc/PlugRailsCookieSessionStore.MessageEncryptor.html deleted file mode 100644 index a28ad51..0000000 --- a/doc/PlugRailsCookieSessionStore.MessageEncryptor.html +++ /dev/null @@ -1,241 +0,0 @@ - - - - - - - - - - PlugRailsCookieSessionStore.MessageEncryptor — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

-PlugRailsCookieSessionStore.MessageEncryptor (plug_rails_cookie_session_store v2.0.0) - -

- - -
-

MessageEncryptor is a simple way to encrypt values which get stored -somewhere you don't trust. -The cipher text and initialization vector are base64 encoded and -returned to you. -This can be used in situations similar to the MessageVerifier, but where -you don't want users to be able to determine the value of the payload.

- - Example -

-
secret_key_base = "072d1e0157c008193fe48a670cce031faa4e..."
-encrypted_cookie_salt = "encrypted cookie"
-encrypted_signed_cookie_salt = "signed encrypted cookie"
-secret = KeyGenerator.generate(secret_key_base, encrypted_cookie_salt)
-sign_secret = KeyGenerator.generate(secret_key_base, encrypted_signed_cookie_salt)
-encryptor = MessageEncryptor.new(secret, sign_secret)
-data = %{current_user: %{name: "José"}}
-encrypted = MessageEncryptor.encrypt_and_sign(encryptor, data)
-decrypted = MessageEncryptor.verify_and_decrypt(encryptor, encrypted)
-decrypted.current_user.name # => "José"
-
- - -
-

- - - Link to this section - - Summary -

- -
-

- Functions -

-
- - -

Encrypts and signs a message.

- -
-
- - -

Decrypts and verifies a message. -We need to verify the message in order to avoid padding attacks. -Reference: http://www.limited-entropy.com/padding-oracle-attacks

- -
- -
- -
- - -
-

- - - Link to this section - -Functions -

-
-
- - - -
- - - Link to this function - -

encrypt_and_sign(message, secret, sign_secret, cipher \\ :aes_256_cbc)

- - -
- -
- -

Encrypts and signs a message.

-
-
-
- - - -
- - - Link to this function - -

verify_and_decrypt(encrypted, secret, sign_secret, cipher \\ :aes_256_cbc)

- - -
- -
- -

Decrypts and verifies a message. -We need to verify the message in order to avoid padding attacks. -Reference: http://www.limited-entropy.com/padding-oracle-attacks

-
-
- -
-
- - -
-
-
-
- - - - diff --git a/doc/PlugRailsCookieSessionStore.MessageVerifier-function-sign.html b/doc/PlugRailsCookieSessionStore.MessageVerifier-function-sign.html deleted file mode 100644 index be36cbb..0000000 --- a/doc/PlugRailsCookieSessionStore.MessageVerifier-function-sign.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - - PlugRailsCookieSessionStore.MessageVerifier.sign — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

PlugRailsCookieSessionStore.MessageVerifier.sign

- -
- You're seeing just the function sign, go back to PlugRailsCookieSessionStore.MessageVerifier module for more information. -
- -
- -
- - - Link to this function - -

sign(binary, secret)

- - -
- -
- -

Signs a binary according to the given secret.

-
-
- - - -
-
-
-
- - - - diff --git a/doc/PlugRailsCookieSessionStore.MessageVerifier-function-verify.html b/doc/PlugRailsCookieSessionStore.MessageVerifier-function-verify.html deleted file mode 100644 index 7e27b05..0000000 --- a/doc/PlugRailsCookieSessionStore.MessageVerifier-function-verify.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - - PlugRailsCookieSessionStore.MessageVerifier.verify — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

PlugRailsCookieSessionStore.MessageVerifier.verify

- -
- You're seeing just the function verify, go back to PlugRailsCookieSessionStore.MessageVerifier module for more information. -
- -
- -
- - - Link to this function - -

verify(binary, secret)

- - -
- -
- -

Decodes and verifies the encoded binary was not tampared with.

-
-
- - - -
-
-
-
- - - - diff --git a/doc/PlugRailsCookieSessionStore.MessageVerifier.html b/doc/PlugRailsCookieSessionStore.MessageVerifier.html deleted file mode 100644 index 7af61ce..0000000 --- a/doc/PlugRailsCookieSessionStore.MessageVerifier.html +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - - PlugRailsCookieSessionStore.MessageVerifier — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

-PlugRailsCookieSessionStore.MessageVerifier (plug_rails_cookie_session_store v2.0.0) - -

- - -
-

MessageVerifier makes it easy to generate and verify messages -which are signed to prevent tampering. -For example, the cookie store uses this verifier to send data -to the client. Although the data can be read by the client, he -cannot tamper it.

-
- - -
-

- - - Link to this section - - Summary -

- -
-

- Functions -

-
- - -

Signs a binary according to the given secret.

- -
-
- - -

Decodes and verifies the encoded binary was not tampared with.

- -
- -
- -
- - -
-

- - - Link to this section - -Functions -

-
-
- -
- - - Link to this function - -

sign(binary, secret)

- - -
- -
- -

Signs a binary according to the given secret.

-
-
-
- -
- - - Link to this function - -

verify(binary, secret)

- - -
- -
- -

Decodes and verifies the encoded binary was not tampared with.

-
-
- -
-
- - -
-
-
-
- - - - diff --git a/doc/PlugRailsCookieSessionStore.html b/doc/PlugRailsCookieSessionStore.html deleted file mode 100644 index 05ff067..0000000 --- a/doc/PlugRailsCookieSessionStore.html +++ /dev/null @@ -1,298 +0,0 @@ - - - - - - - - - - PlugRailsCookieSessionStore — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

-PlugRailsCookieSessionStore (plug_rails_cookie_session_store v2.0.0) - -

- - -
-

Stores the session in a cookie.

This cookie store is based on Plug.Crypto.MessageVerifier -and Plug.Crypto.Message.Encryptor which encrypts and signs -each cookie to ensure they can't be read nor tampered with.

Since this store uses crypto features, it requires you to -set the :secret_key_base field in your connection. This -can be easily achieved with a plug:

plug :put_secret_key_base
-
-def put_secret_key_base(conn, _) do
-  put_in conn.secret_key_base, "-- LONG STRING WITH AT LEAST 64 BYTES --"
-end

- - Options -

-
  • :encrypt - specify whether to encrypt cookies, defaults to true. -When this option is false, the cookie is still signed, meaning it -can't be tempered with but its contents can be read;

  • :encryption_salt - a salt used with conn.secret_key_base to generate -a key for encrypting/decrypting a cookie;

  • :signing_salt - a salt used with conn.secret_key_base to generate a -key for signing/verifying a cookie;

  • :key_iterations - option passed to Plug.Crypto.KeyGenerator -when generating the encryption and signing keys. Defaults to 1000;

  • :key_length - option passed to Plug.Crypto.KeyGenerator -when generating the encryption and signing keys. Defaults to 32;

  • :key_digest - option passed to Plug.Crypto.KeyGenerator -when generating the encryption and signing keys. Defaults to :sha256;

  • :serializer - cookie serializer module that defines encode/1 and -decode/1 returning an {:ok, value} tuple. Defaults to -:external_term_format.

- - Examples -

-
# Use the session plug with the table name
-plug Plug.Session, store: PlugRailsCookieSessionStore,
-                   key: "_my_app_session",
-                   encryption_salt: "cookie store encryption salt",
-                   signing_salt: "cookie store signing salt",
-                   key_length: 64,
-                   serializer: Poison
-
- - -
-

- - - Link to this section - - Summary -

- -
-

- Functions -

-
- - -

Callback implementation for Plug.Session.Store.delete/3.

- -
-
- - -

Callback implementation for Plug.Session.Store.get/3.

- -
-
-
- init(opts) - -
- -

Callback implementation for Plug.Session.Store.init/1.

- -
-
- - -

Callback implementation for Plug.Session.Store.put/4.

- -
- -
- -
- - -
-

- - - Link to this section - -Functions -

-
-
- -
- - - Link to this function - -

delete(conn, sid, opts)

- - -
- -
- -

Callback implementation for Plug.Session.Store.delete/3.

-
-
-
- -
- - - Link to this function - -

get(conn, cookie, opts)

- - -
- -
- -

Callback implementation for Plug.Session.Store.get/3.

-
-
-
- -
- - - Link to this function - -

init(opts)

- - -
- -
- -

Callback implementation for Plug.Session.Store.init/1.

-
-
-
- -
- - - Link to this function - -

put(conn, sid, term, opts)

- - -
- -
- -

Callback implementation for Plug.Session.Store.put/4.

-
-
- -
-
- - -
-
-
-
- - - - diff --git a/doc/api-reference.html b/doc/api-reference.html deleted file mode 100644 index f6763b5..0000000 --- a/doc/api-reference.html +++ /dev/null @@ -1,181 +0,0 @@ - - - - - - - - - - API Reference — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
- - - - - -
-
-
- -

- API Reference plug_rails_cookie_session_store v2.0.0 -

- -
-

- - Modules -

- -
-
- - -

Stores the session in a cookie.

- -
-
- - -

MessageEncryptor is a simple way to encrypt values which get stored -somewhere you don't trust. -The cipher text and initialization vector are base64 encoded and -returned to you. -This can be used in situations similar to the MessageVerifier, but where -you don't want users to be able to determine the value of the payload.

- -
-
- - -

MessageVerifier makes it easy to generate and verify messages -which are signed to prevent tampering. -For example, the cookie store uses this verifier to send data -to the client. Although the data can be read by the client, he -cannot tamper it.

- -
- -
-
- - -
-
- -
-
- -
-
- - -
-
-
-
- - - - diff --git a/doc/dist/app-f27ff079945e43879c46.js b/doc/dist/app-f27ff079945e43879c46.js deleted file mode 100644 index d87baed..0000000 --- a/doc/dist/app-f27ff079945e43879c46.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see app-f27ff079945e43879c46.js.LICENSE.txt */ -!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=49)}([function(e,t,n){"use strict";function r(e){if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(e=function(e,t){if(!e)return;if("string"==typeof e)return o(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return o(e,t)}(e))){var t=0,n=function(){};return{s:n,n:function(){return t>=e.length?{done:!0}:{done:!1,value:e[t++]}},e:function(e){throw e},f:n}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,i,a=!0,l=!1;return{s:function(){r=e[Symbol.iterator]()},n:function(){var e=r.next();return a=e.done,e},e:function(e){l=!0,i=e},f:function(){try{a||null==r.return||r.return()}finally{if(l)throw i}}}}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n/g,">").replace(/"/g,""")}function u(){return document.body.dataset.type}function c(e,t){if(e){var n,o=r(e);try{for(o.s();!(n=o.n()).done;){var i=n.value,a=i.nodeGroups&&i.nodeGroups.find((function(e){return e.nodes.some((function(e){return e.anchor===t}))}));if(a)return a.key}}catch(e){o.e(e)}finally{o.f()}return null}}function d(){return window.location.hash.replace(/^#/,"")}function f(e){return new URLSearchParams(window.location.search).get(e)}function p(e){return fetch(e).then((function(e){return e.ok})).catch((function(){return!1}))}function h(e){"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e)}function m(e){return!e||""===e.trim()}function y(e,t){var n;return function(){for(var r=arguments.length,o=new Array(r),i=0;i":">",'"':""","'":"'","`":"`","=":"="},o=/[&<>"'`=]/g,i=/[&<>"'`=]/;function a(e){return r[e]}function l(e){for(var t=1;t0){var s=I.utils.clone(t)||{};s.position=[a,l],s.index=o.length,o.push(new I.Token(n.slice(a,i),s))}a=i+1}}return o},I.tokenizer.separator=/[\s\-]+/,I.Pipeline=function(){this._stack=[]},I.Pipeline.registeredFunctions=Object.create(null),I.Pipeline.registerFunction=function(e,t){t in this.registeredFunctions&&I.utils.warn("Overwriting existing registered function: "+t),e.label=t,I.Pipeline.registeredFunctions[e.label]=e},I.Pipeline.warnIfFunctionNotRegistered=function(e){e.label&&e.label in this.registeredFunctions||I.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},I.Pipeline.load=function(e){var t=new I.Pipeline;return e.forEach((function(e){var n=I.Pipeline.registeredFunctions[e];if(!n)throw new Error("Cannot load unregistered function: "+e);t.add(n)})),t},I.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach((function(e){I.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)}),this)},I.Pipeline.prototype.after=function(e,t){I.Pipeline.warnIfFunctionNotRegistered(t);var n=this._stack.indexOf(e);if(-1==n)throw new Error("Cannot find existingFn");n+=1,this._stack.splice(n,0,t)},I.Pipeline.prototype.before=function(e,t){I.Pipeline.warnIfFunctionNotRegistered(t);var n=this._stack.indexOf(e);if(-1==n)throw new Error("Cannot find existingFn");this._stack.splice(n,0,t)},I.Pipeline.prototype.remove=function(e){var t=this._stack.indexOf(e);-1!=t&&this._stack.splice(t,1)},I.Pipeline.prototype.run=function(e){for(var t=this._stack.length,n=0;n1&&(ie&&(n=o),i!=e);)r=n-t,o=t+Math.floor(r/2),i=this.elements[2*o];return i==e||i>e?2*o:il?u+=2:a==l&&(t+=n[s+1]*r[u+1],s+=2,u+=2);return t},I.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},I.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),t=1,n=0;t0){var i,a=o.str.charAt(0);a in o.node.edges?i=o.node.edges[a]:(i=new I.TokenSet,o.node.edges[a]=i),1==o.str.length&&(i.final=!0),r.push({node:i,editsRemaining:o.editsRemaining,str:o.str.slice(1)})}if(0!=o.editsRemaining){if("*"in o.node.edges)var l=o.node.edges["*"];else{l=new I.TokenSet;o.node.edges["*"]=l}if(0==o.str.length&&(l.final=!0),r.push({node:l,editsRemaining:o.editsRemaining-1,str:o.str}),o.str.length>1&&r.push({node:o.node,editsRemaining:o.editsRemaining-1,str:o.str.slice(1)}),1==o.str.length&&(o.node.final=!0),o.str.length>=1){if("*"in o.node.edges)var s=o.node.edges["*"];else{s=new I.TokenSet;o.node.edges["*"]=s}1==o.str.length&&(s.final=!0),r.push({node:s,editsRemaining:o.editsRemaining-1,str:o.str.slice(1)})}if(o.str.length>1){var u,c=o.str.charAt(0),d=o.str.charAt(1);d in o.node.edges?u=o.node.edges[d]:(u=new I.TokenSet,o.node.edges[d]=u),1==o.str.length&&(u.final=!0),r.push({node:u,editsRemaining:o.editsRemaining-1,str:c+o.str.slice(2)})}}}return n},I.TokenSet.fromString=function(e){for(var t=new I.TokenSet,n=t,r=0,o=e.length;r=e;t--){var n=this.uncheckedNodes[t],r=n.child.toString();r in this.minimizedNodes?n.parent.edges[n.char]=this.minimizedNodes[r]:(n.child._str=r,this.minimizedNodes[r]=n.child),this.uncheckedNodes.pop()}},I.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},I.Index.prototype.search=function(e){return this.query((function(t){new I.QueryParser(e,t).parse()}))},I.Index.prototype.query=function(e){for(var t=new I.Query(this.fields),n=Object.create(null),r=Object.create(null),o=Object.create(null),i=Object.create(null),a=Object.create(null),l=0;l1?1:e},I.Builder.prototype.k1=function(e){this._k1=e},I.Builder.prototype.add=function(e,t){var n=e[this._ref],r=Object.keys(this._fields);this._documents[n]=t||{},this.documentCount+=1;for(var o=0;o=this.length)return I.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},I.QueryLexer.prototype.width=function(){return this.pos-this.start},I.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},I.QueryLexer.prototype.backup=function(){this.pos-=1},I.QueryLexer.prototype.acceptDigitRun=function(){var e,t;do{t=(e=this.next()).charCodeAt(0)}while(t>47&&t<58);e!=I.QueryLexer.EOS&&this.backup()},I.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(I.QueryLexer.TERM)),e.ignore(),e.more())return I.QueryLexer.lexText},I.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(I.QueryLexer.EDIT_DISTANCE),I.QueryLexer.lexText},I.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(I.QueryLexer.BOOST),I.QueryLexer.lexText},I.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(I.QueryLexer.TERM)},I.QueryLexer.termSeparator=I.tokenizer.separator,I.QueryLexer.lexText=function(e){for(;;){var t=e.next();if(t==I.QueryLexer.EOS)return I.QueryLexer.lexEOS;if(92!=t.charCodeAt(0)){if(":"==t)return I.QueryLexer.lexField;if("~"==t)return e.backup(),e.width()>0&&e.emit(I.QueryLexer.TERM),I.QueryLexer.lexEditDistance;if("^"==t)return e.backup(),e.width()>0&&e.emit(I.QueryLexer.TERM),I.QueryLexer.lexBoost;if("+"==t&&1===e.width())return e.emit(I.QueryLexer.PRESENCE),I.QueryLexer.lexText;if("-"==t&&1===e.width())return e.emit(I.QueryLexer.PRESENCE),I.QueryLexer.lexText;if(t.match(I.QueryLexer.termSeparator))return I.QueryLexer.lexTerm}else e.escapeCharacter()}},I.QueryParser=function(e,t){this.lexer=new I.QueryLexer(e),this.query=t,this.currentClause={},this.lexemeIdx=0},I.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=I.QueryParser.parseClause;e;)e=e(this);return this.query},I.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},I.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},I.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},I.QueryParser.parseClause=function(e){var t=e.peekLexeme();if(null!=t)switch(t.type){case I.QueryLexer.PRESENCE:return I.QueryParser.parsePresence;case I.QueryLexer.FIELD:return I.QueryParser.parseField;case I.QueryLexer.TERM:return I.QueryParser.parseTerm;default:var n="expected either a field or a term, found "+t.type;throw t.str.length>=1&&(n+=" with value '"+t.str+"'"),new I.QueryParseError(n,t.start,t.end)}},I.QueryParser.parsePresence=function(e){var t=e.consumeLexeme();if(null!=t){switch(t.str){case"-":e.currentClause.presence=I.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=I.Query.presence.REQUIRED;break;default:var n="unrecognised presence operator'"+t.str+"'";throw new I.QueryParseError(n,t.start,t.end)}var r=e.peekLexeme();if(null==r){n="expecting term or field, found nothing";throw new I.QueryParseError(n,t.start,t.end)}switch(r.type){case I.QueryLexer.FIELD:return I.QueryParser.parseField;case I.QueryLexer.TERM:return I.QueryParser.parseTerm;default:n="expecting term or field, found '"+r.type+"'";throw new I.QueryParseError(n,r.start,r.end)}}},I.QueryParser.parseField=function(e){var t=e.consumeLexeme();if(null!=t){if(-1==e.query.allFields.indexOf(t.str)){var n=e.query.allFields.map((function(e){return"'"+e+"'"})).join(", "),r="unrecognised field '"+t.str+"', possible fields: "+n;throw new I.QueryParseError(r,t.start,t.end)}e.currentClause.fields=[t.str];var o=e.peekLexeme();if(null==o){r="expecting term, found nothing";throw new I.QueryParseError(r,t.start,t.end)}switch(o.type){case I.QueryLexer.TERM:return I.QueryParser.parseTerm;default:r="expecting term, found '"+o.type+"'";throw new I.QueryParseError(r,o.start,o.end)}}},I.QueryParser.parseTerm=function(e){var t=e.consumeLexeme();if(null!=t){e.currentClause.term=t.str.toLowerCase(),-1!=t.str.indexOf("*")&&(e.currentClause.usePipeline=!1);var n=e.peekLexeme();if(null!=n)switch(n.type){case I.QueryLexer.TERM:return e.nextClause(),I.QueryParser.parseTerm;case I.QueryLexer.FIELD:return e.nextClause(),I.QueryParser.parseField;case I.QueryLexer.EDIT_DISTANCE:return I.QueryParser.parseEditDistance;case I.QueryLexer.BOOST:return I.QueryParser.parseBoost;case I.QueryLexer.PRESENCE:return e.nextClause(),I.QueryParser.parsePresence;default:var r="Unexpected lexeme type '"+n.type+"'";throw new I.QueryParseError(r,n.start,n.end)}else e.nextClause()}},I.QueryParser.parseEditDistance=function(e){var t=e.consumeLexeme();if(null!=t){var n=parseInt(t.str,10);if(isNaN(n)){var r="edit distance must be numeric";throw new I.QueryParseError(r,t.start,t.end)}e.currentClause.editDistance=n;var o=e.peekLexeme();if(null!=o)switch(o.type){case I.QueryLexer.TERM:return e.nextClause(),I.QueryParser.parseTerm;case I.QueryLexer.FIELD:return e.nextClause(),I.QueryParser.parseField;case I.QueryLexer.EDIT_DISTANCE:return I.QueryParser.parseEditDistance;case I.QueryLexer.BOOST:return I.QueryParser.parseBoost;case I.QueryLexer.PRESENCE:return e.nextClause(),I.QueryParser.parsePresence;default:r="Unexpected lexeme type '"+o.type+"'";throw new I.QueryParseError(r,o.start,o.end)}else e.nextClause()}},I.QueryParser.parseBoost=function(e){var t=e.consumeLexeme();if(null!=t){var n=parseInt(t.str,10);if(isNaN(n)){var r="boost must be numeric";throw new I.QueryParseError(r,t.start,t.end)}e.currentClause.boost=n;var o=e.peekLexeme();if(null!=o)switch(o.type){case I.QueryLexer.TERM:return e.nextClause(),I.QueryParser.parseTerm;case I.QueryLexer.FIELD:return e.nextClause(),I.QueryParser.parseField;case I.QueryLexer.EDIT_DISTANCE:return I.QueryParser.parseEditDistance;case I.QueryLexer.BOOST:return I.QueryParser.parseBoost;case I.QueryLexer.PRESENCE:return e.nextClause(),I.QueryParser.parsePresence;default:r="Unexpected lexeme type '"+o.type+"'";throw new I.QueryParseError(r,o.start,o.end)}else e.nextClause()}},void 0===(o="function"==typeof(r=function(){return I})?r.call(t,n,t,e):r)||(e.exports=o)}()},function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var r=n(0);function o(){Object(r.m)("[data-group-id]").forEach((function(e){var t=e.getAttribute("data-group-id");e.addEventListener("mouseenter",(function(e){i(t,!0)})),e.addEventListener("mouseleave",(function(e){i(t,!1)}))}))}function i(e,t){Object(r.m)('[data-group-id="'.concat(e,'"]')).forEach((function(e){e.classList.toggle("hll",t)}))}},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0,t.HandlebarsEnvironment=c;var o=n(2),i=r(n(3)),a=n(8),l=n(35),s=r(n(9)),u=n(10);t.VERSION="4.7.6";t.COMPILER_REVISION=8;t.LAST_COMPATIBLE_COMPILER_REVISION=7;t.REVISION_CHANGES={1:"<= 1.0.rc.2",2:"== 1.0.0-rc.3",3:"== 1.0.0-rc.4",4:"== 1.x.x",5:"== 2.0.0-alpha.x",6:">= 2.0.0-beta.1",7:">= 4.0.0 <4.3.0",8:">= 4.3.0"};function c(e,t,n){this.helpers=e||{},this.partials=t||{},this.decorators=n||{},a.registerDefaultHelpers(this),l.registerDefaultDecorators(this)}c.prototype={constructor:c,logger:s.default,log:s.default.log,registerHelper:function(e,t){if("[object Object]"===o.toString.call(e)){if(t)throw new i.default("Arg not supported with multiple helpers");o.extend(this.helpers,e)}else this.helpers[e]=t},unregisterHelper:function(e){delete this.helpers[e]},registerPartial:function(e,t){if("[object Object]"===o.toString.call(e))o.extend(this.partials,e);else{if(void 0===t)throw new i.default('Attempting to register a partial called "'+e+'" as undefined');this.partials[e]=t}},unregisterPartial:function(e){delete this.partials[e]},registerDecorator:function(e,t){if("[object Object]"===o.toString.call(e)){if(t)throw new i.default("Arg not supported with multiple decorators");o.extend(this.decorators,e)}else this.decorators[e]=t},unregisterDecorator:function(e){delete this.decorators[e]},resetLoggedPropertyAccesses:function(){u.resetLoggedProperties()}};var d=s.default.log;t.log=d,t.createFrame=o.createFrame,t.logger=s.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0,t.registerDefaultHelpers=function(e){o.default(e),i.default(e),a.default(e),l.default(e),s.default(e),u.default(e),c.default(e)},t.moveHelperToHooks=function(e,t,n){e.helpers[t]&&(e.hooks[t]=e.helpers[t],n||delete e.helpers[t])};var o=r(n(28)),i=r(n(29)),a=r(n(30)),l=r(n(31)),s=r(n(32)),u=r(n(33)),c=r(n(34))},function(e,t,n){"use strict";t.__esModule=!0;var r=n(2),o={methodMap:["debug","info","warn","error"],level:"info",lookupLevel:function(e){if("string"==typeof e){var t=r.indexOf(o.methodMap,e.toLowerCase());e=t>=0?t:parseInt(e,10)}return e},log:function(e){if(e=o.lookupLevel(e),"undefined"!=typeof console&&o.lookupLevel(o.level)<=e){var t=o.methodMap[e];console[t]||(t="log");for(var n=arguments.length,r=Array(n>1?n-1:0),i=1;i=t||n<0||h&&e-u>=i}function w(){var e=p();if(x(e))return O(e);l=setTimeout(w,function(e){var n=t-(e-s);return h?f(n,i-(e-u)):n}(e))}function O(e){return l=void 0,v&&r?g(e):(r=o=void 0,a)}function k(){var e=p(),n=x(e);if(r=arguments,o=this,s=e,n){if(void 0===l)return b(s);if(h)return l=setTimeout(w,t),g(s)}return void 0===l&&(l=setTimeout(w,t)),a}return t=y(t)||0,m(n)&&(c=!!n.leading,i=(h="maxWait"in n)?d(y(n.maxWait)||0,t):i,v="trailing"in n?!!n.trailing:v),k.cancel=function(){void 0!==l&&clearTimeout(l),u=0,r=s=o=l=void 0},k.flush=function(){return void 0===l?a:O(p())},k}function m(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function y(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==c.call(e)}(e))return NaN;if(m(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=m(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(n,"");var l=o.test(e);return l||i.test(e)?a(e.slice(2),l?2:8):r.test(e)?NaN:+e}e.exports=function(e,t,n){var r=!0,o=!0;if("function"!=typeof e)throw new TypeError("Expected a function");return m(n)&&(r="leading"in n?!!n.leading:r,o="trailing"in n?!!n.trailing:o),h(e,t,{leading:r,maxWait:t,trailing:o})}}).call(this,n(6))},function(e,t,n){var r=n(1);function o(e){return e&&(e.__esModule?e.default:e)}e.exports=(r.default||r).template({1:function(e,t,r,i,a,l,s){var u,c=null!=t?t:e.nullContext||{},d=e.lambda,f=e.escapeExpression,p=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return(null!=(u=o(n(42)).call(c,s[1],null!=(u=l[0][0])?p(u,"group"):u,{name:"groupChanged",hash:{},fn:e.program(2,a,0,l,s),inverse:e.noop,data:a,blockParams:l,loc:{start:{line:2,column:2},end:{line:4,column:19}}}))?u:"")+"\n"+(null!=(u=o(n(43)).call(c,s[1],l[0][0],{name:"nestingChanged",hash:{},fn:e.program(4,a,0,l,s),inverse:e.noop,data:a,blockParams:l,loc:{start:{line:6,column:2},end:{line:8,column:21}}}))?u:"")+'\n
  • \n \n'+(null!=(u=p(r,"if").call(c,null!=(u=l[0][0])?p(u,"nested_title"):u,{name:"if",hash:{},fn:e.program(10,a,0,l,s),inverse:e.program(12,a,0,l,s),data:a,blockParams:l,loc:{start:{line:15,column:6},end:{line:19,column:13}}}))?u:"")+'\n \n \n\n
      \n
    • \n Top\n
    • \n\n'+(null!=(u=o(n(12)).call(c,null!=(u=l[0][0])?p(u,"headers"):u,{name:"isArray",hash:{},fn:e.program(14,a,0,l,s),inverse:e.program(17,a,0,l,s),data:a,blockParams:l,loc:{start:{line:29,column:6},end:{line:71,column:18}}}))?u:"")+"
    \n
  • \n"},2:function(e,t,n,r,o,i){var a,l=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
  • '+e.escapeExpression(e.lambda(null!=(a=i[1][0])?l(a,"group"):a,t))+"
  • \n"},4:function(e,t,n,r,o,i){var a,l=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return' \n"},6:function(e,t,n,r,o){return"current-page open"},8:function(e,t,n,r,o){return"nested"},10:function(e,t,n,r,o,i){var a,l=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return" "+e.escapeExpression(e.lambda(null!=(a=i[1][0])?l(a,"nested_title"):a,t))+"\n"},12:function(e,t,n,r,o,i){var a,l=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return" "+e.escapeExpression(e.lambda(null!=(a=i[1][0])?l(a,"title"):a,t))+"\n"},14:function(e,t,n,r,o,i){var a,l=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return null!=(a=l(n,"each").call(null!=t?t:e.nullContext||{},null!=(a=i[1][0])?l(a,"headers"):a,{name:"each",hash:{},fn:e.program(15,o,0,i),inverse:e.noop,data:o,blockParams:i,loc:{start:{line:30,column:8},end:{line:34,column:17}}}))?a:""},15:function(e,t,n,r,o,i){var a,l=e.lambda,s=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
  • \n '+(null!=(a=l(null!=t?s(t,"id"):t,t))?a:"")+"\n
  • \n"},17:function(e,t,r,i,a,l){var s,u=null!=t?t:e.nullContext||{},c=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return(null!=(s=o(n(44)).call(u,l[1][0],{name:"showSections",hash:{},fn:e.program(18,a,0,l),inverse:e.noop,data:a,blockParams:l,loc:{start:{line:36,column:8},end:{line:50,column:25}}}))?s:"")+(null!=(s=o(n(45)).call(u,l[1][0],{name:"showSummary",hash:{},fn:e.program(23,a,0,l),inverse:e.noop,data:a,blockParams:l,loc:{start:{line:51,column:8},end:{line:55,column:24}}}))?s:"")+(null!=(s=c(r,"each").call(u,null!=(s=l[1][0])?c(s,"nodeGroups"):s,{name:"each",hash:{},fn:e.program(25,a,1,l),inverse:e.noop,data:a,blockParams:l,loc:{start:{line:56,column:8},end:{line:70,column:17}}}))?s:"")},18:function(e,t,r,i,a,l){var s,u=null!=t?t:e.nullContext||{},c=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
  • \n \n Sections\n \n \n
      \n'+(null!=(s=c(r,"each").call(u,null!=t?c(t,"sections"):t,{name:"each",hash:{},fn:e.program(21,a,0,l),inverse:e.noop,data:a,blockParams:l,loc:{start:{line:43,column:14},end:{line:47,column:23}}}))?s:"")+"
    \n
  • \n"},19:function(e,t,n,r,o){return"open"},21:function(e,t,n,r,o,i){var a,l=e.lambda,s=e.escapeExpression,u=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
  • \n '+(null!=(a=l(null!=t?u(t,"id"):t,t))?a:"")+"\n
  • \n"},23:function(e,t,n,r,o,i){var a,l=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
  • \n Summary\n
  • \n'},25:function(e,t,n,r,o,i){var a,l=e.lambda,s=e.escapeExpression,u=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
  • \n \n '+s(l(null!=(a=i[0][0])?u(a,"name"):a,t))+'\n \n \n
      \n'+(null!=(a=u(n,"each").call(null!=t?t:e.nullContext||{},null!=(a=i[0][0])?u(a,"nodes"):a,{name:"each",hash:{},fn:e.program(26,o,0,i),inverse:e.noop,data:o,blockParams:i,loc:{start:{line:63,column:14},end:{line:67,column:23}}}))?a:"")+"
    \n
  • \n"},26:function(e,t,n,r,o,i){var a,l=e.lambda,s=e.escapeExpression,u=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
  • \n '+s(l(null!=t?u(t,"id"):t,t))+"\n
  • \n"},compiler:[8,">= 4.3.0"],main:function(e,t,n,r,o,i,a){var l,s=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return null!=(l=s(n,"each").call(null!=t?t:e.nullContext||{},null!=t?s(t,"nodes"):t,{name:"each",hash:{},fn:e.program(1,o,2,i,a),inverse:e.noop,data:o,blockParams:i,loc:{start:{line:1,column:0},end:{line:74,column:9}}}))?l:""},useData:!0,useDepths:!0,useBlockParams:!0})},function(e,t,n){var r=n(1);e.exports=(r.default||r).template({1:function(e,t,n,r,o){var i,a,l=null!=t?t:e.nullContext||{},s=e.hooks.helperMissing,u=e.escapeExpression,c=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return' \n
    \n '+(null!=(i="function"==typeof(a=null!=(a=c(n,"title")||(null!=t?c(t,"title"):t))?a:s)?a.call(l,{name:"title",hash:{},data:o,loc:{start:{line:9,column:8},end:{line:9,column:19}}}):a)?i:"")+"\n"+(null!=(i=c(n,"if").call(l,null!=t?c(t,"label"):t,{name:"if",hash:{},fn:e.program(2,o,0),inverse:e.noop,data:o,loc:{start:{line:10,column:8},end:{line:12,column:15}}}))?i:"")+"
    \n\n"+(null!=(i=c(n,"if").call(l,null!=t?c(t,"description"):t,{name:"if",hash:{},fn:e.program(4,o,0),inverse:e.noop,data:o,loc:{start:{line:15,column:6},end:{line:19,column:13}}}))?i:"")+"
    \n"},2:function(e,t,n,r,o){var i,a=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return' ('+e.escapeExpression("function"==typeof(i=null!=(i=a(n,"label")||(null!=t?a(t,"label"):t))?i:e.hooks.helperMissing)?i.call(null!=t?t:e.nullContext||{},{name:"label",hash:{},data:o,loc:{start:{line:11,column:31},end:{line:11,column:40}}}):i)+")\n"},4:function(e,t,n,r,o){var i,a,l=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
    \n '+(null!=(i="function"==typeof(a=null!=(a=l(n,"description")||(null!=t?l(t,"description"):t))?a:e.hooks.helperMissing)?a.call(null!=t?t:e.nullContext||{},{name:"description",hash:{},data:o,loc:{start:{line:17,column:10},end:{line:17,column:27}}}):a)?i:"")+"\n
    \n"},compiler:[8,">= 4.3.0"],main:function(e,t,n,r,o){var i,a,l=null!=t?t:e.nullContext||{},s=e.hooks.helperMissing,u=e.escapeExpression,c=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
    \n \n
    "'+u("function"==typeof(a=null!=(a=c(n,"term")||(null!=t?c(t,"term"):t))?a:s)?a.call(l,{name:"term",hash:{},data:o,loc:{start:{line:3,column:28},end:{line:3,column:36}}}):a)+'"
    \n
    Search the documentation
    \n
    \n'+(null!=(i=c(n,"each").call(l,null!=t?c(t,"suggestions"):t,{name:"each",hash:{},fn:e.program(1,o,0),inverse:e.noop,data:o,loc:{start:{line:6,column:2},end:{line:21,column:11}}}))?i:"")+"
    \n"},useData:!0})},function(e,t,n){var r=n(1);e.exports=(r.default||r).template({1:function(e,t,n,r,o){var i,a,l=null!=t?t:e.nullContext||{},s=e.hooks.helperMissing,u=e.escapeExpression,c=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return' \n"},2:function(e,t,n,r,o){return" selected disabled"},compiler:[8,">= 4.3.0"],main:function(e,t,n,r,o){var i,a=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
    \n \n
    \n"},useData:!0})},function(e,t,n){var r=n(1);function o(e){return e&&(e.__esModule?e.default:e)}e.exports=(r.default||r).template({1:function(e,t,n,r,o){var i=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return"

    Search results for "+e.escapeExpression(e.lambda(null!=t?i(t,"value"):t,t))+"

    \n"},3:function(e,t,n,r,o){return"

    Invalid Search

    \n"},5:function(e,t,n,r,o){var i,a=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return null!=(i=a(n,"each").call(null!=t?t:e.nullContext||{},null!=t?a(t,"results"):t,{name:"each",hash:{},fn:e.program(6,o,0),inverse:e.noop,data:o,loc:{start:{line:8,column:2},end:{line:17,column:11}}}))?i:""},6:function(e,t,n,r,o){var i,a=e.lambda,l=e.escapeExpression,s=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
    \n

    \n '+l(a(null!=t?s(t,"title"):t,t))+" ("+l(a(null!=t?s(t,"type"):t,t))+")\n

    \n"+(null!=(i=s(n,"each").call(null!=t?t:e.nullContext||{},null!=t?s(t,"excerpts"):t,{name:"each",hash:{},fn:e.program(7,o,0),inverse:e.noop,data:o,loc:{start:{line:13,column:8},end:{line:15,column:17}}}))?i:"")+"
    \n"},7:function(e,t,n,r,o){var i;return'

    '+(null!=(i=e.lambda(t,t))?i:"")+"

    \n"},9:function(e,t,r,i,a){var l,s=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return(null!=(l=o(n(12)).call(null!=t?t:e.nullContext||{},null!=t?s(t,"results"):t,{name:"isArray",hash:{},fn:e.program(10,a,0),inverse:e.program(12,a,0),data:a,loc:{start:{line:19,column:2},end:{line:25,column:14}}}))?l:"")+"\n

    The search functionality is full-text based. Here are some tips:

    \n\n
      \n
    • Multiple words (such as foo bar) are searched as OR
    • \n
    • Use * anywhere (such as fo*) as wildcard
    • \n
    • Use + before a word (such as +foo) to make its presence required
    • \n
    • Use - before a word (such as -foo) to make its absence required
    • \n
    • Use WORD^NUMBER (such as foo^2) to boost the given word
    • \n
    • Use WORD~NUMBER (such as foo~2) to do a search with edit distance on word
    • \n
    \n\n

    To quickly go to a module, type, or function, use the autocompletion feature in the sidebar search.

    \n"},10:function(e,t,n,r,o){var i=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return"

    Sorry, we couldn't find anything for "+e.escapeExpression(e.lambda(null!=t?i(t,"value"):t,t))+".

    \n"},12:function(e,t,n,r,o){var i,a=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return null!=(i=a(n,"if").call(null!=t?t:e.nullContext||{},null!=t?a(t,"value"):t,{name:"if",hash:{},fn:e.program(13,o,0),inverse:e.program(15,o,0),data:o,loc:{start:{line:21,column:2},end:{line:25,column:2}}}))?i:""},13:function(e,t,n,r,o){var i=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return"

    Invalid search: "+e.escapeExpression(e.lambda(null!=t?i(t,"errorMessage"):t,t))+".

    \n"},15:function(e,t,n,r,o){return"

    Please type something into the search bar to perform a search.

    \n "},compiler:[8,">= 4.3.0"],main:function(e,t,r,i,a){var l,s=null!=t?t:e.nullContext||{},u=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return(null!=(l=u(r,"if").call(s,null!=t?u(t,"value"):t,{name:"if",hash:{},fn:e.program(1,a,0),inverse:e.program(3,a,0),data:a,loc:{start:{line:1,column:0},end:{line:5,column:7}}}))?l:"")+"\n"+(null!=(l=o(n(46)).call(s,null!=t?u(t,"results"):t,{name:"isNonEmptyArray",hash:{},fn:e.program(5,a,0),inverse:e.program(9,a,0),data:a,loc:{start:{line:7,column:0},end:{line:39,column:20}}}))?l:"")},useData:!0})},function(e,t,n){var r=n(1);e.exports=(r.default||r).template({compiler:[8,">= 4.3.0"],main:function(e,t,n,r,o){return'\n'},useData:!0})},function(e,t,n){var r=n(1);e.exports=(r.default||r).template({1:function(e,t,n,r,o){var i,a=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return null!=(i=a(n,"if").call(null!=t?t:e.nullContext||{},null!=t?a(t,"description"):t,{name:"if",hash:{},fn:e.program(2,o,0),inverse:e.noop,data:o,loc:{start:{line:3,column:4},end:{line:16,column:11}}}))?i:""},2:function(e,t,n,r,o){var i,a=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
    \n
    \n'+(null!=(i=a(n,"if").call(null!=t?t:e.nullContext||{},null!=t?a(t,"displayAs"):t,{name:"if",hash:{},fn:e.program(3,o,0),inverse:e.program(5,o,0),data:o,loc:{start:{line:6,column:10},end:{line:10,column:17}}}))?i:"")+'
    \n
    \n '+e.escapeExpression(e.lambda(null!=t?a(t,"description"):t,t))+"\n
    \n
    \n"},3:function(e,t,n,r,o){var i,a=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return" "+(null!=(i=e.lambda(null!=t?a(t,"displayAs"):t,t))?i:"")+"\n"},5:function(e,t,n,r,o){var i=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return" "+e.escapeExpression(e.lambda(null!=t?i(t,"key"):t,t))+"\n"},compiler:[8,">= 4.3.0"],main:function(e,t,n,r,o){var i,a=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
    \n'+(null!=(i=a(n,"each").call(null!=t?t:e.nullContext||{},null!=t?a(t,"shortcuts"):t,{name:"each",hash:{},fn:e.program(1,o,0),inverse:e.noop,data:o,loc:{start:{line:2,column:2},end:{line:17,column:11}}}))?i:"")+"
    \n"},useData:!0})},function(e,t,n){var r=n(1);e.exports=(r.default||r).template({compiler:[8,">= 4.3.0"],main:function(e,t,n,r,o){return'
    \n \n \n
    \n
    \n'},useData:!0})},function(e,t,n){var r=n(1);e.exports=(r.default||r).template({1:function(e,t,n,r,o){var i,a=null!=t?t:e.nullContext||{},l=e.hooks.helperMissing,s=e.escapeExpression,u=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
    \n '+s("function"==typeof(i=null!=(i=u(n,"name")||(null!=t?u(t,"name"):t))?i:l)?i.call(a,{name:"name",hash:{},data:o,loc:{start:{line:3,column:4},end:{line:3,column:12}}}):i)+"\n
    \n"},compiler:[8,">= 4.3.0"],main:function(e,t,n,r,o){var i,a=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return null!=(i=a(n,"each").call(null!=t?t:e.nullContext||{},null!=t?a(t,"results"):t,{name:"each",hash:{},fn:e.program(1,o,0),inverse:e.noop,data:o,loc:{start:{line:1,column:0},end:{line:5,column:9}}}))?i:""},useData:!0})},function(e,t,n){var r=n(1);e.exports=(r.default||r).template({1:function(e,t,n,r,o){var i,a=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
    \n '+e.escapeExpression(e.lambda(null!=(i=null!=t?a(t,"hint"):t)?a(i,"description"):i,t))+"\n
    \n"},3:function(e,t,n,r,o){var i,a=e.lambda,l=e.escapeExpression,s=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
    \n

    \n '+l(a(null!=(i=null!=t?s(t,"hint"):t)?s(i,"title"):i,t))+'\n
    '+l(a(null!=(i=null!=t?s(t,"hint"):t)?s(i,"version"):i,t))+"
    \n

    \n
    \n"+(null!=(i=s(n,"if").call(null!=t?t:e.nullContext||{},null!=(i=null!=t?s(t,"hint"):t)?s(i,"description"):i,{name:"if",hash:{},fn:e.program(4,o,0),inverse:e.noop,data:o,loc:{start:{line:12,column:2},end:{line:16,column:9}}}))?i:"")},4:function(e,t,n,r,o){var i,a=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return'
    \n '+e.escapeExpression(e.lambda(null!=(i=null!=t?a(t,"hint"):t)?a(i,"description"):i,t))+"\n
    \n"},compiler:[8,">= 4.3.0"],main:function(e,t,n,r,o){var i,a=e.lookupProperty||function(e,t){if(Object.prototype.hasOwnProperty.call(e,t))return e[t]};return null!=(i=a(n,"if").call(null!=t?t:e.nullContext||{},null!=t?a(t,"isPlain"):t,{name:"if",hash:{},fn:e.program(1,o,0),inverse:e.program(3,o,0),data:o,loc:{start:{line:1,column:0},end:{line:17,column:7}}}))?i:""},useData:!0})},function(e,t,n){var r=n(1);e.exports=(r.default||r).template({compiler:[8,">= 4.3.0"],main:function(e,t,n,r,o){return'
    \n
    \n
    \n'},useData:!0})},,,,function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}t.__esModule=!0;var i=o(n(7)),a=r(n(38)),l=r(n(3)),s=o(n(2)),u=o(n(39)),c=r(n(41));function d(){var e=new i.HandlebarsEnvironment;return s.extend(e,i),e.SafeString=a.default,e.Exception=l.default,e.Utils=s,e.escapeExpression=s.escapeExpression,e.VM=u,e.template=function(t){return u.template(t,e)},e}var f=d();f.create=d,c.default(f),f.default=f,t.default=f,e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var r=n(2);t.default=function(e){e.registerHelper("blockHelperMissing",(function(t,n){var o=n.inverse,i=n.fn;if(!0===t)return i(this);if(!1===t||null==t)return o(this);if(r.isArray(t))return t.length>0?(n.ids&&(n.ids=[n.name]),e.helpers.each(t,n)):o(this);if(n.data&&n.ids){var a=r.createFrame(n.data);a.contextPath=r.appendContextPath(n.data.contextPath,n.name),n={data:a}}return i(t,n)}))},e.exports=t.default},function(e,t,n){"use strict";(function(r){t.__esModule=!0;var o,i=n(2),a=n(3),l=(o=a)&&o.__esModule?o:{default:o};t.default=function(e){e.registerHelper("each",(function(e,t){if(!t)throw new l.default("Must pass iterator to #each");var n,o=t.fn,a=t.inverse,s=0,u="",c=void 0,d=void 0;function f(t,n,r){c&&(c.key=t,c.index=n,c.first=0===n,c.last=!!r,d&&(c.contextPath=d+t)),u+=o(e[t],{data:c,blockParams:i.blockParams([e[t],t],[d+t,null])})}if(t.data&&t.ids&&(d=i.appendContextPath(t.data.contextPath,t.ids[0])+"."),i.isFunction(e)&&(e=e.call(this)),t.data&&(c=i.createFrame(t.data)),e&&"object"==typeof e)if(i.isArray(e))for(var p=e.length;s=l.LAST_COMPATIBLE_COMPILER_REVISION&&t<=l.COMPILER_REVISION)return;if(t0)return t.fn(this)}},function(e,t,n){"use strict";n.r(t),t.default=function(e,t){if(e.nodeGroups)return t.fn(this)}},function(e,t,n){"use strict";n.r(t),t.default=function(e,t){return Array.isArray(e)&&e.length>0?t.fn(this):t.inverse(this)}},,,function(e,t,n){"use strict";n.r(t);var r=n(0);function o(){Object(r.l)(".content").querySelectorAll("a").forEach((function(e){e.querySelector("code, img")&&e.classList.add("no-underline")})),Object(r.l)(".content-inner").setAttribute("tabindex",-1),Object(r.l)(".content-inner").focus()}var i=n(13),a=n.n(i);function l(e){return function(e){if(Array.isArray(e))return s(e)}(e)||function(e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return s(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return s(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n"+Object(r.c)(d)+""+e(f,n)}return e(t,a)}(e,G(t).sort((function(e,t){return t.length-e.length})))}var K={autocompleteSuggestions:[],selectedIdx:-1};function Y(){Object(r.l)(".autocomplete").classList.remove("shown")}function Z(e){var t,n,o,i;K.autocompleteSuggestions=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:5;if(Object(r.j)(e))return[];var n=k(),o=[].concat(A(V(n.modules,e,N)),A(B(n.modules,e,F)),A(V(n.tasks,e,H)));return q(o).slice(0,t)}(e),K.selectedIdx=-1,Object(r.j)(e)?Y():(t={term:e,suggestions:K.autocompleteSuggestions},n=t.term,o=t.suggestions,i=T()({suggestions:o,term:n}),Object(r.l)(".autocomplete").innerHTML=i,X(0),Object(r.l)(".autocomplete").classList.add("shown"))}function X(e){K.selectedIdx=function(e){var t=K.autocompleteSuggestions.length+1;return(K.selectedIdx+e+1+t)%t-1}(e);var t=Object(r.l)("".concat(".autocomplete-suggestion",".selected")),n=Object(r.l)("".concat(".autocomplete-suggestion",'[data-index="').concat(K.selectedIdx,'"]'));t&&t.classList.remove("selected"),n&&n.classList.add("selected")}function ee(){var e;(e=Object(r.l)("form.sidebar-search input")).addEventListener("keydown",(function(t){"Escape"===t.key?(te(),e.blur()):"Enter"===t.key?function(e){var t=Object(r.l)("form.sidebar-search input"),n=e.shiftKey||e.ctrlKey,o=-1===K.selectedIdx?null:K.autocompleteSuggestions[K.selectedIdx];e.preventDefault();var i=n?"_blank":"_self",a=document.createElement("a");a.setAttribute("target",i),o?a.setAttribute("href",o.link):a.setAttribute("href","search.html?q=".concat(encodeURIComponent(t.value))),a.click(),n||(te(),ne())}(t):"ArrowUp"===t.key?(X(-1),t.preventDefault()):"ArrowDown"===t.key&&(X(1),t.preventDefault())})),e.addEventListener("input",(function(e){Z(e.target.value)})),e.addEventListener("focus",(function(e){document.body.classList.add("search-focused"),Z(e.target.value)})),e.addEventListener("blur",(function(t){var n=t.relatedTarget;if(n){if(n.matches(".autocomplete-suggestion"))return setTimeout((function(){Object(r.l)(".autocomplete").classList.contains("shown")&&e.focus()}),1e3),null;n.matches("form.sidebar-search .search-close-button")&&te()}ne()})),Object(r.l)(".autocomplete").addEventListener("click",(function(t){t.shiftKey||t.ctrlKey?e.focus():(te(),ne())}))}function te(){Object(r.l)("form.sidebar-search input").value=""}function ne(){document.body.classList.remove("search-focused"),Y()}var re=n(16),oe=n.n(re);function ie(e){return function(e){if(Array.isArray(e))return ae(e)}(e)||function(e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return ae(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ae(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function ae(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&function(e){var t=e.nodes,n=Object(r.l)(".sidebar-projectVersion"),o=oe()({nodes:t});n.innerHTML=o,Object(r.l)(".sidebar-projectVersionsDropdown").addEventListener("change",ce)}({nodes:function(e,t){return function(e,t){return e.some((function(e){return e.version===t}))?e:[{version:t,url:"#"}].concat(ie(e))}(e,t).map((function(e){return function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n1?[].concat(ge(t),[e]):t}fe.a.Pipeline.registerFunction(t,"snakeCaseSplitter"),e.pipeline.before(fe.a.stemmer,t)}function Ee(e){return searchNodes.find((function(t){return t.ref===e}))||null}function Se(e,t){var n=e.doc,o=Object.keys(t).filter((function(e){return"doc"in t[e]})).map((function(e){return t[e].doc.position.map((function(e){var t=me(e,2),o=t[0],i=t[1];return function(e,t,n){var o=Math.max(t-80,0),i=Math.min(t+n+80,e.length);return[o>0?"...":"",e.slice(o,t),""+Object(r.c)(e.slice(t,t+n))+"",e.slice(t+n,i),i=3&&(n={results:We.autocompleteResults},o=n.results,i=Object(r.l)("#quick-switch-results"),a=Be()({results:o}),i.innerHTML=a,Object(r.m)(".quick-switch-result").forEach((function(e){e.addEventListener("click",(function(t){var n=e.getAttribute("data-index");Je(We.autocompleteResults[n].name)}))}))))}))}),300);function Ye(e){We.selectedIdx=function(e){var t=We.autocompleteResults.length;if(null===We.selectedIdx){if(e>=0)return 0;if(e<0)return t-1}return(We.selectedIdx+e+t)%t}(e);var t=Object(r.l)(".quick-switch-result.selected"),n=Object(r.l)('.quick-switch-result[data-index="'.concat(We.selectedIdx,'"]'));t&&t.classList.remove("selected"),n&&n.classList.add("selected")}var Ze=[{key:"c",description:"Toggle sidebar",action:y},{key:"n",description:"Toggle night mode",action:_e},{key:"s",description:"Focus search bar",displayAs:"/ or s",action:rt},{key:"/",action:rt},{key:"g",description:"Go to a HexDocs package",displayAs:"g",action:Ge},{key:"?",displayAs:"?",description:"Bring up this help dialog",action:function(){Object(r.l)("#modal").classList.contains("shown")&&Object(r.l)("#keyboard-shortcuts-modal-body")?Re():ot()}}],Xe={shortcutBeingPressed:null};function et(){Object(r.l)(".display-shortcuts-help").addEventListener("click",(function(e){ot()})),document.addEventListener("keydown",tt),document.addEventListener("keyup",nt)}function tt(e){if(!Xe.shortcutBeingPressed&&!e.target.matches("input, textarea")&&!(e.ctrlKey||e.metaKey||e.altKey)){var t=Ze.find((function(t){return t.key===e.key}));t&&(Xe.shortcutBeingPressed=t,e.preventDefault(),t.action(e))}}function nt(e){Xe.shortcutBeingPressed=null}function rt(e){Re(),g().then((function(){Object(r.l)("form.sidebar-search input").focus()}))}function ot(){Me({title:"Keyboard Shortcuts",body:Ne()({shortcuts:Ze})})}var it=n(22),at=n.n(it),lt=n(23),st=n.n(lt),ut="plain",ct="function",dt="module",ft=[{href:"typespecs.html#basic-types",hint:{kind:ut,description:"Basic type"}},{href:"typespecs.html#literals",hint:{kind:ut,description:"Literal"}},{href:"typespecs.html#built-in-types",hint:{kind:ut,description:"Built-in type"}}],pt={cancelHintFetching:null};function ht(e){var t=mt(e);return t?Promise.resolve(t):function(e){var t=e.replace(".html",".html?hint=true");return new Promise((function(e,n){var r=document.createElement("iframe");function o(n){var r=n.data,o=r.href,a=r.hint;t===o&&(i(),e(a))}function i(){r.remove(),window.removeEventListener("message",o),pt.cancelHintFetching=null}r.setAttribute("sandbox","allow-scripts allow-same-origin"),r.setAttribute("src",t),r.style.display="none",pt.cancelHintFetching=function(){i(),n(new Error("cancelled"))},window.addEventListener("message",o),document.body.appendChild(r)}))}(e)}function mt(e){var t=ft.find((function(t){return e.includes(t.href)}));return t?t.hint:null}var yt=450,vt=768,gt={currentLinkElement:null,hoverDelayTimeout:null};function bt(){var e;e=st()(),Object(r.l)("body .content-inner").insertAdjacentHTML("beforeend",e),Object(r.l)("footer .tooltips-toggle").addEventListener("click",(function(e){(function(e){try{e?localStorage.setItem("tooltipsDisabled","true"):localStorage.removeItem("tooltipsDisabled")}catch(e){}})(!xt()),wt()})),Object(r.m)(".content a").forEach((function(e){var t,n,o;!(t=e).classList.contains("detail-link")&&(n=t.href,o=n.replace("#content",""),window.location.href.split("#")[0]!==o&&function(e){return!!mt(e)||!(e.includes("#")&&!/#.*\//.test(e))&&e.includes(".html")}(t.href))&&(e.addEventListener("mouseenter",(function(t){!function(e){var t,n;(t=!xt(),n=window.innerWidth p"),a=i?i.textContent:"",{kind:ct,title:o.trim(),description:a.trim()}));if(["modules","tasks"].includes(Object(r.f)()))return jt(function(e){for(var t=e.querySelector("h1");t.firstElementChild;)t.removeChild(t.firstElementChild);var n=t.textContent,r=e.querySelector("#moduledoc p"),o=r?r.textContent:"";return{kind:dt,title:n.trim(),description:o.trim()}}(t));var n,o,i,a;return null}();e&&function(e){var t=window.location.href,n={hint:e,href:t};window.parent.postMessage(n,"*")}(e)}}function jt(e){return function(e){for(var t=1;tul{display:block}.sidebar #full-list li.nesting-context{opacity:.6}.sidebar #full-list li.nested{margin-left:2ex}.sidebar #full-list li.group{text-transform:uppercase;font-weight:700;font-size:.8em;margin:2em 0 0;line-height:1.8em;color:#ddd}.sidebar #full-list li a.expand{text-overflow:ellipsis}.sidebar #full-list li a.expand span{color:#d5dae6;opacity:0;padding:0 8px 0 2px;font-size:.8em}.sidebar #full-list li a.expand:hover span{opacity:1}.sidebar #full-list>li.current-page>a,.sidebar #full-list li a.expand span:hover{color:#fff}.sidebar #full-list>li:last-child{margin-bottom:30px}.sidebar #full-list ul{display:none;margin:9px 15px;padding:0}.sidebar #full-list ul li{font-weight:300;line-height:18px;padding:2px 10px}.sidebar #full-list ul li ul{display:none;margin:9px 4px}.sidebar #full-list ul li ul li{border-left:1px solid #767676;padding:0 10px}.sidebar #full-list ul li ul li.current-hash:before{font-family:icomoon;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\F105";margin-left:-10px;font-size:16px;margin-right:5px}.sidebar #full-list ul li ul li.current-hash{border-left:none}.sidebar #full-list ul li ul li.current-hash>a{color:#fff}.sidebar-button{color:#e1e1e1;cursor:pointer;background-color:transparent;border:none;padding:10px 11px;font-size:16px}.sidebar-button:hover{color:#fff}.sidebar-button:active,.sidebar-button:focus,.sidebar-button:hover{outline:none}@media screen and (max-height:500px){.sidebar{overflow-y:auto}.sidebar #full-list{overflow:visible}}.content-inner{font-family:Merriweather,Book Antiqua,Georgia,Century Schoolbook,serif;font-size:1em;line-height:1.6875em;position:relative}.content-inner h1,.content-inner h2,.content-inner h3,.content-inner h4,.content-inner h5,.content-inner h6{font-family:Lato,sans-serif;font-weight:700;line-height:1.5em;word-wrap:break-word}.content-inner h1{font-size:2em;margin:1em 0 .5em}.content-inner h1.signature{margin:0}.content-inner h1.section-heading{margin:1.5em 0 .5em}.content-inner h1 small{font-weight:300}.content-inner h1 a.view-source{font-size:1.2rem}.content-inner h2{font-size:1.6em;margin:1em 0 .5em;font-weight:700}.content-inner h3{font-size:1.375em;margin:1em 0 .5em;font-weight:700}.content-inner a{color:#000;text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}.content-inner a:visited{color:#000}.content-inner a.no-underline{text-decoration:none}.content-inner a.view-source{float:right;color:#727272;text-decoration:none;border:none;-webkit-transition:color .3s ease-in-out;transition:color .3s ease-in-out;margin-top:1px}.content-inner a.view-source:hover{color:#373f52}.content-inner .note{color:#727272;margin-right:5px;font-size:14px;font-weight:400}.content-inner blockquote{font-style:italic;margin:.5em 0;padding:.25em 1.5em;border-left:3px solid #e1e1e1;display:inline-block}.content-inner blockquote :first-child{padding-top:0;margin-top:0}.content-inner blockquote :last-child{padding-bottom:0;margin-bottom:0}.content-inner table{margin:2em 0}.content-inner th{text-align:left;font-family:Lato,sans-serif;text-transform:uppercase;font-weight:700;padding-bottom:.5em}.content-inner tr{border-bottom:1px solid #d5dae6;vertical-align:bottom;height:2.5em}.content-inner td,.content-inner th{padding-left:1em;line-height:2em;vertical-align:top}.content-inner .section-heading:hover a.hover-link{opacity:1;text-decoration:none}.content-inner .section-heading a.hover-link{-webkit-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out;display:inline-block;opacity:0;padding:.3em .6em .6em;line-height:1em;margin-left:-2.7em;text-decoration:none;border:none;font-size:16px;vertical-align:middle}.content-inner .detail h2.section-heading{margin-left:.3em}.content-inner .app-vsn{display:none!important;font-size:.6em;line-height:1.5em}@media screen and (max-width:768px){.content-inner .app-vsn{display:block!important}}.content-inner img{max-width:100%}.content-inner code{font-family:Inconsolata,Menlo,Courier,monospace;font-style:normal;line-height:24px;font-weight:400}.content-inner .summary h2{font-weight:700}.content-inner .summary h2 a{text-decoration:none;border:none}.content-inner .summary span.deprecated{color:#dcc100;font-weight:400;font-style:italic}.content-inner .summary .summary-row .summary-signature{font-family:Inconsolata,Menlo,Courier,monospace;font-weight:700}.content-inner .summary .summary-row .summary-signature a{text-decoration:none;border:none}.content-inner .summary .summary-row .summary-synopsis{font-family:Merriweather,Book Antiqua,Georgia,Century Schoolbook,serif;font-style:italic;padding:0 1.2em;margin:0 0 .5em}.content-inner .summary .summary-row .summary-synopsis p{margin:0;padding:0}@-webkit-keyframes blink-background{0%{background-color:#f7f7f7}to{background-color:#ff9}}@keyframes blink-background{0%{background-color:#f7f7f7}to{background-color:#ff9}}.content-inner .detail:target .detail-header{-webkit-animation-duration:.55s;animation-duration:.55s;-webkit-animation-name:blink-background;animation-name:blink-background;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.content-inner .detail-header{margin:2em 0 1em;padding:.5em 1em;background:#f7f7f7;border-left:3px solid #8e58cb;font-size:1em;font-family:Inconsolata,Menlo,Courier,monospace;position:relative}.content-inner .detail-header .note{float:right}.content-inner .detail-header .signature{display:inline-block;font-family:Inconsolata,Menlo,Courier,monospace;font-size:1rem;font-weight:700}.content-inner .detail-header:hover a.detail-link{opacity:1;text-decoration:none}.content-inner .detail-header a.detail-link{-webkit-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out;position:absolute;top:0;left:0;display:block;opacity:0;padding:.6em;line-height:1.5em;margin-left:-2.5em;text-decoration:none;border:none}.content-inner .specs{padding:1em}.content-inner .specs pre{font-family:Inconsolata,Menlo,Courier,monospace;font-size:.9em;font-style:normal;line-height:24px;white-space:pre-wrap;margin:0;padding:0}.content-inner .docstring{margin:1.2em 0 3em 1.2em}.content-inner .docstring h2,.content-inner .docstring h3,.content-inner .docstring h4,.content-inner .docstring h5{font-weight:700}.content-inner .docstring h2{font-size:1.1em}.content-inner .docstring h3{font-size:1em}.content-inner .docstring h4{font-size:.95em}.content-inner .docstring h5{font-size:.9em}.content-inner div.deprecated{display:block;padding:9px 15px;background-color:#fffeed}.content-inner a.no-underline,.content-inner pre a{color:#8e58cb;text-shadow:none;text-decoration:none;background-image:none}.content-inner a.no-underline:active,.content-inner a.no-underline:focus,.content-inner a.no-underline:hover,.content-inner a.no-underline:visited,.content-inner pre a:active,.content-inner pre a:focus,.content-inner pre a:hover,.content-inner pre a:visited{color:#8e58cb;text-decoration:none}.content-inner code{background-color:#f7f9fc;vertical-align:baseline;border-radius:2px;padding:.1em .2em;border:1px solid #d2ddee;text-transform:none}.content-inner pre{margin:1.5em 0}.content-inner pre code{display:block;overflow-x:auto;white-space:inherit;padding:.5em 1em;background-color:#f7f9fc}.content-inner .footer{margin:6em auto 1em;text-align:center;font-style:italic;font-size:14px;color:#767676}.content-inner .footer .line{display:inline-block}.content-inner .footer .footer-button{background-color:transparent;border:0;cursor:pointer;font-style:italic;outline:none;padding:0 4px;color:#767676;text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}.content-inner .footer .footer-button:visited{color:#767676}.content-inner .footer a{color:#767676;text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}.content-inner .footer a:visited{color:#767676}.content-inner .bottom-actions{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;margin-top:4em}.content-inner .bottom-actions .bottom-actions-button{display:-webkit-box;display:-ms-flexbox;display:flex;text-decoration:none;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;border-radius:4px;border:1px solid rgba(0,0,0,.1);padding:8px 16px;min-width:150px}.content-inner .bottom-actions .bottom-actions-button .subheader{font-size:.8em;color:#8e58cb;white-space:nowrap}.content-inner .bottom-actions .bottom-actions-button[rel=prev] .subheader{text-align:right}@media screen and (max-width:768px){.content-inner .bottom-actions{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}.content-inner .bottom-actions .bottom-actions-item:not(:first-child){margin-bottom:16px}}#search{min-height:200px;position:relative}#search .loading{height:64px;width:64px;vertical-align:middle;position:absolute;top:50%;left:calc(50% - 32px)}#search .loading div{-webkit-box-sizing:border-box;box-sizing:border-box;display:block;position:absolute;width:51px;height:51px;margin:6px;border-radius:50%;-webkit-animation:loading 1.2s cubic-bezier(.5,0,.5,1) infinite;animation:loading 1.2s cubic-bezier(.5,0,.5,1) infinite;border:6px solid transparent;border-top-color:#767676}#search .loading div:first-child{-webkit-animation-delay:-.45s;animation-delay:-.45s}#search .loading div:nth-child(2){-webkit-animation-delay:-.3s;animation-delay:-.3s}#search .loading div:nth-child(3){-webkit-animation-delay:-.15s;animation-delay:-.15s}@-webkit-keyframes loading{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes loading{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}#search .result{margin:2em 0 2.5em}#search .result p{margin:0}#search .result-id{font-size:1.4em;margin:0}#search .result-id a{text-decoration:none;-webkit-transition:color .3s ease-in-out;transition:color .3s ease-in-out}#search .result-id a:active,#search .result-id a:focus,#search .result-id a:visited{color:#000}#search .result-id a:hover{color:#8e58cb}#search .result-elem em,#search .result-id em{font-style:normal;color:#8e58cb}#search .result-id small{font-weight:400}@-webkit-keyframes keyboard-shortcuts-show{0%{opacity:0}to{opacity:1}}@keyframes keyboard-shortcuts-show{0%{opacity:0}to{opacity:1}}.modal{-webkit-animation-duration:.15s;animation-duration:.15s;-webkit-animation-name:keyboard-shortcuts-show;animation-name:keyboard-shortcuts-show;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;display:none;background-color:rgba(0,0,0,.7);position:fixed;top:0;left:0;right:0;bottom:0;z-index:300}.modal.shown{display:block}.modal .modal-contents{margin:75px auto 0;max-width:450px;background-color:#fff;border-radius:3px;-webkit-box-shadow:2px 2px 8px rgba(0,0,0,.2);box-shadow:2px 2px 8px rgba(0,0,0,.2);padding:25px 35px}.modal .modal-title{display:inline-block;font-size:1.3rem;font-weight:700;padding-bottom:20px}.modal .modal-close{cursor:pointer;display:block;float:right;font-size:1.5rem;margin:-8px -8px 0 0;padding:8px;opacity:.3}.modal .modal-close:hover{opacity:.7}#keyboard-shortcuts-modal-body dl.shortcut-row{margin:0;border-bottom:1px solid #d5dae6;padding:12px 0}#keyboard-shortcuts-modal-body dl.shortcut-row:last-of-type{border-bottom-style:none}#keyboard-shortcuts-modal-body .shortcut-description,#keyboard-shortcuts-modal-body .shortcut-keys{display:inline-block}#keyboard-shortcuts-modal-body kbd>kbd{background-color:#d5dae6;border-radius:3px;color:#373f52;font-family:inherit;font-weight:700;display:inline-block;line-height:1;padding:4px 7px 6px;min-width:26px;text-align:center;margin-left:3px}#keyboard-shortcuts-modal-body .shortcut-description,#keyboard-shortcuts-modal-body .shortcut-keys{margin:0}#keyboard-shortcuts-modal-body .shortcut-keys{float:right;text-align:right;min-width:100px;vertical-align:top}#keyboard-shortcuts-modal-body .shortcut-description{position:relative;top:2px;width:250px}#quick-switch-modal-body{width:100%;position:relative}#quick-switch-modal-body .icon-search{position:absolute;left:0;top:0;padding:8px 2px;color:#767676}#quick-switch-modal-body #quick-switch-input{width:100%;padding:8px 6px 6px 26px;border:none;border-bottom:1px solid #767676;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:all .12s ease-out;transition:all .12s ease-out}#quick-switch-modal-body #quick-switch-input:focus{border-bottom:1px solid #373f52;outline:none}#quick-switch-modal-body #quick-switch-results{margin:0}#quick-switch-modal-body #quick-switch-results .quick-switch-result{padding:2px 5px;border-bottom:1px dotted #767676;-webkit-transition:all .12s ease-out;transition:all .12s ease-out}#quick-switch-modal-body #quick-switch-results .quick-switch-result:last-child{border-bottom:none}#quick-switch-modal-body #quick-switch-results .quick-switch-result:hover{cursor:pointer}#quick-switch-modal-body #quick-switch-results .quick-switch-result.selected,#quick-switch-modal-body #quick-switch-results .quick-switch-result:hover{border-left:4px solid #8e58cb;background:#f7f9fc}.autocomplete{display:none;height:0;margin:0 5px 0 12px;overflow:visible;position:relative;width:100%}.autocomplete.shown{display:block}.autocomplete-suggestions{-webkit-box-shadow:2px 2px 10px rgba(0,0,0,.25);box-shadow:2px 2px 10px rgba(0,0,0,.25);background-color:#202530;border-top:1px solid #373f52;left:0;position:absolute;top:-2px;width:276px;z-index:200}.autocomplete-suggestion{color:inherit;display:block;padding:10px;text-decoration:none}.autocomplete-suggestion.selected,.autocomplete-suggestion:hover{background-color:#292f3d;border-left:3px solid #8e58cb}.autocomplete-suggestion em{font-style:normal;font-weight:700}.autocomplete-suggestion .description{opacity:.6;padding-top:3px}.autocomplete-suggestion .label{padding-left:2px;opacity:.75}.autocomplete-suggestion .description,.autocomplete-suggestion .title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}#tooltip{-webkit-box-shadow:0 0 10px rgba(0,0,0,.1);box-shadow:0 0 10px rgba(0,0,0,.1);max-height:300px;max-width:500px;padding:0;position:absolute;pointer-events:none;margin:0;z-index:99;top:0;left:0;visibility:hidden;-webkit-transform:translateY(20px);transform:translateY(20px);opacity:0;-webkit-transition:visibility .2s ease-out,opacity .2s ease-out,-webkit-transform .2s ease-out;transition:visibility .2s ease-out,opacity .2s ease-out,-webkit-transform .2s ease-out;transition:visibility .2s ease-out,transform .2s ease-out,opacity .2s ease-out;transition:visibility .2s ease-out,transform .2s ease-out,opacity .2s ease-out,-webkit-transform .2s ease-out}#tooltip.tooltip-shown{visibility:visible;-webkit-transform:translateY(0);transform:translateY(0);opacity:1}#tooltip .tooltip-body{border:1px solid hsla(0,0%,46.3%,.3)}#tooltip .tooltip-body .signature{min-width:320px;width:100%}#tooltip .tooltip-body .detail-header{border-left:0;margin-bottom:0;margin-top:0}#tooltip .tooltip-body .docstring{background-color:#fff;padding:1.2em;margin:0;width:498px}#tooltip .tooltip-body .docstring-plain{max-width:498px;width:auto}#tooltip .tooltip-body .version-info{float:right;line-height:1.6rem;font-family:Inconsolata,Menlo,Courier,monospace;font-size:.9rem;font-weight:400;margin-bottom:-6px;opacity:.3;padding-left:.3em}.tooltips-toggle .tooltips-option-enable{display:none}.tooltips-toggle[data-is-disabled=true] .tooltips-option-enable{display:inline}.tooltips-toggle[data-is-disabled=true] .tooltips-option-disable{display:none}body.night-mode,body.night-mode .content-outer{background:#212127}body.night-mode .night-mode-toggle .icon-theme:before{content:"\E901"}body.night-mode #search .result-id a:active,body.night-mode #search .result-id a:focus,body.night-mode #search .result-id a:visited{color:#d2d2d2}body.night-mode #search .result-id a:hover{color:#8e58cb}body.night-mode .content-inner{color:#b4b4b4}body.night-mode .content-inner h1,body.night-mode .content-inner h2,body.night-mode .content-inner h3,body.night-mode .content-inner h4,body.night-mode .content-inner h5,body.night-mode .content-inner h6{color:#d2d2d2}body.night-mode .content-inner a{text-decoration:none;color:#d2d2d2;text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}body.night-mode .content-inner a:visited{color:#d2d2d2}body.night-mode .content-inner a.no-underline{text-decoration:none}body.night-mode .content-inner a.view-source{color:#939393;text-decoration:none}body.night-mode .content-inner a.view-source:hover{color:#fff}body.night-mode .content-inner .note{color:#939393}body.night-mode .content-inner .summary h2 a{text-decoration:none}@-webkit-keyframes night-blink-background{0%{background-color:#2c2c31}to{background-color:#660}}@keyframes night-blink-background{0%{background-color:#2c2c31}to{background-color:#660}}body.night-mode .content-inner .detail:target .detail-header{-webkit-animation-name:night-blink-background;animation-name:night-blink-background}body.night-mode .content-inner .detail-header{background:#2c2c31;color:#b4b4b4}body.night-mode .content-inner div.deprecated{background-color:#3c381e}body.night-mode .content-inner code{background-color:#2c2c31;border-color:#44444c}body.night-mode .content-inner pre code{background-color:#2c2c31}body.night-mode .content-inner pre a,body.night-mode .content-inner pre a:visited{color:#fff;text-decoration:none}body.night-mode .content-inner pre a:hover{color:#8e58cb}body.night-mode .content-inner .footer{color:#888}body.night-mode .content-inner .footer .footer-button{color:#888;text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}body.night-mode .content-inner .footer .footer-button:visited{color:#888}body.night-mode .content-inner .footer a{color:#888;text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}body.night-mode .content-inner .footer a:visited{color:#888}body.night-mode .content-inner .bottom-actions .bottom-actions-button{border:1px solid hsla(0,0%,100%,.1)}body.night-mode #search .loading div{border-top-color:#767676}body.night-mode .sidebar-button,body.night-mode .sidebar-closed .sidebar-button{color:#d5dae6}body.night-mode #quick-switch-modal-body .icon-search{color:#888}body.night-mode #quick-switch-modal-body #quick-switch-input{border-bottom-color:#888}body.night-mode #quick-switch-modal-body #quick-switch-results{margin:0}body.night-mode #quick-switch-modal-body #quick-switch-results .quick-switch-result{border-bottom-color:#888}body.night-mode #keyboard-shortcuts-modal{background-color:rgba(0,0,0,.75)}body.night-mode #keyboard-shortcuts-modal .modal-contents{background-color:#212127;color:#b4b4b4}body.night-mode #keyboard-shortcuts-modal .modal-contents dl.shortcut-row{border-bottom:1px solid #38383d}body.night-mode #keyboard-shortcuts-modal .modal-contents dl.shortcut-row:last-of-type{border-bottom-style:none}body.night-mode #keyboard-shortcuts-modal .modal-contents kbd>kbd{color:#b4b4b4;background-color:#2c2c31;border:1px solid #38383d}body.night-mode #tooltip{-webkit-box-shadow:0 0 10px rgba(0,0,0,.5);box-shadow:0 0 10px rgba(0,0,0,.5)}body.night-mode #tooltip .tooltip-body{border:1px solid #2c2c31}body.night-mode #tooltip .tooltip-body .docstring{background:#212127}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}@media print{.main{display:block}.sidebar,.sidebar-button{display:none}.content{padding-left:0;overflow:visible}.summary-row{page-break-inside:avoid}}code.makeup .unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.makeup .hll{background-color:#ffc}.makeup .bp{color:#3465a4}.makeup .c,.makeup .c1,.makeup .ch,.makeup .cm,.makeup .cp,.makeup .cpf,.makeup .cs{color:#737373}.makeup .dl{color:#408200}.makeup .err{color:#a40000;border:#ef2929}.makeup .fm,.makeup .g{color:#4d4d4c}.makeup .gd{color:#a40000}.makeup .ge{color:#4d4d4c;font-style:italic}.makeup .gh{color:navy;font-weight:700}.makeup .gi{color:#00a000}.makeup .go{color:#4d4d4c;font-style:italic}.makeup .gp{color:#737373}.makeup .gr{color:#ef2929}.makeup .gs{color:#4d4d4c;font-weight:700}.makeup .gt{color:#a40000;font-weight:700}.makeup .gu{color:purple;font-weight:700}.makeup .il{color:#0000cf;font-weight:700}.makeup .k,.makeup .kc,.makeup .kd,.makeup .kn,.makeup .kp,.makeup .kr,.makeup .kt{color:#204a87}.makeup .l{color:#4d4d4c}.makeup .ld{color:#c00}.makeup .m,.makeup .mb,.makeup .mf,.makeup .mh,.makeup .mi,.makeup .mo{color:#2937ab}.makeup .n{color:#4d4d4c}.makeup .na{color:#8a7000}.makeup .nb{color:#204a87}.makeup .nc{color:#0000cf}.makeup .nd{color:#5c35cc;font-weight:700}.makeup .ne{color:#c00;font-weight:700}.makeup .nf{color:#b65800}.makeup .ni{color:#bc5400}.makeup .nl{color:#b65800}.makeup .nn{color:#4d4d4c}.makeup .no{color:#a06600}.makeup .nt{color:#204a87;font-weight:700}.makeup .nv,.makeup .nx{color:#4d4d4c}.makeup .o{color:#bc5400}.makeup .ow{color:#204a87}.makeup .p,.makeup .py{color:#4d4d4c}.makeup .s,.makeup .s1,.makeup .s2,.makeup .sa,.makeup .sb,.makeup .sc{color:#408200}.makeup .sd{color:#8f5902;font-style:italic}.makeup .se{color:#204a87}.makeup .sh{color:#408200}.makeup .si{color:#204a87}.makeup .sr{color:#c00}.makeup .ss{color:#a06600}.makeup .sx{color:#408200}.makeup .vc,.makeup .vg,.makeup .vi,.makeup .vm,.makeup .x{color:#4d4d4c}.night-mode .makeup{color:#f8f8f2}.night-mode .makeup .hll{background-color:#49483e}.night-mode .makeup .bp{color:#f8f8f2}.night-mode .makeup .c,.night-mode .makeup .c1,.night-mode .makeup .ch,.night-mode .makeup .cm,.night-mode .makeup .cp,.night-mode .makeup .cpf,.night-mode .makeup .cs{color:#969386}.night-mode .makeup .dl{color:#e6db74}.night-mode .makeup .err{color:#960050;background-color:#1e0010}.night-mode .makeup .fm{color:#a6e22e}.night-mode .makeup .gd{color:#ff5385}.night-mode .makeup .ge{font-style:italic}.night-mode .makeup .gi{color:#a6e22e}.night-mode .makeup .gp{color:#969386}.night-mode .makeup .gs{font-weight:700}.night-mode .makeup .gu{color:#969386}.night-mode .makeup .gt{color:#ff5385;font-weight:700}.night-mode .makeup .il{color:#ae81ff}.night-mode .makeup .k,.night-mode .makeup .kc,.night-mode .makeup .kd{color:#66d9ef}.night-mode .makeup .kn{color:#ff5385}.night-mode .makeup .kp,.night-mode .makeup .kr,.night-mode .makeup .kt{color:#66d9ef}.night-mode .makeup .l,.night-mode .makeup .ld,.night-mode .makeup .m,.night-mode .makeup .mb,.night-mode .makeup .mf,.night-mode .makeup .mh,.night-mode .makeup .mi,.night-mode .makeup .mo{color:#ae81ff}.night-mode .makeup .n{color:#f8f8f2}.night-mode .makeup .na{color:#a6e22e}.night-mode .makeup .nb{color:#f8f8f2}.night-mode .makeup .nc,.night-mode .makeup .nd,.night-mode .makeup .ne,.night-mode .makeup .nf{color:#a6e22e}.night-mode .makeup .ni,.night-mode .makeup .nl,.night-mode .makeup .nn{color:#f8f8f2}.night-mode .makeup .no{color:#66d9ef}.night-mode .makeup .nt{color:#ff5385}.night-mode .makeup .nv{color:#f8f8f2}.night-mode .makeup .nx{color:#a6e22e}.night-mode .makeup .o,.night-mode .makeup .ow{color:#ff5385}.night-mode .makeup .p,.night-mode .makeup .py{color:#f8f8f2}.night-mode .makeup .s,.night-mode .makeup .s1,.night-mode .makeup .s2,.night-mode .makeup .sa,.night-mode .makeup .sb,.night-mode .makeup .sc,.night-mode .makeup .sd{color:#e6db74}.night-mode .makeup .se{color:#ae81ff}.night-mode .makeup .sh,.night-mode .makeup .si,.night-mode .makeup .sr,.night-mode .makeup .ss,.night-mode .makeup .sx{color:#e6db74}.night-mode .makeup .vc,.night-mode .makeup .vg,.night-mode .makeup .vi,.night-mode .makeup .vm{color:#f8f8f2} \ No newline at end of file diff --git a/doc/dist/html/fonts/icomoon.eot b/doc/dist/html/fonts/icomoon.eot deleted file mode 100644 index 50dd714..0000000 Binary files a/doc/dist/html/fonts/icomoon.eot and /dev/null differ diff --git a/doc/dist/html/fonts/icomoon.svg b/doc/dist/html/fonts/icomoon.svg deleted file mode 100644 index 1602a64..0000000 --- a/doc/dist/html/fonts/icomoon.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - -Generated by IcoMoon - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/doc/dist/html/fonts/icomoon.ttf b/doc/dist/html/fonts/icomoon.ttf deleted file mode 100644 index f421262..0000000 Binary files a/doc/dist/html/fonts/icomoon.ttf and /dev/null differ diff --git a/doc/dist/html/fonts/icomoon.woff b/doc/dist/html/fonts/icomoon.woff deleted file mode 100644 index d50dd60..0000000 Binary files a/doc/dist/html/fonts/icomoon.woff and /dev/null differ diff --git a/doc/dist/search_items-863ec2fe87.js b/doc/dist/search_items-863ec2fe87.js deleted file mode 100644 index 49fd342..0000000 --- a/doc/dist/search_items-863ec2fe87.js +++ /dev/null @@ -1 +0,0 @@ -searchNodes=[{"doc":"Stores the session in a cookie. This cookie store is based on Plug.Crypto.MessageVerifier and Plug.Crypto.Message.Encryptor which encrypts and signs each cookie to ensure they can't be read nor tampered with. Since this store uses crypto features, it requires you to set the :secret_key_base field in your connection. This can be easily achieved with a plug: plug :put_secret_key_base def put_secret_key_base ( conn , _ ) do put_in conn . secret_key_base , "-- LONG STRING WITH AT LEAST 64 BYTES --" end Options :encrypt - specify whether to encrypt cookies, defaults to true. When this option is false, the cookie is still signed, meaning it can't be tempered with but its contents can be read; :encryption_salt - a salt used with conn.secret_key_base to generate a key for encrypting/decrypting a cookie; :signing_salt - a salt used with conn.secret_key_base to generate a key for signing/verifying a cookie; :key_iterations - option passed to Plug.Crypto.KeyGenerator when generating the encryption and signing keys. Defaults to 1000; :key_length - option passed to Plug.Crypto.KeyGenerator when generating the encryption and signing keys. Defaults to 32; :key_digest - option passed to Plug.Crypto.KeyGenerator when generating the encryption and signing keys. Defaults to :sha256 ; :serializer - cookie serializer module that defines encode/1 and decode/1 returning an {:ok, value} tuple. Defaults to :external_term_format . Examples # Use the session plug with the table name plug Plug.Session , store : PlugRailsCookieSessionStore , key : "_my_app_session" , encryption_salt : "cookie store encryption salt" , signing_salt : "cookie store signing salt" , key_length : 64 , serializer : Poison","ref":"PlugRailsCookieSessionStore.html","title":"PlugRailsCookieSessionStore","type":"module"},{"doc":"Callback implementation for Plug.Session.Store.delete/3 .","ref":"PlugRailsCookieSessionStore.html#delete/3","title":"PlugRailsCookieSessionStore.delete/3","type":"function"},{"doc":"Callback implementation for Plug.Session.Store.get/3 .","ref":"PlugRailsCookieSessionStore.html#get/3","title":"PlugRailsCookieSessionStore.get/3","type":"function"},{"doc":"Callback implementation for Plug.Session.Store.init/1 .","ref":"PlugRailsCookieSessionStore.html#init/1","title":"PlugRailsCookieSessionStore.init/1","type":"function"},{"doc":"Callback implementation for Plug.Session.Store.put/4 .","ref":"PlugRailsCookieSessionStore.html#put/4","title":"PlugRailsCookieSessionStore.put/4","type":"function"},{"doc":"MessageEncryptor is a simple way to encrypt values which get stored somewhere you don't trust. The cipher text and initialization vector are base64 encoded and returned to you. This can be used in situations similar to the MessageVerifier , but where you don't want users to be able to determine the value of the payload. Example secret_key_base = "072d1e0157c008193fe48a670cce031faa4e..." encrypted_cookie_salt = "encrypted cookie" encrypted_signed_cookie_salt = "signed encrypted cookie" secret = KeyGenerator . generate ( secret_key_base , encrypted_cookie_salt ) sign_secret = KeyGenerator . generate ( secret_key_base , encrypted_signed_cookie_salt ) encryptor = MessageEncryptor . new ( secret , sign_secret ) data = %{ current_user : %{ name : "José" } } encrypted = MessageEncryptor . encrypt_and_sign ( encryptor , data ) decrypted = MessageEncryptor . verify_and_decrypt ( encryptor , encrypted ) decrypted . current_user . name # => "José"","ref":"PlugRailsCookieSessionStore.MessageEncryptor.html","title":"PlugRailsCookieSessionStore.MessageEncryptor","type":"module"},{"doc":"Encrypts and signs a message.","ref":"PlugRailsCookieSessionStore.MessageEncryptor.html#encrypt_and_sign/4","title":"PlugRailsCookieSessionStore.MessageEncryptor.encrypt_and_sign/4","type":"function"},{"doc":"Decrypts and verifies a message. We need to verify the message in order to avoid padding attacks. Reference: http://www.limited-entropy.com/padding-oracle-attacks","ref":"PlugRailsCookieSessionStore.MessageEncryptor.html#verify_and_decrypt/4","title":"PlugRailsCookieSessionStore.MessageEncryptor.verify_and_decrypt/4","type":"function"},{"doc":"MessageVerifier makes it easy to generate and verify messages which are signed to prevent tampering. For example, the cookie store uses this verifier to send data to the client. Although the data can be read by the client, he cannot tamper it.","ref":"PlugRailsCookieSessionStore.MessageVerifier.html","title":"PlugRailsCookieSessionStore.MessageVerifier","type":"module"},{"doc":"Signs a binary according to the given secret.","ref":"PlugRailsCookieSessionStore.MessageVerifier.html#sign/2","title":"PlugRailsCookieSessionStore.MessageVerifier.sign/2","type":"function"},{"doc":"Decodes and verifies the encoded binary was not tampared with.","ref":"PlugRailsCookieSessionStore.MessageVerifier.html#verify/2","title":"PlugRailsCookieSessionStore.MessageVerifier.verify/2","type":"function"}] \ No newline at end of file diff --git a/doc/dist/sidebar_items-45722afe85.js b/doc/dist/sidebar_items-45722afe85.js deleted file mode 100644 index 8a99c58..0000000 --- a/doc/dist/sidebar_items-45722afe85.js +++ /dev/null @@ -1 +0,0 @@ -sidebarNodes={"extras":[{"group":"","headers":[{"anchor":"modules","id":"Modules"}],"id":"api-reference","title":"API Reference"}],"modules":[{"group":"","id":"PlugRailsCookieSessionStore","nodeGroups":[{"key":"functions","name":"Functions","nodes":[{"anchor":"delete/3","id":"delete/3"},{"anchor":"get/3","id":"get/3"},{"anchor":"init/1","id":"init/1"},{"anchor":"put/4","id":"put/4"}]}],"sections":[{"anchor":"module-options","id":"Options"},{"anchor":"module-examples","id":"Examples"}],"title":"PlugRailsCookieSessionStore"},{"group":"","id":"PlugRailsCookieSessionStore.MessageEncryptor","nodeGroups":[{"key":"functions","name":"Functions","nodes":[{"anchor":"encrypt_and_sign/4","id":"encrypt_and_sign/4"},{"anchor":"verify_and_decrypt/4","id":"verify_and_decrypt/4"}]}],"sections":[{"anchor":"module-example","id":"Example"}],"title":"PlugRailsCookieSessionStore.MessageEncryptor"},{"group":"","id":"PlugRailsCookieSessionStore.MessageVerifier","nodeGroups":[{"key":"functions","name":"Functions","nodes":[{"anchor":"sign/2","id":"sign/2"},{"anchor":"verify/2","id":"verify/2"}]}],"sections":[],"title":"PlugRailsCookieSessionStore.MessageVerifier"}],"tasks":[]} \ No newline at end of file diff --git a/doc/index.html b/doc/index.html deleted file mode 100644 index 9ca5b54..0000000 --- a/doc/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - plug_rails_cookie_session_store v2.0.0 — Documentation - - - - - diff --git a/doc/plug_rails_cookie_session_store.epub b/doc/plug_rails_cookie_session_store.epub deleted file mode 100644 index 84f19e0..0000000 Binary files a/doc/plug_rails_cookie_session_store.epub and /dev/null differ diff --git a/doc/search.html b/doc/search.html deleted file mode 100644 index 72b0047..0000000 --- a/doc/search.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - - - - Search — plug_rails_cookie_session_store v2.0.0 - - - - - - - - - - - - - -
    - - - - - -
    -
    -
    - - - - -
    -
    -
    -
    - - - - diff --git a/lib/plug_rails_cookie_session_store.ex b/lib/plug_rails_cookie_session_store.ex index 7399f30..5604b5d 100644 --- a/lib/plug_rails_cookie_session_store.ex +++ b/lib/plug_rails_cookie_session_store.ex @@ -50,6 +50,7 @@ defmodule PlugRailsCookieSessionStore do signing_salt: "cookie store signing salt", key_length: 64, serializer: Poison + """ @behaviour Plug.Session.Store diff --git a/lib/plug_rails_cookie_session_store/message_encryptor.ex b/lib/plug_rails_cookie_session_store/message_encryptor.ex index 06c1345..e2449bd 100644 --- a/lib/plug_rails_cookie_session_store/message_encryptor.ex +++ b/lib/plug_rails_cookie_session_store/message_encryptor.ex @@ -2,11 +2,15 @@ defmodule PlugRailsCookieSessionStore.MessageEncryptor do @moduledoc ~S""" `MessageEncryptor` is a simple way to encrypt values which get stored somewhere you don't trust. + The cipher text and initialization vector are base64 encoded and returned to you. + This can be used in situations similar to the `MessageVerifier`, but where you don't want users to be able to determine the value of the payload. + ## Example + secret_key_base = "072d1e0157c008193fe48a670cce031faa4e..." encrypted_cookie_salt = "encrypted cookie" encrypted_signed_cookie_salt = "signed encrypted cookie" @@ -17,6 +21,7 @@ defmodule PlugRailsCookieSessionStore.MessageEncryptor do encrypted = MessageEncryptor.encrypt_and_sign(encryptor, data) decrypted = MessageEncryptor.verify_and_decrypt(encryptor, encrypted) decrypted.current_user.name # => "José" + """ alias PlugRailsCookieSessionStore.MessageVerifier @@ -38,6 +43,7 @@ defmodule PlugRailsCookieSessionStore.MessageEncryptor do @doc """ Decrypts and verifies a message. + We need to verify the message in order to avoid padding attacks. Reference: http://www.limited-entropy.com/padding-oracle-attacks """ diff --git a/lib/plug_rails_cookie_session_store/message_verifier.ex b/lib/plug_rails_cookie_session_store/message_verifier.ex index 059a4dd..8cb3223 100644 --- a/lib/plug_rails_cookie_session_store/message_verifier.ex +++ b/lib/plug_rails_cookie_session_store/message_verifier.ex @@ -2,13 +2,14 @@ defmodule PlugRailsCookieSessionStore.MessageVerifier do @moduledoc """ `MessageVerifier` makes it easy to generate and verify messages which are signed to prevent tampering. + For example, the cookie store uses this verifier to send data to the client. Although the data can be read by the client, he cannot tamper it. """ @doc """ - Decodes and verifies the encoded binary was not tampared with. + Decodes and verifies the encoded binary was not tampered with. """ def verify(binary, secret) when is_binary(binary) and is_binary(secret) do case String.split(binary, "--") do diff --git a/mix.exs b/mix.exs index 09a5d4a..ed31468 100644 --- a/mix.exs +++ b/mix.exs @@ -1,32 +1,36 @@ defmodule PlugRailsCookieSessionStore.Mixfile do use Mix.Project + @source_url "https://github.com/cconstantin/plug_rails_cookie_session_store" + @version "2.0.0" + def project do [ app: :plug_rails_cookie_session_store, - version: "2.0.0", + version: @version, elixir: "~> 1.0", - description: description(), package: package(), - deps: deps() + deps: deps(), + docs: docs() ] end def application do - [applications: [:crypto, :logger, :plug_crypto]] - end - - defp description do - "Rails compatible Plug session store" + [ + applications: [:crypto, :logger, :plug_crypto] + ] end defp package do [ name: :plug_rails_cookie_session_store, + description: "Rails compatible Plug session store", files: ["lib", "mix.exs", "README*", "LICENSE*"], maintainers: ["Chris Constantin"], licenses: ["MIT"], - links: %{"Github" => "https://github.com/cconstantin/plug_rails_cookie_session_store"} + links: %{ + "GitHub" => @source_url + } ] end @@ -34,7 +38,19 @@ defmodule PlugRailsCookieSessionStore.Mixfile do [ {:plug, ">= 1.11.0"}, {:plug_crypto, ">= 1.2.0"}, - {:ex_doc, ">= 0.24.2", only: :dev} + {:ex_doc, ">= 0.24.2", only: :dev, runtime: false} + ] + end + + defp docs do + [ + extras: [ + "LICENSE.md": [title: "License"], + "README.md": [title: "Overview"] + ], + main: "readme", + source_url: @source_url, + formatters: ["html"] ] end end