diff --git a/.nojekyll b/.nojekyll
new file mode 100644
index 0000000..e69de29
diff --git a/CNAME b/CNAME
new file mode 100644
index 0000000..3d959be
--- /dev/null
+++ b/CNAME
@@ -0,0 +1 @@
+keyv.js.org
diff --git a/README.md b/README.md
index a70dcc9..14519c5 100644
--- a/README.md
+++ b/README.md
@@ -1,31 +1,28 @@
-
-
-
+
+
+
-> Simple key-value storage with support for multiple backends.
-
![Last version](https://img.shields.io/github/tag/keyvhq/keyv.svg?style=flat-square)
[![Coverage Status](https://img.shields.io/coveralls/keyvhq/keyv.svg?style=flat-square)](https://coveralls.io/github/keyvhq/keyv)
[![NPM Status](https://img.shields.io/npm/dm/@keyvhq/keyv.svg?style=flat-square)](https://www.npmjs.org/package/@keyvhq/keyv)
-Keyv provides a consistent interface for key-value storage across multiple backends via storage adapters. It supports TTL based expiry, making it suitable as a cache or a persistent key-value store.
+> **Keyv** is a simple key-value storage with support for multiple backend adapters (MySQL, PostgreSQL, SQLite, Redis, Mongo, DynamoDB, Firestore, Memcached, and more).
## Features
-There are a few existing modules similar to Keyv, however Keyv is different because it:
-
-- Isn't bloated.
-- Has a simple Promise based API.
-- Suitable as a TTL based cache or persistent key-value store.
-- [Easily embeddable](#add-cache-support-to-your-module) inside another module.
-- Works with any storage that implements the [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) API.
-- Handles all JSON types plus `Buffer`.
-- Supports namespaces.
-- Wide range of [**efficient, well tested**](#official-storage-adapters) storage adapters.
-- Connection errors are passed through (db failures won't kill your app).
-- Supports the current active LTS version of Node.js or higher.
+- It isn't bloated.
+- It supports namespaces.
+- It supports TTL based expiry.
+- It has a simple Promise based API.
+- It handles all JSON types plus `Buffer`.
+- It's support a [vary of storages](#official-storage-adapters) adapters.
+- It can be [easily embed](#add-cache-support-to-your-module) inside another module.
+- It works with any storage that implements the [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) API.
+- it handles database errors (db failures won't kill your app).
+- It supports the current active LTS version of Node.js or higher.
+- It's suitable as a TTL based cache or persistent key-value store.
## Installation
@@ -45,7 +42,7 @@ npm install @keyvhq/keyv-mysql --save
If you don't provide a specific storage adapter, a in-memory storage adapter is used by default.
-## Usage
+## Getting Started
Just create a new Keyv instance, passing your storage adapter:
@@ -94,13 +91,15 @@ You can optionally provide your own serialization functions to support extra dat
const keyv = new Keyv({ serialize: JSON.stringify, deserialize: JSON.parse });
```
-**Warning:** Using custom serializers means you lose any guarantee of data consistency. You should do extensive testing with your serialisation functions and chosen storage engine.
+!> Using custom serializers means you lose any guarantee of data consistency. You should do extensive testing with your serialisation functions and chosen storage engine.
+
+## Storage Adapters
-## Official Storage Adapters
+### Official
The official storage adapters are covered by [over 150 integration tests](https://github.com/microlinkhq/keyv/actions/runs/949262324) to guarantee consistent behaviour. They are lightweight, efficient wrappers over the DB clients making use of indexes and native TTLs where available.
-## Third-party Storage Adapters
+### Community
You can also use third-party storage adapters or build your own. Keyv will wrap these storage adapters in TTL functionality and handle complex types internally.
@@ -187,42 +186,42 @@ The options object is also passed through to the storage adapter. Check your sto
#### options.namespace
-Type: `String`
+Type: `String`
Default: `'keyv'`
Namespace for the current instance.
#### options.ttl
-Type: `Number`
+Type: `Number`
Default: `undefined`
Default TTL. Can be overridden by specififying a TTL on `.set()`.
#### options.serialize
-Type: `Function`
+Type: `Function`
Default: `JSONB.stringify`
A custom serialization function.
#### options.deserialize
-Type: `Function`
+Type: `Function`
Default: `JSONB.parse`
A custom deserialization function.
#### options.store
-Type: `Storage adapter instance`
+Type: `Storage adapter instance`
Default: `new Map()`
The storage adapter instance to be used by Keyv.
#### options.adapter
-Type: `String`
+Type: `String`
Default: `undefined`
Specify an adapter to use. e.g `'redis'` or `'mongodb'`.
@@ -245,7 +244,7 @@ Returns a promise which resolves to the retrieved value.
##### options.raw
-Type: `Boolean`
+Type: `Boolean`
Default: `false`
If set to true the raw DB object Keyv stores internally will be returned instead of just the value.
@@ -278,7 +277,7 @@ Returns an [Async Iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScr
## License
-**keyv** © [Microlink](https://microlink.io), Released under the [MIT](https://github.com/microlinkhq/keyv/blob/master/LICENSE.md) License.
+**keyv** © [Microlink](https://microlink.io), Released under the [MIT](https://github.com/microlinkhq/keyv/blob/master/LICENSE.md) License.
Authored and maintained by [Microlink](https://microlink.io) with help from [contributors](https://github.com/microlinkhq/keyv/contributors).
> [microlink.io](https://microlink.io) · GitHub [@MicrolinkHQ](https://github.com/microlinkhq) · Twitter [@microlinkhq](https://twitter.com/microlinkhq)
diff --git a/docs/css/style.css b/docs/css/style.css
new file mode 100644
index 0000000..cec2832
--- /dev/null
+++ b/docs/css/style.css
@@ -0,0 +1,562 @@
+@import url("https://rsms.me/inter/inter-ui.css");
+
+:root {
+ /* colors */
+ --base: #f5f4f4;
+ --black: rgba(18, 16, 12, 0.70196);
+ --gray0: #f9f9f9;
+ --gray1: #ededee;
+ --gray2: #e0e1e1;
+ --gray3: #d2d3d4;
+ --gray4: #c3c4c5;
+ --gray5: #b2b3b5;
+ --gray6: #9fa0a2;
+ --gray7: #88898c;
+ --gray8: #6b6c70;
+ --gray9: #3d3f44;
+ --gray10: #000;
+
+ /* theme */
+
+ --primary-color: var(--gray9);
+ --secondary-color: var(--gray10);
+ --accent-color: #fc6568;
+
+ --text-color: #121102;
+ --text-bold-color: var(--gray10);
+
+ --sidebar-color: var(--primary-color);
+ --sidebar-active-color: var(--secondary-color);
+ --sidebar-border-color: #5f6368;
+ --bg-color: var(--base);
+
+ --serif-font: "IBM Plex Sans", sans-serif;
+ --sans-serif-font: "IBM Plex Sans", sans-serif;
+ --code-font: Nitti, "Microsoft YaHei", "Roboto Mono", 微软雅黑, monospace;
+
+ --codebox-border-color: var(--text-color);
+ --codebox-color: var(--text-color);
+ --codebox-token-var-color: var(--text-color);
+ --codebox-bg: var(--bg-color);
+}
+
+::selection {
+ background: #f9e4ac;
+}
+
+::-moz-selection {
+ background: #f9e4ac;
+}
+
+* {
+ -webkit-font-smoothing: antialiased;
+ -webkit-overflow-scrolling: touch;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ -webkit-text-size-adjust: none;
+ -webkit-touch-callout: none;
+ box-sizing: border-box;
+}
+
+.progress {
+ background-color: var(--primary-color);
+ height: 2px;
+ left: 0;
+ position: fixed;
+ right: 0;
+ top: 0;
+ transition: width 0.2s, opacity 0.4s;
+ width: 0;
+ z-index: 5;
+}
+
+body,
+html {
+ height: 100%;
+}
+
+body {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ color: var(--text-color);
+ font-family: var(--sans-serif-font);
+ font-size: 16px;
+ letter-spacing: 0;
+ margin: 0;
+ overflow-x: hidden;
+}
+
+img {
+ max-width: 100%;
+}
+
+.github-corner {
+ border-bottom: 0;
+ position: fixed;
+ right: 0;
+ text-decoration: none;
+ top: 0;
+ z-index: 1;
+}
+
+.github-corner svg {
+ color: #fff;
+ fill: var(--accent-color);
+ height: 80px;
+ width: 80px;
+}
+
+.github-corner:hover .octo-arm {
+ animation: a 0.56s ease-in-out;
+}
+
+main {
+ display: block;
+ position: relative;
+ width: 100vw;
+ height: 100%;
+ z-index: 0;
+}
+
+.anchor {
+ display: inline-block;
+ text-decoration: none;
+ transition: all 0.3s;
+}
+
+.anchor span {
+ color: var(--secondary-color);
+}
+
+.anchor:hover {
+ text-decoration: underline;
+}
+
+.sidebar {
+ font-family: var(--serif-font);
+ overflow-y: auto;
+ padding: 40px 0 0;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ position: absolute;
+ transition: transform 0.25s ease-out;
+ width: 300px;
+ z-index: 3;
+}
+
+.sidebar .sidebar-nav {
+ line-height: 2em;
+ padding-bottom: 40px;
+}
+
+.sidebar ul {
+ margin: 0;
+ padding: 0;
+}
+
+.sidebar ul,
+.sidebar ul li {
+ list-style: none;
+}
+
+.sidebar ul li a {
+ border-bottom: none;
+ display: block;
+}
+
+.sidebar::-webkit-scrollbar {
+ width: 4px;
+}
+
+.sidebar::-webkit-scrollbar-thumb {
+ background: transparent;
+ border-radius: 4px;
+}
+
+.sidebar:hover::-webkit-scrollbar-thumb {
+ background: hsla(0, 0%, 53%, 0.4);
+}
+
+.sidebar:hover::-webkit-scrollbar-track {
+ background: hsla(0, 0%, 53%, 0.1);
+}
+
+.sidebar-toggle {
+ background-color: transparent;
+ background-color: var(--bg-color);
+ border: 0;
+ outline: none;
+ padding: 10px;
+ bottom: 0;
+ left: 0;
+ position: absolute;
+ text-align: center;
+ transition: opacity 0.3s;
+ width: 30px;
+ width: 284px;
+ z-index: 4;
+}
+
+.sidebar-toggle .sidebar-toggle-button:hover {
+ opacity: 0.4;
+}
+
+.sidebar-toggle span {
+ background-color: var(--primary-color);
+ display: block;
+ margin-bottom: 4px;
+ width: 16px;
+ height: 2px;
+}
+
+body.sticky .sidebar,
+body.sticky .sidebar-toggle {
+ position: fixed;
+}
+
+.content {
+ padding-top: 60px;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 300px;
+ position: absolute;
+ transition: left 0.25s ease;
+}
+
+.markdown-section {
+ margin: 0 auto;
+ max-width: 800px;
+ padding: 30px 15px 40px;
+ position: relative;
+}
+
+.markdown-section>* {
+ box-sizing: border-box;
+ font-size: inherit;
+}
+
+.markdown-section> :first-child {
+ margin-top: 0 !important;
+}
+
+.markdown-section p.tip {
+ background-color: #f8f8f8;
+ border-bottom-right-radius: 2px;
+ border-left: 4px solid var(--accent-color);
+ border-top-right-radius: 2px;
+ margin: 2em 0;
+ padding: 12px 24px 12px 30px;
+ position: relative;
+}
+
+.markdown-section p.tip:before {
+ background-color: var(--accent-color);
+ border-radius: 100%;
+ color: #fff;
+ content: "!";
+ font-family: Dosis, Source Sans Pro, Helvetica Neue, Arial, sans-serif;
+ font-size: 14px;
+ font-weight: 700;
+ left: -12px;
+ line-height: 20px;
+ position: absolute;
+ width: 20px;
+ height: 20px;
+ text-align: center;
+ top: 14px;
+}
+
+@media print {
+
+ .github-corner,
+ .sidebar,
+ .sidebar-toggle {
+ display: none;
+ }
+}
+
+@media screen and (max-width: 768px) {
+
+ .github-corner,
+ .sidebar,
+ .sidebar-toggle {
+ position: fixed;
+ }
+
+ main {
+ height: auto;
+ overflow-x: hidden;
+ }
+
+ .sidebar {
+ left: -300px;
+ transition: transform 0.25s ease-out;
+ }
+
+ .content {
+ left: 0;
+ max-width: 100vw;
+ position: static;
+ padding-top: 20px;
+ transition: transform 0.25s ease;
+ }
+
+ .github-corner {
+ transition: transform 0.25s ease-out;
+ }
+
+ .sidebar-toggle {
+ background-color: transparent;
+ width: auto;
+ }
+
+ .github-corner .octo-arm {
+ animation: a 0.56s ease-in-out;
+ }
+
+ .github-corner:hover .octo-arm {
+ animation: none;
+ }
+}
+
+@keyframes a {
+
+ 0%,
+ to {
+ transform: rotate(0);
+ }
+
+ 20%,
+ 60% {
+ transform: rotate(-25deg);
+ }
+
+ 40%,
+ 80% {
+ transform: rotate(10deg);
+ }
+}
+
+.sidebar,
+body {
+ background-color: var(--bg-color);
+ color: var(--primary-color);
+}
+
+.sidebar {
+ color: #364149;
+}
+
+.sidebar li {
+ margin: 6px 0 6px 15px;
+}
+
+.sidebar ul li a {
+ color: var(--sidebar-color);
+ font-size: 14px;
+ font-weight: 400;
+ overflow: hidden;
+ text-decoration: none;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.sidebar ul li a:hover {
+ text-decoration: underline;
+}
+
+.sidebar ul li.active>a {
+ border-right: 2px solid;
+ color: var(--sidebar-active-color);
+ font-weight: 700;
+}
+
+.markdown-section h1,
+.markdown-section h2,
+.markdown-section h3,
+.markdown-section h4,
+.markdown-section h5 {
+ font-family: var(--serif-font);
+}
+
+.markdown-section strong {
+ font-family: var(--sans-serif-font);
+ color: var(--text-bold-color);
+}
+
+.markdown-section a {
+ color: var(--primary-color);
+ text-decoration: none;
+ font-weight: 600;
+}
+
+.markdown-section li a,
+.markdown-section p a {
+ color: var(--accent-color);
+ text-decoration: underline;
+ text-underline-offset: 1px;
+}
+
+.markdown-section li a:hover,
+.markdown-section p a:hover {
+ opacity: 0.8;
+}
+
+.markdown-section h1 {
+ font-size: 2rem;
+ margin: 4rem 0 1rem;
+}
+
+.markdown-section h2 {
+ font-size: 1.75rem;
+ margin: 3.5rem 0 1rem;
+}
+
+.markdown-section h3 {
+ font-size: 1.5rem;
+ margin: 3rem 0 1rem;
+}
+
+.markdown-section h4 {
+ font-size: 1.25rem;
+ margin: 2.5rem 0 1rem;
+}
+
+.markdown-section h5 {
+ font-size: 1rem;
+}
+
+.markdown-section p {
+ margin: 1.2em 0;
+}
+
+.markdown-section p,
+.markdown-section ul {
+ line-height: 1.8rem;
+ word-spacing: 0.05rem;
+}
+
+.markdown-section ul li {
+ margin-bottom: 10px;
+}
+
+.markdown-section ul {
+ padding-left: 2rem;
+}
+
+.markdown-section blockquote {
+ border-left: 4px solid var(--primary-color);
+ margin: 2em 0;
+ padding-left: 20px;
+}
+
+.markdown-section blockquote p {
+ font-weight: 400;
+ margin-left: 0;
+ padding: 12px 0;
+}
+
+.markdown-section li code,
+.markdown-section p code {
+ color: var(--codebox-token-var-color);
+ border: 1px solid var(--codebox-border-color);
+ background: var(--codebox-bg);
+ font-size: 0.75rem;
+ padding: 3px 10px;
+ border-radius: 3px;
+ white-space: nowrap;
+}
+
+.markdown-section code {
+ border-radius: 2px;
+ color: var(--codebox-token-var-color);
+ font-size: 0.8rem;
+ margin: 0 2px;
+ padding: 3px 5px;
+ white-space: pre-wrap;
+}
+
+.markdown-section pre {
+ border-radius: 5px;
+ background-color: var(--codebox-bg);
+ border: 1px solid var(--codebox-border-color);
+}
+
+.markdown-section code,
+.markdown-section pre {
+ font-family: var(--code-font);
+}
+
+.markdown-section pre {
+ line-height: 1.5rem;
+ margin: 1.2em 0;
+ overflow: auto;
+ padding: 0 0.7rem;
+ position: relative;
+ word-wrap: normal;
+}
+
+.markdown-section pre,
+.markdown-section pre>code {
+ -moz-osx-font-smoothing: initial;
+ -webkit-font-smoothing: initial;
+}
+
+.markdown-section pre>code {
+ background-color: var(--codebox-bg);
+ border-radius: 2px;
+ color: var(--codebox-token-var-color);
+ display: block;
+ font-family: var(--code-font);
+ font-size: 0.8rem;
+ line-height: inherit;
+ margin: 0 2px;
+ max-width: inherit;
+ overflow: inherit;
+ padding: 1.25em 5px;
+ white-space: inherit;
+}
+
+.markdown-section code:after,
+.markdown-section code:before {
+ letter-spacing: 0.8px;
+ letter-spacing: 0.05rem;
+}
+
+.token.class-name,
+.token.function,
+.token.number {
+ color: #d46e00;
+}
+
+.token.string {
+ color: #d40066;
+}
+
+.token.constant,
+.token.keyword {
+ color: #e00400;
+}
+
+.token.comment {
+ color: var(--gray7);
+}
+
+pre:after {
+ color: #ccc;
+ content: attr(data-lang);
+ font-size: 0.6rem;
+ font-weight: 600;
+ height: 15px;
+ line-height: 15px;
+ padding: 5px 10px 0;
+ position: absolute;
+ right: 0;
+ text-align: right;
+ top: 0;
+}
+
+.sidebar ul ul {
+ margin-left: 15px;
+}
diff --git a/docs/js/main.js b/docs/js/main.js
new file mode 100644
index 0000000..bce08c7
--- /dev/null
+++ b/docs/js/main.js
@@ -0,0 +1,16 @@
+/* global codecopy */
+
+window.$docsify = {
+ repo: 'microlinkhq/keyv',
+ maxLevel: 3,
+ executeScript: true,
+ auto2top: true,
+ noEmoji: true,
+ plugins: [
+ function (hook, vm) {
+ hook.ready(function () {
+ codecopy('pre')
+ })
+ }
+ ]
+}
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 0000000..3195099
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,48 @@
+'use strict'
+
+const strip = require('gulp-strip-css-comments')
+const prefix = require('gulp-autoprefixer')
+const cssnano = require('gulp-cssnano')
+const uglify = require('gulp-uglify')
+const concat = require('gulp-concat')
+const gulp = require('gulp')
+
+const src = {
+ css: ['docs/css/style.css'],
+ js: ['docs/js/main.js']
+}
+
+const dist = {
+ path: 'static',
+ name: {
+ css: 'style',
+ js: 'main'
+ }
+}
+
+const styles = () =>
+ gulp
+ .src(src.css)
+ .pipe(concat(`${dist.name.css}.min.css`))
+ .pipe(prefix())
+ .pipe(strip({ all: true }))
+ .pipe(cssnano())
+ .pipe(gulp.dest(dist.path))
+
+const scripts = () =>
+ gulp
+ .src(src.js)
+ .pipe(concat(`${dist.name.js}.min.js`))
+ .pipe(uglify())
+ .pipe(gulp.dest(dist.path))
+
+const build = gulp.parallel(styles, scripts)
+
+function watch () {
+ gulp.watch(src.css, styles)
+ gulp.watch(src.js, scripts)
+}
+
+module.exports.default = gulp.series(build, watch)
+module.exports.build = build
+module.exports.watch = watch
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..c31951a
--- /dev/null
+++ b/index.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Keyv is a simple key-value storage with support for multiple backend adapters (MySQL, PostgreSQL, SQLite, Redis, Mongo, DynamoDB, Firestore, Memcached, and more).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/media/logo-sunset.svg b/media/logo-sunset.svg
new file mode 100644
index 0000000..5839e36
--- /dev/null
+++ b/media/logo-sunset.svg
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
index c8f87c2..ecb9a38 100644
--- a/package.json
+++ b/package.json
@@ -109,7 +109,15 @@
"lerna": "latest",
"lint-staged": "latest",
"simple-git-hooks": "latest",
- "standard": "latest"
+ "standard": "latest",
+ "gulp": "latest",
+ "gulp-autoprefixer": "latest",
+ "gulp-concat": "latest",
+ "gulp-cssnano": "latest",
+ "gulp-strip-css-comments": "latest",
+ "gulp-uglify": "latest",
+ "browser-sync": "latest",
+ "concurrently": "latest"
},
"engines": {
"node": ">= 12"
@@ -118,6 +126,9 @@
"packages/**"
],
"scripts": {
+ "build": "gulp build",
+ "dev": "concurrently \"gulp\" \"npm run dev:server\"",
+ "dev:server": "browser-sync start --server --files \"index.html, README.md, static/**/*.(css|js)\"",
"clean": "lerna clean --yes && rm -rf node_modules",
"contributors": "(lerna exec finepack --parallel && git-authors-cli && finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true",
"install": "lerna bootstrap --no-ci --force-local",
diff --git a/static/banner.jpg b/static/banner.jpg
new file mode 100644
index 0000000..80ead47
Binary files /dev/null and b/static/banner.jpg differ
diff --git a/static/banner.png b/static/banner.png
new file mode 100644
index 0000000..f8c1a23
Binary files /dev/null and b/static/banner.png differ
diff --git a/static/favicon-16x16.png b/static/favicon-16x16.png
new file mode 100644
index 0000000..52b8a6a
Binary files /dev/null and b/static/favicon-16x16.png differ
diff --git a/static/favicon-32x32.png b/static/favicon-32x32.png
new file mode 100644
index 0000000..a7fdc81
Binary files /dev/null and b/static/favicon-32x32.png differ
diff --git a/static/favicon.ico b/static/favicon.ico
new file mode 100644
index 0000000..da5215d
Binary files /dev/null and b/static/favicon.ico differ
diff --git a/static/logo.jpg b/static/logo.jpg
new file mode 100644
index 0000000..f6b7135
Binary files /dev/null and b/static/logo.jpg differ
diff --git a/static/logo.png b/static/logo.png
new file mode 100644
index 0000000..de76afe
Binary files /dev/null and b/static/logo.png differ
diff --git a/static/main.min.js b/static/main.min.js
new file mode 100644
index 0000000..169a3b8
--- /dev/null
+++ b/static/main.min.js
@@ -0,0 +1 @@
+window.$docsify={repo:"microlinkhq/keyv",maxLevel:3,executeScript:!0,auto2top:!0,noEmoji:!0,plugins:[function(o,e){o.ready(function(){codecopy("pre")})}]};
\ No newline at end of file
diff --git a/static/style.min.css b/static/style.min.css
new file mode 100644
index 0000000..e345f7e
--- /dev/null
+++ b/static/style.min.css
@@ -0,0 +1 @@
+@import url("https://rsms.me/inter/inter-ui.css");:root{--base:#f5f4f4;--black:rgba(18,16,12,.70196);--gray0:#f9f9f9;--gray1:#ededee;--gray2:#e0e1e1;--gray3:#d2d3d4;--gray4:#c3c4c5;--gray5:#b2b3b5;--gray6:#9fa0a2;--gray7:#88898c;--gray8:#6b6c70;--gray9:#3d3f44;--gray10:#000;--primary-color:var(--gray9);--secondary-color:var(--gray10);--accent-color:#fc6568;--text-color:#121102;--text-bold-color:var(--gray10);--sidebar-color:var(--primary-color);--sidebar-active-color:var(--secondary-color);--sidebar-border-color:#5f6368;--bg-color:var(--base);--serif-font:"IBM Plex Sans",sans-serif;--sans-serif-font:"IBM Plex Sans",sans-serif;--code-font:Nitti,"Microsoft YaHei","Roboto Mono",微软雅黑,monospace;--codebox-border-color:var(--text-color);--codebox-color:var(--text-color);--codebox-token-var-color:var(--text-color);--codebox-bg:var(--bg-color)}::selection{background:#f9e4ac}::-moz-selection{background:#f9e4ac}*{-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none;box-sizing:border-box}.progress{background-color:var(--primary-color);height:2px;left:0;position:fixed;right:0;top:0;transition:width .2s,opacity .4s;width:0;z-index:4}body,html{height:100%}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;color:var(--text-color);font-family:var(--sans-serif-font);font-size:16px;letter-spacing:0;margin:0;overflow-x:hidden}img{max-width:100%}.github-corner{border-bottom:0;position:fixed;right:0;text-decoration:none;top:0;z-index:1}.github-corner svg{color:#fff;fill:var(--accent-color);height:80px;width:80px}.github-corner:hover .octo-arm{animation:a .56s ease-in-out}main{display:block;position:relative;width:100vw;height:100%;z-index:0}.anchor{display:inline-block;text-decoration:none;transition:all .3s}.anchor span{color:var(--secondary-color)}.anchor:hover{text-decoration:underline}.sidebar{font-family:var(--serif-font);overflow-y:auto;padding:40px 0 0;top:0;bottom:0;left:0;position:absolute;transition:transform .25s ease-out;width:300px;z-index:2}.sidebar .sidebar-nav{line-height:2em;padding-bottom:40px}.sidebar ul{margin:0;padding:0}.sidebar ul,.sidebar ul li{list-style:none}.sidebar ul li a{border-bottom:none;display:block}.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:transparent;border-radius:4px}.sidebar:hover::-webkit-scrollbar-thumb{background:hsla(0,0%,53%,.4)}.sidebar:hover::-webkit-scrollbar-track{background:hsla(0,0%,53%,.1)}.sidebar-toggle{background-color:transparent;background-color:var(--bg-color);border:0;outline:none;padding:10px;bottom:0;left:0;position:absolute;text-align:center;transition:opacity .3s;width:30px;width:284px;z-index:3}.sidebar-toggle .sidebar-toggle-button:hover{opacity:.4}.sidebar-toggle span{background-color:var(--primary-color);display:block;margin-bottom:4px;width:16px;height:2px}body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}.content{padding-top:60px;top:0;right:0;bottom:0;left:300px;position:absolute;transition:left .25s ease}.markdown-section{margin:0 auto;max-width:800px;padding:30px 15px 40px;position:relative}.markdown-section>*{box-sizing:border-box;font-size:inherit}.markdown-section>:first-child{margin-top:0!important}.markdown-section p.tip{background-color:#f8f8f8;border-bottom-right-radius:2px;border-left:4px solid var(--accent-color);border-top-right-radius:2px;margin:2em 0;padding:12px 24px 12px 30px;position:relative}.markdown-section p.tip:before{background-color:var(--accent-color);border-radius:100%;color:#fff;content:"!";font-family:Dosis,Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:14px;font-weight:700;left:-12px;line-height:20px;position:absolute;width:20px;height:20px;text-align:center;top:14px}@media print{.github-corner,.sidebar,.sidebar-toggle{display:none}}@media screen and (max-width:768px){.github-corner,.sidebar,.sidebar-toggle{position:fixed}main{height:auto;overflow-x:hidden}.sidebar{left:-300px;transition:transform .25s ease-out}.content{left:0;max-width:100vw;position:static;padding-top:20px;transition:transform .25s ease}.github-corner{transition:transform .25s ease-out}.sidebar-toggle{background-color:transparent;width:auto}.github-corner .octo-arm{animation:a .56s ease-in-out}.github-corner:hover .octo-arm{animation:none}}@keyframes a{0%,to{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}.sidebar,body{background-color:var(--bg-color);color:var(--primary-color)}.sidebar{color:#364149}.sidebar li{margin:6px 0 6px 15px}.sidebar ul li a{color:var(--sidebar-color);font-size:14px;font-weight:400;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.sidebar ul li a:hover{text-decoration:underline}.sidebar ul li.active>a{border-right:2px solid;color:var(--sidebar-active-color);font-weight:700}.markdown-section h1,.markdown-section h2,.markdown-section h3,.markdown-section h4,.markdown-section h5{font-family:var(--serif-font)}.markdown-section strong{font-family:var(--sans-serif-font);color:var(--text-bold-color)}.markdown-section a{color:var(--primary-color);text-decoration:none;font-weight:600}.markdown-section li a,.markdown-section p a{color:var(--accent-color);text-decoration:underline;text-underline-offset:1px}.markdown-section li a:hover,.markdown-section p a:hover{opacity:.8}.markdown-section h1{font-size:2rem;margin:4rem 0 1rem}.markdown-section h2{font-size:1.75rem;margin:3.5rem 0 1rem}.markdown-section h3{font-size:1.5rem;margin:3rem 0 1rem}.markdown-section h4{font-size:1.25rem;margin:2.5rem 0 1rem}.markdown-section h5{font-size:1rem}.markdown-section p{margin:1.2em 0}.markdown-section p,.markdown-section ul{line-height:1.8rem;word-spacing:.05rem}.markdown-section ul li{margin-bottom:10px}.markdown-section ul{padding-left:2rem}.markdown-section blockquote{border-left:4px solid var(--primary-color);margin:2em 0;padding-left:20px}.markdown-section blockquote p{font-weight:400;margin-left:0;padding:12px 0}.markdown-section li code,.markdown-section p code{color:var(--codebox-token-var-color);border:1px solid var(--codebox-border-color);background:var(--codebox-bg);font-size:.75rem;padding:3px 10px;border-radius:3px;white-space:nowrap}.markdown-section code{border-radius:2px;color:var(--codebox-token-var-color);font-size:.8rem;margin:0 2px;padding:3px 5px;white-space:pre-wrap}.markdown-section pre{border-radius:5px;background-color:var(--codebox-bg);border:1px solid var(--codebox-border-color)}.markdown-section code,.markdown-section pre{font-family:var(--code-font)}.markdown-section pre{line-height:1.5rem;margin:1.2em 0;overflow:auto;padding:0 .7rem;position:relative;word-wrap:normal}.markdown-section pre,.markdown-section pre>code{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial}.markdown-section pre>code{background-color:var(--codebox-bg);border-radius:2px;color:var(--codebox-token-var-color);display:block;font-family:var(--code-font);font-size:.8rem;line-height:inherit;margin:0 2px;max-width:inherit;overflow:inherit;padding:1.25em 5px;white-space:inherit}.markdown-section code:after,.markdown-section code:before{letter-spacing:.8px;letter-spacing:.05rem}.token.class-name,.token.function,.token.number{color:#d46e00}.token.string{color:#d40066}.token.constant,.token.keyword{color:#e00400}.token.comment{color:var(--gray7)}pre:after{color:#ccc;content:attr(data-lang);font-size:.6rem;font-weight:600;height:15px;line-height:15px;padding:5px 10px 0;position:absolute;right:0;text-align:right;top:0}.sidebar ul ul{margin-left:15px}
\ No newline at end of file