diff --git a/.eslintignore b/.eslintignore index 747746059..3728be369 100644 --- a/.eslintignore +++ b/.eslintignore @@ -18,7 +18,11 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -# Build files +# Files generated by build /build /material /site + +# Files generated by visual tests +/gemini-report +/tests/visual/data diff --git a/.githooks/post-merge/npm-update.sh b/.githooks/post-merge/npm-update.sh index 3d5a50b85..cc63394ee 100755 --- a/.githooks/post-merge/npm-update.sh +++ b/.githooks/post-merge/npm-update.sh @@ -25,6 +25,6 @@ CHANGED="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)" # Perform install and prune of NPM dependencies if package.json changed if $(echo "$CHANGED" | grep --quiet package.json); then - echo "Hook[post-merge]: Updating dependencies..." + echo "Hook[post-merge]: Updating dependencies" npm install && npm prune fi diff --git a/.githooks/pre-commit/branch.sh b/.githooks/pre-commit/branch.sh index f38ebcacc..7907e9e43 100755 --- a/.githooks/pre-commit/branch.sh +++ b/.githooks/pre-commit/branch.sh @@ -22,7 +22,7 @@ # Determine current branch BRANCH=$(git rev-parse --abbrev-ref HEAD) -echo "Hook[pre-commit]: Checking branch..." +echo "Hook[pre-commit]: Checking branch" # If we're on master, abort commit if [[ "$BRANCH" == "master" ]]; then diff --git a/.githooks/pre-commit/lint.sh b/.githooks/pre-commit/lint.sh index eeb5688b7..502620ecc 100755 --- a/.githooks/pre-commit/lint.sh +++ b/.githooks/pre-commit/lint.sh @@ -46,6 +46,6 @@ FILES=$(git diff --cached --name-only --diff-filter=ACMR | \ # Run the check and print indicator if [ "$FILES" ]; then - echo "Hook[pre-commit]: Running linter..." + echo "Hook[pre-commit]: Running linter" npm run lint --silent || exit 1 fi diff --git a/.gitignore b/.gitignore index c6cfbd09f..2fd46324f 100644 --- a/.gitignore +++ b/.gitignore @@ -23,14 +23,19 @@ # NPM-related /node_modules -/npm-debug.log +/npm-debug.log* -# Build files +# Files generated by build /build /manifest.json /MANIFEST /site +# Files generated by visual tests +/gemini-report +/tests/visual/baseline/local +/tests/visual/data + # Distribution files /dist /mkdocs_material.egg-info diff --git a/.travis.yml b/.travis.yml index ba3d64433..a5d83512f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,29 @@ node_js: - 6 - 7 +# Build visual tests separately +matrix: + include: + - node_js: 5 + addons: + artifacts: + paths: + - gemini-report + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.8 + - g++-4.8 + env: + - CXX=g++-4.8 + install: yarn install + script: yarn run test:visual:run + +# Limit clone depth to 5, to speed up build +git: + depth: 5 + # Cache dependencies cache: pip: true @@ -34,9 +57,14 @@ cache: directories: - node_modules +# Install yarn as Travis doesn't support it out of the box +before_install: npm install -g yarn + +# Do not install optional dependencies by default +install: yarn install --ignore-optional + # Install dependencies -before_script: - - pip install --user -r requirements.txt +before_script: pip install --user -r requirements.txt # Perform build and tests script: yarn run build diff --git a/Gulpfile.babel.js b/Gulpfile.babel.js index 5fefcc60a..fb3929bd0 100755 --- a/Gulpfile.babel.js +++ b/Gulpfile.babel.js @@ -35,14 +35,17 @@ const config = { src: "src/assets", /* Source directory for assets */ build: "material/assets" /* Target directory for assets */ }, - lib: "lib", /* Libraries */ + lib: "lib", /* Libraries and tasks */ + tests: { + visual: "tests/visual" /* Base directory for visual tests */ + }, views: { src: "src", /* Source directory for views */ build: "material" /* Target directory for views */ } } -const args = yargs +let args = yargs .default("clean", false) /* Clean before build */ .default("karma", true) /* Karma watchdog */ .default("lint", true) /* Lint sources */ @@ -52,6 +55,12 @@ const args = yargs .default("sourcemaps", false) /* Create sourcemaps */ .argv +/* Only use the last value seen, so overrides are possible */ +args = Object.keys(args).reduce((result, arg) => { + result[arg] = [].concat(args[arg]).pop() + return result +}, {}) + /* ---------------------------------------------------------------------------- * Overrides and helpers * ------------------------------------------------------------------------- */ @@ -92,7 +101,10 @@ gulp.src = (...glob) => { * Helper function to load a task */ const load = task => { - return require(`./${config.lib}/tasks/${task}`)(gulp, config, args) + return done => { + return require(`./${config.lib}/tasks/${task}`) + .call(gulp, gulp, config, args)(done) + } } /* ---------------------------------------------------------------------------- @@ -228,12 +240,11 @@ gulp.task("assets:clean", [ * Minify views */ gulp.task("views:build", (args.revision ? [ - "assets:images:build", - "assets:stylesheets:build", - "assets:javascripts:build" + "assets:build" ] : []).concat(args.clean ? [ "views:clean" -] : []), load("views/build")) +] : []), + load("views/build")) /* * Clean views @@ -267,14 +278,45 @@ gulp.task("mkdocs:serve", load("mkdocs/serve")) /* ---------------------------------------------------------------------------- - * Tests + * Visual tests * ------------------------------------------------------------------------- */ /* - * Start karma test runner + * Generate visual tests */ -gulp.task("tests:unit:watch", - load("tests/unit/watch")) +gulp.task("tests:visual:generate", [ +].concat(args.clean ? [ + "tests:visual:clean", + "assets:build", + "views:build" +] : []), + load("tests/visual/generate")) + +/* + * Run visual tests + */ +gulp.task("tests:visual:run", [ + "tests:visual:generate" +], load("tests/visual/run")) + +/* + * Update reference images for visual tests + */ +gulp.task("tests:visual:update", + load("tests/visual/update")) + +/* + * Clean files generated by visual tests + */ +gulp.task("tests:visual:clean", + load("tests/visual/clean")) + +/* + * Open a SauceConnect session for manual testing + */ +gulp.task("tests:visual:session", [ + "tests:visual:generate" +], load("tests/visual/session")) /* ---------------------------------------------------------------------------- * Interface @@ -286,9 +328,9 @@ gulp.task("tests:unit:watch", gulp.task("build", [ "assets:build", "views:build" -].concat(args.mkdocs - ? "mkdocs:build" - : [])) +].concat(args.mkdocs ? [ + "mkdocs:build" +] : [])) /* * Clean assets and documentation diff --git a/lib/.eslintrc b/lib/.eslintrc new file mode 100644 index 000000000..bba4224ca --- /dev/null +++ b/lib/.eslintrc @@ -0,0 +1,6 @@ +{ + "rules": { + "no-invalid-this": 0, + "max-params": 0 + } +} diff --git a/lib/providers/jsx.js b/lib/providers/jsx.js index 371f7c8fe..d34995729 100644 --- a/lib/providers/jsx.js +++ b/lib/providers/jsx.js @@ -21,7 +21,7 @@ */ /* ---------------------------------------------------------------------------- - * Definition + * Module * ------------------------------------------------------------------------- */ export default /* JSX */ { diff --git a/lib/servers/ecstatic.js b/lib/servers/ecstatic.js new file mode 100644 index 000000000..829778729 --- /dev/null +++ b/lib/servers/ecstatic.js @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016-2017 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import ecstatic from "ecstatic" +import * as http from "http" + +/* ---------------------------------------------------------------------------- + * Locals + * ------------------------------------------------------------------------- */ + +/* Static file server */ +let server = null + +/* ---------------------------------------------------------------------------- + * Functions + * ------------------------------------------------------------------------- */ + +/** + * Start static file server + * + * @param {string} directory - Directory to serve + * @param {number} port - Port to listen on + * @param {Function} done - Resolve callback + */ +export const start = (directory, port, done) => { + server = http.createServer(ecstatic({ + root: directory + })) + + /* Listen and register signal handlers */ + server.listen(port, "127.0.0.1", done) + for (const signal of ["SIGTERM", "SIGINT", "exit"]) + process.on(signal, stop) +} + +/** + * Stop static file server + * + * @param {Function} done - Resolve callback + */ +export const stop = done => { + if (server) { + server.close(done) + server = null + } +} diff --git a/lib/servers/sauce-connect.js b/lib/servers/sauce-connect.js new file mode 100644 index 000000000..a6d999d81 --- /dev/null +++ b/lib/servers/sauce-connect.js @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016-2017 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import launcher from "sauce-connect-launcher" + +/* ---------------------------------------------------------------------------- + * Locals + * ------------------------------------------------------------------------- */ + +/* SauceConnect process */ +let server = null + +/* ---------------------------------------------------------------------------- + * Functions + * ------------------------------------------------------------------------- */ + +/** + * Open SauceConnect tunnel + * + * @param {string} id - Unique identifier + * @param {string} username - SauceConnect username + * @param {string} accesskey - SauceConnect accesskey + * @param {Function} done - Resolve callback + */ +export const start = (id, username, accesskey, done) => { + launcher({ + username, + accessKey: accesskey, + tunnelIdentifier: id + }, (err, proc) => { + if (err) + throw new Error(err) + server = proc + done() + }) + + /* Register signal handlers */ + for (const signal of ["SIGTERM", "SIGINT", "exit"]) + process.on(signal, stop) +} + +/** + * Close SauceConnect tunnel + * + * @param {Function} done - Resolve callback + */ +export const stop = done => { + if (server) { + server.close(done) + server = null + } +} diff --git a/lib/tasks/tests/regression/selenium.js b/lib/servers/selenium.js similarity index 74% rename from lib/tasks/tests/regression/selenium.js rename to lib/servers/selenium.js index 8c16f7df3..ebde63212 100644 --- a/lib/tasks/tests/regression/selenium.js +++ b/lib/servers/selenium.js @@ -33,19 +33,33 @@ let server = null * Definition * ------------------------------------------------------------------------- */ +/** + * Start Selenium + * + * @param {Function} done - Resolve callback + */ export const start = done => { selenium.start({}, (err, proc) => { + + /* Register signal handlers */ + for (const signal of ["SIGTERM", "SIGINT", "exit"]) + process.on(signal, stop) if (err) { /* Install selenium, if not present */ if (/^Missing(.*)chromedriver$/.test(err.message)) { - selenium.install(done) - - /* Start selenium again */ - selenium.start({}, (err_, proc_) => { - server = proc_ + new Promise(resolve => { + selenium.install({}, resolve) }) + /* Start selenium again */ + .then(() => { + selenium.start({}, (err_, proc_) => { + server = proc_ + done() + }) + }) + /* Otherwise, throw error */ } else { throw err @@ -53,20 +67,21 @@ export const start = done => { } /* Remember process handle */ - server = server || proc + server = proc done() }) } -export const stop = () => { - if (server) +/** + * Stop Selenium + * + * @param {Function} done - Resolve callback + */ +export const stop = done => { + if (server) { + if (typeof done === "function") + server.on("exit", done) server.kill() + server = null + } } - -/* ---------------------------------------------------------------------------- - * Signal handler - * ------------------------------------------------------------------------- */ - -/* Register signal handler for all relevant events */ -for (const signal of ["SIGTERM", "SIGINT", "exit"]) - process.on(signal, stop) diff --git a/lib/tasks/.eslintrc b/lib/tasks/.eslintrc deleted file mode 100644 index 709b01107..000000000 --- a/lib/tasks/.eslintrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "no-invalid-this": 0 - } -} diff --git a/lib/tasks/assets/javascripts/build/application.js b/lib/tasks/assets/javascripts/build/application.js index a697c83a1..486a1ef66 100644 --- a/lib/tasks/assets/javascripts/build/application.js +++ b/lib/tasks/assets/javascripts/build/application.js @@ -101,7 +101,7 @@ export default (gulp, config, args) => { }, /* Sourcemap support */ - devtool: args.sourcemaps ? "source-map" : "" + devtool: args.sourcemaps ? "inline-source-map" : "" })) /* Revisioning */ diff --git a/lib/tasks/assets/javascripts/lint.js b/lib/tasks/assets/javascripts/lint.js index ffcd5a06b..f71250ecb 100644 --- a/lib/tasks/assets/javascripts/lint.js +++ b/lib/tasks/assets/javascripts/lint.js @@ -23,6 +23,7 @@ import path from "path" import through from "through2" import util from "gulp-util" + import { CLIEngine } from "eslint" /* ---------------------------------------------------------------------------- diff --git a/lib/tasks/assets/stylesheets/build.js b/lib/tasks/assets/stylesheets/build.js index 2f78f1843..10ac045bc 100644 --- a/lib/tasks/assets/stylesheets/build.js +++ b/lib/tasks/assets/stylesheets/build.js @@ -25,6 +25,7 @@ import gulpif from "gulp-if" import mincss from "gulp-cssnano" import mqpacker from "css-mqpacker" import postcss from "gulp-postcss" +import pseudoclasses from "postcss-pseudo-classes" import rev from "gulp-rev" import sass from "gulp-sass" import sourcemaps from "gulp-sourcemaps" @@ -54,7 +55,11 @@ export default (gulp, config, args) => { postcss([ autoprefixer(), mqpacker - ])) + ].concat(!args.optimize ? [ + pseudoclasses({ + "restrictTo": ["hover", "focus"] + }) + ] : []))) /* Minify sources */ .pipe(gulpif(args.optimize, mincss())) @@ -63,7 +68,7 @@ export default (gulp, config, args) => { .pipe(gulpif(args.revision, rev())) .pipe(gulpif(args.revision, version({ manifest: gulp.src("manifest.json") }))) - .pipe(gulpif(args.sourcemaps, sourcemaps.write("."))) + .pipe(gulpif(args.sourcemaps, sourcemaps.write())) .pipe(gulp.dest(`${config.assets.build}/stylesheets`)) .pipe(gulpif(args.revision, rev.manifest("manifest.json", { diff --git a/lib/tasks/mkdocs/serve.js b/lib/tasks/mkdocs/serve.js index 102c2c8b9..14ace0aad 100644 --- a/lib/tasks/mkdocs/serve.js +++ b/lib/tasks/mkdocs/serve.js @@ -39,7 +39,7 @@ export default () => { server.kill() /* Spawn MkDocs server */ - server = child.spawn("mkdocs", ["serve", "-a", "0.0.0.0:8000"], { + server = child.spawn("mkdocs", ["serve", "--dev-addr", "0.0.0.0:8000"], { stdio: "inherit" }) } diff --git a/lib/tasks/tests/visual/clean.js b/lib/tasks/tests/visual/clean.js new file mode 100644 index 000000000..238d548ab --- /dev/null +++ b/lib/tasks/tests/visual/clean.js @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016-2017 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import clean from "del" +import vinyl from "vinyl-paths" + +/* ---------------------------------------------------------------------------- + * Task: clean files generated by visual tests + * ------------------------------------------------------------------------- */ + +export default (gulp, config) => { + return () => { + return gulp.src([ + `${config.tests.visual}/data`, + "./gemini-report" + ]) + .pipe(vinyl(clean)) + } +} diff --git a/lib/tasks/tests/visual/generate.js b/lib/tasks/tests/visual/generate.js new file mode 100644 index 000000000..4f3031c0d --- /dev/null +++ b/lib/tasks/tests/visual/generate.js @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016-2017 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import child from "child_process" +import path from "path" +import through from "through2" +import util from "gulp-util" + +/* ---------------------------------------------------------------------------- + * Task: generate visual tests + * ------------------------------------------------------------------------- */ + +export default (gulp, config) => { + const theme = path.resolve(process.cwd(), config.views.build) + return () => { + return gulp.src(`${config.tests.visual}/suites/**/mkdocs.yml`) + .pipe( + through.obj(function(file, enc, done) { + if (file.isNull() || file.isStream()) + return done() + + /* Resolve test name and destination */ + const name = path.relative(`${config.tests.visual}/suites`, + path.dirname(file.path)) + const site = path.resolve(process.cwd(), + `${config.tests.visual}/data`, name, "_") + + /* Generate test fixtures with freshly built theme */ + const proc = child.spawnSync("mkdocs", [ + "build", "--site-dir", site, "--theme-dir", theme + ], { + cwd: path.dirname(file.path) + }) + + /* Emit error, if any */ + if (proc.status) + this.emit("error", new util.PluginError("mkdocs", + `Terminated with errors: ${proc.stderr.toString()}`)) + + /* Terminate */ + done() + })) + } +} diff --git a/lib/tasks/tests/visual/run.js b/lib/tasks/tests/visual/run.js new file mode 100644 index 000000000..44573a635 --- /dev/null +++ b/lib/tasks/tests/visual/run.js @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016-2017 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import moniker from "moniker" +import path from "path" +import * as ecstatic from "~/lib/servers/ecstatic" +import * as sauce from "~/lib/servers/sauce-connect" +import * as selenium from "~/lib/servers/selenium" + +import Gemini from "gemini" + +/* ---------------------------------------------------------------------------- + * Task: run visual tests + * ------------------------------------------------------------------------- */ + +export default (gulp, config, args) => { + const id = process.env.TRAVIS + ? `Travis #${process.env.TRAVIS_BUILD_NUMBER}` + : `Local #${moniker.choose()}` + return done => { + + /* Start static file server */ + let error = false + new Promise(resolve => { + ecstatic.start(`${config.tests.visual}/data`, 8000, resolve) + + /* Create and start test runner */ + }).then(() => { + return new Promise((resolve, reject) => { + + /* Start SauceConnect tunnel */ + if (process.env.CI || process.env.SAUCE) { + if (!process.env.SAUCE_USERNAME || + !process.env.SAUCE_ACCESS_KEY) + throw new Error( + "SauceConnect: please provide SAUCE_USERNAME " + + "and SAUCE_ACCESS_KEY") + + /* Start tunnel, if credentials are given */ + sauce.start( + id, + process.env.SAUCE_USERNAME, + process.env.SAUCE_ACCESS_KEY, + err => { + return err ? reject(err) : resolve(sauce) + }) + + /* Start Selenium */ + } else { + selenium.start(() => resolve(selenium)) + } + }) + + /* Setup and run Gemini */ + .then(runner => { + const gemini = require( + path.join(process.cwd(), `${config.tests.visual}/config`, + process.env.CI || process.env.SAUCE + ? "gemini.sauce-connect.json" + : "gemini.selenium.json")) + + /* Add dynamic configuration to capabilities */ + for (const key of Object.keys(gemini.browsers)) { + const caps = gemini.browsers[key].desiredCapabilities + caps.tunnelIdentifier = id + caps.public = "private" + caps.name = id + + /* Adjust configuration for Travis CI */ + if (process.env.CI && process.env.TRAVIS) + caps.public = "public" + } + + /* Start Gemini and return runner upon finish */ + return new Gemini(gemini).test(`${config.tests.visual}/suites`, { + reporters: ["flat", "html"], + browsers: args.browsers ? [].concat(args.browsers) : null + }) + + /* Return runner for graceful stop */ + .then(status => { + error = status.failed + status.errored > 0 + return runner + }) + }) + + /* Stop test runner */ + .then(runner => { + return new Promise(resolve => { + runner.stop(resolve) + }) + }) + + /* Stop static file server */ + }) + .then(() => { + ecstatic.stop(() => { + return error + ? done(new Error("Gemini terminated with errors")) + : done() + }) + }, err => { + return done(new Error(err)) + }) + } +} diff --git a/lib/tasks/tests/visual/session.js b/lib/tasks/tests/visual/session.js new file mode 100644 index 000000000..f8dcf4e96 --- /dev/null +++ b/lib/tasks/tests/visual/session.js @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016-2017 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import moniker from "moniker" +import * as ecstatic from "~/lib/servers/ecstatic" +import * as sauce from "~/lib/servers/sauce-connect" + +/* ---------------------------------------------------------------------------- + * Task: run visual tests + * ------------------------------------------------------------------------- */ + +export default (gulp, config) => { + return done => { + + /* Start static file server */ + new Promise(resolve => { + ecstatic.start(`${config.tests.visual}/data`, 8000, resolve) + + /* Open SauceConnect tunnel */ + }).then(() => { + return new Promise((resolve, reject) => { + if (!process.env.SAUCE_USERNAME || + !process.env.SAUCE_ACCESS_KEY) + throw new Error( + "SauceConnect: please provide SAUCE_USERNAME " + + "and SAUCE_ACCESS_KEY") + + /* Open tunnel */ + sauce.start( + `Local #${moniker.choose()}`, + process.env.SAUCE_USERNAME, + process.env.SAUCE_ACCESS_KEY, + err => { + return err ? reject(err) : resolve(sauce) + }) + }) + + /* Close tunnel on CTRL-C */ + .then(() => { + return new Promise(resolve => { + process.on("SIGINT", () => { + sauce.stop(resolve) + }) + }) + }) + + /* Stop static file server */ + }) + .then(() => { + ecstatic.stop(done) + }, err => { + return done(err) + }) + } +} diff --git a/lib/tasks/tests/visual/update.js b/lib/tasks/tests/visual/update.js new file mode 100644 index 000000000..ec5a4cc1a --- /dev/null +++ b/lib/tasks/tests/visual/update.js @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016-2017 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import fs from "fs" +import path from "path" +import through from "through2" + +/* ---------------------------------------------------------------------------- + * Task: update reference images for visual tests + * ------------------------------------------------------------------------- */ + +export default (gulp, config) => { + return () => { + const base = path.join( + process.cwd(), `${config.tests.visual}/config`) + + /* Read Gemini configs and map browsers to screenshot directories */ + const mapping = fs.readdirSync(base) + .reduce((result, filename) => { + return Object.assign(result, (gemini => { + return Object.keys(gemini.browsers) + .reduce((browsers, name) => { + browsers[name] = gemini.screenshotsDir + return browsers + }, {}) + })(require(path.join(base, filename)))) + }, {}) + + /* Prepare filenames */ + const dest = path.join(process.cwd(), `${config.tests.visual}/baseline`) + return gulp.src("gemini-report/images/**/*~current.png") + .pipe( + through.obj(function(file, enc, done) { + if (file.isNull() || file.isStream()) + return done() + + /* Remove the state from the filename */ + file.path = file.path.replace("~current", "") + + /* Retrieve the folder for the environment of the baseline */ + const folder = path.relative(dest, + mapping[path.basename(file.path, ".png")]) + file.path = file.path.replace("images", `images/${folder}`) + + /* Push file to next stage */ + this.push(file) + done() + })) + + /* Update reference images */ + .pipe(gulp.dest(dest)) + } +} diff --git a/material/assets/javascripts/modernizr-5b0c41c2b5.js b/material/assets/javascripts/modernizr-5b0c41c2b5.js new file mode 100644 index 000000000..9bf1df9fe --- /dev/null +++ b/material/assets/javascripts/modernizr-5b0c41c2b5.js @@ -0,0 +1 @@ +!function(e,n,t){function r(e,n){return typeof e===n}function o(){var e,n,t,o,s,i,f;for(var a in w)if(w.hasOwnProperty(a)){if(e=[],n=w[a],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;t=9,r=t<533&&e.match(/android/gi);return n||r||s}();E?_.addTest("fontface",!1):z('@font-face {font-family:"font";src:url("https://")}',function(e,n){var s=t.getElementById("smodernizr"),r=s.sheet||s.styleSheet,o=r?r.cssRules&&r.cssRules[0]?r.cssRules[0].cssText:r.cssText||"":"",i=/src/i.test(o)&&0===o.indexOf(n.split(" ")[0]);_.addTest("fontface",i)});var j="Moz O ms Webkit",k=x._config.usePrefixes?j.split(" "):[];x._cssomPrefixes=k;var N={elem:a("modernizr")};_._q.push(function(){delete N.elem});var A={style:N.elem.style};_._q.unshift(function(){delete A.style});var R=x._config.usePrefixes?j.toLowerCase().split(" "):[];x._domPrefixes=R,x.testAllProps=v,x.testAllProps=y;var q="CSS"in e&&"supports"in e.CSS,L="supportsCSS"in e;_.addTest("supports",q||L),_.addTest("csstransforms3d",function(){var e=!!y("perspective","1px",!0),t=_._config.usePrefixes;if(e&&(!t||"webkitPerspective"in b.style)){var n,s="#modernizr{width:0;height:0}";_.supports?n="@supports (perspective: 1px)":(n="@media (transform-3d)",t&&(n+=",(-webkit-transform-3d)")),n+="{#modernizr{width:7px;height:18px;margin:0;padding:0;border:0}}",z(s+n,function(t){e=7===t.offsetWidth&&18===t.offsetHeight})}return e}),r(),o(S),delete x.addTest,delete x.addAsyncTest;for(var O=0;O<_._q.length;O++)_._q[O]();e.Modernizr=_}(window,document); \ No newline at end of file diff --git a/material/assets/stylesheets/application-bc099a55ca.css b/material/assets/stylesheets/application-bc099a55ca.css deleted file mode 100644 index 9eb7ec3c9..000000000 --- a/material/assets/stylesheets/application-bc099a55ca.css +++ /dev/null @@ -1 +0,0 @@ -html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}html{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none}body{margin:0}hr{overflow:visible;box-sizing:content-box}a{-webkit-text-decoration-skip:objects}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}a:active,a:hover{outline-width:0}small,sub,sup{font-size:80%}sub,sup{position:relative;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}table{border-collapse:collapse;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{padding:0;background:transparent;font-size:inherit}button,input{border:0;outline:0}.admonition:before,.md-icon,.md-nav__button,.md-nav__link:after,.md-nav__title:before,.md-typeset .critic.comment:before,.md-typeset .footnote-backref,.md-typeset .task-list-control .task-list-indicator:before{font-family:Material Icons;font-style:normal;font-variant:normal;font-weight:400;line-height:1;text-transform:none;white-space:nowrap;speak:none;word-wrap:normal;direction:ltr}.md-content__edit,.md-footer-nav__button,.md-header-nav__button,.md-nav__button,.md-nav__title:before{display:inline-block;margin:.4rem;padding:.8rem;font-size:2.4rem;cursor:pointer}.md-icon--arrow-back:before{content:"arrow_back"}.md-icon--arrow-forward:before{content:"arrow_forward"}.md-icon--menu:before{content:"menu"}.md-icon--search:before{content:"search"}.md-icon--home:before{content:"school"}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body,input{color:rgba(0,0,0,.87);-webkit-font-feature-settings:"kern","onum","liga";font-feature-settings:"kern","onum","liga";font-weight:400}.no-fontface body,.no-fontface input{font-family:Helvetica Neue,Helvetica,Arial,sans-serif}code,kbd,pre{color:rgba(0,0,0,.87);-webkit-font-feature-settings:"kern","onum","liga";font-feature-settings:"kern","onum","liga";font-weight:400}.no-fontface code,.no-fontface kbd,.no-fontface pre{font-family:Courier New,Courier,monospace}.md-typeset{font-size:1.6rem;line-height:1.6;-webkit-print-color-adjust:exact}.md-typeset blockquote,.md-typeset ol,.md-typeset p,.md-typeset ul{margin:1em 0}.md-typeset h1{margin:0 0 4rem;color:rgba(0,0,0,.54);font-size:3.125rem;line-height:1.3}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{margin:4rem 0 1.6rem;font-size:2.5rem;line-height:1.4}.md-typeset h3{margin:3.2rem 0 1.6rem;font-size:2rem;font-weight:400;letter-spacing:-.01em;line-height:1.5}.md-typeset h2+h3{margin-top:1.6rem}.md-typeset h4{font-size:1.6rem}.md-typeset h4,.md-typeset h5,.md-typeset h6{margin:1.6rem 0;font-weight:700;letter-spacing:-.01em}.md-typeset h5,.md-typeset h6{color:rgba(0,0,0,.54);font-size:1.28rem}.md-typeset h5{text-transform:uppercase}.md-typeset hr{margin:1.5em 0;border-bottom:.1rem dotted rgba(0,0,0,.26)}.md-typeset a{color:#3f51b5;word-break:break-word}.md-typeset a,.md-typeset a:before{-webkit-transition:color .125s;transition:color .125s}.md-typeset a:active,.md-typeset a:hover{color:#536dfe}.md-typeset code,.md-typeset pre{background-color:hsla(0,0%,93%,.5);color:#37474f;font-size:85%}.md-typeset code{margin:0 .29412em;padding:.07353em 0;border-radius:.2rem;box-shadow:.29412em 0 0 hsla(0,0%,93%,.5),-.29412em 0 0 hsla(0,0%,93%,.5);word-break:break-word;-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset h1 code,.md-typeset h2 code,.md-typeset h3 code,.md-typeset h4 code,.md-typeset h5 code,.md-typeset h6 code{margin:0;background-color:transparent;box-shadow:none}.md-typeset a>code{margin:inherit;padding:inherit;border-radius:none;background-color:inherit;color:inherit;box-shadow:none}.md-typeset pre{margin:1em 0;padding:1rem 1.2rem;border-radius:.2rem;line-height:1.4;overflow:auto;-webkit-overflow-scrolling:touch}.md-typeset pre::-webkit-scrollbar{width:.4rem;height:.4rem}.md-typeset pre::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-typeset pre::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-typeset pre>code{margin:0;background-color:transparent;font-size:inherit;box-shadow:none;-webkit-box-decoration-break:none;box-decoration-break:none}.md-typeset kbd{padding:0 .29412em;border:.1rem solid #c9c9c9;border-radius:.2rem;border-bottom-color:#bcbcbc;background-color:#fcfcfc;color:#555;font-size:85%;box-shadow:0 .1rem 0 #b0b0b0;word-break:break-word}.md-typeset mark{margin:0 .25em;padding:.0625em 0;border-radius:.2rem;background-color:rgba(255,235,59,.5);box-shadow:.25em 0 0 rgba(255,235,59,.5),-.25em 0 0 rgba(255,235,59,.5);word-break:break-word;-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset abbr{border-bottom:.1rem dotted rgba(0,0,0,.54);cursor:help}.md-typeset small{opacity:.75}.md-typeset sub,.md-typeset sup{margin-left:.07812em}.md-typeset blockquote{padding-left:1.2rem;border-left:.4rem solid rgba(0,0,0,.26);color:rgba(0,0,0,.54)}.md-typeset ul{list-style-type:disc}.md-typeset ol,.md-typeset ul{margin-left:.625em;padding:0}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em;margin-left:1.25em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin:.5em 0 .5em .625em}.md-typeset iframe,.md-typeset img,.md-typeset svg{max-width:100%}.md-typeset table:not([class]){box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2);margin:2em 0;border-radius:.2rem;font-size:1.28rem;overflow:hidden}.no-js .md-typeset table:not([class]){display:inline-block;max-width:100%;margin:.8em 0;overflow:auto;-webkit-overflow-scrolling:touch}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}.md-typeset table:not([class]) th{min-width:10rem;padding:1.2rem 1.6rem;background-color:rgba(0,0,0,.54);color:#fff;vertical-align:top}.md-typeset table:not([class]) td{padding:1.2rem 1.6rem;border-top:.1rem solid rgba(0,0,0,.07);vertical-align:top}.md-typeset table:not([class]) tr:first-child td{border-top:0}.md-typeset table:not([class]) a{word-break:normal}.md-typeset .md-typeset__table{margin:1.6em -1.6rem;overflow-x:auto;-webkit-overflow-scrolling:touch}.md-typeset .md-typeset__table table{display:inline-block;margin:0 1.6rem}html{font-size:62.5%}body,html{height:100%}body{position:relative}hr{display:block;height:.1rem;padding:0;border:0}.md-svg{display:none}.md-grid{max-width:122rem;margin-right:auto;margin-left:auto}.md-container,.md-main{overflow:auto}.md-container{display:table;width:100%;height:100%;table-layout:fixed}.md-main{display:table-row;height:100%}.md-main__inner{margin-top:5.6rem;padding-top:3rem;overflow:auto}.csscalc .md-main__inner{min-height:calc(100% - 2.6rem)}@-moz-document url-prefix(){.csscalc .md-main__inner{min-height:calc(100% - 5.6rem)}}.md-toggle{display:none}.md-overlay{position:fixed;top:0;width:0;height:0;-webkit-transition:width 0s .25s,height 0s .25s,opacity .25s;transition:width 0s .25s,height 0s .25s,opacity .25s;background-color:rgba(0,0,0,.54);opacity:0;z-index:2}.md-flex{display:table}.md-flex__cell{display:table-cell;position:relative;vertical-align:top}.md-flex__cell--shrink{width:0}.md-flex__cell--stretch{display:table;width:100%;table-layout:fixed}.md-flex__ellipsis{display:table-cell;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}@page{margin:25mm}.md-content__inner{margin:2.4rem 1.6rem}.md-content__edit{float:right}.md-header{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2);position:fixed;top:0;right:0;left:0;height:5.6rem;-webkit-transition:background-color .25s;transition:background-color .25s;background-color:#3f51b5;color:#fff;z-index:1}.md-header-nav{padding:.4rem}.md-header-nav__button{position:relative;-webkit-transition:opacity .25s;transition:opacity .25s;z-index:1}.md-header-nav__button:hover{opacity:.7}.md-header-nav__button.md-logo img{display:block}.no-js .md-header-nav__button.md-icon--search{display:none}.md-header-nav__title{padding:0 2rem;font-size:1.8rem;line-height:4.8rem}.md-header-nav__parent{color:hsla(0,0%,100%,.7)}.md-header-nav__parent:after{display:inline;color:hsla(0,0%,100%,.3);content:"/"}.md-header-nav__source{display:none}.md-footer-nav{background-color:rgba(0,0,0,.87);color:#fff}.md-footer-nav__inner{padding:.4rem;overflow:auto}.md-footer-nav__link{padding-top:2.8rem;padding-bottom:.8rem;-webkit-transition:opacity .25s;transition:opacity .25s}.md-footer-nav__link:hover{opacity:.7}.md-footer-nav__link--prev{width:25%;float:left}.md-footer-nav__link--next{width:75%;float:right;text-align:right}.md-footer-nav__button{-webkit-transition:background .25s;transition:background .25s}.md-footer-nav__title{position:relative;padding:0 2rem;font-size:1.8rem;line-height:4.8rem}.md-footer-nav__direction{position:absolute;right:0;left:0;margin-top:-2rem;padding:0 2rem;color:hsla(0,0%,100%,.7);font-size:1.5rem}.md-footer-meta{background:rgba(0,0,0,.895)}.md-footer-meta__inner{padding:.4rem;overflow:auto}html .md-footer-meta.md-typeset a{color:hsla(0,0%,100%,.7)}.md-footer-copyright{margin:0 1.2rem;padding:.8rem 0;color:hsla(0,0%,100%,.3);font-size:1.28rem}.md-footer-copyright__highlight{color:hsla(0,0%,100%,.7)}.md-footer-social{margin:0 .8rem;padding:.4rem 0 1.2rem}.md-footer-social__link{display:inline-block;width:3.2rem;height:3.2rem;border:.1rem solid hsla(0,0%,100%,.12);border-radius:100%;color:hsla(0,0%,100%,.7);font-size:1.6rem;text-align:center}.md-footer-social__link:before{line-height:1.9}.md-nav{font-size:1.4rem;line-height:1.3}.md-nav--secondary{-webkit-transition:border-left .25s;transition:border-left .25s;border-left:.4rem solid #3f51b5}.md-nav__title{display:block;padding:1.2rem 1.2rem 0;font-weight:700;text-overflow:ellipsis;overflow:hidden}.md-nav__title:before{display:none;content:"arrow_back"}.md-nav__title .md-nav__button{display:none}.md-nav__list{margin:0;padding:0;list-style:none}.md-nav__item{padding:.625em 1.2rem 0}.md-nav__item:last-child{padding-bottom:1.2rem}.md-nav__item .md-nav__item{padding-right:0}.md-nav__item .md-nav__item:last-child{padding-bottom:0}.md-nav__button img{width:100%;height:auto}.md-nav__link{display:block;-webkit-transition:color .125s;transition:color .125s;text-overflow:ellipsis;cursor:pointer;overflow:hidden}.md-nav__item--nested>.md-nav__link:after{content:"keyboard_arrow_down"}html .md-nav__link[for=toc],html .md-nav__link[for=toc]+.md-nav__link:after,html .md-nav__link[for=toc]~.md-nav{display:none}.md-nav__link[data-md-state=blur]{color:rgba(0,0,0,.54)}.md-nav__link--active,.md-nav__link:active{color:#3f51b5}.md-nav__link:hover{color:#536dfe}.md-nav__source,.no-js .md-search{display:none}.md-search__overlay{display:none;pointer-events:none}.md-search__inner{width:100%}.md-search__form{position:relative}.md-search__input{position:relative;padding:0 1.6rem 0 7.2rem;text-overflow:ellipsis;z-index:1}.md-search__input+.md-search__icon,.md-search__input::-webkit-input-placeholder{color:rgba(0,0,0,.54)}.md-search__input+.md-search__icon,.md-search__input::-moz-placeholder{color:rgba(0,0,0,.54)}.md-search__input+.md-search__icon,.md-search__input:-ms-input-placeholder{color:rgba(0,0,0,.54)}.md-search__input+.md-search__icon,.md-search__input::placeholder{color:rgba(0,0,0,.54)}.md-search__input::-ms-clear{display:none}.md-search__icon{position:absolute;top:.8rem;left:1.2rem;-webkit-transition:color .25s;transition:color .25s;font-size:2.4rem;cursor:pointer;z-index:1}.md-search__icon:before{content:"search"}.md-search__output{position:absolute;width:100%;border-radius:0 0 .2rem .2rem;overflow:hidden}.md-search__scrollwrap{height:100%;background:-webkit-linear-gradient(top,#fff 10%,hsla(0,0%,100%,0)),-webkit-linear-gradient(top,rgba(0,0,0,.26),rgba(0,0,0,.07) 35%,transparent 60%);background:linear-gradient(180deg,#fff 10%,hsla(0,0%,100%,0)),linear-gradient(180deg,rgba(0,0,0,.26),rgba(0,0,0,.07) 35%,transparent 60%);background-attachment:local,scroll;background-color:#fff;background-repeat:no-repeat;background-size:100% 2rem,100% 1rem;box-shadow:inset 0 .1rem 0 rgba(0,0,0,.07);overflow-y:auto;-webkit-overflow-scrolling:touch}.md-search-result__meta{padding:0 1.6rem;background-color:rgba(0,0,0,.07);color:rgba(0,0,0,.54);font-size:1.28rem;line-height:4rem}.md-search-result__list{margin:0;padding:0;border-top:.1rem solid rgba(0,0,0,.07);list-style:none}.md-search-result__item{box-shadow:0 -.1rem 0 rgba(0,0,0,.07)}.md-search-result__link{display:block;padding:0 1.6rem;-webkit-transition:background .25s;transition:background .25s;overflow:auto}.md-search-result__link:hover{background-color:rgba(83,109,254,.1)}.md-search-result__article{margin:1em 0}.md-search-result__title{margin-top:.5em;margin-bottom:0;color:rgba(0,0,0,.87);font-size:1.6rem;font-weight:400;line-height:1.4}.md-search-result__teaser{margin:.5em 0;color:rgba(0,0,0,.54);font-size:1.28rem;line-height:1.4;word-break:break-word}.md-sidebar{position:relative;width:24.2rem;padding:2.4rem 0;float:left;overflow:visible}.md-sidebar[data-md-state=lock]{position:fixed;top:5.6rem;-webkit-backface-visibility:hidden;backface-visibility:hidden}.md-sidebar--secondary{display:none}.md-sidebar__scrollwrap{max-height:100%;margin:0 .4rem;overflow-y:auto}.md-sidebar__scrollwrap::-webkit-scrollbar{width:.4rem;height:.4rem}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#536dfe}@-webkit-keyframes a{0%{height:0}to{height:1.3rem}}@keyframes a{0%{height:0}to{height:1.3rem}}@-webkit-keyframes b{0%{-webkit-transform:translateY(100%);transform:translateY(100%);opacity:0}50%{opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes b{0%{-webkit-transform:translateY(100%);transform:translateY(100%);opacity:0}50%{opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}.md-source{display:block;-webkit-transition:opacity .25s;transition:opacity .25s;font-size:1.3rem;line-height:1.2;white-space:nowrap}.md-source:hover{opacity:.7}.md-source:after,.md-source__icon{display:inline-block;height:4.8rem;content:"";vertical-align:middle}.md-source__icon{width:4.8rem}.md-source__icon svg{margin-top:1.2rem;margin-left:1.2rem}.md-source__icon+.md-source__repository{margin-left:-4.4rem;padding-left:4rem}.md-source__repository{display:inline-block;max-width:100%;margin-left:1.2rem;font-weight:700;text-overflow:ellipsis;overflow:hidden;vertical-align:middle}.md-source__facts{margin:0;padding:0;font-size:1.1rem;font-weight:700;list-style-type:none;opacity:.75;overflow:hidden}[data-md-state=done] .md-source__facts{-webkit-animation:a .25s ease-in;animation:a .25s ease-in}.md-source__fact{float:left}[data-md-state=done] .md-source__fact{-webkit-animation:b .4s ease-out;animation:b .4s ease-out}.md-source__fact:before{margin:0 .2rem;content:"\00B7"}.md-source__fact:first-child:before{display:none}.admonition{position:relative;margin:1.5625em 0;padding:.8rem 1.2rem;border-left:3.2rem solid rgba(68,138,255,.4);border-radius:.2rem;background-color:rgba(68,138,255,.15);font-size:1.28rem}.admonition:before{position:absolute;left:-2.6rem;color:#fff;font-size:2rem;content:"edit";vertical-align:-.25em}.admonition :first-child{margin-top:0}.admonition :last-child{margin-bottom:0}.admonition.summary,.admonition.tldr{border-color:rgba(0,176,255,.4);background-color:rgba(0,176,255,.15)}.admonition.summary:before,.admonition.tldr:before{content:"subject"}.admonition.hint,.admonition.important,.admonition.tip{border-color:rgba(0,191,165,.4);background-color:rgba(0,191,165,.15)}.admonition.hint:before,.admonition.important:before,.admonition.tip:before{content:"whatshot"}.admonition.check,.admonition.done,.admonition.success{border-color:rgba(0,230,118,.4);background-color:rgba(0,230,118,.15)}.admonition.check:before,.admonition.done:before,.admonition.success:before{content:"done"}.admonition.attention,.admonition.caution,.admonition.warning{border-color:rgba(255,145,0,.4);background-color:rgba(255,145,0,.15)}.admonition.attention:before,.admonition.caution:before,.admonition.warning:before{content:"warning"}.admonition.fail,.admonition.failure,.admonition.missing{border-color:rgba(255,82,82,.4);background-color:rgba(255,82,82,.15)}.admonition.fail:before,.admonition.failure:before,.admonition.missing:before{content:"clear"}.admonition.danger,.admonition.error{border-color:rgba(255,23,68,.4);background-color:rgba(255,23,68,.15)}.admonition.danger:before,.admonition.error:before{content:"flash_on"}.admonition.bug{border-color:rgba(245,0,87,.4);background-color:rgba(245,0,87,.15)}.admonition.bug:before{content:"bug_report"}.admonition-title{font-weight:700}html .admonition-title{margin-bottom:0}html .admonition-title+*{margin-top:0}.codehilite .o,.codehilite .ow{color:inherit}.codehilite .ge{color:#000}.codehilite .gr{color:#a00}.codehilite .gh{color:#999}.codehilite .go{color:#888}.codehilite .gp{color:#555}.codehilite .gs{color:inherit}.codehilite .gu{color:#aaa}.codehilite .gt{color:#a00}.codehilite .gd{background-color:#fdd}.codehilite .gi{background-color:#dfd}.codehilite .k{color:#3b78e7}.codehilite .kc{color:#a71d5d}.codehilite .kd,.codehilite .kn{color:#3b78e7}.codehilite .kp{color:#a71d5d}.codehilite .kr,.codehilite .kt{color:#3e61a2}.codehilite .c,.codehilite .cm{color:#999}.codehilite .cp{color:#666}.codehilite .c1,.codehilite .ch,.codehilite .cs{color:#999}.codehilite .na,.codehilite .nb{color:#c2185b}.codehilite .bp{color:#3e61a2}.codehilite .nc{color:#c2185b}.codehilite .no{color:#3e61a2}.codehilite .nd,.codehilite .ni{color:#666}.codehilite .ne,.codehilite .nf{color:#c2185b}.codehilite .nl{color:#3b5179}.codehilite .nn{color:#ec407a}.codehilite .nt{color:#3b78e7}.codehilite .nv,.codehilite .vc,.codehilite .vg,.codehilite .vi{color:#3e61a2}.codehilite .nx{color:#ec407a}.codehilite .il,.codehilite .m,.codehilite .mf,.codehilite .mh,.codehilite .mi,.codehilite .mo{color:#e74c3c}.codehilite .s,.codehilite .sb,.codehilite .sc{color:#0d904f}.codehilite .sd{color:#999}.codehilite .s2{color:#0d904f}.codehilite .se,.codehilite .sh,.codehilite .si,.codehilite .sx{color:#183691}.codehilite .sr{color:#009926}.codehilite .s1,.codehilite .ss{color:#0d904f}.codehilite .err{color:#a61717}.codehilite .w{color:transparent}.codehilite .hll{display:block;margin:0 -1.2rem;padding:0 1.2rem;background-color:rgba(255,235,59,.5)}.md-typeset .codehilite{margin:1em 0;padding:1rem 1.2rem .8rem;border-radius:.2rem;background-color:hsla(0,0%,93%,.5);color:#37474f;line-height:1.4;overflow:auto;-webkit-overflow-scrolling:touch}.md-typeset .codehilite::-webkit-scrollbar{width:.4rem;height:.4rem}.md-typeset .codehilite::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-typeset .codehilite::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-typeset .codehilite pre{display:inline-block;min-width:100%;margin:0;padding:0;background-color:transparent;overflow:visible;vertical-align:top}.md-typeset .codehilitetable{display:block;margin:1em 0;border-radius:.2em;font-size:1.6rem;overflow:hidden}.md-typeset .codehilitetable tbody,.md-typeset .codehilitetable td{display:block;padding:0}.md-typeset .codehilitetable tr{display:-webkit-box;display:-ms-flexbox;display:flex}.md-typeset .codehilitetable .codehilite,.md-typeset .codehilitetable .linenodiv{margin:0;border-radius:0}.md-typeset .codehilitetable .linenodiv{padding:1rem 1.2rem .8rem}.md-typeset .codehilitetable .linenodiv,.md-typeset .codehilitetable .linenodiv>pre{height:100%}.md-typeset .codehilitetable .linenos{background-color:rgba(0,0,0,.07);color:rgba(0,0,0,.26);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.md-typeset .codehilitetable .linenos pre{margin:0;padding:0;background-color:transparent;color:inherit;text-align:right}.md-typeset .codehilitetable .code{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:hidden}.md-typeset>.codehilitetable{box-shadow:none}.md-typeset .footnote{color:rgba(0,0,0,.54);font-size:1.28rem}.md-typeset .footnote ol{margin-left:0}.md-typeset .footnote li{-webkit-transition:color .25s;transition:color .25s}.md-typeset .footnote li:before{display:block;height:0}.md-typeset .footnote li:target{color:rgba(0,0,0,.87)}.md-typeset .footnote li:target:before{margin-top:-9rem;padding-top:9rem;pointer-events:none}.md-typeset .footnote li :first-child{margin-top:0}.md-typeset .footnote li:hover .footnote-backref,.md-typeset .footnote li:target .footnote-backref{-webkit-transform:translateX(0);transform:translateX(0);opacity:1}.md-typeset .footnote li:hover .footnote-backref:hover,.md-typeset .footnote li:target .footnote-backref{color:#536dfe}.md-typeset .footnote-backref{display:inline-block;-webkit-transform:translateX(.5rem);transform:translateX(.5rem);-webkit-transition:color .25s,opacity .125s .125s,-webkit-transform .25s .125s;transition:color .25s,opacity .125s .125s,-webkit-transform .25s .125s;transition:transform .25s .125s,color .25s,opacity .125s .125s;transition:transform .25s .125s,color .25s,opacity .125s .125s,-webkit-transform .25s .125s;color:rgba(0,0,0,.26);font-size:0;opacity:0;vertical-align:text-bottom}.md-typeset .footnote-backref:before{font-size:1.6rem;content:"keyboard_return"}.md-typeset .headerlink{display:inline-block;margin-left:1rem;-webkit-transform:translateY(.5rem);transform:translateY(.5rem);-webkit-transition:color .25s,opacity .125s .25s,-webkit-transform .25s .25s;transition:color .25s,opacity .125s .25s,-webkit-transform .25s .25s;transition:transform .25s .25s,color .25s,opacity .125s .25s;transition:transform .25s .25s,color .25s,opacity .125s .25s,-webkit-transform .25s .25s;opacity:0}html body .md-typeset .headerlink{color:rgba(0,0,0,.26)}.md-typeset [id]:before{display:inline-block;content:""}.md-typeset [id]:target:before{margin-top:-9.8rem;padding-top:9.8rem}.md-typeset [id] .headerlink:focus,.md-typeset [id]:hover .headerlink,.md-typeset [id]:target .headerlink{-webkit-transform:translate(0);transform:translate(0);opacity:1}.md-typeset [id] .headerlink:focus,.md-typeset [id]:hover .headerlink:hover,.md-typeset [id]:target .headerlink{color:#536dfe}.md-typeset h1[id]{padding-top:.8rem}.md-typeset h1[id].headerlink{display:none}.md-typeset h2[id]:before{display:block;margin-top:-.4rem;padding-top:.4rem}.md-typeset h2[id]:target:before{margin-top:-8.4rem;padding-top:8.4rem}.md-typeset h3[id]:before{display:block;margin-top:-.7rem;padding-top:.7rem}.md-typeset h3[id]:target:before{margin-top:-8.7rem;padding-top:8.7rem}.md-typeset h4[id]:before{display:block;margin-top:-.8rem;padding-top:.8rem}.md-typeset h4[id]:target:before{margin-top:-8.8rem;padding-top:8.8rem}.md-typeset h5[id]:before{display:block;margin-top:-1.1rem;padding-top:1.1rem}.md-typeset h5[id]:target:before{margin-top:-9.1rem;padding-top:9.1rem}.md-typeset h6[id]:before{display:block;margin-top:-1.1rem;padding-top:1.1rem}.md-typeset h6[id]:target:before{margin-top:-9.1rem;padding-top:9.1rem}.md-typeset .MJXc-display{margin:.75em 0;padding:.25em 0;overflow:auto;-webkit-overflow-scrolling:touch}.md-typeset .MathJax_CHTML{outline:0}.md-typeset .comment.critic,.md-typeset del.critic,.md-typeset ins.critic{margin:0 .25em;padding:.0625em 0;border-radius:.2rem;-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset del.critic{background-color:#fdd;box-shadow:.25em 0 0 #fdd,-.25em 0 0 #fdd}.md-typeset ins.critic{background-color:#dfd;box-shadow:.25em 0 0 #dfd,-.25em 0 0 #dfd}.md-typeset .critic.comment{background-color:hsla(0,0%,93%,.5);color:#37474f;box-shadow:.25em 0 0 hsla(0,0%,93%,.5),-.25em 0 0 hsla(0,0%,93%,.5)}.md-typeset .critic.comment:before{padding-right:.125em;color:rgba(0,0,0,.26);content:"chat";vertical-align:-.125em}.md-typeset .critic.block{display:block;margin:1em 0;padding-right:1.6rem;padding-left:1.6rem;box-shadow:none}.md-typeset .critic.block :first-child{margin-top:.5em}.md-typeset .critic.block :last-child{margin-bottom:.5em}.md-typeset .emojione{width:2rem;vertical-align:text-top}.md-typeset code.codehilite{margin:0 .29412em;padding:.07353em 0}.md-typeset .task-list-item{position:relative;list-style-type:none}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em;left:-2em}.md-typeset .task-list-control .task-list-indicator:before{position:absolute;top:.05em;left:-1.25em;color:rgba(0,0,0,.26);font-size:1.5em;content:"check_box_outline_blank";vertical-align:-.25em}.md-typeset .task-list-control [type=checkbox]:checked+.task-list-indicator:before{content:"check_box"}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}@media print{.md-typeset a:after{color:rgba(0,0,0,.54);content:" [" attr(href) "]"}.md-typeset code{box-shadow:none;-webkit-box-decoration-break:initial;box-decoration-break:slice}.md-content__edit,.md-footer,.md-header,.md-sidebar,.md-typeset .headerlink{display:none}}@media only screen and (max-width:44.9375em){.md-typeset pre{margin:1em -1.6rem;padding:1rem 1.6rem;border-radius:0}.codehilite .hll{margin:0 -1.6rem;padding:0 1.6rem}.md-typeset>.codehilite{padding:1rem 1.6rem .8rem}.md-typeset>.codehilite,.md-typeset>.codehilitetable{margin:1em -1.6rem;border-radius:0}.md-typeset>.codehilitetable .codehilite,.md-typeset>.codehilitetable .linenodiv{padding:1rem 1.6rem}.md-typeset>p>.MJXc-display{margin:.75em -1.6rem;padding:.25em 1.6rem}}@media only screen and (min-width:100em){html{font-size:68.75%}}@media only screen and (min-width:125em){html{font-size:75%}}@media only screen and (max-width:59.9375em){body[data-md-state=lock]{overflow:hidden}.ios body[data-md-state=lock] .md-container{display:none}.md-content__edit{margin-right:-.8rem}.md-nav--secondary{border-left:0}html .md-nav__link[for=toc]{display:block;padding-right:4.8rem}html .md-nav__link[for=toc]:after{color:inherit;content:"toc"}html .md-nav__link[for=toc]+.md-nav__link{display:none}html .md-nav__link[for=toc]~.md-nav{display:-webkit-box;display:-ms-flexbox;display:flex}.md-nav__source{display:block;padding:.4rem;background-color:rgba(50,64,144,.9675);color:#fff}.md-search__overlay{display:block;position:absolute;top:.4rem;left:.4rem;width:4rem;height:4rem;-webkit-transform-origin:center;transform-origin:center;-webkit-transition:opacity .2s .2s,-webkit-transform .3s .1s;transition:opacity .2s .2s,-webkit-transform .3s .1s;transition:transform .3s .1s,opacity .2s .2s;transition:transform .3s .1s,opacity .2s .2s,-webkit-transform .3s .1s;border-radius:2rem;background-color:#fff;opacity:0;overflow:hidden;z-index:1}[data-md-toggle=search]:checked~.md-header .md-search__overlay{-webkit-transition:opacity .1s,-webkit-transform .4s;transition:opacity .1s,-webkit-transform .4s;transition:transform .4s,opacity .1s;transition:transform .4s,opacity .1s,-webkit-transform .4s;opacity:1}.md-search__inner{position:fixed;top:0;left:100%;height:100%;-webkit-transform:translateX(5%);transform:translateX(5%);-webkit-transition:left 0s .3s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.4,0,.2,1) .15s;transition:left 0s .3s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.4,0,.2,1) .15s;transition:left 0s .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;transition:left 0s .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.4,0,.2,1) .15s;opacity:0;z-index:2}[data-md-toggle=search]:checked~.md-header .md-search__inner{left:0;-webkit-transform:translateX(0);transform:translateX(0);-webkit-transition:left 0s 0s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.1,.7,.1,1) .15s;transition:left 0s 0s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.1,.7,.1,1) .15s;transition:left 0s 0s,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;transition:left 0s 0s,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.1,.7,.1,1) .15s;opacity:1}.md-search__input{width:100%;height:5.6rem;font-size:1.8rem}.md-search__icon{top:1.6rem;left:1.6rem}.md-search__icon:before{content:"arrow_back"}.md-search__output{top:5.6rem;bottom:0}}@media only screen and (max-width:76.1875em){[data-md-toggle=drawer]:checked~.md-overlay{width:100%;height:100%;-webkit-transition:width 0s,height 0s,opacity .25s;transition:width 0s,height 0s,opacity .25s;opacity:1}.md-header-nav__button.md-icon--home,.md-header-nav__button.md-logo{display:none}.md-nav--primary,.md-nav--primary .md-nav{display:-webkit-box;display:-ms-flexbox;display:flex;position:absolute;top:0;right:0;left:0;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:100%;z-index:1}.md-nav--primary{background-color:#fff}.md-nav--primary .md-nav__toggle~.md-nav{box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.4);background-color:#fff}.md-nav--primary .md-nav__item,.md-nav--primary .md-nav__title{font-size:1.6rem;line-height:1.5}html .md-nav--primary .md-nav__title{position:relative;height:11.2rem;padding:6rem 1.6rem .4rem;background-color:rgba(0,0,0,.07);color:rgba(0,0,0,.54);font-weight:400;line-height:4.8rem;white-space:nowrap;cursor:pointer}html .md-nav--primary .md-nav__title:before{display:block;position:absolute;top:.4rem;left:.4rem;width:4rem;height:4rem;color:rgba(0,0,0,.54)}html .md-nav--primary .md-nav__title~.md-nav__list{background:-webkit-linear-gradient(top,#fff 10%,hsla(0,0%,100%,0)),-webkit-linear-gradient(top,rgba(0,0,0,.26),rgba(0,0,0,.07) 35%,transparent 60%);background:linear-gradient(180deg,#fff 10%,hsla(0,0%,100%,0)),linear-gradient(180deg,rgba(0,0,0,.26),rgba(0,0,0,.07) 35%,transparent 60%);background-attachment:local,scroll;background-color:#fff;background-repeat:no-repeat;background-size:100% 2rem,100% 1rem;box-shadow:inset 0 .1rem 0 rgba(0,0,0,.07)}html .md-nav--primary .md-nav__title~.md-nav__list>.md-nav__item:first-child{border-top:0}html .md-nav--primary .md-nav__title--site{position:relative;background-color:#3f51b5;color:#fff}html .md-nav--primary .md-nav__title--site .md-nav__button{display:block;position:absolute;top:.4rem;left:.4rem;width:6.4rem;height:6.4rem;font-size:4.8rem}html .md-nav--primary .md-nav__title--site:before{display:none}.md-nav--primary .md-nav__list{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow-y:auto}.md-nav--primary .md-nav__item{padding:0;border-top:.1rem solid rgba(0,0,0,.07)}.md-nav--primary .md-nav__item--nested>.md-nav__link{padding-right:4.8rem}.md-nav--primary .md-nav__item--nested>.md-nav__link:after{content:"keyboard_arrow_right"}.md-nav--primary .md-nav__link{position:relative;padding:1.6rem}.md-nav--primary .md-nav__link:after{position:absolute;top:50%;right:1.2rem;margin-top:-1.2rem;color:rgba(0,0,0,.54);font-size:2.4rem}.md-nav--primary .md-nav__link:hover:after{color:inherit}.md-nav--primary .md-nav--secondary .md-nav{position:static}.md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:2.8rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:4rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:5.2rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:6.4rem}.md-nav__toggle~.md-nav{display:none}.csstransforms3d .md-nav__toggle~.md-nav{-webkit-transform:translateX(100%);transform:translateX(100%);-webkit-transition:opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);transition:opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity .125s .05s;transition:transform .25s cubic-bezier(.8,0,.6,1),opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);opacity:0}.csstransforms3d .md-nav__toggle~.md-nav,.md-nav__toggle:checked~.md-nav{display:-webkit-box;display:-ms-flexbox;display:flex}.csstransforms3d .md-nav__toggle:checked~.md-nav{-webkit-transform:translateX(0);transform:translateX(0);-webkit-transition:opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .125s .125s;transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);opacity:1}.md-sidebar--primary{position:fixed;top:0;left:-24.2rem;width:24.2rem;height:100%;-webkit-transform:translateX(0);transform:translateX(0);-webkit-transition:box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);background-color:#fff;z-index:2}.no-csstransforms3d .md-sidebar--primary{display:none}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12),0 5px 5px -3px rgba(0,0,0,.4);-webkit-transform:translateX(24.2rem);transform:translateX(24.2rem)}.no-csstransforms3d [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{display:block}.md-sidebar--primary .md-sidebar__scrollwrap{overflow:hidden;position:absolute;top:0;right:0;bottom:0;left:0;margin:0}}@media only screen and (min-width:60em){.md-content{margin-right:24.2rem}.md-header-nav__button.md-icon--search{display:none}.md-header-nav__source{display:block;width:23rem;max-width:23rem;padding-right:1.2rem}.md-search{margin-right:2.8rem;padding:.4rem}.md-search__inner{display:table;position:relative;clear:both}.md-search__form{width:23rem;float:right;-webkit-transition:width .25s cubic-bezier(.1,.7,.1,1);transition:width .25s cubic-bezier(.1,.7,.1,1);border-radius:.2rem}.md-search__input{width:100%;height:4rem;padding-left:4.8rem;-webkit-transition:background-color .25s,color .25s;transition:background-color .25s,color .25s;border-radius:.2rem;background-color:rgba(0,0,0,.26);color:#fff;font-size:1.6rem}.md-search__input+.md-search__icon,.md-search__input::-webkit-input-placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input+.md-search__icon,.md-search__input::-moz-placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input+.md-search__icon,.md-search__input:-ms-input-placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input+.md-search__icon,.md-search__input::placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input:hover{background-color:hsla(0,0%,100%,.12)}[data-md-toggle=search]:checked~.md-header .md-search__input{border-radius:.2rem .2rem 0 0;background-color:#fff;color:rgba(0,0,0,.87);text-overflow:none}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::-webkit-input-placeholder{color:rgba(0,0,0,.54)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::-moz-placeholder{color:rgba(0,0,0,.54)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input:-ms-input-placeholder{color:rgba(0,0,0,.54)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:rgba(0,0,0,.54)}.md-search__output{top:4rem;-webkit-transition:opacity .4s;transition:opacity .4s;opacity:0}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12),0 3px 5px -1px rgba(0,0,0,.4);opacity:1}.md-search__scrollwrap{max-height:0}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap::-webkit-scrollbar{width:.4rem;height:.4rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-search-result__link,.md-search-result__meta{padding-left:4.8rem}.md-sidebar--secondary{display:block;float:right}.md-sidebar--secondary[data-md-state=lock]{margin-left:100%;-webkit-transform:translate(-100%);transform:translate(-100%)}}@media only screen and (min-width:76.25em){.md-content{margin-left:24.2rem;overflow:auto}.md-content__inner{margin:2.4rem}.md-content__inner :last-child{margin-bottom:0}.md-header-nav__button.md-icon--menu{display:none}.md-nav[data-md-state=animate]{-webkit-transition:max-height .25s cubic-bezier(.86,0,.07,1);transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav__toggle~.md-nav{max-height:0;overflow:hidden}.md-nav[data-md-state=expand],.md-nav__toggle:checked~.md-nav{max-height:100%}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--nested>.md-nav__link:after{display:inline-block;-webkit-transform-origin:.45em .45em;transform-origin:.45em .45em;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;vertical-align:-.125em}.js .md-nav__item--nested>.md-nav__link:after{-webkit-transition:-webkit-transform .4s;transition:-webkit-transform .4s;transition:transform .4s;transition:transform .4s,-webkit-transform .4s}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link:after{-webkit-transform:rotateX(180deg);transform:rotateX(180deg)}.md-search__scrollwrap,[data-md-toggle=search]:checked~.md-header .md-search__form{width:68.8rem}.md-sidebar__inner{border-right:.1rem solid rgba(0,0,0,.07)}}@media only screen and (max-width:29.9375em){.md-footer-nav__link--prev .md-footer-nav__title,.md-header-nav__parent{display:none}[data-md-toggle=search]:checked~.md-header .md-search__overlay{-webkit-transform:scale(45);transform:scale(45)}}@media only screen and (min-width:30em){.md-footer-nav__link{width:50%}}@media only screen and (min-width:45em){.md-footer-copyright{max-width:75%;float:left}.md-footer-social{padding:1.2rem 0;float:right}}@media only screen and (min-width:30em) and (max-width:44.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{-webkit-transform:scale(60);transform:scale(60)}}@media only screen and (min-width:45em) and (max-width:59.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{-webkit-transform:scale(75);transform:scale(75)}}@media only screen and (min-width:60em) and (max-width:76.1875em){.md-search__scrollwrap,[data-md-toggle=search]:checked~.md-header .md-search__form{width:46.8rem}}@media only screen and (min-width:60em) and (min-width:76.25em){.md-sidebar--secondary[data-md-state=lock]{margin-left:122rem}} \ No newline at end of file diff --git a/material/assets/stylesheets/application-ee6a3f36b0.css b/material/assets/stylesheets/application-ee6a3f36b0.css new file mode 100644 index 000000000..811822de0 --- /dev/null +++ b/material/assets/stylesheets/application-ee6a3f36b0.css @@ -0,0 +1 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}html{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none}body{margin:0}hr{overflow:visible;box-sizing:content-box}a{-webkit-text-decoration-skip:objects}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}a:active,a:hover{outline-width:0}small,sub,sup{font-size:80%}sub,sup{position:relative;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}table{border-collapse:collapse;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{padding:0;background:transparent;font-size:inherit}button,input{border:0;outline:0}.admonition:before,.md-icon,.md-nav__button,.md-nav__link:after,.md-nav__title:before,.md-typeset .critic.comment:before,.md-typeset .footnote-backref,.md-typeset .task-list-control .task-list-indicator:before{font-family:Material Icons;font-style:normal;font-variant:normal;font-weight:400;line-height:1;text-transform:none;white-space:nowrap;speak:none;word-wrap:normal;direction:ltr}.md-content__edit,.md-footer-nav__button,.md-header-nav__button,.md-nav__button,.md-nav__title:before{display:inline-block;margin:.4rem;padding:.8rem;font-size:2.4rem;cursor:pointer}.md-icon--arrow-back:before{content:"arrow_back"}.md-icon--arrow-forward:before{content:"arrow_forward"}.md-icon--menu:before{content:"menu"}.md-icon--search:before{content:"search"}.md-icon--home:before{content:"school"}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body,input{color:rgba(0,0,0,.87);-webkit-font-feature-settings:"kern","onum","liga";font-feature-settings:"kern","onum","liga";font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-weight:400}code,kbd,pre{color:rgba(0,0,0,.87);-webkit-font-feature-settings:"kern","onum","liga";font-feature-settings:"kern","onum","liga";font-family:Courier New,Courier,monospace;font-weight:400}.md-typeset{font-size:1.6rem;line-height:1.6;-webkit-print-color-adjust:exact}.md-typeset blockquote,.md-typeset ol,.md-typeset p,.md-typeset ul{margin:1em 0}.md-typeset h1{margin:0 0 4rem;color:rgba(0,0,0,.54);font-size:3.125rem;line-height:1.3}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{margin:4rem 0 1.6rem;font-size:2.5rem;line-height:1.4}.md-typeset h3{margin:3.2rem 0 1.6rem;font-size:2rem;font-weight:400;letter-spacing:-.01em;line-height:1.5}.md-typeset h2+h3{margin-top:1.6rem}.md-typeset h4{font-size:1.6rem}.md-typeset h4,.md-typeset h5,.md-typeset h6{margin:1.6rem 0;font-weight:700;letter-spacing:-.01em}.md-typeset h5,.md-typeset h6{color:rgba(0,0,0,.54);font-size:1.28rem}.md-typeset h5{text-transform:uppercase}.md-typeset hr{margin:1.5em 0;border-bottom:.1rem dotted rgba(0,0,0,.26)}.md-typeset a{color:#3f51b5;word-break:break-word}.md-typeset a,.md-typeset a:before{-webkit-transition:color .125s;transition:color .125s}.md-typeset a:active,.md-typeset a:hover{color:#536dfe}.md-typeset code,.md-typeset pre{background-color:hsla(0,0%,93%,.5);color:#37474f;font-size:85%}.md-typeset code{margin:0 .29412em;padding:.07353em 0;border-radius:.2rem;box-shadow:.29412em 0 0 hsla(0,0%,93%,.5),-.29412em 0 0 hsla(0,0%,93%,.5);word-break:break-word;-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset h1 code,.md-typeset h2 code,.md-typeset h3 code,.md-typeset h4 code,.md-typeset h5 code,.md-typeset h6 code{margin:0;background-color:transparent;box-shadow:none}.md-typeset a>code{margin:inherit;padding:inherit;border-radius:none;background-color:inherit;color:inherit;box-shadow:none}.md-typeset pre{margin:1em 0;padding:1rem 1.2rem;border-radius:.2rem;line-height:1.4;overflow:auto;-webkit-overflow-scrolling:touch}.md-typeset pre::-webkit-scrollbar{width:.4rem;height:.4rem}.md-typeset pre::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-typeset pre::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-typeset pre>code{margin:0;background-color:transparent;font-size:inherit;box-shadow:none;-webkit-box-decoration-break:none;box-decoration-break:none}.md-typeset kbd{padding:0 .29412em;border:.1rem solid #c9c9c9;border-radius:.2rem;border-bottom-color:#bcbcbc;background-color:#fcfcfc;color:#555;font-size:85%;box-shadow:0 .1rem 0 #b0b0b0;word-break:break-word}.md-typeset mark{margin:0 .25em;padding:.0625em 0;border-radius:.2rem;background-color:rgba(255,235,59,.5);box-shadow:.25em 0 0 rgba(255,235,59,.5),-.25em 0 0 rgba(255,235,59,.5);word-break:break-word;-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset abbr{border-bottom:.1rem dotted rgba(0,0,0,.54);cursor:help}.md-typeset small{opacity:.75}.md-typeset sub,.md-typeset sup{margin-left:.07812em}.md-typeset blockquote{padding-left:1.2rem;border-left:.4rem solid rgba(0,0,0,.26);color:rgba(0,0,0,.54)}.md-typeset ul{list-style-type:disc}.md-typeset ol,.md-typeset ul{margin-left:.625em;padding:0}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em;margin-left:1.25em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin:.5em 0 .5em .625em}.md-typeset iframe,.md-typeset img,.md-typeset svg{max-width:100%}.md-typeset table:not([class]){box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2);margin:2em 0;border-radius:.2rem;font-size:1.28rem;overflow:hidden}.no-js .md-typeset table:not([class]){display:inline-block;max-width:100%;margin:.8em 0;overflow:auto;-webkit-overflow-scrolling:touch}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}.md-typeset table:not([class]) th{min-width:10rem;padding:1.2rem 1.6rem;background-color:rgba(0,0,0,.54);color:#fff;vertical-align:top}.md-typeset table:not([class]) td{padding:1.2rem 1.6rem;border-top:.1rem solid rgba(0,0,0,.07);vertical-align:top}.md-typeset table:not([class]) tr:first-child td{border-top:0}.md-typeset table:not([class]) a{word-break:normal}.md-typeset .md-typeset__table{margin:1.6em -1.6rem;overflow-x:auto;-webkit-overflow-scrolling:touch}.md-typeset .md-typeset__table table{display:inline-block;margin:0 1.6rem}html{font-size:62.5%}body,html{height:100%}body{position:relative}hr{display:block;height:.1rem;padding:0;border:0}.md-svg{display:none}.md-grid{max-width:122rem;margin-right:auto;margin-left:auto}.md-container,.md-main{overflow:auto}.md-container{display:table;width:100%;height:100%;table-layout:fixed}.md-main{display:table-row;height:100%}.md-main__inner{margin-top:5.6rem;padding-top:3rem;overflow:auto}.csscalc .md-main__inner{min-height:calc(100% - 2.6rem)}@-moz-document url-prefix(){.csscalc .md-main__inner{min-height:calc(100% - 5.6rem)}}.md-toggle{display:none}.md-overlay{position:fixed;top:0;width:0;height:0;-webkit-transition:width 0s .25s,height 0s .25s,opacity .25s;transition:width 0s .25s,height 0s .25s,opacity .25s;background-color:rgba(0,0,0,.54);opacity:0;z-index:2}.md-flex{display:table}.md-flex__cell{display:table-cell;position:relative;vertical-align:top}.md-flex__cell--shrink{width:0}.md-flex__cell--stretch{display:table;width:100%;table-layout:fixed}.md-flex__ellipsis{display:table-cell;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}@page{margin:25mm}.md-content__inner{margin:2.4rem 1.6rem}.md-content__edit{float:right}.md-header{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2);position:fixed;top:0;right:0;left:0;height:5.6rem;-webkit-transition:background-color .25s;transition:background-color .25s;background-color:#3f51b5;color:#fff;z-index:1}.md-header-nav{padding:.4rem}.md-header-nav__button{position:relative;-webkit-transition:opacity .25s;transition:opacity .25s;z-index:1}.md-header-nav__button:hover{opacity:.7}.md-header-nav__button.md-logo img{display:block}.no-js .md-header-nav__button.md-icon--search{display:none}.md-header-nav__title{padding:0 2rem;font-size:1.8rem;line-height:4.8rem}.md-header-nav__parent{color:hsla(0,0%,100%,.7)}.md-header-nav__parent:after{display:inline;color:hsla(0,0%,100%,.3);content:"/"}.md-header-nav__source{display:none}.md-footer-nav{background-color:rgba(0,0,0,.87);color:#fff}.md-footer-nav__inner{padding:.4rem;overflow:auto}.md-footer-nav__link{padding-top:2.8rem;padding-bottom:.8rem;-webkit-transition:opacity .25s;transition:opacity .25s}.md-footer-nav__link:hover{opacity:.7}.md-footer-nav__link--prev{width:25%;float:left}.md-footer-nav__link--next{width:75%;float:right;text-align:right}.md-footer-nav__button{-webkit-transition:background .25s;transition:background .25s}.md-footer-nav__title{position:relative;padding:0 2rem;font-size:1.8rem;line-height:4.8rem}.md-footer-nav__direction{position:absolute;right:0;left:0;margin-top:-2rem;padding:0 2rem;color:hsla(0,0%,100%,.7);font-size:1.5rem}.md-footer-meta{background:rgba(0,0,0,.895)}.md-footer-meta__inner{padding:.4rem;overflow:auto}html .md-footer-meta.md-typeset a{color:hsla(0,0%,100%,.7)}.md-footer-copyright{margin:0 1.2rem;padding:.8rem 0;color:hsla(0,0%,100%,.3);font-size:1.28rem}.md-footer-copyright__highlight{color:hsla(0,0%,100%,.7)}.md-footer-social{margin:0 .8rem;padding:.4rem 0 1.2rem}.md-footer-social__link{display:inline-block;width:3.2rem;height:3.2rem;border:.1rem solid hsla(0,0%,100%,.12);border-radius:100%;color:hsla(0,0%,100%,.7);font-size:1.6rem;text-align:center}.md-footer-social__link:before{line-height:1.9}.md-nav{font-size:1.4rem;line-height:1.3}.md-nav--secondary{-webkit-transition:border-left .25s;transition:border-left .25s;border-left:.4rem solid #3f51b5}.md-nav__title{display:block;padding:1.2rem 1.2rem 0;font-weight:700;text-overflow:ellipsis;overflow:hidden}.md-nav__title:before{display:none;content:"arrow_back"}.md-nav__title .md-nav__button{display:none}.md-nav__list{margin:0;padding:0;list-style:none}.md-nav__item{padding:.625em 1.2rem 0}.md-nav__item:last-child{padding-bottom:1.2rem}.md-nav__item .md-nav__item{padding-right:0}.md-nav__item .md-nav__item:last-child{padding-bottom:0}.md-nav__button img{width:100%;height:auto}.md-nav__link{display:block;-webkit-transition:color .125s;transition:color .125s;text-overflow:ellipsis;cursor:pointer;overflow:hidden}.md-nav__item--nested>.md-nav__link:after{content:"keyboard_arrow_down"}html .md-nav__link[for=toc],html .md-nav__link[for=toc]+.md-nav__link:after,html .md-nav__link[for=toc]~.md-nav{display:none}.md-nav__link[data-md-state=blur]{color:rgba(0,0,0,.54)}.md-nav__link--active,.md-nav__link:active{color:#3f51b5}.md-nav__link:focus,.md-nav__link:hover{color:#536dfe}.md-nav__source,.no-js .md-search{display:none}.md-search__overlay{display:none;pointer-events:none}.md-search__inner{width:100%}.md-search__form{position:relative}.md-search__input{position:relative;padding:0 1.6rem 0 7.2rem;text-overflow:ellipsis;z-index:1}.md-search__input+.md-search__icon,.md-search__input::-webkit-input-placeholder{color:rgba(0,0,0,.54)}.md-search__input+.md-search__icon,.md-search__input::-moz-placeholder{color:rgba(0,0,0,.54)}.md-search__input+.md-search__icon,.md-search__input:-ms-input-placeholder{color:rgba(0,0,0,.54)}.md-search__input+.md-search__icon,.md-search__input::placeholder{color:rgba(0,0,0,.54)}.md-search__input::-ms-clear{display:none}.md-search__icon{position:absolute;top:.8rem;left:1.2rem;-webkit-transition:color .25s;transition:color .25s;font-size:2.4rem;cursor:pointer;z-index:1}.md-search__icon:before{content:"search"}.md-search__output{position:absolute;width:100%;border-radius:0 0 .2rem .2rem;overflow:hidden}.md-search__scrollwrap{height:100%;background:-webkit-linear-gradient(top,#fff 10%,hsla(0,0%,100%,0)),-webkit-linear-gradient(top,rgba(0,0,0,.26),rgba(0,0,0,.07) 35%,transparent 60%);background:linear-gradient(180deg,#fff 10%,hsla(0,0%,100%,0)),linear-gradient(180deg,rgba(0,0,0,.26),rgba(0,0,0,.07) 35%,transparent 60%);background-attachment:local,scroll;background-color:#fff;background-repeat:no-repeat;background-size:100% 2rem,100% 1rem;box-shadow:inset 0 .1rem 0 rgba(0,0,0,.07);overflow-y:auto;-webkit-overflow-scrolling:touch}.md-search-result__meta{padding:0 1.6rem;background-color:rgba(0,0,0,.07);color:rgba(0,0,0,.54);font-size:1.28rem;line-height:4rem}.md-search-result__list{margin:0;padding:0;border-top:.1rem solid rgba(0,0,0,.07);list-style:none}.md-search-result__item{box-shadow:0 -.1rem 0 rgba(0,0,0,.07)}.md-search-result__link{display:block;padding:0 1.6rem;-webkit-transition:background .25s;transition:background .25s;overflow:auto}.md-search-result__link:hover{background-color:rgba(83,109,254,.1)}.md-search-result__article{margin:1em 0}.md-search-result__title{margin-top:.5em;margin-bottom:0;color:rgba(0,0,0,.87);font-size:1.6rem;font-weight:400;line-height:1.4}.md-search-result__teaser{margin:.5em 0;color:rgba(0,0,0,.54);font-size:1.28rem;line-height:1.4;word-break:break-word}.md-sidebar{position:relative;width:24.2rem;padding:2.4rem 0;float:left;overflow:visible}.md-sidebar[data-md-state=lock]{position:fixed;top:5.6rem;-webkit-backface-visibility:hidden;backface-visibility:hidden}.md-sidebar--secondary{display:none}.md-sidebar__scrollwrap{max-height:100%;margin:0 .4rem;overflow-y:auto}.md-sidebar__scrollwrap::-webkit-scrollbar{width:.4rem;height:.4rem}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#536dfe}@-webkit-keyframes a{0%{height:0}to{height:1.3rem}}@keyframes a{0%{height:0}to{height:1.3rem}}@-webkit-keyframes b{0%{-webkit-transform:translateY(100%);transform:translateY(100%);opacity:0}50%{opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes b{0%{-webkit-transform:translateY(100%);transform:translateY(100%);opacity:0}50%{opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}.md-source{display:block;-webkit-transition:opacity .25s;transition:opacity .25s;font-size:1.3rem;line-height:1.2;white-space:nowrap}.md-source:hover{opacity:.7}.md-source:after,.md-source__icon{display:inline-block;height:4.8rem;content:"";vertical-align:middle}.md-source__icon{width:4.8rem}.md-source__icon svg{margin-top:1.2rem;margin-left:1.2rem}.md-source__icon+.md-source__repository{margin-left:-4.4rem;padding-left:4rem}.md-source__repository{display:inline-block;max-width:100%;margin-left:1.2rem;font-weight:700;text-overflow:ellipsis;overflow:hidden;vertical-align:middle}.md-source__facts{margin:0;padding:0;font-size:1.1rem;font-weight:700;list-style-type:none;opacity:.75;overflow:hidden}[data-md-state=done] .md-source__facts{-webkit-animation:a .25s ease-in;animation:a .25s ease-in}.md-source__fact{float:left}[data-md-state=done] .md-source__fact{-webkit-animation:b .4s ease-out;animation:b .4s ease-out}.md-source__fact:before{margin:0 .2rem;content:"\00B7"}.md-source__fact:first-child:before{display:none}.admonition{position:relative;margin:1.5625em 0;padding:.8rem 1.2rem;border-left:3.2rem solid rgba(68,138,255,.4);border-radius:.2rem;background-color:rgba(68,138,255,.15);font-size:1.28rem}.admonition:before{position:absolute;left:-2.6rem;color:#fff;font-size:2rem;content:"edit";vertical-align:-.25em}.admonition :first-child{margin-top:0}.admonition :last-child{margin-bottom:0}.admonition.summary,.admonition.tldr{border-color:rgba(0,176,255,.4);background-color:rgba(0,176,255,.15)}.admonition.summary:before,.admonition.tldr:before{content:"subject"}.admonition.hint,.admonition.important,.admonition.tip{border-color:rgba(0,191,165,.4);background-color:rgba(0,191,165,.15)}.admonition.hint:before,.admonition.important:before,.admonition.tip:before{content:"whatshot"}.admonition.check,.admonition.done,.admonition.success{border-color:rgba(0,230,118,.4);background-color:rgba(0,230,118,.15)}.admonition.check:before,.admonition.done:before,.admonition.success:before{content:"done"}.admonition.attention,.admonition.caution,.admonition.warning{border-color:rgba(255,145,0,.4);background-color:rgba(255,145,0,.15)}.admonition.attention:before,.admonition.caution:before,.admonition.warning:before{content:"warning"}.admonition.fail,.admonition.failure,.admonition.missing{border-color:rgba(255,82,82,.4);background-color:rgba(255,82,82,.15)}.admonition.fail:before,.admonition.failure:before,.admonition.missing:before{content:"clear"}.admonition.danger,.admonition.error{border-color:rgba(255,23,68,.4);background-color:rgba(255,23,68,.15)}.admonition.danger:before,.admonition.error:before{content:"flash_on"}.admonition.bug{border-color:rgba(245,0,87,.4);background-color:rgba(245,0,87,.15)}.admonition.bug:before{content:"bug_report"}.admonition-title{font-weight:700}html .admonition-title{margin-bottom:0}html .admonition-title+*{margin-top:0}.codehilite .o,.codehilite .ow{color:inherit}.codehilite .ge{color:#000}.codehilite .gr{color:#a00}.codehilite .gh{color:#999}.codehilite .go{color:#888}.codehilite .gp{color:#555}.codehilite .gs{color:inherit}.codehilite .gu{color:#aaa}.codehilite .gt{color:#a00}.codehilite .gd{background-color:#fdd}.codehilite .gi{background-color:#dfd}.codehilite .k{color:#3b78e7}.codehilite .kc{color:#a71d5d}.codehilite .kd,.codehilite .kn{color:#3b78e7}.codehilite .kp{color:#a71d5d}.codehilite .kr,.codehilite .kt{color:#3e61a2}.codehilite .c,.codehilite .cm{color:#999}.codehilite .cp{color:#666}.codehilite .c1,.codehilite .ch,.codehilite .cs{color:#999}.codehilite .na,.codehilite .nb{color:#c2185b}.codehilite .bp{color:#3e61a2}.codehilite .nc{color:#c2185b}.codehilite .no{color:#3e61a2}.codehilite .nd,.codehilite .ni{color:#666}.codehilite .ne,.codehilite .nf{color:#c2185b}.codehilite .nl{color:#3b5179}.codehilite .nn{color:#ec407a}.codehilite .nt{color:#3b78e7}.codehilite .nv,.codehilite .vc,.codehilite .vg,.codehilite .vi{color:#3e61a2}.codehilite .nx{color:#ec407a}.codehilite .il,.codehilite .m,.codehilite .mf,.codehilite .mh,.codehilite .mi,.codehilite .mo{color:#e74c3c}.codehilite .s,.codehilite .sb,.codehilite .sc{color:#0d904f}.codehilite .sd{color:#999}.codehilite .s2{color:#0d904f}.codehilite .se,.codehilite .sh,.codehilite .si,.codehilite .sx{color:#183691}.codehilite .sr{color:#009926}.codehilite .s1,.codehilite .ss{color:#0d904f}.codehilite .err{color:#a61717}.codehilite .w{color:transparent}.codehilite .hll{display:block;margin:0 -1.2rem;padding:0 1.2rem;background-color:rgba(255,235,59,.5)}.md-typeset .codehilite{margin:1em 0;padding:1rem 1.2rem .8rem;border-radius:.2rem;background-color:hsla(0,0%,93%,.5);color:#37474f;line-height:1.4;overflow:auto;-webkit-overflow-scrolling:touch}.md-typeset .codehilite::-webkit-scrollbar{width:.4rem;height:.4rem}.md-typeset .codehilite::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-typeset .codehilite::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-typeset .codehilite pre{display:inline-block;min-width:100%;margin:0;padding:0;background-color:transparent;overflow:visible;vertical-align:top}.md-typeset .codehilitetable{display:block;margin:1em 0;border-radius:.2em;font-size:1.6rem;overflow:hidden}.md-typeset .codehilitetable tbody,.md-typeset .codehilitetable td{display:block;padding:0}.md-typeset .codehilitetable tr{display:-webkit-box;display:-ms-flexbox;display:flex}.md-typeset .codehilitetable .codehilite,.md-typeset .codehilitetable .linenodiv{margin:0;border-radius:0}.md-typeset .codehilitetable .linenodiv{padding:1rem 1.2rem .8rem}.md-typeset .codehilitetable .linenodiv,.md-typeset .codehilitetable .linenodiv>pre{height:100%}.md-typeset .codehilitetable .linenos{background-color:rgba(0,0,0,.07);color:rgba(0,0,0,.26);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.md-typeset .codehilitetable .linenos pre{margin:0;padding:0;background-color:transparent;color:inherit;text-align:right}.md-typeset .codehilitetable .code{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:hidden}.md-typeset>.codehilitetable{box-shadow:none}.md-typeset .footnote{color:rgba(0,0,0,.54);font-size:1.28rem}.md-typeset .footnote ol{margin-left:0}.md-typeset .footnote li{-webkit-transition:color .25s;transition:color .25s}.md-typeset .footnote li:before{display:block;height:0}.md-typeset .footnote li:target{color:rgba(0,0,0,.87)}.md-typeset .footnote li:target:before{margin-top:-9rem;padding-top:9rem;pointer-events:none}.md-typeset .footnote li :first-child{margin-top:0}.md-typeset .footnote li:hover .footnote-backref,.md-typeset .footnote li:target .footnote-backref{-webkit-transform:translateX(0);transform:translateX(0);opacity:1}.md-typeset .footnote li:hover .footnote-backref:hover,.md-typeset .footnote li:target .footnote-backref{color:#536dfe}.md-typeset .footnote-backref{display:inline-block;-webkit-transform:translateX(.5rem);transform:translateX(.5rem);-webkit-transition:color .25s,opacity .125s .125s,-webkit-transform .25s .125s;transition:color .25s,opacity .125s .125s,-webkit-transform .25s .125s;transition:transform .25s .125s,color .25s,opacity .125s .125s;transition:transform .25s .125s,color .25s,opacity .125s .125s,-webkit-transform .25s .125s;color:rgba(0,0,0,.26);font-size:0;opacity:0;vertical-align:text-bottom}.md-typeset .footnote-backref:before{font-size:1.6rem;content:"keyboard_return"}.md-typeset .headerlink{display:inline-block;margin-left:1rem;-webkit-transform:translateY(.5rem);transform:translateY(.5rem);-webkit-transition:color .25s,opacity .125s .25s,-webkit-transform .25s .25s;transition:color .25s,opacity .125s .25s,-webkit-transform .25s .25s;transition:transform .25s .25s,color .25s,opacity .125s .25s;transition:transform .25s .25s,color .25s,opacity .125s .25s,-webkit-transform .25s .25s;opacity:0}html body .md-typeset .headerlink{color:rgba(0,0,0,.26)}.md-typeset [id]:before{display:inline-block;content:""}.md-typeset [id]:target:before{margin-top:-9.8rem;padding-top:9.8rem}.md-typeset [id] .headerlink:focus,.md-typeset [id]:hover .headerlink,.md-typeset [id]:target .headerlink{-webkit-transform:translate(0);transform:translate(0);opacity:1}.md-typeset [id] .headerlink:focus,.md-typeset [id]:hover .headerlink:hover,.md-typeset [id]:target .headerlink{color:#536dfe}.md-typeset h1[id]{padding-top:.8rem}.md-typeset h1[id].headerlink{display:none}.md-typeset h2[id]:before{display:block;margin-top:-.4rem;padding-top:.4rem}.md-typeset h2[id]:target:before{margin-top:-8.4rem;padding-top:8.4rem}.md-typeset h3[id]:before{display:block;margin-top:-.7rem;padding-top:.7rem}.md-typeset h3[id]:target:before{margin-top:-8.7rem;padding-top:8.7rem}.md-typeset h4[id]:before{display:block;margin-top:-.8rem;padding-top:.8rem}.md-typeset h4[id]:target:before{margin-top:-8.8rem;padding-top:8.8rem}.md-typeset h5[id]:before{display:block;margin-top:-1.1rem;padding-top:1.1rem}.md-typeset h5[id]:target:before{margin-top:-9.1rem;padding-top:9.1rem}.md-typeset h6[id]:before{display:block;margin-top:-1.1rem;padding-top:1.1rem}.md-typeset h6[id]:target:before{margin-top:-9.1rem;padding-top:9.1rem}.md-typeset .MJXc-display{margin:.75em 0;padding:.25em 0;overflow:auto;-webkit-overflow-scrolling:touch}.md-typeset .MathJax_CHTML{outline:0}.md-typeset .comment.critic,.md-typeset del.critic,.md-typeset ins.critic{margin:0 .25em;padding:.0625em 0;border-radius:.2rem;-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset del.critic{background-color:#fdd;box-shadow:.25em 0 0 #fdd,-.25em 0 0 #fdd}.md-typeset ins.critic{background-color:#dfd;box-shadow:.25em 0 0 #dfd,-.25em 0 0 #dfd}.md-typeset .critic.comment{background-color:hsla(0,0%,93%,.5);color:#37474f;box-shadow:.25em 0 0 hsla(0,0%,93%,.5),-.25em 0 0 hsla(0,0%,93%,.5)}.md-typeset .critic.comment:before{padding-right:.125em;color:rgba(0,0,0,.26);content:"chat";vertical-align:-.125em}.md-typeset .critic.block{display:block;margin:1em 0;padding-right:1.6rem;padding-left:1.6rem;box-shadow:none}.md-typeset .critic.block :first-child{margin-top:.5em}.md-typeset .critic.block :last-child{margin-bottom:.5em}.md-typeset .emojione{width:2rem;vertical-align:text-top}.md-typeset code.codehilite{margin:0 .29412em;padding:.07353em 0}.md-typeset .task-list-item{position:relative;list-style-type:none}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em;left:-2em}.md-typeset .task-list-control .task-list-indicator:before{position:absolute;top:.05em;left:-1.25em;color:rgba(0,0,0,.26);font-size:1.5em;content:"check_box_outline_blank";vertical-align:-.25em}.md-typeset .task-list-control [type=checkbox]:checked+.task-list-indicator:before{content:"check_box"}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}@media print{.md-typeset a:after{color:rgba(0,0,0,.54);content:" [" attr(href) "]"}.md-typeset code{box-shadow:none;-webkit-box-decoration-break:initial;box-decoration-break:slice}.md-content__edit,.md-footer,.md-header,.md-sidebar,.md-typeset .headerlink{display:none}}@media only screen and (max-width:44.9375em){.md-typeset pre{margin:1em -1.6rem;padding:1rem 1.6rem;border-radius:0}.md-footer-nav__link--prev .md-footer-nav__title{display:none}.codehilite .hll{margin:0 -1.6rem;padding:0 1.6rem}.md-typeset>.codehilite{padding:1rem 1.6rem .8rem}.md-typeset>.codehilite,.md-typeset>.codehilitetable{margin:1em -1.6rem;border-radius:0}.md-typeset>.codehilitetable .codehilite,.md-typeset>.codehilitetable .linenodiv{padding:1rem 1.6rem}.md-typeset>p>.MJXc-display{margin:.75em -1.6rem;padding:.25em 1.6rem}}@media only screen and (min-width:100em){html{font-size:68.75%}}@media only screen and (min-width:125em){html{font-size:75%}}@media only screen and (max-width:59.9375em){body[data-md-state=lock]{overflow:hidden}.ios body[data-md-state=lock] .md-container{display:none}.md-content__edit{margin-right:-.8rem}.md-nav--secondary{border-left:0}html .md-nav__link[for=toc]{display:block;padding-right:4.8rem}html .md-nav__link[for=toc]:after{color:inherit;content:"toc"}html .md-nav__link[for=toc]+.md-nav__link{display:none}html .md-nav__link[for=toc]~.md-nav{display:-webkit-box;display:-ms-flexbox;display:flex}.md-nav__source{display:block;padding:.4rem;background-color:rgba(50,64,144,.9675);color:#fff}.md-search__overlay{display:block;position:absolute;top:.4rem;left:.4rem;width:4rem;height:4rem;-webkit-transform-origin:center;transform-origin:center;-webkit-transition:opacity .2s .2s,-webkit-transform .3s .1s;transition:opacity .2s .2s,-webkit-transform .3s .1s;transition:transform .3s .1s,opacity .2s .2s;transition:transform .3s .1s,opacity .2s .2s,-webkit-transform .3s .1s;border-radius:2rem;background-color:#fff;opacity:0;overflow:hidden;z-index:1}[data-md-toggle=search]:checked~.md-header .md-search__overlay{-webkit-transition:opacity .1s,-webkit-transform .4s;transition:opacity .1s,-webkit-transform .4s;transition:transform .4s,opacity .1s;transition:transform .4s,opacity .1s,-webkit-transform .4s;opacity:1}.md-search__inner{position:fixed;top:0;left:100%;height:100%;-webkit-transform:translateX(5%);transform:translateX(5%);-webkit-transition:left 0s .3s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.4,0,.2,1) .15s;transition:left 0s .3s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.4,0,.2,1) .15s;transition:left 0s .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;transition:left 0s .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.4,0,.2,1) .15s;opacity:0;z-index:2}[data-md-toggle=search]:checked~.md-header .md-search__inner{left:0;-webkit-transform:translateX(0);transform:translateX(0);-webkit-transition:left 0s 0s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.1,.7,.1,1) .15s;transition:left 0s 0s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.1,.7,.1,1) .15s;transition:left 0s 0s,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;transition:left 0s 0s,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.1,.7,.1,1) .15s;opacity:1}.md-search__input{width:100%;height:5.6rem;font-size:1.8rem}.md-search__icon{top:1.6rem;left:1.6rem}.md-search__icon:before{content:"arrow_back"}.md-search__output{top:5.6rem;bottom:0}}@media only screen and (max-width:76.1875em){[data-md-toggle=drawer]:checked~.md-overlay{width:100%;height:100%;-webkit-transition:width 0s,height 0s,opacity .25s;transition:width 0s,height 0s,opacity .25s;opacity:1}.md-header-nav__button.md-icon--home,.md-header-nav__button.md-logo{display:none}.md-nav--primary,.md-nav--primary .md-nav{display:-webkit-box;display:-ms-flexbox;display:flex;position:absolute;top:0;right:0;left:0;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:100%;z-index:1}.md-nav--primary{background-color:#fff}.md-nav--primary .md-nav__toggle~.md-nav{box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.4);background-color:#fff}.md-nav--primary .md-nav__item,.md-nav--primary .md-nav__title{font-size:1.6rem;line-height:1.5}html .md-nav--primary .md-nav__title{position:relative;height:11.2rem;padding:6rem 1.6rem .4rem;background-color:rgba(0,0,0,.07);color:rgba(0,0,0,.54);font-weight:400;line-height:4.8rem;white-space:nowrap;cursor:pointer}html .md-nav--primary .md-nav__title:before{display:block;position:absolute;top:.4rem;left:.4rem;width:4rem;height:4rem;color:rgba(0,0,0,.54)}html .md-nav--primary .md-nav__title~.md-nav__list{background:-webkit-linear-gradient(top,#fff 10%,hsla(0,0%,100%,0)),-webkit-linear-gradient(top,rgba(0,0,0,.26),rgba(0,0,0,.07) 35%,transparent 60%);background:linear-gradient(180deg,#fff 10%,hsla(0,0%,100%,0)),linear-gradient(180deg,rgba(0,0,0,.26),rgba(0,0,0,.07) 35%,transparent 60%);background-attachment:local,scroll;background-color:#fff;background-repeat:no-repeat;background-size:100% 2rem,100% 1rem;box-shadow:inset 0 .1rem 0 rgba(0,0,0,.07)}html .md-nav--primary .md-nav__title~.md-nav__list>.md-nav__item:first-child{border-top:0}html .md-nav--primary .md-nav__title--site{position:relative;background-color:#3f51b5;color:#fff}html .md-nav--primary .md-nav__title--site .md-nav__button{display:block;position:absolute;top:.4rem;left:.4rem;width:6.4rem;height:6.4rem;font-size:4.8rem}html .md-nav--primary .md-nav__title--site:before{display:none}.md-nav--primary .md-nav__list{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow-y:auto}.md-nav--primary .md-nav__item{padding:0;border-top:.1rem solid rgba(0,0,0,.07)}.md-nav--primary .md-nav__item--nested>.md-nav__link{padding-right:4.8rem}.md-nav--primary .md-nav__item--nested>.md-nav__link:after{content:"keyboard_arrow_right"}.md-nav--primary .md-nav__link{position:relative;padding:1.6rem}.md-nav--primary .md-nav__link:after{position:absolute;top:50%;right:1.2rem;margin-top:-1.2rem;color:rgba(0,0,0,.54);font-size:2.4rem}.md-nav--primary .md-nav__link:hover:after{color:inherit}.md-nav--primary .md-nav--secondary .md-nav{position:static}.md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:2.8rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:4rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:5.2rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:6.4rem}.md-nav__toggle~.md-nav{display:none}.csstransforms3d .md-nav__toggle~.md-nav{-webkit-transform:translateX(100%);transform:translateX(100%);-webkit-transition:opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);transition:opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity .125s .05s;transition:transform .25s cubic-bezier(.8,0,.6,1),opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);opacity:0}.csstransforms3d .md-nav__toggle~.md-nav,.md-nav__toggle:checked~.md-nav{display:-webkit-box;display:-ms-flexbox;display:flex}.csstransforms3d .md-nav__toggle:checked~.md-nav{-webkit-transform:translateX(0);transform:translateX(0);-webkit-transition:opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .125s .125s;transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);opacity:1}.md-sidebar--primary{position:fixed;top:0;left:-24.2rem;width:24.2rem;height:100%;-webkit-transform:translateX(0);transform:translateX(0);-webkit-transition:box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);background-color:#fff;z-index:2}.no-csstransforms3d .md-sidebar--primary{display:none}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12),0 5px 5px -3px rgba(0,0,0,.4);-webkit-transform:translateX(24.2rem);transform:translateX(24.2rem)}.no-csstransforms3d [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{display:block}.md-sidebar--primary .md-sidebar__scrollwrap{overflow:hidden;position:absolute;top:0;right:0;bottom:0;left:0;margin:0}}@media only screen and (min-width:60em){.md-content{margin-right:24.2rem}.md-header-nav__button.md-icon--search{display:none}.md-header-nav__source{display:block;width:23rem;max-width:23rem;padding-right:1.2rem}.md-search{margin-right:2.8rem;padding:.4rem}.md-search__inner{display:table;position:relative;clear:both}.md-search__form{width:23rem;float:right;-webkit-transition:width .25s cubic-bezier(.1,.7,.1,1);transition:width .25s cubic-bezier(.1,.7,.1,1);border-radius:.2rem}.md-search__input{width:100%;height:4rem;padding-left:4.8rem;-webkit-transition:background-color .25s,color .25s;transition:background-color .25s,color .25s;border-radius:.2rem;background-color:rgba(0,0,0,.26);color:#fff;font-size:1.6rem}.md-search__input+.md-search__icon,.md-search__input::-webkit-input-placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input+.md-search__icon,.md-search__input::-moz-placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input+.md-search__icon,.md-search__input:-ms-input-placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input+.md-search__icon,.md-search__input::placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input:hover{background-color:hsla(0,0%,100%,.12)}[data-md-toggle=search]:checked~.md-header .md-search__input{border-radius:.2rem .2rem 0 0;background-color:#fff;color:rgba(0,0,0,.87);text-overflow:none}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::-webkit-input-placeholder{color:rgba(0,0,0,.54)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::-moz-placeholder{color:rgba(0,0,0,.54)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input:-ms-input-placeholder{color:rgba(0,0,0,.54)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:rgba(0,0,0,.54)}.md-search__output{top:4rem;-webkit-transition:opacity .4s;transition:opacity .4s;opacity:0}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12),0 3px 5px -1px rgba(0,0,0,.4);opacity:1}.md-search__scrollwrap{max-height:0}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap::-webkit-scrollbar{width:.4rem;height:.4rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-search-result__link,.md-search-result__meta{padding-left:4.8rem}.md-sidebar--secondary{display:block;float:right}.md-sidebar--secondary[data-md-state=lock]{margin-left:100%;-webkit-transform:translate(-100%);transform:translate(-100%)}}@media only screen and (min-width:76.25em){.md-content{margin-left:24.2rem;overflow:auto}.md-content__inner{margin:2.4rem}.md-content__inner :last-child{margin-bottom:0}.md-header-nav__button.md-icon--menu{display:none}.md-nav[data-md-state=animate]{-webkit-transition:max-height .25s cubic-bezier(.86,0,.07,1);transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav__toggle~.md-nav{max-height:0;overflow:hidden}.md-nav[data-md-state=expand],.md-nav__toggle:checked~.md-nav{max-height:100%}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--nested>.md-nav__link:after{display:inline-block;-webkit-transform-origin:.45em .45em;transform-origin:.45em .45em;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;vertical-align:-.125em}.js .md-nav__item--nested>.md-nav__link:after{-webkit-transition:-webkit-transform .4s;transition:-webkit-transform .4s;transition:transform .4s;transition:transform .4s,-webkit-transform .4s}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link:after{-webkit-transform:rotateX(180deg);transform:rotateX(180deg)}.md-search__scrollwrap,[data-md-toggle=search]:checked~.md-header .md-search__form{width:68.8rem}.md-sidebar__inner{border-right:.1rem solid rgba(0,0,0,.07)}}@media only screen and (max-width:29.9375em){.md-header-nav__parent{display:none}[data-md-toggle=search]:checked~.md-header .md-search__overlay{-webkit-transform:scale(45);transform:scale(45)}}@media only screen and (min-width:45em){.md-footer-nav__link{width:50%}.md-footer-copyright{max-width:75%;float:left}.md-footer-social{padding:1.2rem 0;float:right}}@media only screen and (min-width:30em) and (max-width:44.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{-webkit-transform:scale(60);transform:scale(60)}}@media only screen and (min-width:45em) and (max-width:59.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{-webkit-transform:scale(75);transform:scale(75)}}@media only screen and (min-width:60em) and (max-width:76.1875em){.md-search__scrollwrap,[data-md-toggle=search]:checked~.md-header .md-search__form{width:46.8rem}}@media only screen and (min-width:60em) and (min-width:76.25em){.md-sidebar--secondary[data-md-state=lock]{margin-left:122rem}} \ No newline at end of file diff --git a/material/base.html b/material/base.html index a21b20548..32d918607 100644 --- a/material/base.html +++ b/material/base.html @@ -19,7 +19,7 @@ {% else %} {% endif %} - + {% endblock %} {% block htmltitle %} {% if page.title %} @@ -31,7 +31,13 @@ {% endif %} {% endblock %} {% block libs %} - + + {% endblock %} + {% block styles %} + + {% if config.extra.palette %} + + {% endif %} {% endblock %} {% block fonts %} {% if config.extra.font != "none" %} @@ -44,15 +50,9 @@ {% endif %} {% endblock %} - {% block styles %} - - {% if config.extra.palette %} - - {% endif %} - {% for path in extra_css %} - - {% endfor %} - {% endblock %} + {% for path in extra_css %} + + {% endfor %} {% block extrahead %}{% endblock %} {% set palette = config.extra.get("palette", {}) %} diff --git a/mkdocs.yml b/mkdocs.yml index 6a5820396..c1df037de 100755 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -31,7 +31,7 @@ repo_url: https://github.com/squidfunk/mkdocs-material # Copyright copyright: 'Copyright © 2016 - 2017 Martin Donath' -# Documentation and theme +# Theme directory theme_dir: material # Options diff --git a/package.json b/package.json index 531e94671..69cdec455 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,9 @@ "clean": "scripts/clean", "lint": "scripts/lint", "start": "scripts/start", - "test": "scripts/test" + "test:visual:run": "scripts/test/visual/run", + "test:visual:update": "scripts/test/visual/update", + "test:visual:session": "scripts/test/visual/session" }, "dependencies": {}, "devDependencies": { @@ -45,6 +47,7 @@ "css-mqpacker": "^5.0.1", "custom-event-polyfill": "^0.3.0", "del": "^2.2.2", + "ecstatic": "^2.1.0", "eslint": "^3.14.0", "eslint-plugin-mocha": "^4.8.0", "fastclick": "^1.0.6", @@ -83,8 +86,9 @@ "material-shadows": "^3.0.1", "mocha": "^3.2.0", "modularscale-sass": "^2.1.1", + "moniker": "^0.1.2", "node-notifier": "^5.0.0", - "selenium-standalone": "^6.0.0", + "postcss-pseudo-classes": "^0.1.0", "stylelint": "^7.8.0", "stylelint-config-standard": "^16.0.0", "stylelint-order": "^0.2.2", @@ -96,6 +100,11 @@ "whatwg-fetch": "^2.0.1", "yargs": "^6.6.0" }, + "optionalDependencies": { + "gemini": "^4.14.3", + "sauce-connect-launcher": "^1.2.0", + "selenium-standalone": "^6.0.0" + }, "engines": { "node": ">= 4.5.0" }, diff --git a/requirements.txt b/requirements.txt index b1b14a966..2109c3ede 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,4 +20,4 @@ mkdocs>=0.16 pygments -pymdown-extensions +pymdown-extensions>=1.2 diff --git a/scripts/build b/scripts/build index f3fff3648..8037cbda3 100755 --- a/scripts/build +++ b/scripts/build @@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then fi # Run command -`npm bin`/gulp build --clean --optimize --revision +`npm bin`/gulp build --clean --optimize --revision "$@" diff --git a/scripts/clean b/scripts/clean index 1b3cb6417..309567950 100755 --- a/scripts/clean +++ b/scripts/clean @@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then fi # Run command -`npm bin`/gulp clean +`npm bin`/gulp clean "$@" diff --git a/scripts/lint b/scripts/lint index 51c64adc0..f83f6c9ba 100755 --- a/scripts/lint +++ b/scripts/lint @@ -28,7 +28,7 @@ if [[ ! -d `npm bin` ]]; then fi # Run ESLint -`npm bin`/eslint . +`npm bin`/eslint --max-warnings 0 . ESLINT=$? # Run Stylelint diff --git a/scripts/start b/scripts/start index d3e0db297..0dc23e37c 100755 --- a/scripts/start +++ b/scripts/start @@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then fi # Run command -`npm bin`/gulp watch --no-lint +`npm bin`/gulp watch --no-lint "$@" diff --git a/scripts/test/visual/run b/scripts/test/visual/run new file mode 100755 index 000000000..794378687 --- /dev/null +++ b/scripts/test/visual/run @@ -0,0 +1,31 @@ +#!/bin/bash + +# Copyright (c) 2016-2017 Martin Donath + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# Check if "npm install" was executed +if [[ ! -d `npm bin` ]]; then + echo "\"node_modules\" not found:" + echo "npm install" + exit 1 +fi + +# Run command +`npm bin`/gulp tests:visual:run --clean --no-optimize "$@" diff --git a/scripts/test/visual/session b/scripts/test/visual/session new file mode 100755 index 000000000..5d30bd2e1 --- /dev/null +++ b/scripts/test/visual/session @@ -0,0 +1,31 @@ +#!/bin/bash + +# Copyright (c) 2016-2017 Martin Donath + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# Check if "npm install" was executed +if [[ ! -d `npm bin` ]]; then + echo "\"node_modules\" not found:" + echo "npm install" + exit 1 +fi + +# Run command +`npm bin`/gulp tests:visual:session "$@" diff --git a/scripts/test b/scripts/test/visual/update similarity index 96% rename from scripts/test rename to scripts/test/visual/update index e6f32df17..61789f24d 100755 --- a/scripts/test +++ b/scripts/test/visual/update @@ -28,4 +28,4 @@ if [[ ! -d `npm bin` ]]; then fi # Run command -`npm bin`/gulp test +`npm bin`/gulp tests:visual:update "$@" diff --git a/src/assets/stylesheets/base/_typeset.scss b/src/assets/stylesheets/base/_typeset.scss index 2eced7319..c4ebedee0 100644 --- a/src/assets/stylesheets/base/_typeset.scss +++ b/src/assets/stylesheets/base/_typeset.scss @@ -34,14 +34,9 @@ body { body, input { color: $md-color-black; - // font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif; font-feature-settings: "kern", "onum", "liga"; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-weight: 400; - - // Use system fonts, if browser doesn't support webfonts - .no-fontface & { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - } } // Proportionally spaced fonts @@ -49,14 +44,9 @@ pre, code, kbd { color: $md-color-black; - // font-family: "Roboto Mono", "Courier New", Courier, monospace; font-feature-settings: "kern", "onum", "liga"; + font-family: "Courier New", Courier, monospace; font-weight: 400; - - // Use system fonts, if browser doesn't support webfonts - .no-fontface & { - font-family: "Courier New", Courier, monospace; - } } // ---------------------------------------------------------------------------- diff --git a/src/assets/stylesheets/layout/_footer.scss b/src/assets/stylesheets/layout/_footer.scss index 2f424519d..2bae7ebbc 100644 --- a/src/assets/stylesheets/layout/_footer.scss +++ b/src/assets/stylesheets/layout/_footer.scss @@ -50,8 +50,8 @@ padding-bottom: 0.8rem; transition: opacity 0.25s; - // [mobile landscape +]: Set proportional width - @include break-from-device(mobile landscape) { + // [tablet +]: Set proportional width + @include break-from-device(tablet) { width: 50%; } @@ -68,8 +68,8 @@ // Title .md-footer-nav__title { - // [mobile portrait -]: Hide title for previous page - @include break-to-device(mobile portrait) { + // [mobile -]: Hide title for previous page + @include break-to-device(mobile) { display: none; } } diff --git a/src/assets/stylesheets/layout/_nav.scss b/src/assets/stylesheets/layout/_nav.scss index 65b9186f9..42339d7ef 100644 --- a/src/assets/stylesheets/layout/_nav.scss +++ b/src/assets/stylesheets/layout/_nav.scss @@ -84,7 +84,7 @@ } } - // Icon buttons + // Button with logo &__button { @extend %md-icon, %md-icon__button; @@ -140,7 +140,8 @@ color: $md-color-primary; } - // Hovered item + // Focused or hovered item + &:focus, &:hover { color: $md-color-accent; } diff --git a/src/base.html b/src/base.html index 24c69ba0a..50d4dae31 100644 --- a/src/base.html +++ b/src/base.html @@ -56,7 +56,8 @@ {% endif %} - + {% endblock %} @@ -75,6 +76,20 @@ {% endblock %} + + {% block styles %} + + + + + + {% if config.extra.palette %} + + {% endif %} + {% endblock %} + {% block fonts %} {% if config.extra.font != "none" %} @@ -101,24 +116,10 @@ href="https://fonts.googleapis.com/icon?family=Material+Icons" /> {% endblock %} - - {% block styles %} - - - - - - {% if config.extra.palette %} - - {% endif %} - - - {% for path in extra_css %} - - {% endfor %} - {% endblock %} + + {% for path in extra_css %} + + {% endfor %} {% block extrahead %}{% endblock %} diff --git a/tests/visual/.eslintrc b/tests/visual/.eslintrc new file mode 100644 index 000000000..fab56404b --- /dev/null +++ b/tests/visual/.eslintrc @@ -0,0 +1,8 @@ +{ + "globals": { + "gemini": true + }, + "rules": { + "no-loop-func": 0 + } +} diff --git a/tests/visual/baseline/ci/admonition/#bug/@screen/chrome.png b/tests/visual/baseline/ci/admonition/#bug/@screen/chrome.png new file mode 100644 index 000000000..806fe08a8 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#bug/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/#bug/@screen/edge.png b/tests/visual/baseline/ci/admonition/#bug/@screen/edge.png new file mode 100644 index 000000000..3e11535a8 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#bug/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/#bug/@screen/firefox.png b/tests/visual/baseline/ci/admonition/#bug/@screen/firefox.png new file mode 100644 index 000000000..d88b7b724 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#bug/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/#bug/@screen/ie11.png b/tests/visual/baseline/ci/admonition/#bug/@screen/ie11.png new file mode 100644 index 000000000..46f3d9341 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#bug/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/#custom-title/@screen/chrome.png b/tests/visual/baseline/ci/admonition/#custom-title/@screen/chrome.png new file mode 100644 index 000000000..4b09877a2 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#custom-title/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/#custom-title/@screen/edge.png b/tests/visual/baseline/ci/admonition/#custom-title/@screen/edge.png new file mode 100644 index 000000000..20c7e3091 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#custom-title/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/#custom-title/@screen/firefox.png b/tests/visual/baseline/ci/admonition/#custom-title/@screen/firefox.png new file mode 100644 index 000000000..5120ddc22 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#custom-title/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/#custom-title/@screen/ie11.png b/tests/visual/baseline/ci/admonition/#custom-title/@screen/ie11.png new file mode 100644 index 000000000..361e39d19 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#custom-title/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/#danger/@screen/chrome.png b/tests/visual/baseline/ci/admonition/#danger/@screen/chrome.png new file mode 100644 index 000000000..b554b828f Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#danger/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/#danger/@screen/edge.png b/tests/visual/baseline/ci/admonition/#danger/@screen/edge.png new file mode 100644 index 000000000..4062f967b Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#danger/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/#danger/@screen/firefox.png b/tests/visual/baseline/ci/admonition/#danger/@screen/firefox.png new file mode 100644 index 000000000..16b41db6f Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#danger/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/#danger/@screen/ie11.png b/tests/visual/baseline/ci/admonition/#danger/@screen/ie11.png new file mode 100644 index 000000000..53132f9e3 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#danger/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/#empty-title/@screen/chrome.png b/tests/visual/baseline/ci/admonition/#empty-title/@screen/chrome.png new file mode 100644 index 000000000..274d8cf9c Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#empty-title/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/#empty-title/@screen/edge.png b/tests/visual/baseline/ci/admonition/#empty-title/@screen/edge.png new file mode 100644 index 000000000..4b5df6a34 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#empty-title/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/#empty-title/@screen/firefox.png b/tests/visual/baseline/ci/admonition/#empty-title/@screen/firefox.png new file mode 100644 index 000000000..64ffdb6d4 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#empty-title/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/#empty-title/@screen/ie11.png b/tests/visual/baseline/ci/admonition/#empty-title/@screen/ie11.png new file mode 100644 index 000000000..774e57df4 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#empty-title/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/#failure/@screen/chrome.png b/tests/visual/baseline/ci/admonition/#failure/@screen/chrome.png new file mode 100644 index 000000000..83c5ae1a7 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#failure/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/#failure/@screen/edge.png b/tests/visual/baseline/ci/admonition/#failure/@screen/edge.png new file mode 100644 index 000000000..25ed98317 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#failure/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/#failure/@screen/firefox.png b/tests/visual/baseline/ci/admonition/#failure/@screen/firefox.png new file mode 100644 index 000000000..63417af5d Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#failure/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/#failure/@screen/ie11.png b/tests/visual/baseline/ci/admonition/#failure/@screen/ie11.png new file mode 100644 index 000000000..e34169026 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#failure/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/#long-title/@screen/chrome.png b/tests/visual/baseline/ci/admonition/#long-title/@screen/chrome.png new file mode 100644 index 000000000..099e79d36 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#long-title/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/#long-title/@screen/edge.png b/tests/visual/baseline/ci/admonition/#long-title/@screen/edge.png new file mode 100644 index 000000000..86d2d68cf Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#long-title/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/#long-title/@screen/firefox.png b/tests/visual/baseline/ci/admonition/#long-title/@screen/firefox.png new file mode 100644 index 000000000..457d7a4c8 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#long-title/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/#long-title/@screen/ie11.png b/tests/visual/baseline/ci/admonition/#long-title/@screen/ie11.png new file mode 100644 index 000000000..ede732bfd Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#long-title/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/#note/@screen/chrome.png b/tests/visual/baseline/ci/admonition/#note/@screen/chrome.png new file mode 100644 index 000000000..7ec218742 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#note/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/#note/@screen/edge.png b/tests/visual/baseline/ci/admonition/#note/@screen/edge.png new file mode 100644 index 000000000..b58d92c96 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#note/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/#note/@screen/firefox.png b/tests/visual/baseline/ci/admonition/#note/@screen/firefox.png new file mode 100644 index 000000000..56b9bd034 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#note/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/#note/@screen/ie11.png b/tests/visual/baseline/ci/admonition/#note/@screen/ie11.png new file mode 100644 index 000000000..0455d62ee Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#note/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/#success/@screen/chrome.png b/tests/visual/baseline/ci/admonition/#success/@screen/chrome.png new file mode 100644 index 000000000..482540382 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#success/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/#success/@screen/edge.png b/tests/visual/baseline/ci/admonition/#success/@screen/edge.png new file mode 100644 index 000000000..b551b1842 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#success/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/#success/@screen/firefox.png b/tests/visual/baseline/ci/admonition/#success/@screen/firefox.png new file mode 100644 index 000000000..99013543e Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#success/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/#success/@screen/ie11.png b/tests/visual/baseline/ci/admonition/#success/@screen/ie11.png new file mode 100644 index 000000000..649c58ecb Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#success/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/#summary/@screen/chrome.png b/tests/visual/baseline/ci/admonition/#summary/@screen/chrome.png new file mode 100644 index 000000000..20fc31338 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#summary/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/#summary/@screen/edge.png b/tests/visual/baseline/ci/admonition/#summary/@screen/edge.png new file mode 100644 index 000000000..67a57b4dd Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#summary/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/#summary/@screen/firefox.png b/tests/visual/baseline/ci/admonition/#summary/@screen/firefox.png new file mode 100644 index 000000000..d46477146 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#summary/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/#summary/@screen/ie11.png b/tests/visual/baseline/ci/admonition/#summary/@screen/ie11.png new file mode 100644 index 000000000..1a1e3c68a Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#summary/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/#tip/@screen/chrome.png b/tests/visual/baseline/ci/admonition/#tip/@screen/chrome.png new file mode 100644 index 000000000..f398eccaf Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#tip/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/#tip/@screen/edge.png b/tests/visual/baseline/ci/admonition/#tip/@screen/edge.png new file mode 100644 index 000000000..17dbc22f2 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#tip/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/#tip/@screen/firefox.png b/tests/visual/baseline/ci/admonition/#tip/@screen/firefox.png new file mode 100644 index 000000000..50265bff7 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#tip/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/#tip/@screen/ie11.png b/tests/visual/baseline/ci/admonition/#tip/@screen/ie11.png new file mode 100644 index 000000000..954df11b3 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#tip/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/#warning/@screen/chrome.png b/tests/visual/baseline/ci/admonition/#warning/@screen/chrome.png new file mode 100644 index 000000000..6bf5d2a11 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#warning/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/#warning/@screen/edge.png b/tests/visual/baseline/ci/admonition/#warning/@screen/edge.png new file mode 100644 index 000000000..d4800fda7 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#warning/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/#warning/@screen/firefox.png b/tests/visual/baseline/ci/admonition/#warning/@screen/firefox.png new file mode 100644 index 000000000..f0b41f4c2 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#warning/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/#warning/@screen/ie11.png b/tests/visual/baseline/ci/admonition/#warning/@screen/ie11.png new file mode 100644 index 000000000..3a2ae5882 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/#warning/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/@mobile-landscape/chrome.png b/tests/visual/baseline/ci/admonition/@mobile-landscape/chrome.png new file mode 100644 index 000000000..36bec7663 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/@mobile-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/@mobile-landscape/edge.png b/tests/visual/baseline/ci/admonition/@mobile-landscape/edge.png new file mode 100644 index 000000000..f11be5b04 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/@mobile-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/@mobile-landscape/firefox.png b/tests/visual/baseline/ci/admonition/@mobile-landscape/firefox.png new file mode 100644 index 000000000..e1435e076 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/@mobile-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/@mobile-landscape/ie11.png b/tests/visual/baseline/ci/admonition/@mobile-landscape/ie11.png new file mode 100644 index 000000000..0ce1b5525 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/@mobile-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/@mobile-portrait/chrome.png b/tests/visual/baseline/ci/admonition/@mobile-portrait/chrome.png new file mode 100644 index 000000000..e175e9dec Binary files /dev/null and b/tests/visual/baseline/ci/admonition/@mobile-portrait/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/@mobile-portrait/edge.png b/tests/visual/baseline/ci/admonition/@mobile-portrait/edge.png new file mode 100644 index 000000000..5df11ca2a Binary files /dev/null and b/tests/visual/baseline/ci/admonition/@mobile-portrait/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/@mobile-portrait/firefox.png b/tests/visual/baseline/ci/admonition/@mobile-portrait/firefox.png new file mode 100644 index 000000000..98fbc5763 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/@mobile-portrait/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/@mobile-portrait/ie11.png b/tests/visual/baseline/ci/admonition/@mobile-portrait/ie11.png new file mode 100644 index 000000000..48d8da9a7 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/@mobile-portrait/ie11.png differ diff --git a/tests/visual/baseline/ci/admonition/@tablet-portrait/chrome.png b/tests/visual/baseline/ci/admonition/@tablet-portrait/chrome.png new file mode 100644 index 000000000..6fa17da83 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/@tablet-portrait/chrome.png differ diff --git a/tests/visual/baseline/ci/admonition/@tablet-portrait/edge.png b/tests/visual/baseline/ci/admonition/@tablet-portrait/edge.png new file mode 100644 index 000000000..79f3e9690 Binary files /dev/null and b/tests/visual/baseline/ci/admonition/@tablet-portrait/edge.png differ diff --git a/tests/visual/baseline/ci/admonition/@tablet-portrait/firefox.png b/tests/visual/baseline/ci/admonition/@tablet-portrait/firefox.png new file mode 100644 index 000000000..6e261b87c Binary files /dev/null and b/tests/visual/baseline/ci/admonition/@tablet-portrait/firefox.png differ diff --git a/tests/visual/baseline/ci/admonition/@tablet-portrait/ie11.png b/tests/visual/baseline/ci/admonition/@tablet-portrait/ie11.png new file mode 100644 index 000000000..9f50f7a5a Binary files /dev/null and b/tests/visual/baseline/ci/admonition/@tablet-portrait/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/@screen/chrome.png new file mode 100644 index 000000000..d7b443215 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/@screen/edge.png new file mode 100644 index 000000000..bcc4dcf4e Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/@screen/firefox.png new file mode 100644 index 000000000..1fa33b1ff Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/@screen/ie11.png new file mode 100644 index 000000000..c95c80a2e Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/@tablet-landscape/chrome.png new file mode 100644 index 000000000..558019e44 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/@tablet-landscape/edge.png new file mode 100644 index 000000000..d47134ea9 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/@tablet-landscape/firefox.png new file mode 100644 index 000000000..cb1047d04 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/@tablet-landscape/ie11.png new file mode 100644 index 000000000..b7ceb3442 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@screen/chrome.png new file mode 100644 index 000000000..cbbd9d515 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@screen/edge.png new file mode 100644 index 000000000..9831312fa Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@screen/firefox.png new file mode 100644 index 000000000..e17b4849a Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@screen/ie11.png new file mode 100644 index 000000000..7c2ab08eb Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@tablet-landscape/chrome.png new file mode 100644 index 000000000..f7948a2ba Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@tablet-landscape/edge.png new file mode 100644 index 000000000..c28eb5917 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@tablet-landscape/firefox.png new file mode 100644 index 000000000..b269cc525 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@tablet-landscape/ie11.png new file mode 100644 index 000000000..a6878135a Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@screen/chrome.png new file mode 100644 index 000000000..5f4cee256 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@screen/edge.png new file mode 100644 index 000000000..ea738bed9 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@screen/firefox.png new file mode 100644 index 000000000..fe68dfb74 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@screen/ie11.png new file mode 100644 index 000000000..32c32fb98 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@tablet-landscape/chrome.png new file mode 100644 index 000000000..7855db4eb Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@tablet-landscape/edge.png new file mode 100644 index 000000000..0bb9782f4 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@tablet-landscape/firefox.png new file mode 100644 index 000000000..c9336ce51 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@tablet-landscape/ie11.png new file mode 100644 index 000000000..8edc6ec79 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:focus/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@screen/chrome.png new file mode 100644 index 000000000..5f4cee256 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@screen/edge.png new file mode 100644 index 000000000..ea738bed9 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@screen/firefox.png new file mode 100644 index 000000000..fe68dfb74 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@screen/ie11.png new file mode 100644 index 000000000..32c32fb98 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@tablet-landscape/chrome.png new file mode 100644 index 000000000..3ba33f63b Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@tablet-landscape/edge.png new file mode 100644 index 000000000..8c0ab418d Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@tablet-landscape/firefox.png new file mode 100644 index 000000000..b98a65427 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@tablet-landscape/ie11.png new file mode 100644 index 000000000..74ecf3623 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/:hover/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@screen/chrome.png new file mode 100644 index 000000000..fc3a74a0b Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@screen/edge.png new file mode 100644 index 000000000..be81431da Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@screen/firefox.png new file mode 100644 index 000000000..0ff4c52e6 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@screen/ie11.png new file mode 100644 index 000000000..33da3be18 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@tablet-landscape/chrome.png new file mode 100644 index 000000000..51dbd3dfb Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@tablet-landscape/edge.png new file mode 100644 index 000000000..e594e8416 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@tablet-landscape/firefox.png new file mode 100644 index 000000000..56e083c08 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@tablet-landscape/ie11.png new file mode 100644 index 000000000..baebdb23e Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item--nested/md-nav__link/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@screen/chrome.png new file mode 100644 index 000000000..e00a4b9e8 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@screen/edge.png new file mode 100644 index 000000000..a6956142a Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@screen/firefox.png new file mode 100644 index 000000000..e6db53055 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@screen/ie11.png new file mode 100644 index 000000000..8e9919c74 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@tablet-landscape/chrome.png new file mode 100644 index 000000000..ee77b9d72 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@tablet-landscape/edge.png new file mode 100644 index 000000000..c087fdb7d Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@tablet-landscape/firefox.png new file mode 100644 index 000000000..b5ef05fa8 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@tablet-landscape/ie11.png new file mode 100644 index 000000000..fba03c788 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/:last-child/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@screen/chrome.png new file mode 100644 index 000000000..7937c1bdf Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@screen/edge.png new file mode 100644 index 000000000..d115b29c1 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@screen/firefox.png new file mode 100644 index 000000000..17b22ca8f Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@screen/ie11.png new file mode 100644 index 000000000..4e48abaf3 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@tablet-landscape/chrome.png new file mode 100644 index 000000000..86390b3e3 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@tablet-landscape/edge.png new file mode 100644 index 000000000..ea4ee7a61 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@tablet-landscape/firefox.png new file mode 100644 index 000000000..a51a29d3d Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@tablet-landscape/ie11.png new file mode 100644 index 000000000..6d91ad847 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__item/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@screen/chrome.png new file mode 100644 index 000000000..24b2ace16 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@screen/edge.png new file mode 100644 index 000000000..2d7890d44 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@screen/firefox.png new file mode 100644 index 000000000..f6363e99a Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@screen/ie11.png new file mode 100644 index 000000000..d472a0ddc Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@tablet-landscape/chrome.png new file mode 100644 index 000000000..a9dbff0f7 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@tablet-landscape/edge.png new file mode 100644 index 000000000..5ecb66589 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@tablet-landscape/firefox.png new file mode 100644 index 000000000..dbdbe508a Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@tablet-landscape/ie11.png new file mode 100644 index 000000000..333513c22 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:focus/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@screen/chrome.png new file mode 100644 index 000000000..24b2ace16 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@screen/edge.png new file mode 100644 index 000000000..2d7890d44 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@screen/firefox.png new file mode 100644 index 000000000..f6363e99a Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@screen/ie11.png new file mode 100644 index 000000000..d472a0ddc Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@tablet-landscape/chrome.png new file mode 100644 index 000000000..a9dbff0f7 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@tablet-landscape/edge.png new file mode 100644 index 000000000..5ecb66589 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@tablet-landscape/firefox.png new file mode 100644 index 000000000..dbdbe508a Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@tablet-landscape/ie11.png new file mode 100644 index 000000000..333513c22 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/:hover/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@screen/chrome.png new file mode 100644 index 000000000..c462bccb1 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@screen/edge.png new file mode 100644 index 000000000..28292e44c Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@screen/firefox.png new file mode 100644 index 000000000..9c025e1fa Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@screen/ie11.png new file mode 100644 index 000000000..bdac1c999 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@tablet-landscape/chrome.png new file mode 100644 index 000000000..86390b3e3 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@tablet-landscape/edge.png new file mode 100644 index 000000000..ea4ee7a61 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@tablet-landscape/firefox.png new file mode 100644 index 000000000..a51a29d3d Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@tablet-landscape/ie11.png new file mode 100644 index 000000000..6d91ad847 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link--active/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@screen/chrome.png new file mode 100644 index 000000000..95e4ce420 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@screen/edge.png new file mode 100644 index 000000000..617ef556d Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@screen/firefox.png new file mode 100644 index 000000000..a95e596d9 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@screen/ie11.png new file mode 100644 index 000000000..b38b18734 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@tablet-landscape/chrome.png new file mode 100644 index 000000000..da8249a2c Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@tablet-landscape/edge.png new file mode 100644 index 000000000..a61d2f9d8 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@tablet-landscape/firefox.png new file mode 100644 index 000000000..b602a8d98 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@tablet-landscape/ie11.png new file mode 100644 index 000000000..79a490781 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:focus/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@screen/chrome.png new file mode 100644 index 000000000..95e4ce420 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@screen/edge.png new file mode 100644 index 000000000..617ef556d Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@screen/firefox.png new file mode 100644 index 000000000..a95e596d9 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@screen/ie11.png new file mode 100644 index 000000000..b38b18734 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@tablet-landscape/chrome.png new file mode 100644 index 000000000..da8249a2c Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@tablet-landscape/edge.png new file mode 100644 index 000000000..a61d2f9d8 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@tablet-landscape/firefox.png new file mode 100644 index 000000000..b602a8d98 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@tablet-landscape/ie11.png new file mode 100644 index 000000000..79a490781 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/:hover/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@screen/chrome.png new file mode 100644 index 000000000..f5c9f2907 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@screen/edge.png new file mode 100644 index 000000000..11a9d57d6 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@screen/firefox.png new file mode 100644 index 000000000..c29eb0aac Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@screen/ie11.png new file mode 100644 index 000000000..5cc0296d6 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@tablet-landscape/chrome.png new file mode 100644 index 000000000..1b2b89acd Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@tablet-landscape/edge.png new file mode 100644 index 000000000..8ddef6eb8 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@tablet-landscape/firefox.png new file mode 100644 index 000000000..2bf7ce201 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@tablet-landscape/ie11.png new file mode 100644 index 000000000..648f4ee4d Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__link/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@screen/chrome.png new file mode 100644 index 000000000..5a675a3ac Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@screen/edge.png new file mode 100644 index 000000000..f9abf1044 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@screen/firefox.png new file mode 100644 index 000000000..f63317db9 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@screen/ie11.png new file mode 100644 index 000000000..0b4d52a2d Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@tablet-landscape/chrome.png new file mode 100644 index 000000000..6a8c19126 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@tablet-landscape/edge.png new file mode 100644 index 000000000..9449614f5 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@tablet-landscape/firefox.png new file mode 100644 index 000000000..0514d7603 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@tablet-landscape/ie11.png new file mode 100644 index 000000000..ca6710d29 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/@tablet-landscape/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@screen/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@screen/chrome.png new file mode 100644 index 000000000..d209af913 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@screen/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@screen/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@screen/edge.png new file mode 100644 index 000000000..4d1fa3b89 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@screen/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@screen/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@screen/firefox.png new file mode 100644 index 000000000..a47b29a5f Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@screen/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@screen/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@screen/ie11.png new file mode 100644 index 000000000..e8fa9f986 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@screen/ie11.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@tablet-landscape/chrome.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@tablet-landscape/chrome.png new file mode 100644 index 000000000..b495ebc93 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@tablet-landscape/chrome.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@tablet-landscape/edge.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@tablet-landscape/edge.png new file mode 100644 index 000000000..2aa3dae80 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@tablet-landscape/edge.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@tablet-landscape/firefox.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@tablet-landscape/firefox.png new file mode 100644 index 000000000..467f52487 Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@tablet-landscape/firefox.png differ diff --git a/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@tablet-landscape/ie11.png b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@tablet-landscape/ie11.png new file mode 100644 index 000000000..cbc8efdac Binary files /dev/null and b/tests/visual/baseline/ci/md-nav--primary/md-nav__title/~overflow/@tablet-landscape/ie11.png differ diff --git a/tests/visual/config.json b/tests/visual/config.json new file mode 100644 index 000000000..61e746b6d --- /dev/null +++ b/tests/visual/config.json @@ -0,0 +1,39 @@ +{ + "breakpoints": [ + { + "name": "mobile-portrait", + "size": { + "width": 320, + "height": 600 + } + }, + { + "name": "mobile-landscape", + "size": { + "width": 560, + "height": 600 + } + }, + { + "name": "tablet-portrait", + "size": { + "width": 800, + "height": 600 + } + }, + { + "name": "tablet-landscape", + "size": { + "width": 1020, + "height": 600 + } + }, + { + "name": "screen", + "size": { + "width": 1280, + "height": 600 + } + } + ] +} diff --git a/tests/visual/config/gemini.sauce-connect.json b/tests/visual/config/gemini.sauce-connect.json new file mode 100644 index 000000000..a3fe7f317 --- /dev/null +++ b/tests/visual/config/gemini.sauce-connect.json @@ -0,0 +1,49 @@ +{ + "rootUrl": "http://localhost:8000", + "gridUrl": "http://ondemand.saucelabs.com/wd/hub", + "screenshotsDir": "./tests/visual/baseline/ci", + "browsers": { + "chrome": { + "desiredCapabilities": { + "browserName": "chrome", + "platform": "Windows 10", + "screenResolution": "1280x1024", + "recordVideo": "false" + } + }, + "firefox": { + "desiredCapabilities": { + "browserName": "firefox", + "version": "47.0", + "platform": "Windows 10", + "screenResolution": "1280x1024", + "recordVideo": "false" + } + }, + "edge": { + "desiredCapabilities": { + "browserName": "MicrosoftEdge", + "platform": "Windows 10", + "screenResolution": "1280x1024", + "recordVideo": "false", + "tolerance": 3.5 + } + }, + "ie11": { + "desiredCapabilities": { + "browserName": "internet explorer", + "version": "11.103", + "platform": "Windows 10", + "screenResolution": "1280x1024", + "recordVideo": "false" + } + } + }, + "system": { + "projectRoot": ".", + "sourceRoot": "./tests/visual/data", + "coverage": { + "enabled": false + } + } +} diff --git a/tests/visual/config/gemini.selenium.json b/tests/visual/config/gemini.selenium.json new file mode 100644 index 000000000..2c657e797 --- /dev/null +++ b/tests/visual/config/gemini.selenium.json @@ -0,0 +1,18 @@ +{ + "rootUrl": "http://localhost:8000", + "screenshotsDir": "./tests/visual/baseline/local", + "browsers": { + "local-chrome": { + "desiredCapabilities": { + "browserName": "chrome" + } + } + }, + "system": { + "projectRoot": ".", + "sourceRoot": "./tests/visual/data", + "coverage": { + "enabled": false + } + } +} diff --git a/tests/visual/helpers/spec.js b/tests/visual/helpers/spec.js new file mode 100644 index 000000000..0c41dacf1 --- /dev/null +++ b/tests/visual/helpers/spec.js @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2016-2017 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import config from "../config.json" +import path from "path" +import yargs from "yargs" + +/* ---------------------------------------------------------------------------- + * Configuration and arguments + * ------------------------------------------------------------------------- */ + +/* Parse arguments from command line */ +const args = yargs.argv + +/* ---------------------------------------------------------------------------- + * Functions + * ------------------------------------------------------------------------- */ + +/** + * Resolve relevant breakpoints matching expression + * + * The breakpoints are assumed to be specified by their names set in the + * configuration file, prefixed with an "@" character. + * + * There are three selection modes: + * + * 1. -@bp: The specified breakpoint and all preceding + * 2. @bp: Only the specified breakpoint + * 3. +@bp: The specified breakpoint and all following + * + * @param {Array.} breakpoints - Breakpoints + * @param {string} expr - Expression + * @return {Array.} Selected breakpoints + */ +const resolve = (breakpoints, expr) => { + if (typeof expr === "undefined") + return breakpoints + + /* Split expression and find the offset of the specified breakpoint */ + const [mode, name] = expr.split("@") + const index = breakpoints.findIndex( + breakpoint => breakpoint.name === name) + + /* Determine whether to go up or down */ + const from = mode !== "-" ? index : 0 + const to = mode !== "+" ? index + 1 : breakpoints.length + + /* Return relevant breakpoints */ + return breakpoints.slice(from, to) +} + +/** + * Filter a set of test suites using a regular expression + * + * @param {Array.} components - Component specifications + * @param {Array.} parent - Parent test suite names + * @return {boolean} Whether at least one suite was kept + */ +const filter = (components, parent = []) => { + const regexp = new RegExp(args.grep.replace(" ", ".*?"), "i") + return Object.keys(components).reduce((match, name) => { + const component = components[name] + + /* Deep-copy current path and call recursive */ + const temp = parent.slice(0).concat(name) + const keep = filter(component.suite || {}, temp) + + /* Remove all states that do not match the regular expression */ + component.states = (component.states || [{ name: "", wait: 0 }]).reduce( + (states, state) => { + const fullname = temp.slice(0) + .concat(state.name.length ? [state.name] : []) + .join(" ") + if (regexp.test(fullname)) + states.push(state) + return states + }, []) + + /* Keep komponent, if there is at least one state or the component has + matching subsuites, so it needs to be kept */ + if (component.states.length || keep) { + if (keep) { + delete component.capture + delete component.break + } + return true + } + + /* Otherwise, delete component */ + delete components[name] + return match + }, false) +} + +/** + * Generate Gemini test suites for the given components + * + * @param {string} dirname - Directory of the test suite + * @param {Array.} components - Component specifications // TODO: document syntax and specificagtion + */ +const generate = (dirname, components) => { + const base = path.relative(`${__dirname}/../suites`, dirname) + + /* Generate a suite for every component */ + for (const name of Object.keys(components)) { + const component = components[name] + + /* Create suite */ + gemini.suite(name, suite => { + if (component.dir || component.url) + suite.setUrl(path.join( + base, component.dir ? component.dir : "", + "_", component.url ? component.url : "")) + + /* The capture selector is assumed to exist */ + if (component.capture) + suite.setCaptureElements(component.capture) + + /* Generate a subsuite for every state */ + const states = component.states || [{ name: "", wait: 0 }] + for (const state of states) { + const test = subsuite => { + + /* Resolve and apply relevant breakpoints */ + const breakpoints = resolve(config.breakpoints, component.break) + for (const breakpoint of breakpoints) { + subsuite.capture(`@${breakpoint.name}`, actions => { + + /* Set window size according to breakpoint */ + actions.setWindowSize( + breakpoint.size.width, breakpoint.size.height) + + /* Add the name as a CSS class to the captured element */ + if (state.name) + actions.executeJS(new Function(` + document.querySelector( + "${component.capture}" + ).classList.add("${state.name}") + `)) + + /* Execute function inside an IIFE */ + if (state.exec) + actions.executeJS(new Function(`(${state.exec})()`)) + + /* Wait the specified time before taking a screenshot */ + if (state.wait) + actions.wait(state.wait) + }) + } + } + + /* No state sub-suite if the name is empty */ + if (state.name.length > 0) + gemini.suite(state.name, subsuite => test(subsuite)) + else + test(suite) + } + + /* Generate sub-suites */ + generate(dirname, component.suite || {}) + }) + } +} + +/** + * Register Gemini test suites for the given components + * + * @param {string} dirname - Directory of the test suite + * @param {Array.} components - Component specifications + */ +const register = (dirname, components) => { + if (args.grep) + filter(components) + generate(dirname, components) +} + +/* ---------------------------------------------------------------------------- + * Exports + * ------------------------------------------------------------------------- */ + +export default { + register +} diff --git a/tests/visual/suites/extensions/admonition/docs/index.md b/tests/visual/suites/extensions/admonition/docs/index.md new file mode 100644 index 000000000..572e14f97 --- /dev/null +++ b/tests/visual/suites/extensions/admonition/docs/index.md @@ -0,0 +1,107 @@ +# Suite + + + +## Default + +!!! note + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +## Format + +### Custom title + +!!! note "Phasellus posuere in sem ut cursus" + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +### Long title + +!!! note "Phasellus posuere in sem ut cursus. Nullam sit amet tincidunt ipsum, sit amet elementum turpis. Etiam ipsum quam, mattis in purus vitae, lacinia fermentum enim." + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +### Empty title + +!!! note "" + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +## Types + +### Note + +!!! note + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +### Summary + +!!! summary + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +### Tip + +!!! tip + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +### Success + +!!! success + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +### Warning + +!!! warning + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +### Failure + +!!! failure + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +### Danger + +!!! danger + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +### Bug + +!!! bug + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. diff --git a/tests/visual/suites/extensions/admonition/mkdocs.yml b/tests/visual/suites/extensions/admonition/mkdocs.yml new file mode 100644 index 000000000..b36cdc90b --- /dev/null +++ b/tests/visual/suites/extensions/admonition/mkdocs.yml @@ -0,0 +1,28 @@ +# Copyright (c) 2016-2017 Martin Donath + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# Test suite +site_name: Admonition Test +markdown_extensions: + - markdown.extensions.admonition + +# Reset webfonts because of flaky tests +extra: + font: none diff --git a/tests/visual/suites/extensions/admonition/suite.js b/tests/visual/suites/extensions/admonition/suite.js new file mode 100644 index 000000000..7bdbb33c5 --- /dev/null +++ b/tests/visual/suites/extensions/admonition/suite.js @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016-2017 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import spec from "~/tests/visual/helpers/spec" + +/* ---------------------------------------------------------------------------- + * Tests + * ------------------------------------------------------------------------- */ + +/* + * Admonition extension + * + * The admonition block looks the same on everything above tablet + * portrait, so we can save a few test cases. + */ +spec.register(__dirname, { + "admonition": { + "url": "/", + "capture": "#default + .admonition", + "break": "-@tablet-portrait", + "suite": { + + /* Admonition block with a custom title */ + "#custom-title": { + "capture": "#custom-title + .admonition", + "break": "@screen" + }, + + /* Admonition block with a long title */ + "#long-title": { + "capture": "#long-title + .admonition", + "break": "@screen" + }, + + /* Admonition block with an empty title */ + "#empty-title": { + "capture": "#empty-title + .admonition", + "break": "@screen" + }, + + /* Admonition block of type "note" */ + "#note": { + "capture": "#note + .admonition", + "break": "@screen" + }, + + /* Admonition block of type "summary" */ + "#summary": { + "capture": "#summary + .admonition", + "break": "@screen" + }, + + /* Admonition block of type "tip" */ + "#tip": { + "capture": "#tip + .admonition", + "break": "@screen" + }, + + /* Admonition block of type "success" */ + "#success": { + "capture": "#success + .admonition", + "break": "@screen" + }, + + /* Admonition block of type "warning" */ + "#warning": { + "capture": "#warning + .admonition", + "break": "@screen" + }, + + /* Admonition block of type "failure" */ + "#failure": { + "capture": "#failure + .admonition", + "break": "@screen" + }, + + /* Admonition block of type "danger" */ + "#danger": { + "capture": "#danger + .admonition", + "break": "@screen" + }, + + /* Admonition block of type "bug" */ + "#bug": { + "capture": "#bug + .admonition", + "break": "@screen" + } + } + } +}) diff --git a/tests/visual/suites/layout/nav/_overflow/docs/default.md b/tests/visual/suites/layout/nav/_overflow/docs/default.md new file mode 100644 index 000000000..89967d7e7 --- /dev/null +++ b/tests/visual/suites/layout/nav/_overflow/docs/default.md @@ -0,0 +1,9 @@ +# Suite + + diff --git a/tests/visual/suites/layout/nav/_overflow/docs/index.md b/tests/visual/suites/layout/nav/_overflow/docs/index.md new file mode 100644 index 000000000..89967d7e7 --- /dev/null +++ b/tests/visual/suites/layout/nav/_overflow/docs/index.md @@ -0,0 +1,9 @@ +# Suite + + diff --git a/tests/visual/suites/layout/nav/_overflow/mkdocs.yml b/tests/visual/suites/layout/nav/_overflow/mkdocs.yml new file mode 100644 index 000000000..3ce249dcf --- /dev/null +++ b/tests/visual/suites/layout/nav/_overflow/mkdocs.yml @@ -0,0 +1,32 @@ +# Copyright (c) 2016-2017 Martin Donath + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# Test suite +site_name: Pneumonoultramicroscopicsilicovolcanoconiosis +pages: + - Pneumonoultramicroscopicsilicovolcanoconiosis: index.md + - Supercalifragilisticexpialidocious: + - Pseudopseudohypoparathyroidism: default.md + - Floccinaucinihilipilification: default.md + - Antidisestablishmentarianism: default.md + +# Reset webfonts because of flaky tests +extra: + font: none diff --git a/tests/visual/suites/layout/nav/docs/default.md b/tests/visual/suites/layout/nav/docs/default.md new file mode 100644 index 000000000..89967d7e7 --- /dev/null +++ b/tests/visual/suites/layout/nav/docs/default.md @@ -0,0 +1,9 @@ +# Suite + + diff --git a/tests/visual/suites/layout/nav/docs/index.md b/tests/visual/suites/layout/nav/docs/index.md new file mode 100644 index 000000000..89967d7e7 --- /dev/null +++ b/tests/visual/suites/layout/nav/docs/index.md @@ -0,0 +1,9 @@ +# Suite + + diff --git a/tests/visual/suites/layout/nav/mkdocs.yml b/tests/visual/suites/layout/nav/mkdocs.yml new file mode 100644 index 000000000..51f48cc59 --- /dev/null +++ b/tests/visual/suites/layout/nav/mkdocs.yml @@ -0,0 +1,35 @@ +# Copyright (c) 2016-2017 Martin Donath + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# Test suite +site_name: Test/Navigation +pages: + - Lorem ipsum dolor sit amet: index.md + - Consectetur adipiscing elit: default.md + - Etiam condimentum lacinia urna id vestibulum: default.md + - A dapibus turpis iaculis at: + - Donec tortor sem: default.md + - Scelerisque ut congue id: default.md + - Pretium ac risus: default.md + - Maecenas tincidunt nulla dui: default.md + +# Reset webfonts because of flaky tests +extra: + font: none diff --git a/tests/visual/suites/layout/nav/suite.js b/tests/visual/suites/layout/nav/suite.js new file mode 100644 index 000000000..aea23679c --- /dev/null +++ b/tests/visual/suites/layout/nav/suite.js @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2016-2017 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import spec from "~/tests/visual/helpers/spec" + +/* ---------------------------------------------------------------------------- + * Functions + * ------------------------------------------------------------------------- */ + +/** + * Open the drawer + */ +const open = () => { + const drawer = document.querySelector("[data-md-toggle=\"drawer\"]") + drawer.checked = true +} + +/* ---------------------------------------------------------------------------- + * Tests + * ------------------------------------------------------------------------- */ + +/* + * Main navigation + */ +spec.register(__dirname, { + "md-nav--primary": { + "url": "/", + "capture": ".md-nav--primary", + "break": "+@tablet-landscape", + "states": [ + { "name": "", "wait": 250, "exec": open } + ], + "suite": { + + /* List title */ + "md-nav__title": { + "capture": ".md-nav--primary .md-nav__title", + "break": "+@tablet-landscape", + "states": [ + { "name": "", "wait": 250, "exec": open } + ], + "suite": { + + /* Long list title with ellipsis */ + "~overflow": { + "dir": "_overflow", + "capture": ".md-nav--primary .md-nav__title", + "break": "+@tablet-landscape", + "states": [ + { "name": "", "wait": 250, "exec": open } + ] + } + } + }, + + /* List item */ + "md-nav__item": { + "capture": ".md-nav--primary .md-nav__item", + "break": "+@tablet-landscape", + "states": [ + { "name": "", "wait": 250, "exec": open } + ], + "suite": { + + /* Last list item */ + ":last-child": { + "capture": + ".md-nav--primary > .md-nav__list > " + + ".md-nav__item:last-child", + "break": "+@tablet-landscape", + "states": [ + { "name": "", "wait": 250, "exec": open } + ] + } + } + }, + + /* Item contains a nested list */ + "md-nav__item--nested": { + "capture": ".md-nav--primary .md-nav__item--nested", + "break": "+@tablet-landscape", + "states": [ + { "name": "", "wait": 250, "exec": open } + ], + "suite": { + + /* Link inside item that contains a nested list */ + "md-nav__link": { + "capture": + ".md-nav--primary .md-nav__item--nested " + + ".md-nav__link", + "break": "+@tablet-landscape", + "states": [ + { "name": "", "wait": 250, "exec": open }, + { "name": ":focus", "wait": 250, "exec": open }, + { "name": ":hover", "wait": 250, "exec": open } + ] + } + } + }, + + /* Link inside item */ + "md-nav__link": { + "capture": ".md-nav--primary .md-nav__item:nth-child(2) .md-nav__link", + "break": "+@tablet-landscape", + "states": [ + { "name": "", "wait": 250, "exec": open }, + { "name": ":focus", "wait": 250, "exec": open }, + { "name": ":hover", "wait": 250, "exec": open } + ] + }, + + /* Active link */ + "md-nav__link--active": { + "capture": ".md-nav--primary .md-nav__item .md-nav__link--active", + "break": "+@tablet-landscape", + "states": [ + { "name": "", "wait": 250, "exec": open }, + { "name": ":focus", "wait": 250, "exec": open }, + { "name": ":hover", "wait": 250, "exec": open } + ] + } + } + } +})