Commit e2d68a6f authored by hyeryung's avatar hyeryung

init

parents
Pipeline #18872 canceled with stages
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
{
"extends": "standard",
"rules": {
"arrow-parens": ["error", "always"],
"comma-dangle": ["error", {
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "always-multiline",
"exports": "always-multiline"
}],
"no-restricted-properties": ["error", {
"property": "substr",
"message": "Use String#slice instead."
}],
"max-len": [1, 120, 2],
"spaced-comment": "off",
"radix": ["error", "always"]
}
}
/build/
/node_modules/
/public/
image: node:10.14.2-stretch
stages: [setup, verify, deploy]
install:
stage: setup
cache:
paths:
- .cache/npm
script:
- &npm_install npm install --quiet --no-progress --cache=.cache/npm
lint:
stage: verify
cache: &pull_cache
policy: pull
paths:
- .cache/npm
script:
- *npm_install
- node_modules/.bin/gulp lint
bundle-stable:
stage: deploy
only:
- master@swd/swlab-ui
cache: *pull_cache
script:
- *npm_install
- node_modules/.bin/gulp bundle
artifacts:
paths:
- build/ui-bundle.zip
bundle-dev:
stage: deploy
except:
- master
cache: *pull_cache
script:
- *npm_install
- node_modules/.bin/gulp bundle
artifacts:
expire_in: 1 day # unless marked as keep from job page
paths:
- build/ui-bundle.zip
pages:
stage: deploy
only:
- master@swd/swlab-ui
cache: *pull_cache
script:
- *npm_install
- node_modules/.bin/gulp preview:build
# FIXME figure out a way to avoid copying these files to preview site
- rm -rf public/_/{helpers,layouts,partials}
artifacts:
paths:
- public
{
"description": "Build tasks for the SWLab UI project",
"flags.tasksDepth": 1
}
{
"extends": "stylelint-config-standard",
"rules": {
"comment-empty-line-before": null,
"no-descending-specificity": null,
}
}
This diff is collapsed.
# SWLab UI
'use strict'
const metadata = require('undertaker/lib/helpers/metadata')
const { watch } = require('gulp')
module.exports = ({ name, desc, opts, call: fn, loop }) => {
if (name) {
const displayName = fn.displayName
if (displayName === '<series>' || displayName === '<parallel>') {
metadata.get(fn).tree.label = `${displayName} ${name}`
}
fn.displayName = name
}
if (loop) {
const delegate = fn
name = delegate.displayName
delegate.displayName = `${name}:loop`
fn = () => watch(loop, { ignoreInitial: false }, delegate)
fn.displayName = name
}
if (desc) fn.description = desc
if (opts) fn.flags = opts
return fn
}
'use strict'
module.exports = (...tasks) => {
const seed = {}
if (tasks.length) {
if (tasks.lastIndexOf(tasks[0]) > 0) {
const task1 = tasks.shift()
seed.default = Object.assign(task1.bind(null), { description: `=> ${task1.displayName}`, displayName: 'default' })
}
return tasks.reduce((acc, it) => (acc[it.displayName || it.name] = it) && acc, seed)
} else {
return seed
}
}
'use strict'
const log = require('fancy-log')
const PluginError = require('plugin-error')
const prettierEslint = require('prettier-eslint')
const { Transform } = require('stream')
const map = (transform) => new Transform({ objectMode: true, transform })
module.exports = () => {
const report = { changed: 0, unchanged: 0 }
return map(format).on('finish', () => {
if (report.changed > 0) {
const changed = 'formatted '
.concat(report.changed)
.concat(' file')
.concat(report.changed === 1 ? '' : 's')
const unchanged = 'left '
.concat(report.unchanged)
.concat(' file')
.concat(report.unchanged === 1 ? '' : 's')
.concat(' unchanged')
log(`prettier-eslint: ${changed}; ${unchanged}`)
} else {
log(`prettier-eslint: left ${report.unchanged} file${report.unchanged === 1 ? '' : 's'} unchanged`)
}
})
function format (file, enc, next) {
if (file.isNull()) return next()
if (file.isStream()) return next(new PluginError('gulp-prettier-eslint', 'Streaming not supported'))
const input = file.contents.toString()
const output = prettierEslint({ text: input, filePath: file.path })
if (input === output) {
report.unchanged += 1
} else {
report.changed += 1
file.contents = Buffer.from(output)
}
next(null, file)
}
}
'use strict'
const Asciidoctor = require('@asciidoctor/core')()
const fs = require('fs-extra')
const handlebars = require('handlebars')
const merge = require('merge-stream')
const ospath = require('path')
const path = ospath.posix
const requireFromString = require('require-from-string')
const { Transform } = require('stream')
const map = (transform = () => {}, flush = undefined) => new Transform({ objectMode: true, transform, flush })
const vfs = require('vinyl-fs')
const yaml = require('js-yaml')
const ASCIIDOC_ATTRIBUTES = { experimental: '', icons: 'font', sectanchors: '', 'source-highlighter': 'highlight.js' }
module.exports = (src, previewSrc, previewDest, sink = () => map()) => (done) =>
Promise.all([
loadSampleUiModel(previewSrc),
toPromise(
merge(compileLayouts(src), registerPartials(src), registerHelpers(src), copyImages(previewSrc, previewDest))
),
])
.then(([baseUiModel, { layouts }]) => {
const extensions = ((baseUiModel.asciidoc || {}).extensions || []).map((request) => {
ASCIIDOC_ATTRIBUTES[request.replace(/^@|\.js$/, '').replace(/[/]/g, '-') + '-loaded'] = ''
const extension = require(request)
extension.register.call(Asciidoctor.Extensions)
return extension
})
const asciidoc = { extensions }
for (const component of baseUiModel.site.components) {
for (const version of component.versions || []) version.asciidoc = asciidoc
}
baseUiModel = { ...baseUiModel, env: process.env }
delete baseUiModel.asciidoc
return [baseUiModel, layouts]
})
.then(([baseUiModel, layouts]) =>
vfs
.src('**/*.adoc', { base: previewSrc, cwd: previewSrc })
.pipe(
map((file, enc, next) => {
const siteRootPath = path.relative(ospath.dirname(file.path), ospath.resolve(previewSrc))
const uiModel = { ...baseUiModel }
uiModel.page = { ...uiModel.page }
uiModel.siteRootPath = siteRootPath
uiModel.uiRootPath = path.join(siteRootPath, '_')
if (file.stem === '404') {
uiModel.page = { layout: '404', title: 'Page Not Found' }
} else {
const doc = Asciidoctor.load(file.contents, { safe: 'safe', attributes: ASCIIDOC_ATTRIBUTES })
uiModel.page.attributes = Object.entries(doc.getAttributes())
.filter(([name, val]) => name.startsWith('page-'))
.reduce((accum, [name, val]) => {
accum[name.slice(5)] = val
return accum
}, {})
uiModel.page.layout = doc.getAttribute('page-layout', 'default')
uiModel.page.title = doc.getDocumentTitle()
uiModel.page.contents = Buffer.from(doc.convert())
}
file.extname = '.html'
try {
file.contents = Buffer.from(layouts.get(uiModel.page.layout)(uiModel))
next(null, file)
} catch (e) {
next(transformHandlebarsError(e, uiModel.page.layout))
}
})
)
.pipe(vfs.dest(previewDest))
.on('error', done)
.pipe(sink())
)
function loadSampleUiModel (src) {
return fs.readFile(ospath.join(src, 'ui-model.yml'), 'utf8').then((contents) => yaml.safeLoad(contents))
}
function registerPartials (src) {
return vfs.src('partials/*.hbs', { base: src, cwd: src }).pipe(
map((file, enc, next) => {
handlebars.registerPartial(file.stem, file.contents.toString())
next()
})
)
}
function registerHelpers (src) {
handlebars.registerHelper('resolvePage', resolvePage)
handlebars.registerHelper('resolvePageURL', resolvePageURL)
return vfs.src('helpers/*.js', { base: src, cwd: src }).pipe(
map((file, enc, next) => {
handlebars.registerHelper(file.stem, requireFromString(file.contents.toString()))
next()
})
)
}
function compileLayouts (src) {
const layouts = new Map()
return vfs.src('layouts/*.hbs', { base: src, cwd: src }).pipe(
map(
(file, enc, next) => {
const srcName = path.join(src, file.relative)
layouts.set(file.stem, handlebars.compile(file.contents.toString(), { preventIndent: true, srcName }))
next()
},
function (done) {
this.push({ layouts })
done()
}
)
)
}
function copyImages (src, dest) {
return vfs
.src('**/*.{png,svg}', { base: src, cwd: src })
.pipe(vfs.dest(dest))
.pipe(map((file, enc, next) => next()))
}
function resolvePage (spec, context = {}) {
if (spec) return { pub: { url: resolvePageURL(spec) } }
}
function resolvePageURL (spec, context = {}) {
if (spec) return '/' + (spec = spec.split(':').pop()).slice(0, spec.lastIndexOf('.')) + '.html'
}
function transformHandlebarsError ({ message, stack }, layout) {
const m = stack.match(/^ *at Object\.ret \[as (.+?)\]/m)
const templatePath = `src/${m ? 'partials/' + m[1] : 'layouts/' + layout}.hbs`
const err = new Error(`${message}${~message.indexOf('\n') ? '\n^ ' : ' '}in UI template ${templatePath}`)
err.stack = [err.toString()].concat(stack.slice(message.length + 8)).join('\n')
return err
}
function toPromise (stream) {
return new Promise((resolve, reject, data = {}) =>
stream
.on('error', reject)
.on('data', (chunk) => chunk.constructor === Object && Object.assign(data, chunk))
.on('finish', () => resolve(data))
)
}
'use strict'
const autoprefixer = require('autoprefixer')
const browserify = require('browserify')
const concat = require('gulp-concat')
const cssnano = require('cssnano')
const fs = require('fs-extra')
const imagemin = require('gulp-imagemin')
const merge = require('merge-stream')
const ospath = require('path')
const path = ospath.posix
const postcss = require('gulp-postcss')
const postcssCalc = require('postcss-calc')
const postcssImport = require('postcss-import')
const postcssUrl = require('postcss-url')
const postcssVar = require('postcss-custom-properties')
const { Transform } = require('stream')
const map = (transform) => new Transform({ objectMode: true, transform })
const through = () => map((file, enc, next) => next(null, file))
const uglify = require('gulp-uglify')
const vfs = require('vinyl-fs')
module.exports = (src, dest, preview) => () => {
const opts = { base: src, cwd: src }
const sourcemaps = preview || process.env.SOURCEMAPS === 'true'
const postcssPlugins = [
postcssImport,
(css, { messages, opts: { file } }) =>
Promise.all(
messages
.reduce((accum, { file: depPath, type }) => (type === 'dependency' ? accum.concat(depPath) : accum), [])
.map((importedPath) => fs.stat(importedPath).then(({ mtime }) => mtime))
).then((mtimes) => {
const newestMtime = mtimes.reduce((max, curr) => (!max || curr > max ? curr : max), file.stat.mtime)
if (newestMtime > file.stat.mtime) file.stat.mtimeMs = +(file.stat.mtime = newestMtime)
}),
postcssUrl([
{
filter: (asset) => new RegExp('^[~][^/]*(?:font|typeface)[^/]*/.*/files/.+[.](?:ttf|woff2?)$').test(asset.url),
url: (asset) => {
const relpath = asset.pathname.slice(1)
const abspath = require.resolve(relpath)
const basename = ospath.basename(abspath)
const destpath = ospath.join(dest, 'font', basename)
if (!fs.pathExistsSync(destpath)) fs.copySync(abspath, destpath)
return path.join('..', 'font', basename)
},
},
]),
postcssVar({ preserve: preview }),
// NOTE to make vars.css available to all top-level stylesheets, use the next line in place of the previous one
//postcssVar({ importFrom: path.join(src, 'css', 'vars.css'), preserve: preview }),
preview ? postcssCalc : () => {}, // cssnano already applies postcssCalc
autoprefixer,
preview
? () => {}
: (css, result) => cssnano({ preset: 'default' })(css, result).then(() => postcssPseudoElementFixer(css, result)),
]
return merge(
vfs.src('ui.yml', { ...opts, allowEmpty: true }),
vfs
.src('js/+([0-9])-*.js', { ...opts, read: false, sourcemaps })
.pipe(bundle(opts))
.pipe(uglify({ output: { comments: /^! / } }))
// NOTE concat already uses stat from newest combined file
.pipe(concat('js/site.js')),
vfs
.src('js/vendor/*([^.])?(.bundle).js', { ...opts, read: false })
.pipe(bundle(opts))
.pipe(uglify({ output: { comments: /^! / } })),
vfs
.src('js/vendor/*.min.js', opts)
.pipe(map((file, enc, next) => next(null, Object.assign(file, { extname: '' }, { extname: '.js' })))),
// NOTE use the next line to bundle a JavaScript library that cannot be browserified, like jQuery
//vfs.src(require.resolve('<package-name-or-require-path>'), opts).pipe(concat('js/vendor/<library-name>.js')),
vfs
.src(['css/site.css', 'css/vendor/*.css'], { ...opts, sourcemaps })
.pipe(postcss((file) => ({ plugins: postcssPlugins, options: { file } }))),
vfs.src('font/*.{ttf,woff*(2)}', opts),
vfs.src('img/**/*.{gif,ico,jpg,png,svg}', opts).pipe(
preview
? through()
: imagemin(
[
imagemin.gifsicle(),
imagemin.jpegtran(),
imagemin.optipng(),
imagemin.svgo({
plugins: [
{ cleanupIDs: { preservePrefixes: ['icon-', 'view-'] } },
{ removeViewBox: false },
{ removeDesc: false },
],
}),
].reduce((accum, it) => (it ? accum.concat(it) : accum), [])
)
),
vfs.src('helpers/*.js', opts),
vfs.src('layouts/*.hbs', opts),
vfs.src('partials/*.hbs', opts),
vfs.src('static/**/*[!~]', { ...opts, base: ospath.join(src, 'static'), dot: true })
).pipe(vfs.dest(dest, { sourcemaps: sourcemaps && '.' }))
}
function bundle ({ base: basedir, ext: bundleExt = '.bundle.js' }) {
return map((file, enc, next) => {
if (bundleExt && file.relative.endsWith(bundleExt)) {
const mtimePromises = []
const bundlePath = file.path
browserify(file.relative, { basedir, detectGlobals: false })
.plugin('browser-pack-flat/plugin')
.on('file', (bundledPath) => {
if (bundledPath !== bundlePath) mtimePromises.push(fs.stat(bundledPath).then(({ mtime }) => mtime))
})
.bundle((bundleError, bundleBuffer) =>
Promise.all(mtimePromises).then((mtimes) => {
const newestMtime = mtimes.reduce((max, curr) => (curr > max ? curr : max), file.stat.mtime)
if (newestMtime > file.stat.mtime) file.stat.mtimeMs = +(file.stat.mtime = newestMtime)
if (bundleBuffer !== undefined) file.contents = bundleBuffer
next(bundleError, Object.assign(file, { path: file.path.slice(0, file.path.length - 10) + '.js' }))
})
)
return
}
fs.readFile(file.path, 'UTF-8').then((contents) => {
next(null, Object.assign(file, { contents: Buffer.from(contents) }))
})
})
}
function postcssPseudoElementFixer (css, result) {
css.walkRules(/(?:^|[^:]):(?:before|after)/, (rule) => {
rule.selector = rule.selectors.map((it) => it.replace(/(^|[^:]):(before|after)$/, '$1::$2')).join(',')
})
}
'use strict'
const prettier = require('../lib/gulp-prettier-eslint')
const vfs = require('vinyl-fs')
module.exports = (files) => () =>
vfs
.src(files)
.pipe(prettier())
.pipe(vfs.dest((file) => file.base))
'use strict'
const camelCase = (name) => name.replace(/[-]./g, (m) => m.slice(1).toUpperCase())
module.exports = require('require-directory')(module, __dirname, { recurse: false, rename: camelCase })
'use strict'
const stylelint = require('gulp-stylelint')
const vfs = require('vinyl-fs')
module.exports = (files) => (done) =>
vfs
.src(files)
.pipe(stylelint({ reporters: [{ formatter: 'string', console: true }], failAfterError: true }))
.on('error', done)
'use strict'
const eslint = require('gulp-eslint')
const vfs = require('vinyl-fs')
module.exports = (files) => (done) =>
vfs
.src(files)
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError())
.on('error', done)
'use strict'
const ospath = require('path')
const vfs = require('vinyl-fs')
const zip = (() => {
try {
return require('@vscode/gulp-vinyl-zip')
} catch {
return require('gulp-vinyl-zip')
}
})()
module.exports = (src, dest, bundleName, onFinish) => () =>
vfs
.src('**/*', { base: src, cwd: src, dot: true })
.pipe(zip.dest(ospath.join(dest, `${bundleName}-bundle.zip`)))
.on('finish', () => onFinish && onFinish(ospath.resolve(dest, `${bundleName}-bundle.zip`)))
'use strict'
const fs = require('fs-extra')
const { Transform } = require('stream')
const map = (transform) => new Transform({ objectMode: true, transform })
const vfs = require('vinyl-fs')
module.exports = (files) => () =>
vfs.src(files, { allowEmpty: true }).pipe(map((file, enc, next) => fs.remove(file.path, next)))
'use strict'
const connect = require('gulp-connect')
const os = require('os')
const ANY_HOST = '0.0.0.0'
const URL_RX = /(https?):\/\/(?:[^/: ]+)(:\d+)?/
module.exports = (root, opts = {}, watch = undefined) => (done) => {
connect.server({ ...opts, middleware: opts.host === ANY_HOST ? decorateLog : undefined, root }, function () {
this.server.on('close', done)
if (watch) watch()
})
}
function decorateLog (_, app) {
const _log = app.log
app.log = (msg) => {
if (msg.startsWith('Server started ')) {
const localIp = getLocalIp()
const replacement = '$1://localhost$2' + (localIp ? ` and $1://${localIp}$2` : '')
msg = msg.replace(URL_RX, replacement)
}
_log(msg)
}
return []
}
function getLocalIp () {
for (const records of Object.values(os.networkInterfaces())) {
for (const record of records) {
if (!record.internal && record.family === 'IPv4') return record.address
}
}
return 'localhost'
}
'use strict'
const { parallel, series, watch } = require('gulp')
const createTask = require('./gulp.d/lib/create-task')
const exportTasks = require('./gulp.d/lib/export-tasks')
const log = require('fancy-log')
const bundleName = 'ui'
const buildDir = 'build'
const previewSrcDir = 'preview-src'
const previewDestDir = 'public'
const srcDir = 'src'
const destDir = `${previewDestDir}/_`
const { reload: livereload } = process.env.LIVERELOAD === 'true' ? require('gulp-connect') : {}
const serverConfig = { host: '0.0.0.0', port: 5252, livereload }
const task = require('./gulp.d/tasks')
const glob = {
all: [srcDir, previewSrcDir],
css: `${srcDir}/css/**/*.css`,
js: ['gulpfile.js', 'gulp.d/**/*.js', `${srcDir}/helpers/*.js`, `${srcDir}/js/**/+([^.])?(.bundle).js`],
}
const cleanTask = createTask({
name: 'clean',
desc: 'Clean files and folders generated by build',
call: task.remove(['build', 'public']),
})
const lintCssTask = createTask({
name: 'lint:css',
desc: 'Lint the CSS source files using stylelint (standard config)',
call: task.lintCss(glob.css),
})
const lintJsTask = createTask({
name: 'lint:js',
desc: 'Lint the JavaScript source files using eslint (JavaScript Standard Style)',
call: task.lintJs(glob.js),
})
const lintTask = createTask({
name: 'lint',
desc: 'Lint the CSS and JavaScript source files',
call: parallel(lintCssTask, lintJsTask),
})
const formatTask = createTask({
name: 'format',
desc: 'Format the JavaScript source files using prettify (JavaScript Standard Style)',
call: task.format(glob.js),
})
const buildTask = createTask({
name: 'build',
desc: 'Build and stage the UI assets for bundling',
call: task.build(
srcDir,
destDir,
process.argv.slice(2).some((name) => name.startsWith('preview'))
),
})
const bundleBuildTask = createTask({
name: 'bundle:build',
call: series(cleanTask, lintTask, buildTask),
})
const bundlePackTask = createTask({
name: 'bundle:pack',
desc: 'Create a bundle of the staged UI assets for publishing',
call: task.pack(
destDir,
buildDir,
bundleName,
(bundlePath) => !process.env.CI && log(`Antora option: --ui-bundle-url=${bundlePath}`)
),
})
const bundleTask = createTask({
name: 'bundle',
desc: 'Clean, lint, build, and bundle the UI for publishing',
call: series(bundleBuildTask, bundlePackTask),
})
const packTask = createTask({
name: 'pack',
desc: '(deprecated; use bundle instead)',
call: series(bundleTask),
})
const buildPreviewPagesTask = createTask({
name: 'preview:build-pages',
call: task.buildPreviewPages(srcDir, previewSrcDir, previewDestDir, livereload),
})
const previewBuildTask = createTask({
name: 'preview:build',
desc: 'Process and stage the UI assets and generate pages for the preview',
call: parallel(buildTask, buildPreviewPagesTask),
})
const previewServeTask = createTask({
name: 'preview:serve',
call: task.serve(previewDestDir, serverConfig, () => watch(glob.all, previewBuildTask)),
})
const previewTask = createTask({
name: 'preview',
desc: 'Generate a preview site and launch a server to view it',
call: series(previewBuildTask, previewServeTask),
})
module.exports = exportTasks(
bundleTask,
cleanTask,
lintTask,
formatTask,
buildTask,
bundleTask,
bundlePackTask,
previewTask,
previewBuildTask,
packTask
)
'use strict'
// This placeholder script allows this package to be discovered using require.resolve.
// It may be used in the future to export information about the files in this UI.
This diff is collapsed.
{
"name": "swlab-ui",
"description": "swlab-ui",
"homepage": "https://gitlab.bwg.co.kr/swd/swlab-ui.git",
"license": "MPL-2.0",
"repository": {
"type": "git",
"url": "https://gitlab.bwg.co.kr/swd/swlab-ui.git"
},
"engines": {
"node": ">= 8.0.0"
},
"browserslist": [
"last 2 versions"
],
"devDependencies": {
"@asciidoctor/core": "~2.2",
"@fontsource/roboto": "~4.5",
"@fontsource/roboto-mono": "~4.5",
"@vscode/gulp-vinyl-zip": "~2.5",
"autoprefixer": "~9.7",
"browser-pack-flat": "~3.4",
"browserify": "~16.5",
"cssnano": "~4.1",
"eslint": "~6.8",
"eslint-config-standard": "~14.1",
"eslint-plugin-import": "~2.20",
"eslint-plugin-node": "~11.1",
"eslint-plugin-promise": "~4.2",
"eslint-plugin-standard": "~4.0",
"fancy-log": "~1.3",
"fs-extra": "~8.1",
"gulp": "~4.0",
"gulp-concat": "~2.6",
"gulp-connect": "~5.7",
"gulp-eslint": "~6.0",
"gulp-imagemin": "~6.2",
"gulp-postcss": "~8.0",
"gulp-stylelint": "~13.0",
"gulp-uglify": "~3.0",
"handlebars": "~4.7",
"highlight.js": "9.18.3",
"js-yaml": "~3.13",
"merge-stream": "~2.0",
"postcss-calc": "~7.0",
"postcss-custom-properties": "~9.1",
"postcss-import": "~12.0",
"postcss-url": "~8.0",
"prettier-eslint": "~9.0",
"require-directory": "~2.1",
"require-from-string": "~2.0",
"stylelint": "~13.3",
"stylelint-config-standard": "~20.0",
"vinyl-fs": "~3.0"
}
}
*,
*::before,
*::after {
box-sizing: inherit;
}
html {
box-sizing: border-box;
font-size: var(--body-font-size);
height: 100%;
scroll-behavior: smooth;
}
@media screen and (min-width: 1024px) {
html {
font-size: var(--body-font-size--desktop);
}
}
body {
background: var(--body-background);
color: var(--body-font-color);
font-family: var(--body-font-family);
line-height: var(--body-line-height);
margin: 0;
tab-size: 4;
word-wrap: anywhere; /* aka overflow-wrap; used when hyphens are disabled or aren't sufficient */
}
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a:active {
background-color: none;
}
code,
kbd,
pre {
font-family: var(--monospace-font-family);
}
b,
dt,
strong,
th {
font-weight: var(--body-font-weight-bold);
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
em em { /* stylelint-disable-line */
font-style: normal;
}
strong strong { /* stylelint-disable-line */
font-weight: normal;
}
button {
cursor: pointer;
font-family: inherit;
font-size: 1em;
line-height: var(--body-line-height);
margin: 0;
}
button::-moz-focus-inner {
border: none;
padding: 0;
}
summary {
cursor: pointer;
-webkit-tap-highlight-color: transparent;
outline: none;
}
table {
border-collapse: collapse;
word-wrap: normal; /* table widths aren't computed as expected when word-wrap is enabled */
}
object[type="image/svg+xml"]:not([width]) {
width: fit-content;
}
::placeholder {
opacity: 0.5;
}
@media (pointer: fine) {
@supports (scrollbar-width: thin) {
html {
scrollbar-color: var(--scrollbar-thumb-color) var(--scrollbar-track-color);
}
body * {
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-thumb-color) transparent;
}
}
html::-webkit-scrollbar {
background-color: var(--scrollbar-track-color);
height: 12px;
width: 12px;
}
body ::-webkit-scrollbar {
height: 6px;
width: 6px;
}
::-webkit-scrollbar-thumb {
background-clip: padding-box;
background-color: var(--scrollbar-thumb-color);
border: 3px solid transparent;
border-radius: 12px;
}
body ::-webkit-scrollbar-thumb {
border-width: 1.75px;
border-radius: 6px;
}
::-webkit-scrollbar-thumb:hover {
background-color: var(--scrollbar_hover-thumb-color);
}
}
@media screen and (min-width: 1024px) {
.body {
display: flex;
}
}
.breadcrumbs {
display: none;
flex: 1 1;
padding: 0 0.5rem 0 0.75rem;
line-height: var(--nav-line-height);
}
@media screen and (min-width: 1024px) {
.breadcrumbs {
display: block;
}
}
a + .breadcrumbs {
padding-left: 0.05rem;
}
.breadcrumbs ul {
display: flex;
flex-wrap: wrap;
margin: 0;
padding: 0;
list-style: none;
}
.breadcrumbs li {
display: inline;
margin: 0;
}
.breadcrumbs li::after {
content: "/";
padding: 0 0.5rem;
}
.breadcrumbs li:last-of-type::after {
content: none;
}
This diff is collapsed.
footer.footer {
background-color: var(--footer-background);
color: var(--footer-font-color);
font-size: calc(15 / var(--rem-base) * 1rem);
line-height: var(--footer-line-height);
padding: 1.5rem;
}
.footer p {
margin: 0.5rem 0;
}
.footer a {
color: var(--footer-link-font-color);
}
@media screen and (max-width: 1023.5px) {
html.is-clipped--navbar {
overflow-y: hidden;
}
}
body {
padding-top: var(--navbar-height);
}
.navbar {
background: var(--navbar-background);
color: var(--navbar-font-color);
font-size: calc(16 / var(--rem-base) * 1rem);
height: var(--navbar-height);
position: fixed;
top: 0;
width: 100%;
z-index: var(--z-index-navbar);
}
.navbar a {
text-decoration: none;
}
.navbar-brand {
display: flex;
flex: auto;
padding-left: 1rem;
}
.navbar-brand .navbar-item {
color: var(--navbar-font-color);
}
.navbar-brand .navbar-item:first-child {
align-self: center;
padding: 0;
font-size: calc(22 / var(--rem-base) * 1rem);
flex-wrap: wrap;
line-height: 1;
}
.navbar-brand .navbar-item:first-child a {
color: inherit;
word-wrap: normal;
}
.navbar-brand .navbar-item:first-child :not(:last-child) {
padding-right: 0.375rem;
}
.navbar-brand .navbar-item.search {
flex: auto;
justify-content: flex-end;
}
#search-input {
color: #333;
font-family: inherit;
font-size: 0.95rem;
width: 150px;
border: 1px solid #dbdbdb;
border-radius: 0.1em;
line-height: 1.5;
padding: 0 0.25em;
}
#search-input:disabled {
background-color: #dbdbdb;
/* disable cursor */
cursor: not-allowed;
pointer-events: all !important;
}
#search-input:disabled::placeholder {
color: #4c4c4c;
}
#search-input:focus {
outline: none;
}
.navbar-burger {
background: none;
border: none;
outline: none;
line-height: 1;
position: relative;
width: 3rem;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-left: auto;
min-width: 0;
}
.navbar-burger span {
background-color: var(--navbar-font-color);
height: 1.5px;
width: 1rem;
}
.navbar-burger:not(.is-active) span {
transition: transform ease-out 0.25s, opacity 0s 0.25s, margin-top ease-out 0.25s 0.25s;
}
.navbar-burger span + span {
margin-top: 0.25rem;
}
.navbar-burger.is-active span + span {
margin-top: -1.5px;
}
.navbar-burger.is-active span:nth-child(1) {
transform: rotate(45deg);
}
.navbar-burger.is-active span:nth-child(2) {
opacity: 0;
}
.navbar-burger.is-active span:nth-child(3) {
transform: rotate(-45deg);
}
.navbar-item,
.navbar-link {
color: var(--navbar-menu-font-color);
display: block;
line-height: var(--doc-line-height);
padding: 0.5rem 1rem;
}
.navbar-item.has-dropdown {
padding: 0;
}
.navbar-item .icon {
width: 1.25rem;
height: 1.25rem;
display: block;
}
.navbar-item .icon img,
.navbar-item .icon svg {
fill: currentColor;
width: inherit;
height: inherit;
}
.navbar-link {
padding-right: 2.5em;
}
.navbar-dropdown .navbar-item {
padding-left: 1.5rem;
padding-right: 1.5rem;
}
.navbar-dropdown .navbar-item.has-label {
display: flex;
justify-content: space-between;
}
.navbar-dropdown .navbar-item small {
color: var(--toolbar-muted-color);
font-size: calc(12 / var(--rem-base) * 1rem);
}
.navbar-divider {
background-color: var(--navbar-menu-border-color);
border: none;
height: 1px;
margin: 0.25rem 0;
}
.navbar .button {
display: inline-flex;
align-items: center;
background: var(--navbar-button-background);
border: 1px solid var(--navbar-button-border-color);
border-radius: 0.15rem;
height: 1.75rem;
color: var(--navbar-button-font-color);
padding: 0 0.75em;
white-space: nowrap;
}
@media screen and (max-width: 768.5px) {
.navbar-brand .navbar-item.search {
padding-left: 0;
padding-right: 0;
}
}
@media screen and (min-width: 769px) {
#search-input {
width: 200px;
}
}
@media screen and (max-width: 1023.5px) {
.navbar-brand {
height: inherit;
}
.navbar-brand .navbar-item {
align-items: center;
display: flex;
}
.navbar-menu {
background: var(--navbar-menu-background);
box-shadow: 0 8px 16px rgba(10, 10, 10, 0.1);
max-height: var(--body-min-height);
overflow-y: auto;
overscroll-behavior: none;
padding: 0.5rem 0;
}
.navbar-menu:not(.is-active) {
display: none;
}
.navbar-menu a.navbar-item:hover,
.navbar-menu .navbar-link:hover {
background: var(--navbar-menu_hover-background);
}
}
@media screen and (min-width: 1024px) {
.navbar-burger {
display: none;
}
.navbar,
.navbar-menu,
.navbar-end {
display: flex;
}
.navbar-item,
.navbar-link {
display: flex;
position: relative;
flex: none;
}
.navbar-item:not(.has-dropdown),
.navbar-link {
align-items: center;
}
.navbar-item.is-hoverable:hover .navbar-dropdown {
display: block;
}
.navbar-link::after {
border-width: 0 0 1px 1px;
border-style: solid;
content: "";
display: block;
height: 0.5em;
pointer-events: none;
position: absolute;
transform: rotate(-45deg);
width: 0.5em;
margin-top: -0.375em;
right: 1.125em;
top: 50%;
}
.navbar-end > .navbar-item,
.navbar-end .navbar-link {
color: var(--navbar-font-color);
}
.navbar-end > a.navbar-item:hover,
.navbar-end .navbar-link:hover,
.navbar-end .navbar-item.has-dropdown:hover .navbar-link {
background: var(--navbar_hover-background);
color: var(--navbar-font-color);
}
.navbar-end .navbar-link::after {
border-color: currentColor;
}
.navbar-dropdown {
background: var(--navbar-menu-background);
border: 1px solid var(--navbar-menu-border-color);
border-top: none;
border-radius: 0 0 0.25rem 0.25rem;
display: none;
top: 100%;
left: 0;
min-width: 100%;
position: absolute;
}
.navbar-dropdown .navbar-item {
padding: 0.5rem 3rem 0.5rem 1rem;
white-space: nowrap;
}
.navbar-dropdown .navbar-item small {
position: relative;
right: -2rem;
}
.navbar-dropdown .navbar-item:last-child {
border-radius: inherit;
}
.navbar-dropdown.is-right {
left: auto;
right: 0;
}
.navbar-dropdown a.navbar-item:hover {
background: var(--navbar-menu_hover-background);
}
}
/*! Adapted from the GitHub style by Vasily Polovnyov <vast@whiteants.net> */
.hljs-comment,
.hljs-quote {
color: #998;
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-subst {
color: #333;
font-weight: var(--monospace-font-weight-bold);
}
.hljs-number,
.hljs-literal,
.hljs-variable,
.hljs-template-variable,
.hljs-tag .hljs-attr {
color: #008080;
}
.hljs-string,
.hljs-doctag {
color: #d14;
}
.hljs-title,
.hljs-section,
.hljs-selector-id {
color: #900;
font-weight: var(--monospace-font-weight-bold);
}
.hljs-subst {
font-weight: normal;
}
.hljs-type,
.hljs-class .hljs-title {
color: #458;
font-weight: var(--monospace-font-weight-bold);
}
.hljs-tag,
.hljs-name,
.hljs-attribute {
color: #000080;
font-weight: normal;
}
.hljs-regexp,
.hljs-link {
color: #009926;
}
.hljs-symbol,
.hljs-bullet {
color: #990073;
}
.hljs-built_in,
.hljs-builtin-name {
color: #0086b3;
}
.hljs-meta {
color: #999;
font-weight: var(--monospace-font-weight-bold);
}
.hljs-deletion {
background: #fdd;
}
.hljs-addition {
background: #dfd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: var(--monospace-font-weight-bold);
}
body.-toc aside.toc.sidebar {
display: none;
}
@media screen and (max-width: 1023.5px) {
aside.toc.sidebar {
display: none;
}
main > .content {
overflow-x: auto;
}
}
@media screen and (min-width: 1024px) {
main {
flex: auto;
min-width: 0; /* min-width: 0 required for flexbox to constrain overflowing elements */
}
main > .content {
display: flex;
}
aside.toc.embedded {
display: none;
}
aside.toc.sidebar {
flex: 0 0 var(--toc-width);
order: 1;
}
}
@media screen and (min-width: 1216px) {
aside.toc.sidebar {
flex-basis: var(--toc-width--widescreen);
}
}
@media screen and (max-width: 1023.5px) {
html.is-clipped--nav {
overflow-y: hidden;
}
}
.nav-container {
position: fixed;
top: var(--navbar-height);
left: 0;
width: 100%;
font-size: calc(17 / var(--rem-base) * 1rem);
z-index: var(--z-index-nav);
visibility: hidden;
}
@media screen and (min-width: 769px) {
.nav-container {
width: var(--nav-width);
}
}
@media screen and (min-width: 1024px) {
.nav-container {
font-size: calc(15.5 / var(--rem-base) * 1rem);
flex: none;
position: static;
top: 0;
visibility: visible;
}
}
.nav-container.is-active {
visibility: visible;
}
.nav {
background: var(--nav-background);
position: relative;
top: var(--toolbar-height);
height: var(--nav-height);
}
@media screen and (min-width: 769px) {
.nav {
box-shadow: 0.5px 0 3px var(--nav-border-color);
}
}
@media screen and (min-width: 1024px) {
.nav {
top: var(--navbar-height);
box-shadow: none;
position: sticky;
height: var(--nav-height--desktop);
}
}
.nav a {
color: inherit;
}
.nav .panels {
display: flex;
flex-direction: column;
height: inherit;
}
.nav-panel-menu {
overflow-y: scroll;
overscroll-behavior: none;
height: var(--nav-panel-menu-height);
}
.nav-panel-menu:not(.is-active) .nav-menu {
opacity: 0.75;
}
.nav-panel-menu:not(.is-active)::after {
content: "";
background: rgba(0, 0, 0, 0.5);
display: block;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.nav-menu {
min-height: 100%;
padding: 0.5rem 0.75rem;
line-height: var(--nav-line-height);
position: relative;
}
.nav-menu-toggle {
background: transparent url(../img/octicons-16.svg#view-unfold) no-repeat center / 100% 100%;
border: none;
float: right;
height: 1em;
margin-right: -0.5rem;
opacity: 0.75;
outline: none;
padding: 0;
position: sticky;
top: calc((var(--nav-line-height) - 1 + 0.5) * 1rem);
visibility: hidden;
width: 1em;
}
.nav-menu-toggle.is-active {
background-image: url(../img/octicons-16.svg#view-fold);
}
.nav-panel-menu.is-active:hover .nav-menu-toggle {
visibility: visible;
}
.nav-menu h3.title {
color: var(--nav-heading-font-color);
font-size: inherit;
font-weight: var(--body-font-weight-bold);
margin: 0;
padding: 0.25em 0 0.125em;
}
.nav-list {
list-style: none;
margin: 0 0 0 0.75rem;
padding: 0;
}
.nav-menu > .nav-list + .nav-list {
margin-top: 0.5rem;
}
.nav-item {
margin-top: 0.5em;
}
/* adds some breathing room below a nested list */
.nav-item-toggle ~ .nav-list {
padding-bottom: 0.125rem;
}
/* matches list without a title */
.nav-item[data-depth="0"] > .nav-list:first-child {
display: block;
margin: 0;
}
.nav-item:not(.is-active) > .nav-list {
display: none;
}
.nav-item-toggle {
background: transparent url(../img/caret.svg) no-repeat center / 50%;
border: none;
outline: none;
line-height: inherit;
padding: 0;
position: absolute;
height: calc(var(--nav-line-height) * 1em);
width: calc(var(--nav-line-height) * 1em);
margin-top: -0.05em;
margin-left: calc(var(--nav-line-height) * -1em);
}
.nav-item.is-active > .nav-item-toggle {
transform: rotate(90deg);
}
.is-current-page > .nav-link,
.is-current-page > .nav-text {
font-weight: var(--body-font-weight-bold);
}
.nav-panel-explore {
background: var(--nav-background);
display: flex;
flex-direction: column;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.nav-panel-explore:not(:first-child) {
top: auto;
max-height: var(--nav-panel-explore-height);
}
.nav-panel-explore .context {
font-size: calc(15 / var(--rem-base) * 1rem);
flex-shrink: 0;
color: var(--nav-muted-color);
box-shadow: 0 -1px 0 var(--nav-panel-divider-color);
padding: 0 0.5rem;
display: flex;
align-items: center;
justify-content: space-between;
line-height: 1;
height: var(--drawer-height);
}
.nav-panel-explore:not(:first-child) .context {
cursor: pointer;
}
.nav-panel-explore .context .version {
display: flex;
align-items: inherit;
}
.nav-panel-explore .context .version::after {
content: "";
background: url(../img/chevron.svg) no-repeat center right / auto 100%;
width: 1.25em;
height: 0.75em;
}
.nav-panel-explore .components {
line-height: var(--nav-line-height);
flex-grow: 1;
box-shadow: inset 0 1px 5px var(--nav-panel-divider-color);
background: var(--nav-secondary-background);
padding: 0.75rem 0.75rem 0 0.75rem;
margin: 0;
overflow-y: scroll;
overscroll-behavior: none;
max-height: 100%;
display: block;
}
.nav-panel-explore:not(.is-active) .components {
display: none;
}
.nav-panel-explore .component {
display: block;
}
.nav-panel-explore .component + .component {
margin-top: 0.75rem;
}
.nav-panel-explore .component:last-child {
margin-bottom: 0.75rem;
}
.nav-panel-explore .component .title {
font-weight: var(--body-font-weight-bold);
text-indent: 0.375rem hanging;
}
.nav-panel-explore .versions {
display: flex;
flex-wrap: wrap;
padding-left: 0;
margin: -0.125rem -0.375rem 0 0.375rem;
line-height: 1;
list-style: none;
}
.nav-panel-explore .component .version {
margin: 0.375rem 0.375rem 0 0;
}
.nav-panel-explore .component .version a {
background: var(--nav-border-color);
border-radius: 0.25rem;
white-space: nowrap;
padding: 0.25em 0.5em;
display: inherit;
opacity: 0.75;
}
.nav-panel-explore .component .is-current a {
background: var(--nav-heading-font-color);
color: var(--nav-secondary-background);
font-weight: var(--body-font-weight-bold);
opacity: 1;
}
.page-versions {
margin: 0 0.2rem 0 auto;
position: relative;
line-height: 1;
}
@media screen and (min-width: 1024px) {
.page-versions {
margin-right: 0.7rem;
}
}
.page-versions .version-menu-toggle {
color: inherit;
background: url(../img/chevron.svg) no-repeat;
background-position: right 0.5rem top 50%;
background-size: auto 0.75em;
border: none;
outline: none;
line-height: inherit;
padding: 0.5rem 1.5rem 0.5rem 0.5rem;
position: relative;
z-index: var(--z-index-page-version-menu);
}
.page-versions .version-menu {
display: flex;
min-width: 100%;
flex-direction: column;
align-items: flex-end;
background: linear-gradient(to bottom, var(--page-version-menu-background) 0%, var(--page-version-menu-background) 100%) no-repeat;
padding: 1.375rem 1.5rem 0.5rem 0.5rem;
position: absolute;
top: 0;
right: 0;
white-space: nowrap;
}
.page-versions:not(.is-active) .version-menu {
display: none;
}
.page-versions .version {
display: block;
padding-top: 0.5rem;
}
.page-versions .version.is-current {
display: none;
}
.page-versions .version.is-missing {
color: var(--page-version-missing-font-color);
font-style: italic;
text-decoration: none;
}
nav.pagination {
display: flex;
border-top: 1px solid var(--toolbar-border-color);
line-height: 1;
margin: 2rem -1rem -1rem;
padding: 0.75rem 1rem 0;
}
nav.pagination span {
display: flex;
flex: 50%;
flex-direction: column;
}
nav.pagination .prev {
padding-right: 0.5rem;
}
nav.pagination .next {
margin-left: auto;
padding-left: 0.5rem;
text-align: right;
}
nav.pagination span::before {
color: var(--toolbar-muted-color);
font-size: 0.75em;
padding-bottom: 0.1em;
}
nav.pagination .prev::before {
content: "Prev";
}
nav.pagination .next::before {
content: "Next";
}
nav.pagination a {
font-weight: var(--body-font-weight-bold);
line-height: 1.3;
position: relative;
}
nav.pagination a::before,
nav.pagination a::after {
color: var(--toolbar-muted-color);
font-weight: normal;
font-size: 1.5em;
line-height: 0.75;
position: absolute;
top: 0;
width: 1rem;
}
nav.pagination .prev a::before {
content: "\2039";
transform: translateX(-100%);
}
nav.pagination .next a::after {
content: "\203a";
}
@page {
margin: 0.5in;
}
@media print {
.hide-for-print {
display: none !important;
}
html {
font-size: var(--body-font-size--print);
}
a {
color: inherit !important;
text-decoration: underline;
}
a.bare,
a[href^="#"],
a[href^="mailto:"] {
text-decoration: none;
}
tr,
img,
object,
svg {
page-break-inside: avoid;
}
thead {
display: table-header-group;
}
pre {
hyphens: none;
white-space: pre-wrap;
}
body {
padding-top: 2rem;
}
.navbar {
background: none;
color: inherit;
position: absolute;
}
.navbar * {
color: inherit !important;
}
.navbar > :not(.navbar-brand),
.nav-container,
.toolbar,
aside.toc,
nav.pagination {
display: none;
}
.doc {
color: inherit;
margin: auto;
max-width: none;
padding-bottom: 2rem;
}
.doc .admonitionblock td.icon {
color-adjust: exact;
}
.doc .listingblock code[data-lang]::before {
display: block;
}
footer.footer {
background: none;
border-top: 1px solid var(--panel-border-color);
color: var(--quote-attribution-font-color);
padding: 0.25rem 0.5rem 0;
}
.footer * {
color: inherit;
}
}
@import "typeface-roboto.css";
@import "typeface-roboto-mono.css";
@import "vars.css";
@import "base.css";
@import "body.css";
@import "nav.css";
@import "main.css";
@import "toolbar.css";
@import "breadcrumbs.css";
@import "page-versions.css";
@import "toc.css";
@import "doc.css";
@import "pagination.css";
@import "header.css";
@import "footer.css";
@import "highlight.css";
@import "print.css";
.toc-menu {
color: var(--toc-font-color);
}
.toc.sidebar .toc-menu {
margin-right: 0.75rem;
position: sticky;
top: var(--toc-top);
}
.toc .toc-menu h3 {
color: var(--toc-heading-font-color);
font-size: calc(16 / var(--rem-base) * 1rem);
font-weight: var(--body-font-weight-bold);
line-height: 1.3;
margin: 0 -0.5px;
padding-bottom: 0.25rem;
}
.toc.sidebar .toc-menu h3 {
display: flex;
flex-direction: column;
height: 2.5rem;
justify-content: flex-end;
}
.toc .toc-menu ul {
font-size: calc(15 / var(--rem-base) * 1rem);
line-height: var(--toc-line-height);
list-style: none;
margin: 0;
padding: 0;
}
.toc.sidebar .toc-menu ul {
max-height: var(--toc-height);
overflow-y: auto;
overscroll-behavior: none;
}
@supports (scrollbar-width: none) {
.toc.sidebar .toc-menu ul {
scrollbar-width: none;
}
}
.toc .toc-menu ul::-webkit-scrollbar {
width: 0;
height: 0;
}
@media screen and (min-width: 1024px) {
.toc .toc-menu h3 {
font-size: calc(15 / var(--rem-base) * 1rem);
}
.toc .toc-menu ul {
font-size: calc(13.5 / var(--rem-base) * 1rem);
}
}
.toc .toc-menu li {
margin: 0;
}
.toc .toc-menu li[data-level="2"] a {
padding-left: 1.25rem;
}
.toc .toc-menu li[data-level="3"] a {
padding-left: 2rem;
}
.toc .toc-menu a {
color: inherit;
border-left: 2px solid var(--toc-border-color);
display: inline-block;
padding: 0.25rem 0 0.25rem 0.5rem;
text-decoration: none;
}
.sidebar.toc .toc-menu a {
display: block;
outline: none;
}
.toc .toc-menu a:hover {
color: var(--link-font-color);
}
.toc .toc-menu a.is-active {
border-left-color: var(--link-font-color);
color: var(--doc-font-color);
}
.sidebar.toc .toc-menu a:focus {
background: var(--panel-background);
}
.toolbar {
color: var(--toolbar-font-color);
align-items: center;
background-color: var(--toolbar-background);
box-shadow: 0 1px 0 var(--toolbar-border-color);
display: flex;
font-size: calc(15 / var(--rem-base) * 1rem);
height: var(--toolbar-height);
justify-content: flex-start;
position: sticky;
top: var(--navbar-height);
z-index: var(--z-index-toolbar);
}
.toolbar a {
color: inherit;
}
.nav-toggle {
background: url(../img/menu.svg) no-repeat 50% 47.5%;
background-size: 49%;
border: none;
outline: none;
line-height: inherit;
padding: 0;
height: var(--toolbar-height);
width: var(--toolbar-height);
margin-right: -0.25rem;
}
@media screen and (min-width: 1024px) {
.nav-toggle {
display: none;
}
}
.nav-toggle.is-active {
background-image: url(../img/back.svg);
background-size: 41.5%;
}
.home-link {
display: block;
background: url(../img/home-o.svg) no-repeat center;
height: calc(var(--toolbar-height) / 2);
width: calc(var(--toolbar-height) / 2);
margin: calc(var(--toolbar-height) / 4);
}
.home-link:hover,
.home-link.is-current {
background-image: url(../img/home.svg);
}
.edit-this-page {
display: none;
padding-right: 0.5rem;
}
@media screen and (min-width: 1024px) {
.edit-this-page {
display: block;
}
}
.toolbar .edit-this-page a {
color: var(--toolbar-muted-color);
}
@font-face {
font-family: "Roboto Mono";
font-style: normal;
font-weight: 400;
src:
url(~@fontsource/roboto-mono/files/roboto-mono-latin-400-normal.woff2) format("woff2"),
url(~@fontsource/roboto-mono/files/roboto-mono-latin-400-normal.woff) format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/*
@font-face {
font-family: "Roboto Mono";
font-style: normal;
font-weight: 400;
src: url(~@fontsource/roboto-mono/files/roboto-mono-cyrillic-400-normal.woff2) format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
*/
@font-face {
font-family: "Roboto Mono";
font-style: normal;
font-weight: 600;
src:
url(~@fontsource/roboto-mono/files/roboto-mono-latin-500-normal.woff2) format("woff2"),
url(~@fontsource/roboto-mono/files/roboto-mono-latin-500-normal.woff) format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/*
@font-face {
font-family: "Roboto Mono";
font-style: normal;
font-weight: 600;
src: url(~@fontsource/roboto-mono/files/roboto-mono-cyrillic-500-normal.woff2) format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
*/
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 400;
src:
url(~@fontsource/roboto/files/roboto-latin-400-normal.woff2) format("woff2"),
url(~@fontsource/roboto/files/roboto-latin-400-normal.woff) format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 400;
src: url(~@fontsource/roboto/files/roboto-cyrillic-400-normal.woff2) format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 400;
src:
url(~@fontsource/roboto/files/roboto-latin-400-italic.woff2) format("woff2"),
url(~@fontsource/roboto/files/roboto-latin-400-italic.woff) format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 400;
src: url(~@fontsource/roboto/files/roboto-cyrillic-400-italic.woff2) format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 600;
src:
url(~@fontsource/roboto/files/roboto-latin-500-normal.woff2) format("woff2"),
url(~@fontsource/roboto/files/roboto-latin-500-normal.woff) format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 600;
src: url(~@fontsource/roboto/files/roboto-cyrillic-500-normal.woff2) format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 600;
src:
url(~@fontsource/roboto/files/roboto-latin-500-italic.woff2) format("woff2"),
url(~@fontsource/roboto/files/roboto-latin-500-italic.woff) format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 600;
src: url(~@fontsource/roboto/files/roboto-cyrillic-500-italic.woff2) format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
:root {
/* colors */
--color-white: #fff;
--color-smoke-10: #fefefe;
--color-smoke-30: #fafafa;
--color-smoke-50: #f5f5f5;
--color-smoke-70: #f0f0f0;
--color-smoke-90: #e1e1e1;
--color-gray-10: #c1c1c1;
--color-gray-30: #9c9c9c;
--color-gray-40: #8e8e8e;
--color-gray-50: #808080;
--color-gray-70: #5d5d5d;
--color-jet-20: #4a4a4a;
--color-jet-30: #424242;
--color-jet-50: #333;
--color-jet-70: #222;
--color-jet-80: #191919;
--color-black: #000;
/* fonts */
--rem-base: 18; /* used to compute rem value from desired pixel value (e.g., calc(18 / var(--rem-base) * 1rem) = 18px) */
--body-font-size: 1.0625em; /* 17px */
--body-font-size--desktop: 1.125em; /* 18px */
--body-font-size--print: 0.9375em; /* 15px */
--body-line-height: 1.15;
--body-font-color: var(--color-jet-70);
--body-font-family: "Roboto", sans-serif;
--body-font-weight-bold: 600;
--monospace-font-family: "Roboto Mono", monospace;
--monospace-font-weight-bold: 600;
/* base */
--body-background: var(--color-white);
--panel-background: var(--color-smoke-30);
--panel-border-color: var(--color-smoke-90);
--scrollbar-track-color: var(--color-smoke-30);
--scrollbar-thumb-color: var(--color-gray-10);
--scrollbar_hover-thumb-color: var(--color-gray-30);
/* navbar */
--navbar-background: var(--color-jet-80);
--navbar-font-color: var(--color-white);
--navbar_hover-background: var(--color-black);
--navbar-button-background: var(--color-white);
--navbar-button-border-color: var(--panel-border-color);
--navbar-button-font-color: var(--body-font-color);
--navbar-menu-border-color: var(--panel-border-color);
--navbar-menu-background: var(--color-white);
--navbar-menu-font-color: var(--body-font-color);
--navbar-menu_hover-background: var(--color-smoke-50);
/* nav */
--nav-background: var(--panel-background);
--nav-border-color: var(--color-gray-10);
--nav-line-height: 1.35;
--nav-heading-font-color: var(--color-jet-30);
--nav-muted-color: var(--color-gray-70);
--nav-panel-divider-color: var(--color-smoke-90);
--nav-secondary-background: var(--color-smoke-70);
/* toolbar */
--toolbar-background: var(--panel-background);
--toolbar-border-color: var(--panel-border-color);
--toolbar-font-color: var(--color-gray-70);
--toolbar-muted-color: var(--color-gray-40);
--page-version-menu-background: var(--color-smoke-70);
--page-version-missing-font-color: var(--color-gray-40);
/* admonitions */
--caution-color: #a0439c;
--caution-on-color: var(--color-white);
--important-color: #d32f2f;
--important-on-color: var(--color-white);
--note-color: #217ee7;
--note-on-color: var(--color-white);
--tip-color: #41af46;
--tip-on-color: var(--color-white);
--warning-color: #e18114;
--warning-on-color: var(--color-white);
/* doc */
--doc-font-color: var(--color-jet-50);
--doc-font-size: inherit;
--doc-font-size--desktop: calc(17 / var(--rem-base) * 1rem);
--doc-line-height: 1.6;
--doc-margin: 0 auto;
--doc-margin--desktop: 0 2rem;
--heading-font-color: var(--color-jet-80);
--heading-font-weight: normal;
--alt-heading-font-weight: var(--body-font-weight-bold);
--section-divider-color: var(--panel-border-color);
--link-font-color: #1565c0;
--link_hover-font-color: #104d92;
--link_unresolved-font-color: var(--important-color);
--abstract-background: var(--color-smoke-70);
--abstract-font-color: var(--color-jet-20);
--abstract-border-color: var(--panel-border-color);
--admonition-background: var(--panel-background);
--admonition-label-font-weight: var(--body-font-weight-bold);
--caption-font-color: var(--color-gray-70);
--caption-font-style: italic;
--caption-font-weight: var(--body-font-weight-bold);
--code-background: var(--panel-background);
--code-font-color: var(--body-font-color);
--example-background: var(--color-white);
--example-border-color: var(--color-gray-70);
--kbd-background: var(--panel-background);
--kbd-border-color: var(--color-gray-10);
--pre-background: var(--panel-background);
--pre-border-color: var(--panel-border-color);
--pre-annotation-font-color: var(--color-gray-50);
--quote-background: var(--panel-background);
--quote-border-color: var(--color-gray-70);
--quote-font-color: var(--color-gray-70);
--quote-attribution-font-color: var(--color-gray-40);
--sidebar-background: var(--color-smoke-90);
--table-border-color: var(--panel-border-color);
--table-stripe-background: var(--panel-background);
--table-footer-background: linear-gradient(to bottom, var(--color-smoke-70) 0%, var(--color-white) 100%);
/* toc */
--toc-font-color: var(--nav-muted-color);
--toc-heading-font-color: var(--doc-font-color);
--toc-border-color: var(--panel-border-color);
--toc-line-height: 1.2;
/* footer */
--footer-line-height: var(--doc-line-height);
--footer-background: var(--color-smoke-90);
--footer-font-color: var(--color-gray-70);
--footer-link-font-color: var(--color-jet-80);
/* dimensions and positioning */
--navbar-height: calc(63 / var(--rem-base) * 1rem);
--toolbar-height: calc(45 / var(--rem-base) * 1rem);
--drawer-height: var(--toolbar-height);
--body-top: var(--navbar-height);
--body-min-height: calc(100vh - var(--body-top));
--nav-height: calc(var(--body-min-height) - var(--toolbar-height));
--nav-height--desktop: var(--body-min-height);
--nav-panel-menu-height: calc(100% - var(--drawer-height));
--nav-panel-explore-height: calc(50% + var(--drawer-height));
--nav-width: calc(270 / var(--rem-base) * 1rem);
--toc-top: calc(var(--body-top) + var(--toolbar-height));
--toc-height: calc(100vh - var(--toc-top) - 2.5rem);
--toc-width: calc(162 / var(--rem-base) * 1rem);
--toc-width--widescreen: calc(216 / var(--rem-base) * 1rem);
--doc-max-width: calc(720 / var(--rem-base) * 1rem);
--doc-max-width--desktop: calc(828 / var(--rem-base) * 1rem);
/* stacking */
--z-index-nav: 1;
--z-index-toolbar: 2;
--z-index-page-version-menu: 3;
--z-index-navbar: 4;
}
'use strict'
module.exports = (...args) => {
const numArgs = args.length
if (numArgs === 3) return args[0] && args[1]
if (numArgs < 3) throw new Error('{{and}} helper expects at least 2 arguments')
args.pop()
return args.every((it) => it)
}
'use strict'
const TAG_ALL_RX = /<[^>]+>/g
module.exports = (html) => html && html.replace(TAG_ALL_RX, '')
'use strict'
module.exports = (a, b) => a === b
'use strict'
module.exports = (value) => (value || 0) + 1
'use strict'
module.exports = (a, b) => a !== b
'use strict'
module.exports = (val) => !val
'use strict'
module.exports = (...args) => {
const numArgs = args.length
if (numArgs === 3) return args[0] || args[1]
if (numArgs < 3) throw new Error('{{or}} helper expects at least 2 arguments')
args.pop()
return args.some((it) => it)
}
'use strict'
const { posix: path } = require('path')
module.exports = (to, from, ctx) => {
if (!to) return '#'
if (to.charAt() !== '/') return to
// NOTE only legacy invocation provides both to and from
if (!ctx) from = (ctx = from).data.root.page.url
if (!from) return (ctx.data.root.site.path || '') + to
let hash = ''
const hashIdx = to.indexOf('#')
if (~hashIdx) {
hash = to.slice(hashIdx)
to = to.slice(0, hashIdx)
}
if (to === from) return hash || (isDir(to) ? './' : path.basename(to))
const rel = path.relative(path.dirname(from + '.'), to)
return rel ? (isDir(to) ? rel + '/' : rel) + hash : (isDir(to) ? './' : '../' + path.basename(to)) + hash
}
function isDir (str) {
return str.charAt(str.length - 1) === '/'
}
'use strict'
module.exports = () => new Date().getFullYear().toString()
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100"
height="100"
viewBox="0 0 100 100"
version="1.1"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
sodipodi:docname="back.svg"
enable-background="new">
<title>Left arrow</title>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="6.108138"
inkscape:cx="21.142679"
inkscape:cy="42.629076"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1001"
inkscape:window-x="0"
inkscape:window-y="41"
inkscape:window-maximized="1"
scale-x="1" />
<metadata>
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Left arrow</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Sarah White</dc:title>
</cc:Agent>
</dc:creator>
<dc:publisher>
<cc:Agent>
<dc:title>OpenDevise Inc.</dc:title>
</cc:Agent>
</dc:publisher>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
transform="translate(-3.926492e-7,-270.54187)">
<path
d="m 50.000978,280.44162 -40.1010516,40.10025 40.1010516,40.10025 5.6556,-5.65551 -30.434757,-30.44194 h 64.878253 v -8.0056 H 25.221821 l 30.434757,-30.44001 z" />
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30"
height="30"
viewBox="0 0 30 30"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="caret.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="16"
inkscape:cx="31.65919"
inkscape:cy="23.730414"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2688"
inkscape:window-height="1478"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1022.3622)">
<path
style="opacity:1;fill:#c1c1c1;fill-opacity:1;stroke:#c1c1c1;stroke-width:1.99999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 10.18745,1025.362 14.0001,12.0002 -14.0001,12.0001 z"
id="rect3338"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc"
inkscape:transform-center-x="-2.1875" />
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30"
height="30"
viewBox="0 0 30 30"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="chevron.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.627417"
inkscape:cx="10.05311"
inkscape:cy="10.530062"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2560"
inkscape:window-height="1406"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1022.3622)">
<path
style="opacity:1;fill:#5d5d5d;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="M 3.6699219,6.5898438 1.4550781,8.6152344 15,23.374272 28.544922,8.6152344 26.330078,6.5898438 15,18.759498 Z"
transform="translate(0,1022.3622)"
id="rect4136"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 100 100"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="home.svg">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10">
<inkscape:path-effect
is_visible="true"
id="path-effect4225"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4221"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4213"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4209"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4204"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4191"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4187"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4183"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4179"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4173"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4169"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4165"
is_visible="true" />
</defs>
<sodipodi:namedview
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1406"
id="namedview8"
showgrid="false"
inkscape:zoom="8.1458701"
inkscape:cx="33.343764"
inkscape:cy="44.907032"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g4" />
<g
transform="translate(0,-952.36218)"
id="g4">
<path
style="fill:none;fill-rule:evenodd;stroke:#222;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
d="M 50.019531 13.576172 L 21.439453 39.115234 L 21.419922 86.460938 L 42.925781 86.460938 L 42.951172 61.294922 L 57.048828 61.294922 L 57.074219 86.460938 L 78.619141 86.460938 L 78.638672 39.150391 L 50.019531 13.576172 z "
id="path4175"
transform="translate(0,952.36218)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#222;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 63.815035,25.903568 0,-9.217018 8.656932,0 -2e-6,16.95383 z"
id="path4193"
transform="translate(0,952.36218)"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
inkscape:connector-curvature="0"
style="fill:none;fill-rule:evenodd;stroke:#222;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 21.43888,991.47783 -9.98234,8.92037"
id="path4177" />
<path
inkscape:connector-curvature="0"
style="fill:none;fill-rule:evenodd;stroke:#222;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 88.58189,1000.3982 -9.94315,-8.88535"
id="path4170" />
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 100 100"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="home-hovered.svg">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10">
<inkscape:path-effect
is_visible="true"
id="path-effect4225"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4221"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4213"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4209"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4204"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4191"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4187"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4183"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4179"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4173"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4169"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4165"
is_visible="true" />
</defs>
<sodipodi:namedview
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1406"
id="namedview8"
showgrid="false"
inkscape:zoom="8.1458701"
inkscape:cx="-15.147065"
inkscape:cy="42.942846"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g4" />
<g
transform="translate(0,-952.36218)"
id="g4">
<path
style="fill:#222;fill-rule:evenodd;stroke:#222;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
d="M 50.019531 13.576172 L 21.439453 39.115234 L 21.419922 86.460938 L 42.925781 86.460938 L 42.951172 61.294922 L 57.048828 61.294922 L 57.074219 86.460938 L 78.619141 86.460938 L 78.638672 39.150391 L 50.019531 13.576172 z "
id="path4175"
transform="translate(0,952.36218)" />
<path
style="fill:#222;fill-rule:evenodd;stroke:#222;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
d="m 63.815035,25.903568 0,-9.217018 8.656932,0 -2e-6,16.95383 z"
id="path4193"
transform="translate(0,952.36218)"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
inkscape:connector-curvature="0"
style="fill:none;fill-rule:evenodd;stroke:#222;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 21.43888,991.47783 -9.98234,8.92037"
id="path4177" />
<path
inkscape:connector-curvature="0"
style="fill:none;fill-rule:evenodd;stroke:#222;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 88.58189,1000.3982 -9.94315,-8.88535"
id="path4170" />
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 100 100"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="menu.svg">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10">
<inkscape:path-effect
is_visible="true"
id="path-effect4225"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4221"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4213"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4209"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4204"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4191"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4187"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4183"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4179"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4173"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4169"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4165"
is_visible="true" />
</defs>
<sodipodi:namedview
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1406"
id="namedview8"
showgrid="false"
inkscape:zoom="5.76"
inkscape:cx="14.532031"
inkscape:cy="43.425849"
inkscape:window-x="0"
inkscape:window-y="1440"
inkscape:window-maximized="1"
inkscape:current-layer="g4" />
<g
transform="translate(0,-952.36218)"
id="g4">
<g
id="g4238"
transform="translate(-1.5e-6,-0.2053541)">
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4149"
d="m 35,972.34003 55.000003,0"
style="fill:none;fill-rule:evenodd;stroke:#222;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.94117647" />
<rect
y="964.84003"
x="10"
height="15"
width="15"
id="rect4184"
style="opacity:1;fill:#222;fill-opacity:1;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#222;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.94117647"
d="m 42.999999,1016.2452 44.999999,0"
id="path4180"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<rect
style="opacity:1;fill:#222;fill-opacity:1;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4186"
width="10"
height="10"
x="23"
y="1011.2452" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4182"
d="m 42.999999,1035.295 44.999999,0"
style="fill:none;fill-rule:evenodd;stroke:#222;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.94117647" />
<rect
y="1030.295"
x="23"
height="10"
width="10"
id="rect4188"
style="opacity:1;fill:#222;fill-opacity:1;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4210"
d="m 42.999999,997.1955 44.999999,0"
style="fill:none;fill-rule:evenodd;stroke:#222;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.94117647" />
<rect
y="992.1955"
x="23"
height="10"
width="10"
id="rect4212"
style="opacity:1;fill:#222;fill-opacity:1;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<title>Octicons (16px subset)</title>
<desc>Octicons v11.2.0 by GitHub - https://primer.style/octicons/ - License: MIT</desc>
<metadata
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:title>@primer/octicons</dc:title>
<dc:identifier>11.2.0</dc:identifier>
<dc:description>A scalable set of icons handcrafted with &lt;3 by GitHub</dc:description>
<dc:format>image/svg+xml</dc:format>
<dc:creator>
<cc:Agent>
<dc:title>GitHub</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title>Copyright (c) 2020 GitHub Inc.</dc:title>
</cc:Agent>
</dc:rights>
<cc:license rdf:resource="https://opensource.org/licenses/MIT" />
<dc:relation>https://primer.style/octicons/</dc:relation>
</cc:Work>
</rdf:RDF>
</metadata>
<symbol id="icon-clippy" viewBox="0 0 16 16">
<path
fill-rule="evenodd"
d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z" />
</symbol>
<symbol id="icon-fold" viewBox="0 0 16 16">
<path d="M10.896 2H8.75V.75a.75.75 0 0 0-1.5 0V2H5.104a.25.25 0 0 0-.177.427l2.896 2.896a.25.25 0 0 0 .354 0l2.896-2.896A.25.25 0 0 0 10.896 2ZM8.75 15.25a.75.75 0 0 1-1.5 0V14H5.104a.25.25 0 0 1-.177-.427l2.896-2.896a.25.25 0 0 1 .354 0l2.896 2.896a.25.25 0 0 1-.177.427H8.75v1.25Zm-6.5-6.5a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5ZM6 8a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1 0-1.5h.5A.75.75 0 0 1 6 8Zm2.25.75a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5ZM12 8a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1 0-1.5h.5A.75.75 0 0 1 12 8Zm2.25.75a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5Z" />
</symbol>
<symbol id="icon-unfold" viewBox="0 0 16 16">
<path d="m8.177.677 2.896 2.896a.25.25 0 0 1-.177.427H8.75v1.25a.75.75 0 0 1-1.5 0V4H5.104a.25.25 0 0 1-.177-.427L7.823.677a.25.25 0 0 1 .354 0ZM7.25 10.75a.75.75 0 0 1 1.5 0V12h2.146a.25.25 0 0 1 .177.427l-2.896 2.896a.25.25 0 0 1-.354 0l-2.896-2.896A.25.25 0 0 1 5.104 12H7.25v-1.25Zm-5-2a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5ZM6 8a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1 0-1.5h.5A.75.75 0 0 1 6 8Zm2.25.75a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5ZM12 8a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1 0-1.5h.5A.75.75 0 0 1 12 8Zm2.25.75a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5Z" />
</symbol>
<use href="#icon-clippy" width="16" height="16" x="0" y="0" />
<view id="view-clippy" viewBox="0 0 16 16" />
<use href="#icon-fold" width="16" height="16" x="0" y="16" />
<view id="view-fold" viewBox="0 16 16 16" />
<use href="#icon-unfold" width="16" height="16" x="0" y="32" />
<view id="view-unfold" viewBox="0 32 16 16" />
</svg>
;(function () {
'use strict'
var SECT_CLASS_RX = /^sect(\d)$/
var navContainer = document.querySelector('.nav-container')
if (!navContainer) return
var navToggle = document.querySelector('.nav-toggle')
var nav = navContainer.querySelector('.nav')
var navMenuToggle = navContainer.querySelector('.nav-menu-toggle')
navToggle.addEventListener('click', showNav)
navContainer.addEventListener('click', trapEvent)
var menuPanel = navContainer.querySelector('[data-panel=menu]')
if (!menuPanel) return
var explorePanel = navContainer.querySelector('[data-panel=explore]')
var currentPageItem = menuPanel.querySelector('.is-current-page')
var originalPageItem = currentPageItem
if (currentPageItem) {
activateCurrentPath(currentPageItem)
scrollItemToMidpoint(menuPanel, currentPageItem.querySelector('.nav-link'))
} else {
menuPanel.scrollTop = 0
}
find(menuPanel, '.nav-item-toggle').forEach(function (btn) {
var li = btn.parentElement
btn.addEventListener('click', toggleActive.bind(li))
var navItemSpan = findNextElement(btn, '.nav-text')
if (navItemSpan) {
navItemSpan.style.cursor = 'pointer'
navItemSpan.addEventListener('click', toggleActive.bind(li))
}
})
if (navMenuToggle && menuPanel.querySelector('.nav-item-toggle')) {
navMenuToggle.style.display = ''
navMenuToggle.addEventListener('click', function () {
var collapse = !this.classList.toggle('is-active')
find(menuPanel, '.nav-item > .nav-item-toggle').forEach(function (btn) {
collapse ? btn.parentElement.classList.remove('is-active') : btn.parentElement.classList.add('is-active')
})
if (currentPageItem) {
if (collapse) activateCurrentPath(currentPageItem)
scrollItemToMidpoint(menuPanel, currentPageItem.querySelector('.nav-link'))
} else {
menuPanel.scrollTop = 0
}
})
}
if (explorePanel) {
explorePanel.querySelector('.context').addEventListener('click', function () {
// NOTE logic assumes there are only two panels
find(nav, '[data-panel]').forEach(function (panel) {
panel.classList.toggle('is-active')
})
})
}
// NOTE prevent text from being selected by double click
menuPanel.addEventListener('mousedown', function (e) {
if (e.detail > 1) e.preventDefault()
})
function onHashChange () {
var navLink
var hash = window.location.hash
if (hash) {
if (hash.indexOf('%')) hash = decodeURIComponent(hash)
navLink = menuPanel.querySelector('.nav-link[href="' + hash + '"]')
if (!navLink) {
var targetNode = document.getElementById(hash.slice(1))
if (targetNode) {
var current = targetNode
var ceiling = document.querySelector('article.doc')
while ((current = current.parentNode) && current !== ceiling) {
var id = current.id
// NOTE: look for section heading
if (!id && (id = SECT_CLASS_RX.test(current.className))) id = (current.firstElementChild || {}).id
if (id && (navLink = menuPanel.querySelector('.nav-link[href="#' + id + '"]'))) break
}
}
}
}
var navItem
if (navLink) {
navItem = navLink.parentNode
} else if (originalPageItem) {
navLink = (navItem = originalPageItem).querySelector('.nav-link')
} else {
return
}
if (navItem === currentPageItem) return
find(menuPanel, '.nav-item.is-active').forEach(function (el) {
el.classList.remove('is-active', 'is-current-path', 'is-current-page')
})
navItem.classList.add('is-current-page')
currentPageItem = navItem
activateCurrentPath(navItem)
scrollItemToMidpoint(menuPanel, navLink)
}
if (menuPanel.querySelector('.nav-link[href^="#"]')) {
if (window.location.hash) onHashChange()
window.addEventListener('hashchange', onHashChange)
}
function activateCurrentPath (navItem) {
var ancestorClasses
var ancestor = navItem.parentNode
while (!(ancestorClasses = ancestor.classList).contains('nav-menu')) {
if (ancestor.tagName === 'LI' && ancestorClasses.contains('nav-item')) {
ancestorClasses.add('is-active', 'is-current-path')
}
ancestor = ancestor.parentNode
}
navItem.classList.add('is-active')
}
function toggleActive () {
if (this.classList.toggle('is-active')) {
var padding = parseFloat(window.getComputedStyle(this).marginTop)
var rect = this.getBoundingClientRect()
var menuPanelRect = menuPanel.getBoundingClientRect()
var overflowY = (rect.bottom - menuPanelRect.top - menuPanelRect.height + padding).toFixed()
if (overflowY > 0) menuPanel.scrollTop += Math.min((rect.top - menuPanelRect.top - padding).toFixed(), overflowY)
}
}
function showNav (e) {
if (navToggle.classList.contains('is-active')) return hideNav(e)
trapEvent(e)
var html = document.documentElement
html.classList.add('is-clipped--nav')
navToggle.classList.add('is-active')
navContainer.classList.add('is-active')
var bounds = nav.getBoundingClientRect()
var expectedHeight = window.innerHeight - Math.round(bounds.top)
if (Math.round(bounds.height) !== expectedHeight) nav.style.height = expectedHeight + 'px'
html.addEventListener('click', hideNav)
}
function hideNav (e) {
trapEvent(e)
var html = document.documentElement
html.classList.remove('is-clipped--nav')
navToggle.classList.remove('is-active')
navContainer.classList.remove('is-active')
html.removeEventListener('click', hideNav)
}
function trapEvent (e) {
e.stopPropagation()
}
function scrollItemToMidpoint (panel, el) {
var rect = panel.getBoundingClientRect()
var effectiveHeight = rect.height
var navStyle = window.getComputedStyle(nav)
if (navStyle.position === 'sticky') effectiveHeight -= rect.top - parseFloat(navStyle.top)
panel.scrollTop = Math.max(0, (el.getBoundingClientRect().height - effectiveHeight) * 0.5 + el.offsetTop)
}
function find (from, selector) {
return [].slice.call(from.querySelectorAll(selector))
}
function findNextElement (from, selector) {
var el = from.nextElementSibling
return el && selector ? el[el.matches ? 'matches' : 'msMatchesSelector'](selector) && el : el
}
})()
;(function () {
'use strict'
var sidebar = document.querySelector('aside.toc.sidebar')
if (!sidebar) return
if (document.querySelector('body.-toc')) return sidebar.parentNode.removeChild(sidebar)
var levels = parseInt(sidebar.dataset.levels || 2, 10)
if (levels < 0) return
var articleSelector = 'article.doc'
var article = document.querySelector(articleSelector)
if (!article) return
var headingsSelector = []
for (var level = 0; level <= levels; level++) {
var headingSelector = [articleSelector]
if (level) {
for (var l = 1; l <= level; l++) headingSelector.push((l === 2 ? '.sectionbody>' : '') + '.sect' + l)
headingSelector.push('h' + (level + 1) + '[id]' + (level > 1 ? ':not(.discrete)' : ''))
} else {
headingSelector.push('h1[id].sect0')
}
headingsSelector.push(headingSelector.join('>'))
}
var headings = find(headingsSelector.join(','), article.parentNode)
if (!headings.length) return sidebar.parentNode.removeChild(sidebar)
var lastActiveFragment
var links = {}
var list = headings.reduce(function (accum, heading) {
var link = document.createElement('a')
link.textContent = heading.textContent
links[(link.href = '#' + heading.id)] = link
var listItem = document.createElement('li')
listItem.dataset.level = parseInt(heading.nodeName.slice(1), 10) - 1
listItem.appendChild(link)
accum.appendChild(listItem)
return accum
}, document.createElement('ul'))
var menu = sidebar.querySelector('.toc-menu')
if (!menu) (menu = document.createElement('div')).className = 'toc-menu'
var title = document.createElement('h3')
title.textContent = sidebar.dataset.title || 'Contents'
menu.appendChild(title)
menu.appendChild(list)
var startOfContent = !document.getElementById('toc') && article.querySelector('h1.page ~ :not(.is-before-toc)')
if (startOfContent) {
var embeddedToc = document.createElement('aside')
embeddedToc.className = 'toc embedded'
embeddedToc.appendChild(menu.cloneNode(true))
startOfContent.parentNode.insertBefore(embeddedToc, startOfContent)
}
window.addEventListener('load', function () {
onScroll()
window.addEventListener('scroll', onScroll)
})
function onScroll () {
var scrolledBy = window.pageYOffset
var buffer = getNumericStyleVal(document.documentElement, 'fontSize') * 1.15
var ceil = article.offsetTop
if (scrolledBy && window.innerHeight + scrolledBy + 2 >= document.documentElement.scrollHeight) {
lastActiveFragment = Array.isArray(lastActiveFragment) ? lastActiveFragment : Array(lastActiveFragment || 0)
var activeFragments = []
var lastIdx = headings.length - 1
headings.forEach(function (heading, idx) {
var fragment = '#' + heading.id
if (idx === lastIdx || heading.getBoundingClientRect().top + getNumericStyleVal(heading, 'paddingTop') > ceil) {
activeFragments.push(fragment)
if (lastActiveFragment.indexOf(fragment) < 0) links[fragment].classList.add('is-active')
} else if (~lastActiveFragment.indexOf(fragment)) {
links[lastActiveFragment.shift()].classList.remove('is-active')
}
})
list.scrollTop = list.scrollHeight - list.offsetHeight
lastActiveFragment = activeFragments.length > 1 ? activeFragments : activeFragments[0]
return
}
if (Array.isArray(lastActiveFragment)) {
lastActiveFragment.forEach(function (fragment) {
links[fragment].classList.remove('is-active')
})
lastActiveFragment = undefined
}
var activeFragment
headings.some(function (heading) {
if (heading.getBoundingClientRect().top + getNumericStyleVal(heading, 'paddingTop') - buffer > ceil) return true
activeFragment = '#' + heading.id
})
if (activeFragment) {
if (activeFragment === lastActiveFragment) return
if (lastActiveFragment) links[lastActiveFragment].classList.remove('is-active')
var activeLink = links[activeFragment]
activeLink.classList.add('is-active')
if (list.scrollHeight > list.offsetHeight) {
list.scrollTop = Math.max(0, activeLink.offsetTop + activeLink.offsetHeight - list.offsetHeight)
}
lastActiveFragment = activeFragment
} else if (lastActiveFragment) {
links[lastActiveFragment].classList.remove('is-active')
lastActiveFragment = undefined
}
}
function find (selector, from) {
return [].slice.call((from || document).querySelectorAll(selector))
}
function getNumericStyleVal (el, prop) {
return parseFloat(window.getComputedStyle(el)[prop])
}
})()
;(function () {
'use strict'
var article = document.querySelector('article.doc')
if (!article) return
var toolbar = document.querySelector('.toolbar')
var supportsScrollToOptions = 'scrollTo' in document.documentElement
function decodeFragment (hash) {
return hash && (~hash.indexOf('%') ? decodeURIComponent(hash) : hash).slice(1)
}
function computePosition (el, sum) {
return article.contains(el) ? computePosition(el.offsetParent, el.offsetTop + sum) : sum
}
function jumpToAnchor (e) {
if (e) {
if (e.altKey || e.ctrlKey) return
window.location.hash = '#' + this.id
e.preventDefault()
}
var y = computePosition(this, 0) - toolbar.getBoundingClientRect().bottom
var instant = e === false && supportsScrollToOptions
instant ? window.scrollTo({ left: 0, top: y, behavior: 'instant' }) : window.scrollTo(0, y)
}
window.addEventListener('load', function jumpOnLoad (e) {
var fragment, target
if ((fragment = decodeFragment(window.location.hash)) && (target = document.getElementById(fragment))) {
jumpToAnchor.call(target, false)
setTimeout(jumpToAnchor.bind(target, false), 250)
}
window.removeEventListener('load', jumpOnLoad)
})
Array.prototype.slice.call(document.querySelectorAll('a[href^="#"]')).forEach(function (el) {
var fragment, target
if ((fragment = decodeFragment(el.hash)) && (target = document.getElementById(fragment))) {
el.addEventListener('click', jumpToAnchor.bind(target))
}
})
})()
;(function () {
'use strict'
var toggle = document.querySelector('.page-versions .version-menu-toggle')
if (!toggle) return
var selector = document.querySelector('.page-versions')
toggle.addEventListener('click', function (e) {
selector.classList.toggle('is-active')
e.stopPropagation() // trap event
})
document.documentElement.addEventListener('click', function () {
selector.classList.remove('is-active')
})
})()
;(function () {
'use strict'
var navbarBurger = document.querySelector('.navbar-burger')
if (!navbarBurger) return
navbarBurger.addEventListener('click', toggleNavbarMenu.bind(navbarBurger))
function toggleNavbarMenu (e) {
e.stopPropagation() // trap event
document.documentElement.classList.toggle('is-clipped--navbar')
navbarBurger.setAttribute('aria-expanded', this.classList.toggle('is-active'))
var menu = document.getElementById(this.getAttribute('aria-controls') || this.dataset.target)
if (menu.classList.toggle('is-active')) {
menu.style.maxHeight = ''
var expectedMaxHeight = window.innerHeight - Math.round(menu.getBoundingClientRect().top)
var actualMaxHeight = parseInt(window.getComputedStyle(menu).maxHeight, 10)
if (actualMaxHeight !== expectedMaxHeight) menu.style.maxHeight = expectedMaxHeight + 'px'
}
}
})()
;(function () {
'use strict'
var CMD_RX = /^\$ (\S[^\\\n]*(\\\n(?!\$ )[^\\\n]*)*)(?=\n|$)/gm
var LINE_CONTINUATION_RX = /( ) *\\\n *|\\\n( ?) */g
var TRAILING_SPACE_RX = / +$/gm
var config = (document.getElementById('site-script') || { dataset: {} }).dataset
var supportsCopy = window.navigator.clipboard
var svgAs = config.svgAs
var uiRootPath = (config.uiRootPath == null ? window.uiRootPath : config.uiRootPath) || '.'
;[].slice.call(document.querySelectorAll('.doc pre.highlight, .doc .literalblock pre')).forEach(function (pre) {
var code, language, lang, copy, toast, toolbox
if (pre.classList.contains('highlight')) {
code = pre.querySelector('code')
if ((language = code.dataset.lang) && language !== 'console') {
;(lang = document.createElement('span')).className = 'source-lang'
lang.appendChild(document.createTextNode(language))
}
} else if (pre.innerText.startsWith('$ ')) {
var block = pre.parentNode.parentNode
block.classList.remove('literalblock')
block.classList.add('listingblock')
pre.classList.add('highlightjs', 'highlight')
;(code = document.createElement('code')).className = 'language-console hljs'
code.dataset.lang = 'console'
code.appendChild(pre.firstChild)
pre.appendChild(code)
} else {
return
}
;(toolbox = document.createElement('div')).className = 'source-toolbox'
if (lang) toolbox.appendChild(lang)
if (supportsCopy) {
;(copy = document.createElement('button')).className = 'copy-button'
copy.setAttribute('title', 'Copy to clipboard')
if (svgAs === 'svg') {
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
svg.setAttribute('class', 'copy-icon')
var use = document.createElementNS('http://www.w3.org/2000/svg', 'use')
use.setAttribute('href', uiRootPath + '/img/octicons-16.svg#icon-clippy')
svg.appendChild(use)
copy.appendChild(svg)
} else {
var img = document.createElement('img')
img.src = uiRootPath + '/img/octicons-16.svg#view-clippy'
img.alt = 'copy icon'
img.className = 'copy-icon'
copy.appendChild(img)
}
;(toast = document.createElement('span')).className = 'copy-toast'
toast.appendChild(document.createTextNode('Copied!'))
copy.appendChild(toast)
toolbox.appendChild(copy)
}
pre.parentNode.appendChild(toolbox)
if (copy) copy.addEventListener('click', writeToClipboard.bind(copy, code))
})
function extractCommands (text) {
var cmds = []
var m
while ((m = CMD_RX.exec(text))) cmds.push(m[1].replace(LINE_CONTINUATION_RX, '$1$2'))
return cmds.join(' && ')
}
function writeToClipboard (code) {
var text = code.innerText.replace(TRAILING_SPACE_RX, '')
if (code.dataset.lang === 'console' && text.startsWith('$ ')) text = extractCommands(text)
window.navigator.clipboard.writeText(text).then(
function () {
this.classList.add('clicked')
this.offsetHeight // eslint-disable-line no-unused-expressions
this.classList.remove('clicked')
}.bind(this),
function () {}
)
}
})()
This diff is collapsed.
<!DOCTYPE html>
<html lang="en">
<head>
{{> head defaultPageTitle='Page Not Found'}}
</head>
<body class="status-404">
{{> header}}
{{> body}}
{{> footer}}
</body>
</html>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<div class="body">
{{> nav}}
{{> main}}
</div>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{{> footer-content}}
{{> footer-scripts}}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment