diff --git a/.env b/.env
new file mode 100644
index 0000000..b78a910
--- /dev/null
+++ b/.env
@@ -0,0 +1,3 @@
+GITHUB_USERNAME='nyagami'
+GITHUB_REPOSITORY='plugins'
+GITHUB_BRANCH='main'
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6c02cb0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+node_modules/**/*
+.vscode
diff --git a/README.md b/README.md
index c71dd2b..5d4dd33 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,58 @@
-# LNReader Sources
+
+
+# LNReader Plugins
-Repository to host source related issues, and requests for [LNReader](https://github.com/LNReader/lnreader).
+Repository to host plugins and related issues, and requests for [LNReader](https://github.com/LNReader/lnreader).
+## Contributing
+1. Please use this [template](./template.js) or [template.min](./template.min.js)
+2. Choose your language in [./plugins](./plugins)
++ If your language doenst exist, please request us. We will add it soon.
+3. Write your scripts
++ See example: [Hako](./plugins/vietnamese/LNHako.js)
+
+## Test your script
+We use expressjs to make an UI web for testing.
+1. Installing
+ ```
+ npm install
+ ```
+2. Running
+ ```
+ nodemon index.js
+ ```
+ + Then open http://localhost:3000
+3. Testing
+ + Find you plugin
+ + Check if all functions of your plugin work properly
+#### No need to reload webpage after changing your plugin script.
+- One more thing: you can use [cheerio_space](./cheerio_space) to build functions without requesting to the site.
+----------
+
+ If you want to test plugin in app side, remember to config these things.
+
+in [.env](./.env)
+```
+GITHUB_USERNAME='nyagami'
+GITHUB_REPOSITORY='plugins'
+GITHUB_BRANCH='main'
+```
+
+in [pluginManager.ts](https://github.com/nyagami/lnreader/blob/install_sources/src/plugins/pluginManager.ts)
+```ts
+const fetchPlugins = async () => {
+ const availablePlugins: Record> = await fetch(
+ 'https://raw.githubusercontent.com/nyagami/plugins/main/plugins/plugins.min.json',
+ ).then(res => res.json());
+ return availablePlugins;
+};
+```
+
+----------
The developer of this application does not have any affiliation with the content providers available.
diff --git a/api/plugins.js b/api/plugins.js
new file mode 100644
index 0000000..a020c3f
--- /dev/null
+++ b/api/plugins.js
@@ -0,0 +1,60 @@
+const fs = require('fs');
+const languages = require('@libs/languages');
+const path = require('path')
+const root = path.dirname(require.main.filename);
+
+const githubIconsLink = 'https://raw.githubusercontent.com/nyagami/plugins/main/icons';
+const githubIconSuffix = '?raw=true';
+const githubPluginsLink = 'https://raw.githubusercontent.com/nyagami/plugins/main/plugins';
+const githubPluginSuffix = '?newtest=true';
+
+const all_plugins = () => {
+ const res = {}
+ for (let language in languages) { //language with English name
+ const langPath = path.join(root, 'plugins', language.toLowerCase());
+ if (!fs.existsSync(langPath)) continue;
+ const plugins = fs.readdirSync(langPath);
+ res[languages[language]] = [];
+ plugins.forEach(plugin => {
+ if(plugin.startsWith('.')) return;
+ const requirePath = `@plugins/${language.toLowerCase()}/${plugin.split('.')[0]}`
+ const instance = require(requirePath);
+ const { id, name, lang, version, icon, description } = instance;
+ const info = { id, name, lang, version, description } // lang: language with native name
+ info.url = `${githubPluginsLink}/${language.toLowerCase()}/${plugin}${githubPluginSuffix}`;
+ info.iconUrl = `${githubIconsLink}/${icon}${githubIconSuffix}`;
+ info.requirePath = requirePath;
+ res[lang].push(info);
+ });
+ }
+ return res;
+}
+
+const popularNovels = async (pluginRequirePath, {showLatestNovels, filters}) => {
+ return await require(pluginRequirePath).popularNovels(1, {showLatestNovels, filters});
+}
+
+const searchNovels = async (pluginRequirePath, searchTerm) => {
+ return await require(pluginRequirePath).searchNovels(searchTerm);
+}
+
+const parseNovelAndChapters = async(pluginRequirePath, novelUrl) => {
+ return await require(pluginRequirePath).parseNovelAndChapters(novelUrl);
+}
+
+const parseChapter = async (pluginRequirePath, chapterUrl) => {
+ return await require(pluginRequirePath).parseChapter(chapterUrl);
+}
+
+const fetchImage = async (pluginRequirePath, url) => {
+ return await require(pluginRequirePath).fetchImage(url);
+}
+
+module.exports = {
+ all_plugins,
+ popularNovels,
+ searchNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ fetchImage
+}
\ No newline at end of file
diff --git a/cheerio_space/source.html b/cheerio_space/source.html
new file mode 100644
index 0000000..5132f98
--- /dev/null
+++ b/cheerio_space/source.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+ Html source to test with cheerio.
+ Do not make too many requests, you could get banned from site.
+
+
\ No newline at end of file
diff --git a/cheerio_space/test.js b/cheerio_space/test.js
new file mode 100644
index 0000000..925eb83
--- /dev/null
+++ b/cheerio_space/test.js
@@ -0,0 +1,6 @@
+const cheerio = require('cheerio');
+const fs = require('fs');
+const path = require('path');
+
+const body = fs.readFileSync(path.join(__dirname, 'source.html')).toString();
+const loadedCheerio = cheerio.load(body);
diff --git a/icons/src/kr/agitoon/agit.png b/icons/src/kr/agitoon/agit.png
new file mode 100644
index 0000000..9c623d9
Binary files /dev/null and b/icons/src/kr/agitoon/agit.png differ
diff --git a/icons/src/pt/reaperscans/webicon.png b/icons/src/pt/reaperscans/webicon.png
new file mode 100644
index 0000000..bff0874
Binary files /dev/null and b/icons/src/pt/reaperscans/webicon.png differ
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..34cae07
--- /dev/null
+++ b/index.js
@@ -0,0 +1,47 @@
+require('module-alias/register');
+
+const path = require('path');
+const express = require('express');
+const bodyParser = require('body-parser');
+const pluginApi = require('@api/plugins');
+
+const app = express();
+const port = 3000;
+const host = 'localhost';
+
+app.use(bodyParser.json());
+app.use('/static', express.static(path.join(__dirname, 'test_web', 'static')));
+app.get('/all_plugins', (req, res) => {
+ res.json(pluginApi.all_plugins());
+});
+app.post('/popularNovels/', async (req, res) => {
+ const filters = req.body['filters'] || {};
+ const showLatestNovels = req.body['showLatestNovels'] || false
+ const novels = await pluginApi.popularNovels(req.body['pluginRequirePath'], {showLatestNovels, filters});
+ res.json(novels);
+});
+app.post('/searchNovels/', async(req, res) => {
+ const novels = await pluginApi.searchNovels(req.body['pluginRequirePath'], req.body['searchTerm']);
+ res.json(novels);
+})
+app.post('/parseNovelAndChapters/', async(req, res) => {
+ const sourceNovel = await pluginApi.parseNovelAndChapters(req.body['pluginRequirePath'], req.body['novelUrl']);
+ res.json(sourceNovel);
+})
+app.post('/parseChapter/', async(req, res) => {
+ const chapterText = await pluginApi.parseChapter(req.body['pluginRequirePath'], req.body['chapterUrl']);
+ res.json(chapterText);
+})
+app.post('/fetchImage/', async(req, res) => {
+ const base64 = await pluginApi.fetchImage(req.body['pluginRequirePath'], req.body['url']);
+ res.json(base64);
+})
+
+app.get('/', (req, res) => {
+ res.sendFile(path.join(__dirname, 'test_web', 'index.html'));
+});
+
+
+app.listen(port, host, () => {
+ console.log("testing plugins web listening on http://localhost:3000");
+});
\ No newline at end of file
diff --git a/jsconfig.json b/jsconfig.json
new file mode 100644
index 0000000..a6b1ab6
--- /dev/null
+++ b/jsconfig.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "@api/*": [
+ "./api/*",
+ ],
+ "@libs/*": [
+ "./libs/*",
+ ],
+ "@icons/*": [
+ "./icons/*",
+ ],
+ "@plugins/*": [
+ "./plugins/*",
+ ],
+ "@scripts/*": [
+ "./scripts/*",
+ ]
+ },
+ },
+}
\ No newline at end of file
diff --git a/libs/fetchApi.js b/libs/fetchApi.js
new file mode 100644
index 0000000..78b564e
--- /dev/null
+++ b/libs/fetchApi.js
@@ -0,0 +1,14 @@
+const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
+
+const defaultUserAgentString =
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36';
+
+async function fetchApi (url, init, pluginId){
+ const headers = {
+ ...init?.headers,
+ 'User-Agent': defaultUserAgentString,
+ };
+ return await fetch(url, { ...init, headers });
+}
+
+module.exports = fetchApi
\ No newline at end of file
diff --git a/libs/fetchFile.js b/libs/fetchFile.js
new file mode 100644
index 0000000..86c9d3f
--- /dev/null
+++ b/libs/fetchFile.js
@@ -0,0 +1,15 @@
+const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
+
+async function fetchFile(url, init){
+ if(!init) init = {};
+ try{
+ const res = await fetch(url, init);
+ if(!res.ok) return undefined;
+ const arrayBuffer = await res.arrayBuffer();
+ return Buffer.from(arrayBuffer).toString('base64');
+ }catch(e){
+ return undefined;
+ }
+}
+
+module.exports = fetchFile;
\ No newline at end of file
diff --git a/libs/filterInputs.js b/libs/filterInputs.js
new file mode 100644
index 0000000..06b6427
--- /dev/null
+++ b/libs/filterInputs.js
@@ -0,0 +1,7 @@
+const FilterInputs = {
+ TextInput: 0,
+ Picker: 1,
+ Checkbox: 2,
+}
+
+module.exports = FilterInputs
diff --git a/libs/isAbsoluteUrl.js b/libs/isAbsoluteUrl.js
new file mode 100644
index 0000000..11d6435
--- /dev/null
+++ b/libs/isAbsoluteUrl.js
@@ -0,0 +1,25 @@
+const isUrlAbsolute = (url) => {
+ if (url) {
+ if (url.indexOf('//') === 0) {
+ return true;
+ } // URL is protocol-relative (= absolute)
+ if (url.indexOf('://') === -1) {
+ return false;
+ } // URL has no protocol (= relative)
+ if (url.indexOf('.') === -1) {
+ return false;
+ } // URL does not contain a dot, i.e. no TLD (= relative, possibly REST)
+ if (url.indexOf('/') === -1) {
+ return false;
+ } // URL does not contain a single slash (= relative)
+ if (url.indexOf(':') > url.indexOf('/')) {
+ return false;
+ } // The first colon comes after the first slash (= relative)
+ if (url.indexOf('://') < url.indexOf('.')) {
+ return true;
+ } // Protocol is defined before first dot (= absolute)
+ }
+ return false; // Anything else must be relative
+ };
+
+module.exports = isUrlAbsolute;
\ No newline at end of file
diff --git a/libs/languages.js b/libs/languages.js
new file mode 100644
index 0000000..1e91d33
--- /dev/null
+++ b/libs/languages.js
@@ -0,0 +1,14 @@
+module.exports = {
+ Arabic: 'العربية',
+ Chinese: '中文, 汉语, 漢語',
+ English: 'English',
+ French: 'français, française',
+ Indonesian: 'Bahasa Indonesia',
+ Japanese: '日本語',
+ Korean: '한국어, 조선말',
+ Portuguese: 'Português',
+ Russian: 'русский язык',
+ Spanish: 'español, castellano',
+ Turkish: 'Türkçe',
+ Vietnamese: 'Tiếng Việt',
+}
\ No newline at end of file
diff --git a/libs/novelStatus.js b/libs/novelStatus.js
new file mode 100644
index 0000000..69a9a03
--- /dev/null
+++ b/libs/novelStatus.js
@@ -0,0 +1,9 @@
+module.exports = {
+ Unknown: 'Unknown',
+ Ongoing: 'Ongoing',
+ Completed: 'Completed',
+ Licensed: 'Licensed',
+ PublishingFinished: 'Publishing Finished',
+ Cancelled: 'Cancelled',
+ OnHiatus: 'On Hiatus',
+};
\ No newline at end of file
diff --git a/libs/parseDate.js b/libs/parseDate.js
new file mode 100644
index 0000000..5f481a3
--- /dev/null
+++ b/libs/parseDate.js
@@ -0,0 +1,30 @@
+const dayjs = require('dayjs');
+
+const parseMadaraDate = date => {
+ let releaseDate = date;
+
+ if (date.includes('ago')) {
+ let timeAgo = date;
+ releaseDate = new Date();
+
+ timeAgo = timeAgo.match(/\d+/)[0];
+
+ if (timeAgo.includes('hours ago') || timeAgo.includes('hour ago')) {
+ releaseDate.setHours(releaseDate.getHours() - timeAgo);
+ }
+
+ if (timeAgo.includes('days ago') || timeAgo.includes('day ago')) {
+ releaseDate.setDate(releaseDate.getDate() - timeAgo);
+ }
+
+ if (timeAgo.includes('months ago') || timeAgo.includes('month ago')) {
+ releaseDate.setMonth(releaseDate.getMonth() - timeAgo);
+ }
+
+ releaseDate = dayjs(releaseDate).format('LL');
+ }
+
+ return releaseDate;
+};
+
+module.exports = parseMadaraDate;
\ No newline at end of file
diff --git a/nodemon.json b/nodemon.json
new file mode 100644
index 0000000..d7f117e
--- /dev/null
+++ b/nodemon.json
@@ -0,0 +1,3 @@
+{
+ "ignore": ["plugins/plugins.json", "plugins/plugins.min.json", "cheerio_space/*"]
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..c5ce302
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,2897 @@
+{
+ "name": "lnreader-plugins",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "lnreader-plugins",
+ "version": "1.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "body-parser": "^1.20.2",
+ "cheerio": "^1.0.0-rc.10",
+ "cli-color": "^2.0.3",
+ "dayjs": "^1.11.4",
+ "dotenv": "^16.0.3",
+ "express": "^4.18.2",
+ "module-alias": "^2.2.2",
+ "node-fetch": "^3.3.1"
+ },
+ "devDependencies": {
+ "nodemon": "^2.0.22",
+ "pre-commit": "^1.2.2"
+ }
+ },
+ "node_modules/abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "dev": true
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.2",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
+ "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.5",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.2",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/body-parser/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/body-parser/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/cheerio": {
+ "version": "1.0.0-rc.10",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz",
+ "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==",
+ "dependencies": {
+ "cheerio-select": "^1.5.0",
+ "dom-serializer": "^1.3.2",
+ "domhandler": "^4.2.0",
+ "htmlparser2": "^6.1.0",
+ "parse5": "^6.0.1",
+ "parse5-htmlparser2-tree-adapter": "^6.0.1",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+ }
+ },
+ "node_modules/cheerio-select": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.6.0.tgz",
+ "integrity": "sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==",
+ "dependencies": {
+ "css-select": "^4.3.0",
+ "css-what": "^6.0.1",
+ "domelementtype": "^2.2.0",
+ "domhandler": "^4.3.1",
+ "domutils": "^2.8.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/cli-color": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz",
+ "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==",
+ "dependencies": {
+ "d": "^1.0.1",
+ "es5-ext": "^0.10.61",
+ "es6-iterator": "^2.0.3",
+ "memoizee": "^0.4.15",
+ "timers-ext": "^0.1.7"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "dev": true,
+ "engines": [
+ "node >= 0.8"
+ ],
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "dev": true
+ },
+ "node_modules/cross-spawn": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+ "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^4.0.1",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "node_modules/css-select": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
+ "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.0.1",
+ "domhandler": "^4.3.1",
+ "domutils": "^2.8.0",
+ "nth-check": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/css-what": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+ "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/d": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+ "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+ "dependencies": {
+ "es5-ext": "^0.10.50",
+ "type": "^1.0.1"
+ }
+ },
+ "node_modules/data-uri-to-buffer": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
+ "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/dayjs": {
+ "version": "1.11.4",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.4.tgz",
+ "integrity": "sha512-Zj/lPM5hOvQ1Bf7uAvewDaUcsJoI6JmNqmHhHl3nyumwe0XHwt8sWdOVAPACJzCebL8gQCi+K49w7iKWnGwX9g=="
+ },
+ "node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/dom-serializer": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+ "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.2.0",
+ "entities": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ]
+ },
+ "node_modules/domhandler": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+ "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+ "dependencies": {
+ "domelementtype": "^2.2.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+ "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
+ "dependencies": {
+ "dom-serializer": "^1.0.1",
+ "domelementtype": "^2.2.0",
+ "domhandler": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "16.0.3",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
+ "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/entities": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/es5-ext": {
+ "version": "0.10.62",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+ "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "es6-iterator": "^2.0.3",
+ "es6-symbol": "^3.1.3",
+ "next-tick": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+ "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+ "dependencies": {
+ "d": "1",
+ "es5-ext": "^0.10.35",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "node_modules/es6-symbol": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+ "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+ "dependencies": {
+ "d": "^1.0.1",
+ "ext": "^1.1.2"
+ }
+ },
+ "node_modules/es6-weak-map": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
+ "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
+ "dependencies": {
+ "d": "1",
+ "es5-ext": "^0.10.46",
+ "es6-iterator": "^2.0.3",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/event-emitter": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+ "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
+ "dependencies": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.18.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+ "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.1",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.5.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/express/node_modules/body-parser": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+ "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/express/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/express/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/express/node_modules/raw-body": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/ext": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
+ "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
+ "dependencies": {
+ "type": "^2.7.2"
+ }
+ },
+ "node_modules/ext/node_modules/type": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
+ "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
+ },
+ "node_modules/fetch-blob": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+ "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "dependencies": {
+ "node-domexception": "^1.0.0",
+ "web-streams-polyfill": "^3.0.3"
+ },
+ "engines": {
+ "node": "^12.20 || >= 14.13"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/finalhandler/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/finalhandler/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/formdata-polyfill": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+ "dependencies": {
+ "fetch-blob": "^3.1.2"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+ "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/htmlparser2": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
+ "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.0.0",
+ "domutils": "^2.5.2",
+ "entities": "^2.0.0"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+ "dev": true
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-promise": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "dev": true
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "node_modules/lru-cache": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+ "dev": true,
+ "dependencies": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "node_modules/lru-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
+ "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==",
+ "dependencies": {
+ "es5-ext": "~0.10.2"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/memoizee": {
+ "version": "0.4.15",
+ "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz",
+ "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==",
+ "dependencies": {
+ "d": "^1.0.1",
+ "es5-ext": "^0.10.53",
+ "es6-weak-map": "^2.0.3",
+ "event-emitter": "^0.3.5",
+ "is-promise": "^2.2.2",
+ "lru-queue": "^0.1.0",
+ "next-tick": "^1.1.0",
+ "timers-ext": "^0.1.7"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/module-alias": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz",
+ "integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q=="
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/next-tick": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
+ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
+ },
+ "node_modules/node-domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "github",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "engines": {
+ "node": ">=10.5.0"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz",
+ "integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==",
+ "dependencies": {
+ "data-uri-to-buffer": "^4.0.0",
+ "fetch-blob": "^3.1.4",
+ "formdata-polyfill": "^4.0.10"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/node-fetch"
+ }
+ },
+ "node_modules/nodemon": {
+ "version": "2.0.22",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz",
+ "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==",
+ "dev": true,
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "debug": "^3.2.7",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^3.1.2",
+ "pstree.remy": "^1.1.8",
+ "semver": "^5.7.1",
+ "simple-update-notifier": "^1.0.7",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ },
+ "bin": {
+ "nodemon": "bin/nodemon.js"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/nodemon"
+ }
+ },
+ "node_modules/nopt": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
+ "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
+ "dev": true,
+ "dependencies": {
+ "abbrev": "1"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.12.3",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+ "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/os-shim": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz",
+ "integrity": "sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/parse5": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
+ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
+ },
+ "node_modules/parse5-htmlparser2-tree-adapter": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
+ "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
+ "dependencies": {
+ "parse5": "^6.0.1"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pre-commit": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz",
+ "integrity": "sha512-qokTiqxD6GjODy5ETAIgzsRgnBWWQHQH2ghy86PU7mIn/wuWeTwF3otyNQZxWBwVn8XNr8Tdzj/QfUXpH+gRZA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "cross-spawn": "^5.0.1",
+ "spawn-sync": "^1.0.15",
+ "which": "1.2.x"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
+ "dev": true
+ },
+ "node_modules/pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
+ "dev": true
+ },
+ "node_modules/qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+ "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dev": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/readable-stream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/send/node_modules/debug/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "node_modules/shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/simple-update-notifier": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
+ "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==",
+ "dev": true,
+ "dependencies": {
+ "semver": "~7.0.0"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/simple-update-notifier/node_modules/semver": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
+ "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/spawn-sync": {
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz",
+ "integrity": "sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "concat-stream": "^1.4.7",
+ "os-shim": "^0.1.2"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/string_decoder/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/timers-ext": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
+ "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
+ "dependencies": {
+ "es5-ext": "~0.10.46",
+ "next-tick": "1"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/touch": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
+ "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
+ "dev": true,
+ "dependencies": {
+ "nopt": "~1.0.10"
+ },
+ "bin": {
+ "nodetouch": "bin/nodetouch.js"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+ "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
+ },
+ "node_modules/type": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+ "dev": true
+ },
+ "node_modules/undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+ "dev": true
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/web-streams-polyfill": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
+ "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/which": {
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz",
+ "integrity": "sha512-16uPglFkRPzgiUXYMi1Jf8Z5EzN1iB4V0ZtMXcHZnwsBtQhhHeCqoWw7tsUY42hJGNDWtUsVLTjakIa5BgAxCw==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
+ "dev": true
+ }
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "dev": true
+ },
+ "accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "requires": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ }
+ },
+ "anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true
+ },
+ "body-parser": {
+ "version": "1.20.2",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
+ "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
+ "requires": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.5",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.2",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ },
+ "boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true
+ },
+ "bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+ },
+ "call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ }
+ },
+ "cheerio": {
+ "version": "1.0.0-rc.10",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz",
+ "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==",
+ "requires": {
+ "cheerio-select": "^1.5.0",
+ "dom-serializer": "^1.3.2",
+ "domhandler": "^4.2.0",
+ "htmlparser2": "^6.1.0",
+ "parse5": "^6.0.1",
+ "parse5-htmlparser2-tree-adapter": "^6.0.1",
+ "tslib": "^2.2.0"
+ }
+ },
+ "cheerio-select": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.6.0.tgz",
+ "integrity": "sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==",
+ "requires": {
+ "css-select": "^4.3.0",
+ "css-what": "^6.0.1",
+ "domelementtype": "^2.2.0",
+ "domhandler": "^4.3.1",
+ "domutils": "^2.8.0"
+ }
+ },
+ "chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "requires": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "fsevents": "~2.3.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ }
+ },
+ "cli-color": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz",
+ "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==",
+ "requires": {
+ "d": "^1.0.1",
+ "es5-ext": "^0.10.61",
+ "es6-iterator": "^2.0.3",
+ "memoizee": "^0.4.15",
+ "timers-ext": "^0.1.7"
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "requires": {
+ "safe-buffer": "5.2.1"
+ }
+ },
+ "content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
+ },
+ "cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+ },
+ "core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "dev": true
+ },
+ "cross-spawn": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+ "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^4.0.1",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "css-select": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
+ "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
+ "requires": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.0.1",
+ "domhandler": "^4.3.1",
+ "domutils": "^2.8.0",
+ "nth-check": "^2.0.1"
+ }
+ },
+ "css-what": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+ "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="
+ },
+ "d": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+ "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+ "requires": {
+ "es5-ext": "^0.10.50",
+ "type": "^1.0.1"
+ }
+ },
+ "data-uri-to-buffer": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
+ "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="
+ },
+ "dayjs": {
+ "version": "1.11.4",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.4.tgz",
+ "integrity": "sha512-Zj/lPM5hOvQ1Bf7uAvewDaUcsJoI6JmNqmHhHl3nyumwe0XHwt8sWdOVAPACJzCebL8gQCi+K49w7iKWnGwX9g=="
+ },
+ "debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
+ "destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
+ },
+ "dom-serializer": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+ "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
+ "requires": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.2.0",
+ "entities": "^2.0.0"
+ }
+ },
+ "domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
+ },
+ "domhandler": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+ "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+ "requires": {
+ "domelementtype": "^2.2.0"
+ }
+ },
+ "domutils": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+ "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
+ "requires": {
+ "dom-serializer": "^1.0.1",
+ "domelementtype": "^2.2.0",
+ "domhandler": "^4.2.0"
+ }
+ },
+ "dotenv": {
+ "version": "16.0.3",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
+ "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ=="
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
+ },
+ "entities": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
+ },
+ "es5-ext": {
+ "version": "0.10.62",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+ "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+ "requires": {
+ "es6-iterator": "^2.0.3",
+ "es6-symbol": "^3.1.3",
+ "next-tick": "^1.1.0"
+ }
+ },
+ "es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+ "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.35",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "es6-symbol": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+ "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+ "requires": {
+ "d": "^1.0.1",
+ "ext": "^1.1.2"
+ }
+ },
+ "es6-weak-map": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
+ "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.46",
+ "es6-iterator": "^2.0.3",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
+ },
+ "event-emitter": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+ "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "express": {
+ "version": "4.18.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+ "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+ "requires": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.1",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.5.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "dependencies": {
+ "body-parser": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+ "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+ "requires": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ }
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "raw-body": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+ "requires": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ }
+ }
+ },
+ "ext": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
+ "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
+ "requires": {
+ "type": "^2.7.2"
+ },
+ "dependencies": {
+ "type": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
+ "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
+ }
+ }
+ },
+ "fetch-blob": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+ "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+ "requires": {
+ "node-domexception": "^1.0.0",
+ "web-streams-polyfill": "^3.0.3"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ },
+ "formdata-polyfill": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+ "requires": {
+ "fetch-blob": "^3.1.2"
+ }
+ },
+ "forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
+ },
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "optional": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "get-intrinsic": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+ "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.3"
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true
+ },
+ "has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
+ },
+ "htmlparser2": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
+ "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
+ "requires": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.0.0",
+ "domutils": "^2.5.2",
+ "entities": "^2.0.0"
+ }
+ },
+ "http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "requires": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+ "dev": true
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "is-promise": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "lru-cache": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+ "dev": true,
+ "requires": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "lru-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
+ "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==",
+ "requires": {
+ "es5-ext": "~0.10.2"
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
+ },
+ "memoizee": {
+ "version": "0.4.15",
+ "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz",
+ "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==",
+ "requires": {
+ "d": "^1.0.1",
+ "es5-ext": "^0.10.53",
+ "es6-weak-map": "^2.0.3",
+ "event-emitter": "^0.3.5",
+ "is-promise": "^2.2.2",
+ "lru-queue": "^0.1.0",
+ "next-tick": "^1.1.0",
+ "timers-ext": "^0.1.7"
+ }
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
+ },
+ "mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "requires": {
+ "mime-db": "1.52.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "module-alias": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz",
+ "integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q=="
+ },
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
+ },
+ "next-tick": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
+ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
+ },
+ "node-domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="
+ },
+ "node-fetch": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz",
+ "integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==",
+ "requires": {
+ "data-uri-to-buffer": "^4.0.0",
+ "fetch-blob": "^3.1.4",
+ "formdata-polyfill": "^4.0.10"
+ }
+ },
+ "nodemon": {
+ "version": "2.0.22",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz",
+ "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==",
+ "dev": true,
+ "requires": {
+ "chokidar": "^3.5.2",
+ "debug": "^3.2.7",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^3.1.2",
+ "pstree.remy": "^1.1.8",
+ "semver": "^5.7.1",
+ "simple-update-notifier": "^1.0.7",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ }
+ },
+ "nopt": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
+ "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
+ "dev": true,
+ "requires": {
+ "abbrev": "1"
+ }
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ },
+ "nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "requires": {
+ "boolbase": "^1.0.0"
+ }
+ },
+ "object-inspect": {
+ "version": "1.12.3",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+ "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
+ },
+ "on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "os-shim": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz",
+ "integrity": "sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A==",
+ "dev": true
+ },
+ "parse5": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
+ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
+ },
+ "parse5-htmlparser2-tree-adapter": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
+ "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
+ "requires": {
+ "parse5": "^6.0.1"
+ }
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
+ },
+ "picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true
+ },
+ "pre-commit": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz",
+ "integrity": "sha512-qokTiqxD6GjODy5ETAIgzsRgnBWWQHQH2ghy86PU7mIn/wuWeTwF3otyNQZxWBwVn8XNr8Tdzj/QfUXpH+gRZA==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^5.0.1",
+ "spawn-sync": "^1.0.15",
+ "which": "1.2.x"
+ }
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "requires": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ }
+ },
+ "pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
+ "dev": true
+ },
+ "pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
+ "dev": true
+ },
+ "qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+ },
+ "raw-body": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+ "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+ "requires": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ }
+ }
+ },
+ "readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ },
+ "send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
+ "dev": true
+ },
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
+ },
+ "simple-update-notifier": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
+ "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==",
+ "dev": true,
+ "requires": {
+ "semver": "~7.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
+ "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
+ "dev": true
+ }
+ }
+ },
+ "spawn-sync": {
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz",
+ "integrity": "sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==",
+ "dev": true,
+ "requires": {
+ "concat-stream": "^1.4.7",
+ "os-shim": "^0.1.2"
+ }
+ },
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ }
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "timers-ext": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
+ "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
+ "requires": {
+ "es5-ext": "~0.10.46",
+ "next-tick": "1"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+ },
+ "touch": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
+ "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
+ "dev": true,
+ "requires": {
+ "nopt": "~1.0.10"
+ }
+ },
+ "tslib": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+ "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
+ },
+ "type": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+ "dev": true
+ },
+ "undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+ "dev": true
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
+ },
+ "web-streams-polyfill": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
+ "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q=="
+ },
+ "which": {
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz",
+ "integrity": "sha512-16uPglFkRPzgiUXYMi1Jf8Z5EzN1iB4V0ZtMXcHZnwsBtQhhHeCqoWw7tsUY42hJGNDWtUsVLTjakIa5BgAxCw==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
+ "dev": true
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..2bd9b28
--- /dev/null
+++ b/package.json
@@ -0,0 +1,37 @@
+{
+ "name": "lnreader-plugins",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "start": "node ./index.js",
+ "test": "exit 0",
+ "json": "node ./scripts/json_plugins.js && git add ."
+ },
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "body-parser": "^1.20.2",
+ "cheerio": "^1.0.0-rc.10",
+ "cli-color": "^2.0.3",
+ "dayjs": "^1.11.4",
+ "dotenv": "^16.0.3",
+ "express": "^4.18.2",
+ "module-alias": "^2.2.2",
+ "node-fetch": "^3.3.1"
+ },
+ "_moduleAliases": {
+ "@api": "./api",
+ "@libs": "./libs",
+ "@icons": "./icons",
+ "@plugins": "./plugins",
+ "@scripts": "./scripts"
+ },
+ "devDependencies": {
+ "nodemon": "^2.0.22",
+ "pre-commit": "^1.2.2"
+ },
+ "pre-commit": [
+ "json"
+ ]
+}
diff --git a/plugins/chinese/.chinese b/plugins/chinese/.chinese
new file mode 100644
index 0000000..e69de29
diff --git a/plugins/english/.english b/plugins/english/.english
new file mode 100644
index 0000000..e69de29
diff --git a/plugins/english/LightNovelReader.js b/plugins/english/LightNovelReader.js
new file mode 100644
index 0000000..91e4126
--- /dev/null
+++ b/plugins/english/LightNovelReader.js
@@ -0,0 +1,178 @@
+const cheerio = require('cheerio');
+const languages = require('@libs/languages');
+const isUrlAbsolute = require('@libs/isAbsoluteUrl');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+
+const pluginId = 'LNR.org';
+const baseUrl = 'https://lightnovelreader.org';
+
+async function popularNovels(page) {
+ const url = baseUrl + '/ranking/top-rated/' + page;
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ const novels = [];
+
+ loadedCheerio('.category-items.ranking-category.cm-list > ul > li').each(
+ function () {
+ let novelUrl = loadedCheerio(this).find('a').attr('href');
+
+ if (novelUrl && !isUrlAbsolute(novelUrl)) {
+ novelUrl = baseUrl + novelUrl;
+ }
+
+ if (novelUrl) {
+ const novelName = loadedCheerio(this)
+ .find('.category-name a')
+ .text()
+ .trim();
+ let novelCover = loadedCheerio(this)
+ .find('.category-img img')
+ .attr('src');
+
+ if (novelCover && !isUrlAbsolute(novelCover)) {
+ novelCover = baseUrl + novelCover;
+ }
+
+ const novel = {
+ url: novelUrl,
+ name: novelName,
+ cover: novelCover,
+ };
+
+ novels.push(novel);
+ }
+ },
+ );
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ const novel = {
+ url: novelUrl,
+ chapters: [],
+ };
+
+ novel.name = loadedCheerio('.section-header-title > h2').text();
+
+ let novelCover = loadedCheerio('.novels-detail img').attr('src');
+
+ novel.cover = novelCover
+ ? isUrlAbsolute(novelCover)
+ ? novelCover
+ : baseUrl + novelCover
+ : undefined;
+
+ novel.summary = loadedCheerio(
+ 'div.container > div > div.col-12.col-xl-9 > div > div:nth-child(5) > div',
+ )
+ .text()
+ .trim();
+
+ novel.author = loadedCheerio(
+ 'div.novels-detail-right > ul > li:nth-child(6) > .novels-detail-right-in-right > a',
+ )
+ .text()
+ .trim();
+
+ novel.genres = loadedCheerio(
+ 'body > section:nth-child(4) > div > div > div.col-12.col-xl-9 > div > div:nth-child(2) > div > div.novels-detail-right > ul > li:nth-child(3) > div.novels-detail-right-in-right',
+ )
+ .text()
+ .trim()
+
+ novel.status = loadedCheerio(
+ 'div.novels-detail-right > ul > li:nth-child(2) > .novels-detail-right-in-right',
+ )
+ .text()
+ .trim();
+
+ loadedCheerio('.cm-tabs-content > ul > li').each(function () {
+ let chapterUrl = loadedCheerio(this).find('a').attr('href');
+
+ if (chapterUrl && !isUrlAbsolute(chapterUrl)) {
+ chapterUrl = baseUrl + chapterUrl;
+ }
+
+ if (chapterUrl) {
+ const chapterName = loadedCheerio(this).find('a').text().trim();
+ const releaseDate = null;
+
+ const chapter = {
+ name: chapterName,
+ releaseTime: releaseDate,
+ url: chapterUrl,
+ };
+
+ novel.chapters.push(chapter);
+ }
+ });
+
+ return novel;
+};
+
+async function parseChapter(chapterUrl) {
+ const url = chapterUrl;
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ const chapterText = loadedCheerio('#chapterText').html() || '';
+
+ return chapterText;
+};
+
+
+async function searchNovels (searchTerm) {
+ const url = baseUrl + `/search/autocomplete?dataType=json&query=${searchTerm}`;
+ const result = await fetchApi(url);
+ const body = await result.json();
+ const data = body.results || [];
+
+ const novels = [];
+
+ data.forEach(item => {
+ let novelUrl = item.link;
+ let novelName = item.original_title
+ let novelCover = item.image;
+
+ novels.push({
+ url: novelUrl,
+ name: novelName,
+ cover: novelCover,
+ });
+ });
+
+ return novels;
+};
+
+async function fetchImage (url) {
+ return await fetchFile(url, {});
+}
+
+module.exports = {
+ id: pluginId,
+ name: 'LightNovelReader',
+ icon: 'src/en/lightnovelreader/icon.png',
+ version: '1.0.0',
+ site: baseUrl,
+ lang: languages.English,
+ description: 'This is description for plugin',
+ protected: false,
+ fetchImage,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+}
\ No newline at end of file
diff --git a/plugins/english/NovelFullMe.js b/plugins/english/NovelFullMe.js
new file mode 100644
index 0000000..018a10e
--- /dev/null
+++ b/plugins/english/NovelFullMe.js
@@ -0,0 +1,167 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const languages = require('@libs/languages');
+const fetchFile = require('@libs/fetchFile');
+
+const pluginId = 'NF.me';
+const sourceName = 'NovelFull.me';
+
+const baseUrl = 'https://novelfull.me/';
+
+async function popularNovels (page) {
+ const url = `${baseUrl}popular?page=${page}`;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.book-item').each(function () {
+ const novelName = loadedCheerio(this).find('.title').text();
+ const novelCover =
+ 'https:' + loadedCheerio(this).find('img').attr('data-src');
+ const novelUrl =
+ baseUrl + loadedCheerio(this).find('.title a').attr('href').substring(1);
+
+ const novel = { name: novelName, cover: novelCover, url: novelUrl };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {
+ url,
+ name: '',
+ cover: '',
+ author: '',
+ status: '',
+ genres: '',
+ summary: '',
+ chapters: [],
+ };
+
+ novel.name = loadedCheerio('.name h1').text().trim();
+
+ novel.cover =
+ 'https:' + loadedCheerio('.img-cover img').attr('data-src');
+
+ novel.summary = loadedCheerio(
+ 'body > div.layout > div.main-container.book-details > div > div.row.no-gutters > div.col-lg-8 > div.mt-1 > div.section.box.mt-1.summary > div.section-body > p.content',
+ )
+ .text()
+ .trim();
+
+ novel.author = 'Unknown';
+
+ novel.status = loadedCheerio(
+ 'body > div.layout > div.main-container.book-details > div > div.row.no-gutters > div.col-lg-8 > div.book-info > div.detail > div.meta.box.mt-1.p-10 > p:nth-child(1) > a > span',
+ )
+ .text()
+ ?.trim();
+
+ novel.genres = loadedCheerio(
+ 'body > div.layout > div.main-container.book-details > div > div.row.no-gutters > div.col-lg-8 > div.book-info > div.detail > div.meta.box.mt-1.p-10 > p:nth-child(2)',
+ )
+ .text()
+ ?.replace('Genres :', '')
+ .replace(/[\s\n]+/g, ' ')
+ .trim();
+
+ let chapters = [];
+
+ const chaptersUrl =
+ novelUrl.replace(baseUrl, 'https://novelfull.me/api/novels/') +
+ '/chapters?source=detail';
+
+ const chaptersRequest = await fetchApi(chaptersUrl);
+ const chaptersHtml = await chaptersRequest.text();
+
+ loadedCheerio = cheerio.load(chaptersHtml);
+
+ loadedCheerio('li').each(function () {
+ const chapterName = loadedCheerio(this)
+ .find('.chapter-title')
+ .text()
+ .trim();
+
+ const releaseDate = loadedCheerio(this)
+ .find('.chapter-update')
+ .text()
+ .trim();
+
+ const chapterUrl = loadedCheerio(this).find('a').attr('href');
+
+ chapters.push({ name: chapterName, releaseTime: releaseDate, url: chapterUrl });
+ });
+
+ novel.chapters = chapters.reverse();
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ loadedCheerio('#listen-chapter').remove();
+ loadedCheerio('#google_translate_element').remove();
+
+ const chapterText = loadedCheerio('.chapter__content').html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = `${baseUrl}search?status=all&sort=views&q=${searchTerm}`;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.book-item').each(function () {
+ const novelName = loadedCheerio(this).find('.title').text();
+ const novelCover =
+ 'https:' + loadedCheerio(this).find('img').attr('data-src');
+ const novelUrl =
+ baseUrl + loadedCheerio(this).find('.title a').attr('href').substring(1);
+
+ const novel = {name: novelName, cover: novelCover, url: novelUrl };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ lang: languages.English,
+ version: '1.0.0',
+ icon: 'src/en/novelfullme/icon.png',
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/english/NovelOnline.js b/plugins/english/NovelOnline.js
new file mode 100644
index 0000000..698ea01
--- /dev/null
+++ b/plugins/english/NovelOnline.js
@@ -0,0 +1,120 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const pluginId = 'NO.net';
+const sourceName = 'novelsOnline';
+
+const baseUrl = 'https://novelsonline.net';
+
+async function searchNovels (searchTerm) {
+ const result = await fetchApi(
+ 'https://novelsonline.net/sResults.php',
+ {
+ headers: {
+ 'Accept': '*/*',
+ 'Accept-Language': 'pl,en-US;q=0.7,en;q=0.3',
+ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
+ },
+ method: 'POST',
+ body: 'q=' + encodeURIComponent(searchTerm),
+ },
+ pluginId
+ ).then(res => res.text());
+ let $ = cheerio.load(result);
+
+ const headers = $('li');
+ return headers
+ .map((i, h) => {
+ const novelName = $(h).text();
+ const novelUrl = $(h).find('a').attr('href');
+ const novelCover = $(h).find('img').attr('src');
+
+ if (!novelUrl) {
+ return null;
+ }
+
+ return {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+ })
+ .get()
+ .filter(sr => sr !== null);
+};
+
+async function parseNovelAndChapters (novelUrl){
+ let novel = {
+ url: novelUrl,
+ chapters: [],
+ };
+
+ const result = await fetchApi(novelUrl).then(res => res.text());
+ let $ = cheerio.load(result);
+
+ novel.name = $('h1').text();
+ novel.cover = $('.novel-cover').find('a > img').attr('src');
+ novel.author = $(
+ 'div.novel-details > div:nth-child(5) > div.novel-detail-body',
+ )
+ .find('li')
+ .map((_, el) => $(el).text())
+ .get()
+ .join(', ');
+
+ novel.genres = $(
+ 'div.novel-details > div:nth-child(2) > div.novel-detail-body',
+ )
+ .find('li')
+ .map((_, el) => $(el).text())
+ .get()
+ .join(',');
+
+ novel.summary = $(
+ 'div.novel-right > div > div:nth-child(1) > div.novel-detail-body',
+ ).text();
+
+ novel.chapters = $('ul.chapter-chs > li > a')
+ .map((_, el) => {
+ const chapterUrl = $(el).attr('href');
+ const chapterName = $(el).text();
+
+ return {
+ name: chapterName,
+ releaseTime: '',
+ url: chapterUrl,
+ };
+ })
+ .get();
+
+ return novel;
+};
+
+async function popularNovels (page) {
+ return { novels: [] }; /** TO DO */
+};
+
+async function parseChapter (chapterUrl) {
+ const result = await fetchApi(chapterUrl).then(res => res.text());
+ let loadedCheerio = cheerio.load(result);
+
+ const chapterText = loadedCheerio('#contentall').html() || '';
+
+ return chapterText;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ lang: languages.English,
+ icon: 'src/coverNotAvailable.jpg',
+ version: '1.0.0',
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/english/allnovelfull.js b/plugins/english/allnovelfull.js
new file mode 100644
index 0000000..b1240a5
--- /dev/null
+++ b/plugins/english/allnovelfull.js
@@ -0,0 +1,171 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const pluginId = 'ANF.com';
+const sourceName = 'AllNovelFull';
+const baseUrl = 'https://allnovelfull.com';
+
+async function popularNovels (page) {
+ const url = `${baseUrl}/most-popular?page=${page}`;
+
+ const result = await fetchApi(url);
+ console.log(result.ok);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ const novels = [];
+ loadedCheerio('.col-truyen-main .list-truyen .row').each(function () {
+ const novelName = loadedCheerio(this).find('h3.truyen-title > a').text();
+ const novelCover =
+ baseUrl + loadedCheerio(this).find('img.cover').attr('src');
+ const novelUrl =
+ baseUrl + loadedCheerio(this).find('h3.truyen-title > a').attr('href');
+
+ const novel = {
+ url: novelUrl,
+ name: novelName,
+ cover: novelCover,
+ };
+ console.log(novel);
+ novels.push(novel);
+ });
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {
+ url: novelUrl,
+ };
+
+ novel.name = loadedCheerio('div.book > img').attr('alt');
+
+ novel.cover = baseUrl + loadedCheerio('div.book > img').attr('src');
+
+ novel.summary = loadedCheerio('div.desc-text').text().trim();
+
+ novel.author = loadedCheerio('div.info > div > h3')
+ .filter(function () {
+ return loadedCheerio(this).text().trim() === 'Author:';
+ })
+ .siblings()
+ .text();
+
+ novel.genres = loadedCheerio('div.info > div')
+ .filter(function () {
+ return loadedCheerio(this).find('h3').text().trim() === 'Genre:';
+ })
+ .text()
+ .replace('Genre:', '');
+
+ novel.status = loadedCheerio('div.info > div > h3')
+ .filter(function () {
+ return loadedCheerio(this).text().trim() === 'Status:';
+ })
+ .next()
+ .text();
+
+ const novelId = loadedCheerio('#rating').attr('data-novel-id');
+
+ async function getChapters (id) {
+ const chapterListUrl = baseUrl + '/ajax/chapter-option?novelId=' + id;
+
+ const data = await fetchApi(chapterListUrl);
+ const chapters = await data.text();
+
+ loadedCheerio = cheerio.load(chapters);
+
+ let novelChapters = [];
+
+ loadedCheerio('select > option').each(function () {
+ let chapterName = loadedCheerio(this).text();
+ let releaseDate = null;
+ let chapterUrl = loadedCheerio(this)
+ .attr('value')
+ ?.replace(`/${novelUrl}`, '');
+
+ if (chapterUrl) {
+ novelChapters.push({
+ name: chapterName,
+ releaseTime: releaseDate,
+ url: chapterUrl,
+ });
+ }
+ });
+
+ return novelChapters;
+ };
+
+ if (novelId) {
+ novel.chapters = await getChapters(novelId);
+ }
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = baseUrl + chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ const chapterText = loadedCheerio('#chapter-content').html() || '';
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm){
+ const url = `${baseUrl}/search?keyword=${searchTerm}`;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('div.col-truyen-main > div.list-truyen > .row').each(
+ function () {
+ const novelUrl =
+ baseUrl + loadedCheerio(this).find('h3.truyen-title > a').attr('href');
+
+ const novelName = loadedCheerio(this).find('h3.truyen-title > a').text();
+ const novelCover = baseUrl + loadedCheerio(this).find('img').attr('src');
+
+ if (novelUrl) {
+ novels.push({
+ url: novelUrl,
+ name: novelName,
+ cover: novelCover,
+ });
+ }
+ },
+ );
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ lang: languages.English,
+ icon: 'src/en/allnovelfull/icon.png',
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
diff --git a/plugins/english/bestlightnovel.js b/plugins/english/bestlightnovel.js
new file mode 100644
index 0000000..c88e0cd
--- /dev/null
+++ b/plugins/english/bestlightnovel.js
@@ -0,0 +1,143 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+const Status = require('@libs/novelStatus');
+
+const pluginId = "BLN.com";
+const sourceName = 'BestLightNovel';
+
+const baseUrl = 'https://bestlightnovel.com/';
+
+async function popularNovels (page) {
+ const url =
+ baseUrl + 'novel_list?type=topview&category=all&state=all&page=1' + page;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.update_item.list_category').each(function () {
+ const novelName = loadedCheerio(this).find('h3 > a').text();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+ const novelUrl = loadedCheerio(this).find('h3 > a').attr('href');
+
+ const novel = { name: novelName, cover: novelCover, url: novelUrl };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {
+ url,
+ name: '',
+ cover: '',
+ author: '',
+ status: Status.Unknown,
+ genres: '',
+ summary: '',
+ chapters: [],
+ };
+
+ novel.name = loadedCheerio('.truyen_info_right h1').text().trim();
+ novel.cover = loadedCheerio('.info_image img').attr('src');
+ novel.summary = loadedCheerio('#noidungm').text()?.trim();
+ novel.author = loadedCheerio(
+ '#main_body > div.cotgiua > div.truyen_info_wrapper > div.truyen_info > div.entry-header > div.truyen_if_wrap > ul > li:nth-child(2) > a',
+ )
+ .text()
+ ?.trim();
+
+ let status = loadedCheerio(
+ '#main_body > div.cotgiua > div.truyen_info_wrapper > div.truyen_info > div.entry-header > div.truyen_if_wrap > ul > li:nth-child(4) > a',
+ )
+ .text()
+ ?.trim();
+
+ novel.status =
+ status === 'ONGOING'
+ ? Status.Ongoing
+ : status === 'COMPLETED'
+ ? Status.Completed
+ : Status.Unknown;
+
+ let novelChapters = [];
+
+ loadedCheerio('.chapter-list div.row').each(function () {
+ const chapterName = loadedCheerio(this).find('a').text().trim();
+ const releaseDate = loadedCheerio(this)
+ .find('span:nth-child(2)')
+ .text()
+ .trim();
+ const chapterUrl = loadedCheerio(this).find('a').attr('href');
+
+ novelChapters.push({ name: chapterName, releaseTime: releaseDate, url: chapterUrl });
+ });
+
+ novel.chapters = novelChapters.reverse();
+
+ return novel;
+};
+
+async function parseChapter ( chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ const chapterText = loadedCheerio('#vung_doc').html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = `${baseUrl}search_novels/${searchTerm}`;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.update_item.list_category').each(function () {
+ const novelName = loadedCheerio(this).find('h3 > a').text();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+ const novelUrl = loadedCheerio(this).find('h3 > a').attr('href');
+
+ const novel = { name: novelName, cover: novelCover, url: novelUrl };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ lang: languages.English,
+ icon: 'src/en/bestlightnovel/icon.png',
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/english/comrademao.js b/plugins/english/comrademao.js
new file mode 100644
index 0000000..0d323e1
--- /dev/null
+++ b/plugins/english/comrademao.js
@@ -0,0 +1,149 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+const dayjs = require('dayjs');
+
+const pluginId = 'comrademao';
+
+const sourceName = 'Comrade Mao';
+
+const baseUrl = 'https://comrademao.com/';
+
+async function popularNovels (page) {
+ let url = baseUrl + 'page/' + page + '/?post_type=novel';
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.listupd')
+ .find('div.bs')
+ .each(function () {
+ const novelName = loadedCheerio(this).find('.tt').text().trim();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+ const novelUrl = loadedCheerio(this).find('a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novel = { url };
+
+ novel.name = loadedCheerio('.entry-title').text().trim();
+
+ novel.cover = loadedCheerio('div.thumbook > div > img').attr('src');
+
+ novel.summary = loadedCheerio('div.infox > div:nth-child(6) > span > p')
+ .text()
+ .trim();
+
+ novel.genres = loadedCheerio('div.infox > div:nth-child(4) > span')
+ .text()
+ .replace(/\s/g, '');
+
+ novel.status = loadedCheerio('div.infox > div:nth-child(3) > span')
+ .text()
+ .trim();
+
+ novel.author = loadedCheerio('div.infox > div:nth-child(2) > span')
+ .text()
+ .trim();
+
+ let novelChapters = [];
+
+ loadedCheerio('#chapterlist')
+ .find('li')
+ .each(function () {
+ const releaseDate = dayjs(
+ loadedCheerio(this).find('.chapterdate').text(),
+ ).format('LL');
+ const chapterName = loadedCheerio(this).find('.chapternum').text();
+ const chapterUrl = loadedCheerio(this).find('a').attr('href');
+
+ novelChapters.push({
+ name: chapterName,
+ url: chapterUrl,
+ releaseTime: releaseDate,
+ });
+ });
+
+ novel.chapters = novelChapters.reverse();
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let chapterText = loadedCheerio('#chaptercontent').html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = baseUrl + '?s=' + searchTerm + '&post_type=novel';
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.listupd')
+ .find('div.bs')
+ .each(function () {
+ const novelName = loadedCheerio(this).find('.tt').text().trim();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+ const novelUrl = loadedCheerio(this).find('a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ lang: languages.English,
+ icon: 'src/en/comrademao/icon.png',
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
diff --git a/plugins/english/divinedaolibrary.js b/plugins/english/divinedaolibrary.js
new file mode 100644
index 0000000..4f6870d
--- /dev/null
+++ b/plugins/english/divinedaolibrary.js
@@ -0,0 +1,155 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const defaultCoverUri =
+ 'https://github.com/LNReader/lnreader-sources/blob/main/icons/src/coverNotAvailable.jpg?raw=true';
+
+const pluginId = 'DDL.com';
+
+const sourceName = 'Divine Dao Library';
+
+const baseUrl = 'https://www.divinedaolibrary.com/';
+
+async function popularNovels (page) {
+ let url = baseUrl + 'novels';
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('#main')
+ .find('li')
+ .each(function () {
+ const novelName = loadedCheerio(this).find('a').text();
+ const novelCover = defaultCoverUri;
+ const novelUrl = loadedCheerio(this).find(' a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novel = {url };
+
+ novel.name = loadedCheerio('h1.entry-title').text().trim();
+
+ novel.cover =
+ loadedCheerio('.entry-content').find('img').attr('data-ezsrc') || defaultCoverUri;
+
+ novel.summary = loadedCheerio('#main > article > div > p:nth-child(6)')
+ .text()
+ .trim();
+
+ novel.genres = null;
+
+ novel.status = null;
+
+ novel.author = loadedCheerio('#main > article > div > h3:nth-child(2)')
+ .text()
+ .replace(/Author:/g, '')
+ .trim();
+
+ let novelChapters = [];
+
+ loadedCheerio('#main')
+ .find('li > span > a')
+ .each(function () {
+ const chapterName = loadedCheerio(this).text().trim();
+ const releaseDate = null;
+ const chapterUrl = loadedCheerio(this).attr('href');
+
+ novelChapters.push({ name: chapterName, releaseTime: releaseDate, url: chapterUrl });
+ });
+
+ novel.chapters = novelChapters;
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let chapterName = loadedCheerio('.entry-title').text().trim();
+
+ let chapterText = loadedCheerio('.entry-content').html();
+
+ if (!chapterText) {
+ chapterText = loadedCheerio('.page-header').html();
+ }
+
+ chapterText = `${chapterName}
` + chapterText;
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ let url = baseUrl + 'novels';
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('#main')
+ .find('li')
+ .each(function () {
+ const novelName = loadedCheerio(this).find('a').text();
+ const novelCover = defaultCoverUri;
+ const novelUrl = loadedCheerio(this).find(' a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ novels = novels.filter(novel =>
+ novel.name.toLowerCase().includes(searchTerm.toLowerCase()),
+ );
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ lang: languages.English,
+ icon: 'src/en/divinedaolibrary/icon.png',
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
diff --git a/plugins/english/foxaholic.js b/plugins/english/foxaholic.js
new file mode 100644
index 0000000..6ad359c
--- /dev/null
+++ b/plugins/english/foxaholic.js
@@ -0,0 +1,162 @@
+const cheerio = require('cheerio');
+const languages = require('@libs/languages');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+
+const pluginId = 'foxaholic';
+const baseUrl = 'https://www.foxaholic.com/';
+
+async function popularNovels (page){
+ const link = `${baseUrl}novel/page/${page}/?m_orderby=rating`;
+
+ const result = await fetchApi(link, {}, pluginId);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ const novels = [];
+
+ loadedCheerio('.page-item-detail').each(function () {
+ const name = loadedCheerio(this).find('.h5 > a').text();
+ const cover = loadedCheerio(this).find('img').attr('data-src');
+ const url = loadedCheerio(this).find('.h5 > a').attr('href');
+
+ const novel = {
+ name,
+ url,
+ cover,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl){
+ const url = novelUrl;
+ const result = await fetchApi(url, {}, pluginId);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ const novel = {
+ url,
+ chapters: [],
+ };
+
+ novel.name = loadedCheerio('.post-title > h1')
+ .text()
+ .replace(/[\t\n]/g, '')
+ .trim();
+
+ novel.cover = loadedCheerio('.summary_image > a > img').attr('data-src');
+
+ loadedCheerio('.post-content_item').each(function () {
+ const detailName = loadedCheerio(this)
+ .find('.summary-heading > h5')
+ .text()
+ .replace(/[\t\n]/g, '')
+ .trim();
+ const detail = loadedCheerio(this)
+ .find('.summary-content')
+ .text()
+ .replace(/[\t\n]/g, '')
+ .trim();
+
+ switch (detailName) {
+ case 'Genre':
+ novel.genre = detail.trim().replace(/[\t\n]/g, ',');
+ break;
+ case 'Author':
+ novel.author = detail.trim();
+ break;
+ case 'Novel':
+ novel.status = detail.trim();
+ break;
+ }
+ });
+
+ loadedCheerio('.description-summary > div.summary__content')
+ .find('em')
+ .remove();
+
+ novel.summary = loadedCheerio('.description-summary > div.summary__content')
+ .text()
+ .trim();
+
+ let chapter = [];
+ loadedCheerio('.wp-manga-chapter').each(function () {
+ const name = loadedCheerio(this)
+ .find('a')
+ .text()
+ .replace(/[\t\n]/g, '')
+ .trim();
+ const releaseTime = loadedCheerio(this).find('span').text().trim();
+ const url = loadedCheerio(this).find('a').attr('href');
+
+ chapter.push({ name, releaseTime, url });
+ });
+
+ novel.chapters = chapter.reverse();
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl){
+ const result = await fetchApi(chapterUrl, {}, pluginId);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let chapterText = loadedCheerio('.reading-content').html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = `${baseUrl}?s=${searchTerm}&post_type=wp-manga`;
+ const result = await fetchApi(url, {}, pluginId);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ const novels = [];
+
+ loadedCheerio('.c-tabs-item__content').each(function () {
+ const novelName = loadedCheerio(this).find('.h4 > a').text();
+ const novelCover = loadedCheerio(this).find('img').attr('data-src');
+ const novelUrl = loadedCheerio(this).find('.h4 > a').attr('href');
+
+ novels.push({
+ name: novelName,
+ url: novelUrl,
+ cover: novelCover,
+ });
+ });
+
+ return novels;
+};
+
+async function fetchImage (url){
+ const headers = {
+ Referer: baseUrl,
+ }
+ return await fetchFile(url, {headers: headers});
+};
+
+module.exports = {
+ id: pluginId,
+ name: 'Foxaholic',
+ version: '1.0.0',
+ icon: 'src/en/foxaholic/icon.png',
+ site: baseUrl,
+ lang: languages.English,
+ description: 'Digging Pits',
+ protected: false,
+ fetchImage,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+};
\ No newline at end of file
diff --git a/plugins/english/freewebnovel.js b/plugins/english/freewebnovel.js
new file mode 100644
index 0000000..f93cd68
--- /dev/null
+++ b/plugins/english/freewebnovel.js
@@ -0,0 +1,173 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const pluginId = 'FWN.com';
+const sourceName = "Web NOVEL";
+const baseUrl = 'https://freewebnovel.com/';
+
+async function popularNovels (page) {
+ let url = baseUrl + 'completed-novel/' + page;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.li-row').each(function () {
+ const novelName = loadedCheerio(this).find('.tit').text();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+
+ let novelUrl = 'https://freewebnovel.com' + loadedCheerio(this)
+ .find('h3 > a')
+ .attr('href')
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novel = {};
+
+ novel.url = url;
+
+ novel.name = loadedCheerio('h1.tit').text();
+
+ novel.cover = loadedCheerio('.pic > img').attr('src');
+
+ novel.genres = loadedCheerio('[title=Genre]')
+ .next()
+ .text()
+ .replace(/[\t\n]/g, '');
+
+ novel.author = loadedCheerio('[title=Author]')
+ .next()
+ .text()
+ .replace(/[\t\n]/g, '');
+
+ novel.artist = null;
+
+ novel.status = loadedCheerio('[title=Status]')
+ .next()
+ .text()
+ .replace(/[\t\n]/g, '');
+
+ let novelSummary = loadedCheerio('.inner').text().trim();
+ novel.summary = novelSummary;
+
+ let novelChapters = [];
+
+ let latestChapter;
+
+ loadedCheerio('h3.tit').each(function (res) {
+ if (loadedCheerio(this).find('a').text() === novel.name) {
+ latestChapter = loadedCheerio(this)
+ .next()
+ .find('span.s3')
+ .text()
+ .match(/\d+/);
+ }
+ });
+
+ latestChapter = latestChapter[0];
+ let prefixUrl = novelUrl.replace('.html', '/');
+
+ for (let i = 1; i <= parseInt(latestChapter, 10); i++) {
+ const chapterName = 'Chapter ' + i;
+
+ const releaseDate = null;
+
+ let chapterUrl = 'chapter-' + i;
+ chapterUrl = `${prefixUrl}${chapterUrl}.html`
+ const chapter = { name: chapterName, releaseTime: releaseDate, url: chapterUrl };
+
+ novelChapters.push(chapter);
+ }
+
+ novel.chapters = novelChapters;
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let chapterText = loadedCheerio('div.txt').html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = baseUrl + 'search/';
+
+ const formData = {
+ searchkey: searchTerm,
+ };
+
+ const result = await fetchApi(url, {
+ method: 'POST',
+ body: formData,
+ });
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.li-row > .li > .con').each(function () {
+ const novelName = loadedCheerio(this).find('.tit').text();
+ const novelCover = loadedCheerio(this)
+ .find('.pic > a > img')
+ .attr('data-cfsrc');
+
+ let novelUrl = "https://freewebnovel.com" + loadedCheerio(this)
+ .find('h3 > a')
+ .attr('href')
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ lang: languages.English,
+ icon: 'src/en/freewebnovel/icon.png',
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
diff --git a/plugins/english/novelpub.js b/plugins/english/novelpub.js
new file mode 100644
index 0000000..6e6c9e0
--- /dev/null
+++ b/plugins/english/novelpub.js
@@ -0,0 +1,182 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const baseUrl = 'https://www.novelpub.com/';
+
+const sourceName = 'NovelPub';
+const pluginId = 'novelpub.com';
+
+const headers = {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ 'User-Agent':
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
+};
+
+async function popularNovels (page) {
+ let url = baseUrl + 'browse/all/popular/all/' + page;
+
+ const result = await fetchApi(url, { method: 'GET', headers });
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.novel-item.ads').remove();
+
+ loadedCheerio('.novel-item').each(function () {
+ const novelName = loadedCheerio(this).find('.novel-title').text().trim();
+ const novelCover = loadedCheerio(this).find('img').attr('data-src');
+ const novelUrl =
+ baseUrl +
+ loadedCheerio(this).find('.novel-title > a').attr('href').substring(1);
+
+ const novel = { name: novelName, cover: novelCover, url: novelUrl };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url, { method: 'GET', headers });
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = { url, genres: '' };
+
+ novel.name = loadedCheerio('h1.novel-title').text().trim();
+
+ novel.cover = loadedCheerio('figure.cover > img').attr('data-src');
+
+ loadedCheerio('div.categories > ul > li').each(function () {
+ novel.genres +=
+ loadedCheerio(this)
+ .text()
+ .replace(/[\t\n]/g, '') + ',';
+ });
+
+ loadedCheerio('div.header-stats > span').each(function () {
+ if (loadedCheerio(this).find('small').text() === 'Status') {
+ novel.status = loadedCheerio(this).find('strong').text();
+ }
+ });
+
+ novel.genres = novel.genres.slice(0, -1);
+
+ novel.author = loadedCheerio('.author > a > span').text();
+
+ novel.summary = loadedCheerio('.summary > .content').text().trim();
+
+ const delay = ms => new Promise(res => setTimeout(res, ms));
+
+ let lastPage = 1;
+
+ lastPage = loadedCheerio(
+ '#novel > header > div.header-body.container > div.novel-info > div.header-stats > span:nth-child(1) > strong',
+ )
+ .text()
+ ?.trim();
+
+ lastPage = Math.ceil(lastPage / 100);
+
+ const getChapters = async () => {
+ let novelChapters = [];
+
+ for (let i = 1; i <= lastPage; i++) {
+ const chaptersUrl = `${novelUrl}/chapters/page-${i}`;
+
+ const chaptersRequest = await fetchApi(chaptersUrl, { headers });
+ const chaptersHtml = await chaptersRequest.text();
+
+ loadedCheerio = cheerio.load(chaptersHtml);
+
+ loadedCheerio('.chapter-list li').each(function () {
+ const chapterName = loadedCheerio(this)
+ .find('.chapter-title')
+ .text()
+ .trim();
+
+ const releaseDate = loadedCheerio(this)
+ .find('.chapter-update')
+ .text()
+ .trim();
+
+ const chapterUrl =
+ baseUrl + loadedCheerio(this).find('a').attr('href').substring(1);
+
+ novelChapters.push({ name: chapterName, releaseTime: releaseDate, url: chapterUrl });
+ });
+
+ await delay(1000);
+ }
+
+ return novelChapters;
+ };
+
+ novel.chapters = await getChapters();
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url, { method: 'GET', headers });
+
+ const body = await result.text();
+ const loadedCheerio = cheerio.load(body);
+
+ const chapterText = loadedCheerio('#chapter-container').html();
+ return chapterText;
+};
+
+// They have API to search, pls update it, im quite lazy xD
+async function searchNovels (searchTerm) {
+ const url = `${baseUrl}lnwsearchlive?inputContent=${searchTerm}`;
+
+ const result = await fetchApi(url, { method: 'GET', headers });
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+// let results = JSON.parse(loadedCheerio('body').text());
+
+// loadedCheerio = cheerio.load(results.resultview);
+
+// loadedCheerio('.novel-item').each(function () {
+// const novelName = loadedCheerio(this).find('.novel-title').text().trim();
+// const novelCover = loadedCheerio(this).find('img').attr('src');
+// const novelUrl =
+// baseUrl + loadedCheerio(this).find('a').attr('href').substring(1);
+
+// const novel = { name: novelName, cover: novelCover, url: novelUrl };
+
+// novels.push(novel);
+// });
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ lang: languages.English,
+ icon: 'src/en/novelpub/icon.png',
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/french/.french b/plugins/french/.french
new file mode 100644
index 0000000..e69de29
diff --git a/plugins/french/chireads.js b/plugins/french/chireads.js
new file mode 100644
index 0000000..42d012b
--- /dev/null
+++ b/plugins/french/chireads.js
@@ -0,0 +1,126 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const pluginId = 'chireads.com';
+const sourceName = 'Chireads';
+
+const baseUrl = 'https://chireads.com/';
+
+async function popularNovels (page) {
+ const url = `${baseUrl}category/translatedtales/page/${page}/`;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('#content li').each(function () {
+ const novelName = loadedCheerio(this).find('.news-list-tit h5').text();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+ const novelUrl = loadedCheerio(this)
+ .find('.news-list-tit h5 a')
+ .attr('href');
+
+ const novel = { name: novelName, cover: novelCover, url :novelUrl };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {
+ url,
+ name: '',
+ cover: '',
+ author: '',
+ artist: '',
+ status: '',
+ genres: '',
+ summary: '',
+ chapters: [],
+ };
+
+ novel.name = loadedCheerio('.inform-title').text().trim();
+
+ novel.cover = loadedCheerio('.inform-product img').attr('src');
+
+ novel.summary = loadedCheerio('.inform-inform-txt').text().trim();
+
+ let chapters = [];
+
+ loadedCheerio('.chapitre-table a').each(function () {
+ const chapterName = loadedCheerio(this).text().trim();
+ const releaseDate = null;
+ const chapterUrl = loadedCheerio(this).attr('href');
+
+ chapters.push({ name: chapterName, releaseTime: releaseDate, url: chapterUrl });
+ });
+
+ novel.chapters = chapters;
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ const chapterText = loadedCheerio('#content').html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = `${baseUrl}search?x=0&y=0&name=${searchTerm}`;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('#content li').each(function () {
+ const novelName = loadedCheerio(this).find('.news-list-tit h5').text();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+ const novelUrl = loadedCheerio(this)
+ .find('.news-list-tit h5 a')
+ .attr('href');
+
+ const novel = { name: novelName, cover: novelCover, url: novelUrl };
+
+ novels.push(novel);
+ });
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ icon: 'src/fr/chireads/icon.png',
+ lang: languages.French,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/french/noveldeglace.js b/plugins/french/noveldeglace.js
new file mode 100644
index 0000000..562aaf8
--- /dev/null
+++ b/plugins/french/noveldeglace.js
@@ -0,0 +1,147 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const sourceName = 'NovelDeGlace';
+const pluginId = 'NDG.com';
+
+const baseUrl = 'https://noveldeglace.com/';
+
+async function popularNovels (page) {
+ let url = baseUrl + 'roman';
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('article').each(function () {
+ const novelName = loadedCheerio(this).find('h2').text().trim();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+ const novelUrl = loadedCheerio(this)
+ .find('h2 > a')
+ .attr('href')
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url, {}, pluginId);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {url};
+
+ novel.name = loadedCheerio(
+ 'div.entry-content > div > strong',
+ )[0].nextSibling.nodeValue.trim();
+
+ novel.cover = loadedCheerio('.su-row > div > div > img').attr('src');
+
+ novel.summary = loadedCheerio('div[data-title=Synopsis]').text();
+
+ const author = loadedCheerio(
+ 'div.romans > div.project-large > div.su-row > div.su-column.su-column-size-3-4 > div > div:nth-child(3) > strong',
+ )[0];
+
+ novel.author = author ? author.nextSibling.nodeValue.trim() : null;
+
+ novel.genres = loadedCheerio('.genre')
+ .text()
+ .replace('Genre : ', '')
+ .replace(/, /g, ',');
+
+ let novelChapters = [];
+
+ loadedCheerio('.chpt').each(function () {
+ const chapterName = loadedCheerio(this).find('a').text().trim();
+ const releaseDate = null;
+ const chapterUrl = loadedCheerio(this).find('a').attr('href');
+
+ const chapter = {
+ name: chapterName,
+ releaseTime: releaseDate,
+ url: chapterUrl,
+ };
+
+ novelChapters.push(chapter);
+ });
+
+ novel.chapters = novelChapters;
+
+ return novel;
+};
+
+async function parseChapter ( chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url, {}, pluginId);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let chapterText = loadedCheerio('.chapter-content').html();
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ let url = baseUrl + 'roman';
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('article').each(function () {
+ const novelName = loadedCheerio(this).find('h2').text().trim();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+ const novelUrl = loadedCheerio(this)
+ .find('h2 > a')
+ .attr('href')
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ novels = novels.filter(novel =>
+ novel.name.toLowerCase().includes(searchTerm.toLowerCase()),
+ );
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ icon: 'src/fr/noveldeglace/icon.png',
+ lang: languages.French,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/indonesian/.indonesian b/plugins/indonesian/.indonesian
new file mode 100644
index 0000000..e69de29
diff --git a/plugins/indonesian/indowebnovel.js b/plugins/indonesian/indowebnovel.js
new file mode 100644
index 0000000..053de72
--- /dev/null
+++ b/plugins/indonesian/indowebnovel.js
@@ -0,0 +1,142 @@
+const cheerio = require('cheerio')
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const pluginId = "IDWN.id";
+const sourceName = 'IndoWebNovel';
+
+const baseUrl = 'https://indowebnovel.id/id/';
+
+async function popularNovels (page) {
+ const url = `${baseUrl}daftar-novel/`;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.novellist-blc li').each(function () {
+ const novelName = loadedCheerio(this).find('a').text();
+ const novelCover = null;
+ const novelUrl = loadedCheerio(this).find('a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {
+ url,
+ name: '',
+ cover: '',
+ author: '',
+ status: '',
+ genres: '',
+ summary: '',
+ chapters: [],
+ };
+
+ novel.name = loadedCheerio('.series-title').text().trim();
+
+ novel.cover = loadedCheerio('.series-thumb > img').attr('src');
+
+ novel.summary = loadedCheerio('.series-synops').text().trim();
+
+ novel.status = loadedCheerio('.status').text().trim();
+
+ novel.genres = [];
+
+ loadedCheerio('.series-genres').each(function () {
+ novel.genres.push(loadedCheerio(this).find('a').text().trim());
+ });
+
+ novel.genres = novel.genres.toString();
+
+ let chapters = [];
+
+ loadedCheerio('.series-chapterlist li').each(function () {
+ const chapterName = loadedCheerio(this).find('a').text().trim();
+ const releaseDate = null;
+ const chapterUrl = loadedCheerio(this).find('a').attr('href');
+
+ chapters.push({ name: chapterName, releaseTime: releaseDate, url: chapterUrl });
+ });
+
+ novel.chapters = chapters.reverse();
+
+ return novel;
+};
+
+async function parseChapter ( chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ const chapterText = loadedCheerio('.reader').html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = `${baseUrl}daftar-novel/`;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.novellist-blc li').each(function () {
+ const novelName = loadedCheerio(this).find('a').text();
+ const novelCover = null;
+ const novelUrl = loadedCheerio(this).find('a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ if (novelName.toLowerCase().includes(searchTerm.toLowerCase())) {
+ novels.push(novel);
+ }
+ });
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ icon: 'src/id/indowebnovel/icon.png',
+ version: '1.0.0',
+ lang: languages.Indonesian,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/indonesian/novelringan.js b/plugins/indonesian/novelringan.js
new file mode 100644
index 0000000..bcc7183
--- /dev/null
+++ b/plugins/indonesian/novelringan.js
@@ -0,0 +1,162 @@
+const cheerio = require('cheerio')
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+const Status = require('@libs/novelStatus');
+
+const pluginId = "novelringan.com";
+
+const sourceName = 'NovelRingan';
+
+const baseUrl = 'https://novelringan.com/';
+const coverUriPrefix = 'https://i0.wp.com/novelringan.com/wp-content/uploads/';
+
+async function popularNovels (page) {
+ const url = `${baseUrl}/top-novel/page/${page}`;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ const novels = [];
+
+ loadedCheerio('article.post').each(function () {
+ const novelName = loadedCheerio(this).find('.entry-title').text()?.trim();
+ const novelCover =
+ coverUriPrefix + loadedCheerio(this).find('img').attr('data-sxrx');
+ const novelUrl = loadedCheerio(this).find('h2 > a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels ;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novel = {
+ url,
+ name: '',
+ cover: '',
+ genres: '',
+ author: '',
+ status: Status.Unknown,
+ artist: '',
+ summary: '',
+ chapters: [],
+ };
+
+ novel.name = loadedCheerio('.entry-title').text()?.trim();
+ novel.cover =
+ coverUriPrefix + loadedCheerio('img.ts-post-image').attr('data-sxrx');
+ novel.summary = loadedCheerio(
+ 'body > div.site-container > div > main > article > div > div.maininfo > span > p',
+ ).text();
+
+ let genreSelector = loadedCheerio(
+ 'body > div.site-container > div > main > article > div > div.maininfo > span > ul > li:nth-child(4)',
+ ).text();
+
+ novel.genres = genreSelector.includes('Genre')
+ ? genreSelector.replace('Genre:', '').trim()
+ : '';
+
+ let statusSelector = loadedCheerio(
+ 'body > div.site-container > div > main > article > div > div.maininfo > span > ul > li:nth-child(3)',
+ ).text();
+
+ novel.status = statusSelector.includes('Status')
+ ? statusSelector.replace('Status:', '').trim()
+ : Status.Unknown;
+
+ let chapters = [];
+
+ loadedCheerio('.bxcl > ul > li').each(function () {
+ const chapterName = loadedCheerio(this).find('a').text();
+ const releaseDate = null;
+ const chapterUrl = loadedCheerio(this).find('a').attr('href');
+
+ const chapter = {
+ name: chapterName,
+ releaseTime: releaseDate,
+ url: chapterUrl,
+ };
+
+ chapters.push(chapter);
+ });
+
+ novel.chapters = chapters.reverse();
+
+ return novel;
+};
+
+async function parseChapter ( chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ loadedCheerio('.entry-content div[style="display:none"]').remove();
+
+ const chapterText = loadedCheerio('.entry-content').html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = baseUrl + '?s=' + searchTerm;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('article.post').each(function () {
+ const novelName = loadedCheerio(this).find('.entry-title').text();
+ const novelCover =
+ coverUriPrefix + loadedCheerio(this).find('img').attr('data-sxrx');
+
+ const novelUrl = loadedCheerio(this).find('h2 > a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+ return novels;
+};
+
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ icon: 'src/id/novelringan/icon.png',
+ version: '1.0.0',
+ lang: languages.Indonesian,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/indonesian/sakuranovel.js b/plugins/indonesian/sakuranovel.js
new file mode 100644
index 0000000..f0a6365
--- /dev/null
+++ b/plugins/indonesian/sakuranovel.js
@@ -0,0 +1,151 @@
+const cheerio = require('cheerio')
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const pluginId = "sakura.id";
+const sourceName = 'SakuraNovel';
+
+const baseUrl = 'https://sakuranovel.id/';
+
+async function popularNovels (page) {
+ const url = `${baseUrl}advanced-search/page/${page}/?title&author&yearx&status&type&order=rating&country%5B0%5D=china&country%5B1%5D=jepang&country%5B2%5D=unknown`;
+
+ const result = await fetchApi(url, {}, pluginId);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.flexbox2-item').each(function () {
+ const novelName = loadedCheerio(this)
+ .find('.flexbox2-title span')
+ .first()
+ .text();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+ const novelUrl = loadedCheerio(this)
+ .find('.flexbox2-content > a')
+ .attr('href');
+
+ const novel = {name: novelName, cover: novelCover, url: novelUrl };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const result = await fetchApi(novelUrl, {}, pluginId);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {
+ name: sourceName,
+ url: novelUrl,
+ };
+
+ novel.name = loadedCheerio('.series-title h2').text().trim();
+
+ novel.cover = loadedCheerio('.series-thumb img').attr('src');
+
+ loadedCheerio('.series-infolist > li').each(function () {
+ const detailName = loadedCheerio(this).find('b').text().trim();
+ const detail = loadedCheerio(this).find('b').next().text().trim();
+
+ switch (detailName) {
+ case 'Author':
+ novel.author = detail;
+ break;
+ }
+ });
+
+ novel.status = loadedCheerio('.status').text().trim();
+
+ novel.genres = loadedCheerio('.series-genres')
+ .prop('innerHTML')
+ .replace(/<.*?>(.*?)<.*?>/g, '$1,')
+ .slice(0, -1);
+
+ novel.summary = loadedCheerio('.series-synops').text().trim();
+
+ let chapters = [];
+
+ loadedCheerio('.series-chapterlist li').each(function () {
+ const chapterName = loadedCheerio(this)
+ .find('a span')
+ .first()
+ .text()
+ .replace(`${novel.novelName} – `, '')
+ .replace('Bahasa Indonesia', '')
+ .replace(/\s+/g, ' ')
+ .trim();
+
+ const releaseDate = loadedCheerio(this)
+ .find('a span')
+ .first()
+ .next()
+ .text();
+ const chapterUrl = loadedCheerio(this).find('a').attr('href');
+
+ chapters.push({ name: chapterName, releaseTime: releaseDate, url: chapterUrl });
+ });
+
+ novel.chapters = chapters.reverse();
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const result = await fetchApi( chapterUrl, {}, pluginId);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ const chapterText = loadedCheerio('.reader').html();
+
+ return chapterText
+};
+
+async function searchNovels (searchTerm) {
+ const url = `${baseUrl}?s=${searchTerm}`;
+ const result = await fetchApi(url, {}, pluginId);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.flexbox2-item').each(function () {
+ const novelName = loadedCheerio(this)
+ .find('.flexbox2-title span')
+ .first()
+ .text();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+ const novelUrl = loadedCheerio(this)
+ .find('.flexbox2-content > a')
+ .attr('href');
+
+ const novel = { name: novelName, cover: novelCover, url: novelUrl };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ icon: 'src/id/sakuranovel/icon.png',
+ version: '1.0.0',
+ lang: languages.Indonesian,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/japanese/.japanese b/plugins/japanese/.japanese
new file mode 100644
index 0000000..e69de29
diff --git a/plugins/japanese/Syosetu.js b/plugins/japanese/Syosetu.js
new file mode 100644
index 0000000..4825255
--- /dev/null
+++ b/plugins/japanese/Syosetu.js
@@ -0,0 +1,205 @@
+const cheerio = require('cheerio');
+const languages = require('@libs/languages');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+// const novelStatus = require('@libs/novelStatus');
+// const isUrlAbsolute = require('@libs/isAbsoluteUrl');
+// const parseDate = require('@libs/parseDate');
+
+const pluginId = 'yomou.syosetu';
+
+const defaultCoverUri =
+ 'https://github.com/LNReader/lnreader-sources/blob/main/icons/src/coverNotAvailable.jpg?raw=true';
+
+const searchUrl = (pagenum, order) => {
+ return `https://yomou.syosetu.com/search.php?order=${order || 'hyoka'}${!isNaN((pagenum = parseInt(pagenum, 10))) // check if pagenum is a number
+ ? `&p=${pagenum <= 1 || pagenum > 100 ? '1' : pagenum}` // check if pagenum is between 1 and 100
+ : '' // if isn't don't set ?p
+ }`;
+};
+
+const novelCover = defaultCoverUri;
+
+async function popularNovels(pageNo) {
+ let novels = [];
+
+ async function getNovelsFromPage(pagenumber) {
+ // load page
+ const result = await fetchApi(searchUrl(pagenumber || null));
+ const body = await result.text();
+ // Cheerio it!
+ const cheerioQuery = cheerio.load(body, { decodeEntities: false });
+ let pageNovels = [];
+ // find class=searchkekka_box
+ cheerioQuery('.searchkekka_box').each(function (i, e) {
+ // get div with link and name
+ const novelDIV = cheerioQuery(this).find('.novel_h');
+ // get link element
+ const novelA = novelDIV.children()[0];
+ // add new novel to array
+ pageNovels.push({
+ name: novelDIV.text(), // get the name
+ url: novelA.attribs.href, // get last part of the link
+ cover: novelCover, // TODO: IDK what to do about covers... On Syo they don't have them
+ });
+ });
+ // return all novels from this page
+ return pageNovels;
+ };
+
+ novels = await getNovelsFromPage(pageNo);
+
+ return novels;
+};
+
+async function parseNovelAndChapters(novelUrl) {
+ let chapters = [];
+ const result = await fetchApi(novelUrl);
+ const body = await result.text();
+ const cheerioQuery = cheerio.load(body, { decodeEntities: false });
+
+ // create novel object
+ let novel = {
+ url: novelUrl,
+ name: cheerioQuery('.novel_title').text(),
+ author: cheerioQuery('.novel_writername').text().replace('作者:', ''),
+ cover: novelCover,
+ };
+
+ // Get all the chapters
+ const cqGetChapters = cheerioQuery('.novel_sublist2');
+ if (cqGetChapters.length !== 0) {
+ // has more than 1 chapter
+ novel.summary = cheerioQuery('#novel_ex')
+ .text()
+ .replace(/<\s*br.*?>/g, '\n');
+ cqGetChapters.each(function (i, e) {
+ const chapterA = cheerioQuery(this).find('a');
+ const [chapterName, releaseDate, chapterUrl] = [
+ // set the variables
+ chapterA.text(),
+ cheerioQuery(this)
+ .find('dt') // get title
+ .text() // get text
+ .replace(/(.)/g, '') // remove "(edited)" mark
+ .trim(), // trim spaces
+ 'https://ncode.syosetu.com' + chapterA.attr('href'),
+ ];
+ chapters.push({ name: chapterName, releaseTime: releaseDate, url: chapterUrl });
+ });
+ } else {
+ /**
+ * Because there are oneshots on the site, they have to be treated with special care
+ * that's what pisses me off in Shosetsu app. They have this extension,
+ * but every oneshot is set as "there are no chapters" and all contents are thrown into the description!!
+ */
+ // get summary for oneshot chapter
+
+ const nameResult = await fetchApi(searchUrl() + `&word=${novel.name}`);
+ const nameBody = await nameResult.text();
+ const summaryQuery = cheerio.load(nameBody, { decodeEntities: false });
+ const foundText = summaryQuery('.searchkekka_box')
+ .first()
+ .find('.ex')
+ .text()
+ .replace(/\s{2,}/g, '\n');
+ novel.summary = foundText;
+
+ // add single chapter
+ chapters.push({
+ name: 'Oneshot',
+ releaseTime: cheerioQuery('head')
+ .find("meta[name='WWWC']")
+ .attr('content'), // get date from metadata
+ url: novelUrl, // set chapterUrl to oneshot so that chapterScraper knows it's a one-shot
+ });
+ }
+ novel.chapters = chapters;
+ return novel;
+};
+
+async function parseChapter(chapterUrl) {
+ const result = await fetchApi(chapterUrl);
+ const body = await result.text();
+
+ // create cheerioQuery
+ const cheerioQuery = cheerio.load(body, {
+ decodeEntities: false,
+ });
+
+ let chapterText = cheerioQuery('#novel_honbun') // get chapter text
+ .html();
+ return chapterText;
+};
+
+
+async function searchNovels(searchTerm, pageNo) {
+ let novels = [];
+
+ // returns list of novels from given page
+ async function getNovelsFromPage (pagenumber) {
+ // load page
+ const result = await fetchApi(
+ searchUrl(pagenumber || null, null) + `&word=${searchTerm}`
+ );
+ const body = await result.text();
+ // Cheerio it!
+ const cheerioQuery = cheerio.load(body, { decodeEntities: false });
+
+ let pageNovels = [];
+ // find class=searchkekka_box
+ cheerioQuery('.searchkekka_box').each(function (i, e) {
+ // get div with link and name
+ const novelDIV = cheerioQuery(this).find('.novel_h');
+ // get link element
+ const novelA = novelDIV.children()[0];
+ // add new novel to array
+ pageNovels.push({
+ name: novelDIV.text(), // get the name
+ url: novelA.attribs.href, // get last part of the link
+ cover: novelCover, // TODO: IDK what to do about covers... On Syo they don't have them
+ });
+ });
+ // return all novels from this page
+ return pageNovels;
+ };
+
+ // counter of loaded pages
+ // let pagesLoaded = 0;
+ // do {
+ // // always load first one
+ // novels.push(...(await getNovelsFromPage(pagesLoaded + 1)));
+ // pagesLoaded++;
+ // } while (pagesLoaded < maxPageLoad && isNext); // check if we should load more
+
+ novels = await getNovelsFromPage(1);
+
+ /** Use
+ * novels.push(...(await getNovelsFromPage(pageNumber)))
+ * if you want to load more
+ */
+
+ // respond with novels!
+ return novels;
+};
+
+async function fetchImage(url) {
+
+ return await fetchFile(url);
+};
+
+module.exports = {
+ id: pluginId,
+ name: 'Syosetu',
+ icon: 'src/jp/syosetu/icon.png',
+ version: '1.0.0',
+ site: 'https://yomou.syosetu.com/',
+ lang: languages.Japanese,
+ description: '小説を読もう!は「小説家になろう」に投稿された',
+ protected: false,
+ fetchImage,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+}
\ No newline at end of file
diff --git a/plugins/korean/Agitoon.js b/plugins/korean/Agitoon.js
new file mode 100644
index 0000000..d099189
--- /dev/null
+++ b/plugins/korean/Agitoon.js
@@ -0,0 +1,155 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const pluginId = 'agit.xyz';
+const sourceName = 'Agitoon';
+const baseUrl = 'https://agit501.xyz/';
+
+async function popularNovels (page) {
+ const list_limit = 20 * (page - 1);
+ const day = new Date().getDay();
+
+ const res = await fetchApi(baseUrl + 'novel/index.update.php', {
+ headers: {
+ 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
+ },
+ body: `mode=get_data_novel_list_p&novel_menu=3&np_day=${day}&np_rank=1&np_distributor=0&np_genre=00&np_order=1&np_genre_ex_1=00&np_genre_ex_2=00&list_limit=${list_limit}&is_query_first=true`,
+ method: 'POST',
+ });
+
+ const resJson = await res.json();
+
+ const novels = resJson.list.map(novel => {
+ return {
+ url: baseUrl + 'novel/list/' + novel.wr_id,
+ name: novel.wr_subject,
+ cover: baseUrl + novel.np_dir + '/thumbnail/' + novel.np_thumbnail,
+ };
+ });
+
+ return novels ;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const novelId = novelUrl.split('/').reverse()[0];
+
+ // cheerio
+ const result = await fetchApi(novelUrl);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body, { decodeEntities: false });
+ const name = loadedCheerio('h5.pt-2').text();
+ const summary = loadedCheerio('.pt-1.mt-1.pb-1.mb-1').text();
+ const author = loadedCheerio('.post-item-list-cate-v')
+ .first()
+ .text()
+ .split(' : ')
+ .reverse()[0];
+ const cover =
+ baseUrl.slice(0, baseUrl.length - 1) +
+ loadedCheerio('div.col-5.pr-0.pl-0 img').attr('src');
+ const genresTag = loadedCheerio('.col-7 > .post-item-list-cate > span');
+ let genres = '';
+
+ genresTag.each((_, element) => {
+ genres += loadedCheerio(element).text();
+ genres += ', ';
+ });
+ genres = genres.slice(0, genres.length - 2);
+
+ // normal REST HTTP requests
+ let chapters = [];
+
+ const res = await fetchApi(baseUrl + 'novel/list.update.php', {
+ headers: {
+ 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
+ },
+ body: `mode=get_data_novel_list_c&wr_id_p=${novelId}&page_no=1&cnt_list=10000&order_type=Asc`,
+ method: 'POST',
+ });
+
+ const resJson = await res.json();
+
+ chapters = resJson.list.map(chapter => {
+ return {
+ name: chapter.wr_subject,
+ url: baseUrl + `novel/view/${chapter.wr_id}/2`,
+ releaseTime: chapter.wr_datetime,
+ };
+ });
+
+ const novel = {
+ url: novelUrl,
+ name,
+ cover,
+ summary,
+ author,
+ status: '',
+ genres: genres,
+ chapters,
+ };
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const result = await fetchApi(chapterUrl);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ const contentTag = loadedCheerio('#id_wr_content > p');
+
+ let content = '';
+ contentTag.each((_, element) => {
+ content += loadedCheerio(element).text();
+ content += '
';
+ });
+
+ // gets rid of the popup thingy
+ content = content.replace(
+ '팝업메뉴는 빈공간을 더치하거나 스크룰시 사라집니다',
+ '',
+ );
+
+ return content;
+};
+
+async function searchNovels (searchTerm) {
+ const rawResults = await fetchApi('https://agit501.xyz/novel/search.php', {
+ headers: {
+ 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
+ },
+ body: `mode=get_data_novel_list_p_sch&search_novel=${searchTerm}&list_limit=0`,
+ method: 'POST',
+ });
+
+ const results = await rawResults.json();
+ if (results.list_count === 0) {
+ return [];
+ }
+
+ const novels = results.list.map(result => {
+ return {
+ url: baseUrl + 'novel/list/' + result.wr_id,
+ name: result.wr_subject,
+ cover: baseUrl + result.np_dir + '/thumbnail/' + result.np_thumbnail,
+ };
+ });
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ icon: 'src/kr/agitoon/agit.png',
+ lang: languages.Korean,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/plugins.json b/plugins/plugins.json
new file mode 100644
index 0000000..293022f
--- /dev/null
+++ b/plugins/plugins.json
@@ -0,0 +1,287 @@
+{
+ "中文, 汉语, 漢語": [],
+ "English": [
+ {
+ "id": "LNR.org",
+ "name": "LightNovelReader",
+ "site": "https://lightnovelreader.org",
+ "lang": "English",
+ "version": "1.0.0",
+ "description": "This is description for plugin",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/LightNovelReader.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/lightnovelreader/icon.png"
+ },
+ {
+ "id": "NF.me",
+ "name": "NovelFull.me",
+ "site": "https://novelfull.me/",
+ "lang": "English",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/NovelFullMe.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/novelfullme/icon.png"
+ },
+ {
+ "id": "NO.net",
+ "name": "novelsOnline",
+ "site": "https://novelsonline.net",
+ "lang": "English",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/NovelOnline.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/coverNotAvailable.jpg"
+ },
+ {
+ "id": "ANF.com",
+ "name": "AllNovelFull",
+ "site": "https://allnovelfull.com",
+ "lang": "English",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/allnovelfull.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/allnovelfull/icon.png"
+ },
+ {
+ "id": "BLN.com",
+ "name": "BestLightNovel",
+ "site": "https://bestlightnovel.com/",
+ "lang": "English",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/bestlightnovel.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/bestlightnovel/icon.png"
+ },
+ {
+ "id": "comrademao",
+ "name": "Comrade Mao",
+ "site": "https://comrademao.com/",
+ "lang": "English",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/comrademao.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/comrademao/icon.png"
+ },
+ {
+ "id": "DDL.com",
+ "name": "Divine Dao Library",
+ "site": "https://www.divinedaolibrary.com/",
+ "lang": "English",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/divinedaolibrary.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/divinedaolibrary/icon.png"
+ },
+ {
+ "id": "foxaholic",
+ "name": "Foxaholic",
+ "site": "https://www.foxaholic.com/",
+ "lang": "English",
+ "version": "1.0.0",
+ "description": "Digging Pits",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/foxaholic.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/foxaholic/icon.png"
+ },
+ {
+ "id": "FWN.com",
+ "name": "Web NOVEL",
+ "site": "https://freewebnovel.com/",
+ "lang": "English",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/freewebnovel.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/freewebnovel/icon.png"
+ },
+ {
+ "id": "novelpub.com",
+ "name": "NovelPub",
+ "site": "https://www.novelpub.com/",
+ "lang": "English",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/novelpub.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/novelpub/icon.png"
+ }
+ ],
+ "français, française": [
+ {
+ "id": "chireads.com",
+ "name": "Chireads",
+ "site": "https://chireads.com/",
+ "lang": "français, française",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/french/chireads.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/fr/chireads/icon.png"
+ },
+ {
+ "id": "NDG.com",
+ "name": "NovelDeGlace",
+ "site": "https://noveldeglace.com/",
+ "lang": "français, française",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/french/noveldeglace.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/fr/noveldeglace/icon.png"
+ }
+ ],
+ "Bahasa Indonesia": [
+ {
+ "id": "IDWN.id",
+ "name": "IndoWebNovel",
+ "site": "https://indowebnovel.id/id/",
+ "lang": "Bahasa Indonesia",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/indonesian/indowebnovel.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/id/indowebnovel/icon.png"
+ },
+ {
+ "id": "novelringan.com",
+ "name": "NovelRingan",
+ "site": "https://novelringan.com/",
+ "lang": "Bahasa Indonesia",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/indonesian/novelringan.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/id/novelringan/icon.png"
+ },
+ {
+ "id": "sakura.id",
+ "name": "SakuraNovel",
+ "site": "https://sakuranovel.id/",
+ "lang": "Bahasa Indonesia",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/indonesian/sakuranovel.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/id/sakuranovel/icon.png"
+ }
+ ],
+ "日本語": [
+ {
+ "id": "yomou.syosetu",
+ "name": "Syosetu",
+ "site": "https://yomou.syosetu.com/",
+ "lang": "日本語",
+ "version": "1.0.0",
+ "description": "小説を読もう!は「小説家になろう」に投稿された",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/japanese/Syosetu.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/jp/syosetu/icon.png"
+ }
+ ],
+ "한국어, 조선말": [
+ {
+ "id": "agit.xyz",
+ "name": "Agitoon",
+ "site": "https://agit501.xyz/",
+ "lang": "한국어, 조선말",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/korean/Agitoon.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/kr/agitoon/agit.png"
+ }
+ ],
+ "Português": [],
+ "русский язык": [
+ {
+ "id": "jaomix.ru",
+ "name": "Jaomix",
+ "site": "https://jaomix.ru",
+ "lang": "русский язык",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/russian/jaomix.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/ru/jaomix/icon.png"
+ },
+ {
+ "id": "RNBH.org",
+ "name": "RanobeHub",
+ "site": "https://ranobehub.org/",
+ "lang": "русский язык",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/russian/ranobehub.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/ru/ranobehub/icon.png"
+ },
+ {
+ "id": "RNRF",
+ "name": "РанобэРФ",
+ "site": "https://ранобэ.рф",
+ "lang": "русский язык",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/russian/ranoberf.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/ru/ranoberf/icon.png"
+ }
+ ],
+ "español, castellano": [
+ {
+ "id": "HasuTL",
+ "name": "Hasu Translations",
+ "site": "https://hasutl.wordpress.com/",
+ "lang": "español, castellano",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/hasutl.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/hasutl/icon.png"
+ },
+ {
+ "id": "ligera.com",
+ "name": "Novelas Ligera",
+ "site": "https://novelasligera.com/",
+ "lang": "español, castellano",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/novelasligera.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/novelasligera/icon.png"
+ },
+ {
+ "id": "awuxia.com",
+ "name": "ReinoWuxia",
+ "site": "http://www.reinowuxia.com/",
+ "lang": "español, castellano",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/novelawuxia.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/novelawuxia/icon.png"
+ },
+ {
+ "id": "oasisTL.wp",
+ "name": "Oasis Translations",
+ "site": "https://oasistranslations.wordpress.com/",
+ "lang": "español, castellano",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/oasistranslations.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/oasistranslations/icon.png"
+ },
+ {
+ "id": "skynovels.net",
+ "name": "SkyNovels",
+ "site": "https://www.skynovels.net/",
+ "lang": "español, castellano",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/skynovels.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/skynovels/icon.png"
+ },
+ {
+ "id": "TNL.com",
+ "name": "TuNovelaLigera",
+ "site": "https://tunovelaligera.com/",
+ "lang": "español, castellano",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/tunovelaligera.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/tunovelaligera/icon.png"
+ },
+ {
+ "id": "yuukitls.com",
+ "name": "Yuuki Tls",
+ "site": "https://yuukitls.com/",
+ "lang": "español, castellano",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/yukitls.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/yuukitls/icon.png"
+ }
+ ],
+ "Türkçe": [
+ {
+ "id": "epiknovel.com",
+ "name": "EpikNovel",
+ "site": "https://www.epiknovel.com/",
+ "lang": "Türkçe",
+ "version": "1.0.0",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/turkish/epiknovel.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/tr/epiknovel/icon.png"
+ }
+ ],
+ "Tiếng Việt": [
+ {
+ "id": "ln.hako",
+ "name": "Hako",
+ "site": "https://ln.hako.vn",
+ "lang": "Tiếng Việt",
+ "version": "1.0.0",
+ "description": "Cổng LightNovel",
+ "url": "https://raw.githubusercontent.com/nyagami/plugins/main/plugins/vietnamese/LNHako.js",
+ "iconUrl": "https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/vi/hakolightnovel/icon.png"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/plugins/plugins.min.json b/plugins/plugins.min.json
new file mode 100644
index 0000000..e465c27
--- /dev/null
+++ b/plugins/plugins.min.json
@@ -0,0 +1 @@
+{"中文, 汉语, 漢語":[],"English":[{"id":"LNR.org","name":"LightNovelReader","site":"https://lightnovelreader.org","lang":"English","version":"1.0.0","description":"This is description for plugin","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/LightNovelReader.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/lightnovelreader/icon.png"},{"id":"NF.me","name":"NovelFull.me","site":"https://novelfull.me/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/NovelFullMe.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/novelfullme/icon.png"},{"id":"NO.net","name":"novelsOnline","site":"https://novelsonline.net","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/NovelOnline.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/coverNotAvailable.jpg"},{"id":"ANF.com","name":"AllNovelFull","site":"https://allnovelfull.com","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/allnovelfull.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/allnovelfull/icon.png"},{"id":"BLN.com","name":"BestLightNovel","site":"https://bestlightnovel.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/bestlightnovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/bestlightnovel/icon.png"},{"id":"comrademao","name":"Comrade Mao","site":"https://comrademao.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/comrademao.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/comrademao/icon.png"},{"id":"DDL.com","name":"Divine Dao Library","site":"https://www.divinedaolibrary.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/divinedaolibrary.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/divinedaolibrary/icon.png"},{"id":"foxaholic","name":"Foxaholic","site":"https://www.foxaholic.com/","lang":"English","version":"1.0.0","description":"Digging Pits","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/foxaholic.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/foxaholic/icon.png"},{"id":"FWN.com","name":"Web NOVEL","site":"https://freewebnovel.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/freewebnovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/freewebnovel/icon.png"},{"id":"novelpub.com","name":"NovelPub","site":"https://www.novelpub.com/","lang":"English","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/english/novelpub.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/en/novelpub/icon.png"}],"français, française":[{"id":"chireads.com","name":"Chireads","site":"https://chireads.com/","lang":"français, française","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/french/chireads.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/fr/chireads/icon.png"},{"id":"NDG.com","name":"NovelDeGlace","site":"https://noveldeglace.com/","lang":"français, française","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/french/noveldeglace.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/fr/noveldeglace/icon.png"}],"Bahasa Indonesia":[{"id":"IDWN.id","name":"IndoWebNovel","site":"https://indowebnovel.id/id/","lang":"Bahasa Indonesia","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/indonesian/indowebnovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/id/indowebnovel/icon.png"},{"id":"novelringan.com","name":"NovelRingan","site":"https://novelringan.com/","lang":"Bahasa Indonesia","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/indonesian/novelringan.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/id/novelringan/icon.png"},{"id":"sakura.id","name":"SakuraNovel","site":"https://sakuranovel.id/","lang":"Bahasa Indonesia","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/indonesian/sakuranovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/id/sakuranovel/icon.png"}],"日本語":[{"id":"yomou.syosetu","name":"Syosetu","site":"https://yomou.syosetu.com/","lang":"日本語","version":"1.0.0","description":"小説を読もう!は「小説家になろう」に投稿された","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/japanese/Syosetu.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/jp/syosetu/icon.png"}],"한국어, 조선말":[{"id":"agit.xyz","name":"Agitoon","site":"https://agit501.xyz/","lang":"한국어, 조선말","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/korean/Agitoon.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/kr/agitoon/agit.png"}],"Português":[],"русский язык":[{"id":"jaomix.ru","name":"Jaomix","site":"https://jaomix.ru","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/russian/jaomix.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/ru/jaomix/icon.png"},{"id":"RNBH.org","name":"RanobeHub","site":"https://ranobehub.org/","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/russian/ranobehub.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/ru/ranobehub/icon.png"},{"id":"RNRF","name":"РанобэРФ","site":"https://ранобэ.рф","lang":"русский язык","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/russian/ranoberf.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/ru/ranoberf/icon.png"}],"español, castellano":[{"id":"HasuTL","name":"Hasu Translations","site":"https://hasutl.wordpress.com/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/hasutl.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/hasutl/icon.png"},{"id":"ligera.com","name":"Novelas Ligera","site":"https://novelasligera.com/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/novelasligera.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/novelasligera/icon.png"},{"id":"awuxia.com","name":"ReinoWuxia","site":"http://www.reinowuxia.com/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/novelawuxia.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/novelawuxia/icon.png"},{"id":"oasisTL.wp","name":"Oasis Translations","site":"https://oasistranslations.wordpress.com/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/oasistranslations.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/oasistranslations/icon.png"},{"id":"skynovels.net","name":"SkyNovels","site":"https://www.skynovels.net/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/skynovels.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/skynovels/icon.png"},{"id":"TNL.com","name":"TuNovelaLigera","site":"https://tunovelaligera.com/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/tunovelaligera.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/tunovelaligera/icon.png"},{"id":"yuukitls.com","name":"Yuuki Tls","site":"https://yuukitls.com/","lang":"español, castellano","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/spanish/yukitls.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/es/yuukitls/icon.png"}],"Türkçe":[{"id":"epiknovel.com","name":"EpikNovel","site":"https://www.epiknovel.com/","lang":"Türkçe","version":"1.0.0","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/turkish/epiknovel.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/tr/epiknovel/icon.png"}],"Tiếng Việt":[{"id":"ln.hako","name":"Hako","site":"https://ln.hako.vn","lang":"Tiếng Việt","version":"1.0.0","description":"Cổng LightNovel","url":"https://raw.githubusercontent.com/nyagami/plugins/main/plugins/vietnamese/LNHako.js","iconUrl":"https://raw.githubusercontent.com/nyagami/plugins/main/icons/src/vi/hakolightnovel/icon.png"}]}
\ No newline at end of file
diff --git a/plugins/portuguese/.portuguese b/plugins/portuguese/.portuguese
new file mode 100644
index 0000000..e69de29
diff --git a/plugins/russian/.russian b/plugins/russian/.russian
new file mode 100644
index 0000000..e69de29
diff --git a/plugins/russian/jaomix.js b/plugins/russian/jaomix.js
new file mode 100644
index 0000000..18907ed
--- /dev/null
+++ b/plugins/russian/jaomix.js
@@ -0,0 +1,217 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+const Status = require('@libs/novelStatus');
+const FilterInputs = require('@libs/filterInputs');
+
+const pluginId = 'jaomix.ru';
+const sourceName = 'Jaomix';
+
+const baseUrl = 'https://jaomix.ru';
+
+async function popularNovels (page, { showLatestNovels, filters }) {
+ let url = baseUrl + '/?searchrn&sortby=';
+ url += filters?.sort ? filters?.sort : (showLatestNovels ? 'upd' : 'count');
+
+ if (filters?.type?.length) {
+ url += filters.type.map(i => `&lang[]=${i}`).join('');
+ }
+
+ if (filters?.genres?.length) {
+ url += filters.genres.map(i => `&genre[]=${i}`).join('');
+ }
+ url += `&page=${page}`;
+
+ const result = await fetchApi(url);
+ let body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+ let novels = [];
+
+ loadedCheerio('div[class="block-home"] > div[class="one"]').each(function () {
+ const novelName = loadedCheerio(this)
+ .find('div[class="img-home"] > a')
+ .attr('title');
+ const novelCover = loadedCheerio(this)
+ .find('div[class="img-home"] > a > img')
+ .attr('src')
+ .replace('-150x150', '');
+ const novelUrl = loadedCheerio(this)
+ .find('div[class="img-home"] > a')
+ .attr('href');
+
+ const novel = { name: novelName, cover: novelCover, url: novelUrl };
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const result = await fetchApi(novelUrl);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+ let novel = {
+ url: novelUrl,
+ };
+
+ novel.name = loadedCheerio('div[class="desc-book"] > h1').text().trim();
+ novel.cover = loadedCheerio('div[class="img-book"] > img').attr('src');
+ novel.summary = loadedCheerio('div[id="desc-tab"]').text().trim();
+
+ loadedCheerio('#info-book > p').each(function () {
+ let text = loadedCheerio(this).text().replace(/,/g, '').split(' ');
+ if (text[0] === 'Автор:') {
+ novel.author = text.splice(1).join(' ');
+ } else if (text[0] === 'Жанры:') {
+ novel.genres = text.splice(1).join(',');
+ } else if (text[0] === 'Статус:') {
+ novel.status = text.includes('продолжается')
+ ? Status.Ongoing
+ : Status.Completed;
+ }
+ });
+
+ const chapters = [];
+
+ loadedCheerio('.download-chapter div.title').each(function () {
+ chapters.push({
+ name: loadedCheerio(this).find('a').attr('title'),
+ releaseTime: loadedCheerio(this).find('time').text(),
+ url: loadedCheerio(this).find('a').attr('href'),
+ });
+ });
+
+ novel.chapters = chapters.reverse();
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const result = await fetchApi(chapterUrl);
+ const body = await result.text();
+ const loadedCheerio = cheerio.load(body);
+
+ loadedCheerio('div[class="adblock-service"]').remove();
+ const chapterText = loadedCheerio('div[class="entry-content"]').html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = `${baseUrl}/?searchrn=${searchTerm}&but=Поиск по названию&sortby=upd`;
+ const result = await fetchApi(url);
+ let body = await result.text();
+ const loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+ loadedCheerio('div[class="block-home"] > div[class="one"]').each(function () {
+ const novelName = loadedCheerio(this)
+ .find('div[class="img-home"] > a')
+ .attr('title');
+ const novelCover = loadedCheerio(this)
+ .find('div[class="img-home"] > a > img')
+ .attr('src')
+ .replace('-150x150', '');
+ const novelUrl = loadedCheerio(this)
+ .find('div[class="img-home"] > a')
+ .attr('href');
+
+ const novel = {name: novelName, cover: novelCover, url: novelUrl };
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+const filters = [
+ {
+ key: 'sort',
+ label: 'Сортировка',
+ values: [
+ { label: 'Имя', value: 'alphabet' },
+ { label: 'Просмотры', value: 'count' },
+ { label: 'Дате добавления', value: 'new' },
+ { label: 'Дате обновления', value: 'upd' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+ {
+ key: 'type',
+ label: 'Тип',
+ values: [
+ { label: 'Английский', value: 'Английский' },
+ { label: 'Китайский', value: 'Китайский' },
+ { label: 'Корейский', value: 'Корейский' },
+ { label: 'Японский', value: 'Японский' },
+ ],
+ inputType: FilterInputs.Checkbox,
+ },
+ {
+ key: 'genres',
+ label: 'Жанры',
+ values: [
+ { label: 'Adult', value: 'Adult' },
+ { label: 'Ecchi', value: 'Ecchi' },
+ { label: 'Josei', value: 'Josei' },
+ { label: 'Lolicon', value: 'Lolicon' },
+ { label: 'Mature', value: 'Mature' },
+ { label: 'Sci-fi', value: 'Sci-fi' },
+ { label: 'Shoujo', value: 'Shoujo' },
+ { label: 'Wuxia', value: 'Wuxia' },
+ { label: 'Xianxia', value: 'Xianxia' },
+ { label: 'Xuanhuan', value: 'Xuanhuan' },
+ { label: 'Yaoi', value: 'Yaoi' },
+ { label: 'Боевые Искусства', value: 'Боевые Искусства' },
+ { label: 'Виртуальный Мир', value: 'Виртуальный Мир' },
+ { label: 'Гарем', value: 'Гарем' },
+ { label: 'Детектив', value: 'Детектив' },
+ { label: 'Драма', value: 'Драма' },
+ { label: 'Игра', value: 'Игра' },
+ { label: 'Истории из жизни', value: 'Истории из жизни' },
+ { label: 'Исторический', value: 'Исторический' },
+ { label: 'История', value: 'История' },
+ { label: 'Комедия', value: 'Комедия' },
+ { label: 'Меха', value: 'Меха' },
+ { label: 'Мистика', value: 'Мистика' },
+ { label: 'Научная Фантастика', value: 'Научная Фантастика' },
+ { label: 'Повседневность', value: 'Повседневность' },
+ { label: 'Постапокалипсис', value: 'Постапокалипсис' },
+ { label: 'Приключения', value: 'Приключения' },
+ { label: 'Психология', value: 'Психология' },
+ { label: 'Романтика', value: 'Романтика' },
+ { label: 'Сёнэн', value: 'Сёнэн' },
+ { label: 'Сёнэн-ай', value: 'Сёнэн-ай' },
+ { label: 'Сверхъестественное', value: 'Сверхъестественное' },
+ { label: 'Спорт', value: 'Спорт' },
+ { label: 'Сэйнэн', value: 'Сэйнэн' },
+ { label: 'Сюаньхуа', value: 'Сюаньхуа' },
+ { label: 'Трагедия', value: 'Трагедия' },
+ { label: 'Триллер', value: 'Триллер' },
+ { label: 'Фантастика', value: 'Фантастика' },
+ { label: 'Фэнтези', value: 'Фэнтези' },
+ { label: 'Хоррор', value: 'Хоррор' },
+ { label: 'Школьная жизнь', value: 'Школьная жизнь' },
+ { label: 'Шоунен', value: 'Шоунен' },
+ { label: 'Экшн', value: 'Экшн' },
+ { label: 'Этти', value: 'Этти' },
+ ],
+ inputType: FilterInputs.Checkbox,
+ },
+];
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ lang: languages.Russian,
+ icon: 'src/ru/jaomix/icon.png',
+ filters,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/russian/ranobehub.js b/plugins/russian/ranobehub.js
new file mode 100644
index 0000000..044f702
--- /dev/null
+++ b/plugins/russian/ranobehub.js
@@ -0,0 +1,1131 @@
+const dayjs = require('dayjs');
+const cheerio = require('cheerio');
+const Status = require('@libs/novelStatus');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+const FilterInputs = require('@libs/filterInputs');
+
+const pluginId = "RNBH.org";
+
+const sourceName = 'RanobeHub';
+
+const baseUrl = 'https://ranobehub.org/';
+
+async function popularNovels (page, { showLatestNovels, filters }){
+ let url = baseUrl + `api/search?page=${page}&sort=`;
+ url += filters?.sort ? filters?.sort :
+ (showLatestNovels ? 'last_chapter_at' : 'computed_rating');
+ url += '&status=' + (filters?.status ? filters?.status : '0');
+
+ if (filters?.country?.length) {
+ url += '&country=' + filters?.country.join(',');
+ }
+
+ let tags = [].concat(filters?.tags, filters?.events).filter(t => t);
+ if (tags?.length) {
+ url += '&tags:positive=' + tags.join(',');
+ }
+ url += '&take=40';
+ const result = await fetchApi(url);
+ const body = await result.json();
+
+ let novels = [];
+
+ body.resource.forEach(novel => {
+ const novelName = novel.names.rus;
+ const novelCover = novel.poster.medium;
+ const novelUrl = novel.url;
+
+ novels.push({
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ });
+ });
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const novelId = novelUrl.substring('https://ranobehub.org/ranobe/'.length).split('-')[0];
+ const result = await fetchApi(`${baseUrl}api/ranobe/${novelId}`);
+ const json = await result.json();
+
+ let novel = {
+ url: json.data.url,
+ novelUrl,
+ name: json.data.names.rus,
+ cover: json.data.posters.medium,
+ summary: json.data.description,
+ author: json.data?.authors[0]?.name_eng || '',
+ status: json.data.status.title.includes('процессе')
+ ? Status.Ongoing
+ : Status.Completed,
+ };
+
+ let tags = []
+ .concat(json.data.tags.events, json.data.tags.genres)
+ .map(item => item?.names?.rus || item?.names?.eng || item?.title)
+ .filter(item => item);
+
+ if (tags.length > 0) {
+ novel.genres = tags.join(', ');
+ }
+
+ let novelChapters = [];
+
+ const fetchChaptersUrl = `${baseUrl}api/ranobe/${novelId}/contents`;
+
+ const chaptersRaw = await fetchApi(fetchChaptersUrl);
+ const chaptersJSON = await chaptersRaw.json();
+
+ chaptersJSON.volumes.forEach(volume =>
+ volume.chapters.forEach(chapter =>
+ novelChapters.push({
+ name: chapter.name,
+ url: chapter.url,
+ releaseTime: dayjs(parseInt(chapter.changed_at, 10) * 1000).format(
+ 'LLL',
+ ),
+ }),
+ ),
+ );
+
+ novel.chapters = novelChapters;
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const result = await fetchApi(chapterUrl);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let chapterText = loadedCheerio(
+ 'body > div.pusher.container_main > div:nth-child(5) > div:nth-child(1)',
+ ).html();
+
+ // Remove script tags
+ chapterText = chapterText?.replace(
+ /<\s*script[^>]*>[\s\S]*?<\/script>/gim,
+ '',
+ );
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = `${baseUrl}api/fulltext/global?query=${searchTerm}&take=5`;
+
+ const result = await fetchApi(url);
+ const data = await result.json();
+
+ let novels = [];
+
+ data
+ .find(item => item.meta.key === 'ranobe')
+ ?.data.forEach(novel =>
+ novels.push({
+ name: novel.names.rus,
+ url: "https://ranobehub.org/ranobe/" + novel.url.match(
+ /https:\/\/ranobehub\.org\/ranobe\/(.*?)\?utm_source=search_name&utm_medium=search&utm_campaign=search_using/,
+ )[1],
+ cover: novel.image.replace('/small', '/medium'),
+ }),
+ );
+
+ return novels;
+};
+
+const filters = [
+ {
+ key: 'sort',
+ label: 'Сортировка',
+ values: [
+ { label: 'по рейтингу', value: 'computed_rating' },
+ { label: 'по дате обновления', value: 'last_chapter_at' },
+ { label: 'по дате добавления', value: 'created_at' },
+ { label: 'по названию', value: 'name_rus' },
+ { label: 'по просмотрам', value: 'views' },
+ { label: 'по количеству глав', value: 'count_chapters' },
+ { label: 'по объему перевода', value: 'count_of_symbols' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+ {
+ key: 'status',
+ label: 'Статус перевода',
+ values: [
+ { label: 'Любой', value: '' },
+ { label: 'В процессе', value: '1' },
+ { label: 'Завершено', value: '2' },
+ { label: 'Заморожено', value: '3' },
+ { label: 'Неизвестно', value: '4' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+ {
+ key: 'country',
+ label: 'Тип',
+ values: [
+ { label: 'Китай', value: '2' },
+ { label: 'Корея', value: '3' },
+ { label: 'США', value: '4' },
+ { label: 'Япония', value: '1' },
+ ],
+ inputType: FilterInputs.Checkbox,
+ },
+ {
+ key: 'events',
+ label: 'События',
+ values: [
+ { label: 'Авантюристы', value: '353' },
+ { label: 'Автоматоны', value: '538' },
+ { label: 'Агрессивные персонажи', value: '434' },
+ { label: 'Ад', value: '509' },
+ { label: 'Адаптация в радиопостановку', value: '522' },
+ { label: 'Академия', value: '25' },
+ { label: 'Актеры озвучки', value: '578' },
+ { label: 'Активный главный герой', value: '132' },
+ { label: 'Алхимия', value: '116' },
+ { label: 'Альтернативный мир', value: '28' },
+ { label: 'Амнезия/Потеря памяти', value: '247' },
+ { label: 'Анабиоз', value: '657' },
+ { label: 'Ангелы', value: '218' },
+ { label: 'Андрогинные персонажи', value: '217' },
+ { label: 'Андроиды', value: '82' },
+ { label: 'Анти-магия', value: '471' },
+ { label: 'Антигерой', value: '346' },
+ { label: 'Антикварный магазин', value: '572' },
+ { label: 'Антисоциальный главный герой', value: '562' },
+ { label: 'Антиутопия', value: '663' },
+ { label: 'Апатичный протагонист', value: '29' },
+ { label: 'Апокалипсис', value: '314' },
+ { label: 'Аранжированный брак', value: '285' },
+ { label: 'Армия', value: '598' },
+ { label: 'Артефакты', value: '117' },
+ { label: 'Артисты', value: '460' },
+ { label: 'Банды', value: '581' },
+ { label: 'БДСМ', value: '676' },
+ { label: 'Бедный главный герой', value: '309' },
+ { label: 'Безжалостный главный герой', value: '144' },
+ { label: 'Беззаботный главный герой', value: '355' },
+ { label: 'Безусловная любовь', value: '650' },
+ { label: 'Беременность', value: '131' },
+ { label: 'Бесполый главный герой', value: '222' },
+ { label: 'Бессмертные', value: '275' },
+ { label: 'Бесстрашный протагонист', value: '619' },
+ { label: 'Бесстыдный главный герой', value: '256' },
+ { label: 'Бесчестный главный герой', value: '699' },
+ { label: 'Библиотека', value: '342' },
+ { label: 'Бизнесмен ', value: '813' },
+ { label: 'Биочип', value: '120' },
+ { label: 'Бисексуальный главный герой', value: '822' },
+ { label: 'Близнецы', value: '148' },
+ { label: 'Боги', value: '211' },
+ { label: 'Богини', value: '356' },
+ { label: 'Боевая академия', value: '369' },
+ { label: 'Боевые духи', value: '347' },
+ { label: 'Боевые соревнования', value: '422' },
+ { label: 'Божественная защита', value: '336' },
+ { label: 'Божественные силы', value: '224' },
+ {
+ label:
+ 'Большая разница в возрасте между героем и его любовным интересом',
+ value: '348',
+ },
+ { label: 'Борьба за власть', value: '544' },
+ { label: 'Брак', value: '363' },
+ { label: 'Брак по расчету', value: '65' },
+ { label: 'Братский комплекс', value: '31' },
+ { label: 'Братство', value: '413' },
+ { label: 'Братья и сестры', value: '518' },
+ { label: 'Буддизм', value: '742' },
+ { label: 'Быстрая культивация', value: '273' },
+ { label: 'Быстрообучаемый', value: '221' },
+ { label: 'Валькирии', value: '667' },
+ { label: 'Вампиры', value: '266' },
+ { label: 'Ваншот', value: '679' },
+ { label: 'Ведьмы', value: '169' },
+ { label: 'Вежливый главный герой', value: '289' },
+ { label: 'Верные подчиненные', value: '225' },
+ { label: 'Взрослый главный герой', value: '183' },
+ { label: 'Видит то, чего не видят другие', value: '636' },
+ { label: 'Виртуальная реальность', value: '313' },
+ { label: 'Владелец магазина', value: '653' },
+ { label: 'Внезапная сила', value: '376' },
+ { label: 'Внезапное богатство', value: '802' },
+ {
+ label: 'Внешний вид отличается от фактического возраста',
+ value: '334',
+ },
+ { label: 'Военные Летописи', value: '740' },
+ { label: 'Возвращение из другого мира', value: '673' },
+ { label: 'Войны', value: '58' },
+ { label: 'Вокалоид', value: '678' },
+ { label: 'Волшебники/Волшебницы', value: '477' },
+ { label: 'Волшебные звери', value: '201' },
+ { label: 'Воображаемый друг', value: '614' },
+ { label: 'Воры', value: '326' },
+ { label: 'Воскрешение', value: '78' },
+ { label: 'Враги становятся возлюбленными', value: '428' },
+ { label: 'Враги становятся союзниками', value: '502' },
+ { label: 'Врата в другой мир', value: '558' },
+ { label: 'Врачи', value: '286' },
+ { label: 'Временной парадокс', value: '163' },
+ { label: 'Всемогущий главный герой', value: '42' },
+ { label: 'Вторжение на землю', value: '77' },
+ { label: 'Второй шанс', value: '112' },
+ { label: 'Вуайеризм', value: '851' },
+ { label: 'Выживание', value: '290' },
+ { label: 'Высокомерные персонажи', value: '268' },
+ { label: 'Гадание', value: '540' },
+ { label: 'Гарем рабов', value: '828' },
+ { label: 'Геймеры', value: '302' },
+ { label: 'Генералы', value: '223' },
+ { label: 'Генетические модификации', value: '620' },
+ { label: 'Гениальный главный герой', value: '566' },
+ { label: 'Герои', value: '173' },
+ { label: 'Героиня — сорванец', value: '525' },
+ { label: 'Герой влюбляется первым', value: '64' },
+ { label: 'Гетерохромия', value: '510' },
+ { label: 'Гильдии', value: '323' },
+ { label: 'Гипнотизм', value: '768' },
+ { label: 'Главный герой влюбляется первым', value: '655' },
+ { label: 'Главный герой играет роль', value: '396' },
+ { label: 'Главный герой носит очки', value: '637' },
+ { label: 'Главный герой пацифист', value: '675' },
+ { label: 'Главный герой с несколькими телами', value: '628' },
+ { label: 'Главный герой силен с самого начала', value: '45' },
+ { label: 'Главный герой — бог', value: '486' },
+ { label: 'Главный герой — гуманоид', value: '595' },
+ { label: 'Главный герой — женщина', value: '63' },
+ { label: 'Главный герой — мужчина', value: '39' },
+ { label: 'Главный герой — наполовину человек', value: '362' },
+ { label: 'Главный герой — отец', value: '859' },
+ { label: 'Главный герой — раб', value: '832' },
+ { label: 'Главный герой — ребенок', value: '415' },
+ { label: 'Главный герой — рубака', value: '400' },
+ { label: 'Главный герой — собиратель гарема', value: '439' },
+ { label: 'Гладиаторы', value: '549' },
+ { label: 'Глуповатый главный герой', value: '295' },
+ { label: 'Гоблины', value: '529' },
+ { label: 'Големы', value: '569' },
+ { label: 'Гомункул', value: '850' },
+ { label: 'Горничные', value: '380' },
+ { label: 'Госпиталь', value: '1043' },
+ { label: 'Готовка', value: '193' },
+ { label: 'Гриндинг', value: '303' },
+ { label: 'Дао Компаньон', value: '384' },
+ { label: 'Даосизм', value: '792' },
+ { label: 'Дарк', value: '151' },
+ { label: 'Дварфы', value: '220' },
+ { label: 'Двойная личность', value: '601' },
+ { label: 'Двойник', value: '547' },
+ { label: 'Дворецкий', value: '623' },
+ { label: 'Дворяне', value: '41' },
+ { label: 'Дворянство/Аристократия', value: '354' },
+ { label: 'Девушки-монстры', value: '634' },
+ { label: 'Демоническая техника культивации', value: '706' },
+ { label: 'Демоны', value: '6' },
+ { label: 'Денежный долг', value: '841' },
+ { label: 'Депрессия', value: '494' },
+ { label: 'Детективы', value: '561' },
+ { label: 'Дискриминация', value: '34' },
+ {
+ label: 'Добыча денег одно из основных стремлений главного героя',
+ value: '307',
+ },
+ { label: 'Долгая разлука', value: '200' },
+ { label: 'Домашние дела', value: '178' },
+ { label: 'Домогательство', value: '394' },
+ { label: 'Драконы', value: '195' },
+ { label: 'Драконьи всадники', value: '555' },
+ { label: 'Древние времена', value: '102' },
+ { label: 'Древний Китай', value: '284' },
+ { label: 'Дружба', value: '97' },
+ { label: 'Друзья детства', value: '170' },
+ { label: 'Друзья становятся врагами', value: '507' },
+ { label: 'Друиды', value: '427' },
+ { label: 'Дух лисы', value: '842' },
+ { label: 'Духи/Призраки', value: '46' },
+ { label: 'Духовный советник', value: '351' },
+ { label: 'Душевность', value: '587' },
+ { label: 'Души', value: '136' },
+ { label: 'Европейская атмосфера', value: '457' },
+ { label: 'Есть аниме-адаптация', value: '26' },
+ { label: 'Есть видеоигра по мотивам', value: '491' },
+ { label: 'Есть манга-адаптация', value: '27' },
+ { label: 'Есть манхва-адаптация', value: '453' },
+ { label: 'Есть маньхуа-адаптация', value: '298' },
+ { label: 'Есть сериал-адаптация', value: '421' },
+ { label: 'Есть фильм по мотивам', value: '47' },
+ { label: 'Женища-наставник', value: '438' },
+ { label: 'Жертва изнасилования влюбляется в насильника', value: '414' },
+ { label: 'Жесткая, двуличная личность', value: '249' },
+ { label: 'Жестокие персонажи', value: '436' },
+ { label: 'Жестокое обращение с ребенком', value: '617' },
+ { label: 'Жестокость', value: '127' },
+ { label: 'Животноводство', value: '765' },
+ { label: 'Животные черты', value: '466' },
+ { label: 'Жизнь в квартире', value: '554' },
+ { label: 'Жрицы', value: '564' },
+ { label: 'Заботливый главный герой', value: '176' },
+ { label: 'Забывчивый главный герой', value: '579' },
+ { label: 'Заговоры', value: '177' },
+ { label: 'Закалка тела', value: '269' },
+ { label: 'Законники', value: '769' },
+ { label: 'Замкнутый главный герой', value: '533' },
+ { label: 'Запечатанная сила', value: '344' },
+ { label: 'Застенчивые персонажи', value: '443' },
+ { label: 'Звери', value: '119' },
+ { label: 'Звери-компаньоны', value: '192' },
+ { label: 'Злой протагонист', value: '125' },
+ { label: 'Злые боги', value: '437' },
+ { label: 'Злые организации', value: '503' },
+ { label: 'Злые религии', value: '725' },
+ { label: 'Знаменитости', value: '397' },
+ { label: 'Знаменитый главный герой', value: '469' },
+ { label: 'Знания современного мира', value: '185' },
+ { label: 'Зомби', value: '321' },
+ { label: 'Игра на выживание', value: '162' },
+ { label: 'Игривый протагонист', value: '700' },
+ { label: 'Игровая система рейтинга', value: '301' },
+ { label: 'Игровые элементы', value: '152' },
+ { label: 'Игрушки (18+)', value: '644' },
+ { label: 'Из грязи в князи', value: '330' },
+ { label: 'Из женщины в мужчину ', value: '688' },
+ { label: 'Из мужчины в женщину', value: '698' },
+ { label: 'Из полного в худого', value: '809' },
+ { label: 'Из слабого в сильного', value: '81' },
+ { label: 'Из страшно(го/й) в красиво(го/ю)', value: '810' },
+ { label: 'Извращенный главный герой', value: '349' },
+ { label: 'Изгои', value: '472' },
+ { label: 'Изменение расы', value: '627' },
+ { label: 'Изменения внешнего вида', value: '191' },
+ { label: 'Изменения личности', value: '99' },
+ { label: 'Изнасилование', value: '110' },
+ { label: 'Изображения жестокости', value: '260' },
+ { label: 'Империи', value: '749' },
+ { label: 'Инвалидность', value: '656' },
+ { label: 'Индустриализация', value: '180' },
+ { label: 'Инженер', value: '35' },
+ { label: 'Инцест', value: '463' },
+ { label: 'Искусственный интеллект', value: '118' },
+ { label: 'Исследования', value: '635' },
+ { label: 'Каннибализм', value: '377' },
+ { label: 'Карточные игры', value: '654' },
+ { label: 'Киберспорт', value: '658' },
+ { label: 'Кланы', value: '950' },
+ { label: 'Класс безработного [Игровой класс в игре]', value: '727' },
+ { label: 'Клоны', value: '365' },
+ { label: 'Клубы', value: '96' },
+ { label: 'Книги', value: '341' },
+ { label: 'Книги навыков', value: '312' },
+ { label: 'Книжный червь', value: '455' },
+ { label: 'Коварство', value: '111' },
+ { label: 'Коллеги', value: '683' },
+ { label: 'Колледж/Университет', value: '712' },
+ { label: 'Кома', value: '826' },
+ { label: 'Командная работа', value: '426' },
+ { label: 'Комедийный оттенок', value: '523' },
+ { label: 'Комплекс неполноценности', value: '489' },
+ { label: 'Комплекс семейных отношений', value: '104' },
+ { label: 'Конкуренция', value: '746' },
+ { label: 'Контракты', value: '483' },
+ { label: 'Контроль разума/сознания', value: '262' },
+ { label: 'Копейщик', value: '339' },
+ { label: 'Королевская битва', value: '1025' },
+ { label: 'Королевская власть', value: '53' },
+ { label: 'Королевства', value: '141' },
+ { label: 'Коррупция', value: '378' },
+ { label: 'Космические войны', value: '674' },
+ { label: 'Красивый герой', value: '107' },
+ { label: 'Крафт', value: '287' },
+ { label: 'Кризис личности', value: '599' },
+ { label: 'Кругосветное путешествие', value: '257' },
+ { label: 'Кудере', value: '440' },
+ { label: 'Кузены', value: '701' },
+ { label: 'Кузнец', value: '454' },
+ { label: 'Кукловоды', value: '431' },
+ { label: 'Куклы/марионетки', value: '573' },
+ { label: 'Культивация', value: '123' },
+ { label: 'Куннилингус', value: '632' },
+ { label: 'Легенды', value: '430' },
+ { label: 'Легкая жизнь', value: '604' },
+ { label: 'Ленивый главный герой', value: '570' },
+ { label: 'Лидерство', value: '424' },
+ { label: 'Лоли', value: '92' },
+ { label: 'Лотерея', value: '401' },
+ { label: 'Любовный интерес влюбляется первым', value: '647' },
+ { label: 'Любовный интерес главного героя носит очки', value: '576' },
+ { label: 'Любовный треугольник', value: '98' },
+ { label: 'Любовь детства', value: '500' },
+ { label: 'Любовь с первого взгляда', value: '730' },
+ { label: 'Магические надписи', value: '373' },
+ { label: 'Магические печати', value: '277' },
+ { label: 'Магические технологии', value: '357' },
+ {
+ label:
+ 'Магическое пространство/измерение, доступное не всем персонажам',
+ value: '244',
+ },
+ { label: 'Магия', value: '38' },
+ { label: 'Магия призыва', value: '333' },
+ { label: 'Мазохистские персонажи', value: '660' },
+ { label: 'Манипулятивные персонажи', value: '130' },
+ { label: 'Мания', value: '91' },
+ { label: 'Мастер на все руки', value: '390' },
+ { label: 'Мастурбация', value: '846' },
+ { label: 'Махо-сёдзё', value: '496' },
+ { label: 'Медицинские знания', value: '441' },
+ { label: 'Медленная романтическая линия', value: '113' },
+ { label: 'Медленное развитие на старте ', value: '670' },
+ { label: 'Межпространственные путешествия', value: '316' },
+ { label: 'Менеджмент', value: '182' },
+ { label: 'Мертвый главный герой', value: '794' },
+ { label: 'Месть', value: '88' },
+ { label: 'Метаморфы', value: '234' },
+ { label: 'Меч и магия', value: '55' },
+ { label: 'Мечник', value: '607' },
+ { label: 'Мечты', value: '733' },
+ { label: 'Милая история', value: '709' },
+ { label: 'Милое дитя', value: '596' },
+ { label: 'Милый главный герой', value: '697' },
+ { label: 'Мировое дерево', value: '385' },
+ { label: 'Мистический ореол вокруг семьи', value: '409' },
+ { label: 'Мифические звери', value: '418' },
+ { label: 'Мифология', value: '468' },
+ { label: 'Младшие братья', value: '843' },
+ { label: 'Младшие сестры', value: '465' },
+ { label: 'ММОРПГ (ЛитРПГ)', value: '306' },
+ { label: 'Множество перемещенных людей', value: '488' },
+ { label: 'Множество реальностей', value: '278' },
+ { label: 'Множество реинкарнированных людей', value: '227' },
+ { label: 'Модели', value: '649' },
+ { label: 'Молчаливый персонаж', value: '705' },
+ { label: 'Монстры', value: '69' },
+ { label: 'Мужская гей-пара', value: '685' },
+ { label: 'Мужчина-яндере', value: '155' },
+ { label: 'Музыка', value: '589' },
+ { label: 'Музыкальные группы', value: '588' },
+ { label: 'Мутации', value: '668' },
+ { label: 'Мутированные существа', value: '317' },
+ { label: 'Навык кражи', value: '626' },
+ { label: 'Навязчивая любовь', value: '85' },
+ { label: 'Наемники', value: '324' },
+ { label: 'Назойливый возлюбленный', value: '501' },
+ { label: 'Наивный главный герой', value: '66' },
+ { label: 'Наркотики', value: '661' },
+ { label: 'Нарциссический главный герой', value: '470' },
+ { label: 'Насилие сексуального характера', value: '824' },
+ { label: 'Наследование', value: '372' },
+ { label: 'Национализм', value: '318' },
+ { label: 'Не блещущий внешне главный герой', value: '328' },
+ { label: 'Не родные братья и сестры', value: '464' },
+ { label: 'Небеса', value: '508' },
+ { label: 'Небесное испытание', value: '274' },
+ { label: 'Негуманоидный главный герой', value: '622' },
+ { label: 'Недоверчивый главный герой', value: '485' },
+ { label: 'Недооцененный главный герой', value: '140' },
+ { label: 'Недоразумения', value: '202' },
+ { label: 'Неизлечимая болезнь', value: '75' },
+ { label: 'Некромант', value: '308' },
+ { label: 'Нелинейная история', value: '157' },
+ { label: 'Ненавистный главный герой', value: '487' },
+ { label: 'Ненадежный рассказчик', value: '165' },
+ { label: 'Нерезиденты', value: '821' },
+ { label: 'Нерешительный главный герой', value: '741' },
+ { label: 'Несерьезный главный герой', value: '294' },
+ { label: 'Несколько временных линий', value: '517' },
+ { label: 'Несколько главных героев', value: '475' },
+ { label: 'Несколько идентичностей', value: '615' },
+ { label: 'Несколько личностей', value: '474' },
+ { label: 'Нетораре', value: '721' },
+ { label: 'Нетори', value: '450' },
+ { label: 'Неудачливый главный герой', value: '567' },
+ { label: 'Ниндзя', value: '358' },
+ { label: 'Обещание из детства', value: '738' },
+ { label: 'Обманщик', value: '411' },
+ { label: 'Обмен телами', value: '94' },
+ { label: 'Обнаженка', value: '417' },
+ { label: 'Обольщение', value: '718' },
+ { label: 'Оборотни', value: '624' },
+ { label: 'Обратный гарем', value: '255' },
+ { label: 'Общество монстров', value: '226' },
+ { label: 'Обязательство', value: '548' },
+ { label: 'Огнестрельное оружие', value: '179' },
+ { label: 'Ограниченная продолжительность жизни', value: '73' },
+ { label: 'Одержимость', value: '447' },
+ { label: 'Одинокий главный герой', value: '304' },
+ { label: 'Одиночество', value: '199' },
+ { label: 'Одиночное проживание', value: '207' },
+ { label: 'Околосмертные переживания', value: '773' },
+ { label: 'Оммёдзи', value: '542' },
+ { label: 'Омоложение', value: '237' },
+ { label: 'Организованная преступность', value: '478' },
+ { label: 'Оргия', value: '825' },
+ { label: 'Орки', value: '228' },
+ { label: 'Освоение навыков', value: '235' },
+ { label: 'Основано на аниме', value: '553' },
+ { label: 'Основано на видео игре', value: '704' },
+ { label: 'Основано на визуальной новелле ', value: '861' },
+ { label: 'Основано на песне', value: '677' },
+ { label: 'Основано на фильме', value: '552' },
+ { label: 'Осторожный главный герой', value: '122' },
+ { label: 'Отаку', value: '512' },
+ { label: 'Открытый космос', value: '150' },
+ { label: 'Отношения в сети', value: '713' },
+ { label: 'Отношения между богом и человеком', value: '603' },
+ { label: 'Отношения между людьми и нелюдьми', value: '205' },
+ { label: 'Отношения на расстоянии', value: '852' },
+ { label: 'Отношения начальник-подчиненный', value: '590' },
+ { label: 'Отношения Сенпай-Коухай', value: '513' },
+ { label: 'Отношения ученика и учителя', value: '451' },
+ { label: 'Отношения учитель-ученик', value: '343' },
+ { label: 'Отношения хозяин-слуга', value: '206' },
+ { label: 'Отомэ игра', value: '723' },
+ { label: 'Отсутствие здравого смысла', value: '605' },
+ { label: 'Отсутствие родителей', value: '575' },
+ { label: 'Офисный роман', value: '686' },
+ { label: 'Официанты', value: '681' },
+ { label: 'Охотники', value: '288' },
+ { label: 'Очаровательный главный герой', value: '659' },
+ { label: 'Падшее дворянство', value: '618' },
+ { label: 'Падшие ангелы', value: '505' },
+ { label: 'Пайзури', value: '630' },
+ { label: 'Паразиты', value: '535' },
+ { label: 'Параллельные миры', value: '86' },
+ { label: 'Парк развлечений', value: '586' },
+ { label: 'Пародия', value: '319' },
+ { label: 'Певцы/Певицы', value: '734' },
+ { label: 'Первая любовь', value: '716' },
+ { label: 'Первоисточник новеллы — манга', value: '560' },
+ { label: 'Первый раз', value: '845' },
+ {
+ label: 'Перемещение в другой мир, имея при себе современные достижения',
+ value: '732',
+ },
+ { label: 'Перемещение в игровой мир', value: '532' },
+ { label: 'Перемещение в иной мир', value: '754' },
+ { label: 'Перерождение в ином мире', value: '755' },
+ { label: 'Переселение души/Трансмиграция', value: '139' },
+ { label: 'Персонаж использует щит', value: '631' },
+ { label: 'Петля времени', value: '79' },
+ { label: 'Пираты', value: '817' },
+ { label: 'Писатели', value: '408' },
+ { label: 'Питомцы', value: '253' },
+ { label: 'Племенное общество', value: '291' },
+ { label: 'Повелитель демонов', value: '171' },
+ {
+ label: 'Повествование от нескольких лиц/Несколько точек зрения',
+ value: '156',
+ },
+ { label: 'Подземелья', value: '219' },
+ { label: 'Пожелания', value: '166' },
+ { label: 'Познание Дао', value: '360' },
+ { label: 'Покинутое дитя', value: '534' },
+ { label: 'Полигамия', value: '296' },
+ { label: 'Политика', value: '43' },
+ { label: 'Полиция', value: '801' },
+ { label: 'Полулюди', value: '335' },
+ { label: 'Пользователь уникального оружия', value: '432' },
+ { label: 'Популярный любовный интерес', value: '241' },
+ { label: 'Постапокалиптика', value: '60' },
+ { label: 'Потерянные цивилизации', value: '751' },
+ { label: 'Похищения людей', value: '707' },
+ { label: 'Поэзия', value: '404' },
+ { label: 'Правонарушители', value: '694' },
+ { label: 'Прагматичный главный герой', value: '536' },
+ { label: 'Преданный любовный интерес', value: '106' },
+ { label: 'Предательство', value: '103' },
+ { label: 'Предвидение', value: '52' },
+ { label: 'Прекрасная героиня', value: '30' },
+ { label: 'Преступники', value: '728' },
+ { label: 'Преступность', value: '83' },
+ { label: 'Призванный герой', value: '147' },
+ { label: 'Призраки', value: '51' },
+ { label: 'Принуждение к отношениям', value: '602' },
+ { label: 'Принцессы', value: '933' },
+ { label: 'Притворная пара', value: '600' },
+ { label: 'Причудливые персонажи', value: '297' },
+ { label: 'Пришельцы/Инопланетяне', value: '76' },
+ { label: 'Программист', value: '666' },
+ { label: 'Проклятия', value: '48' },
+ { label: 'Промывание мозгов', value: '519' },
+ { label: 'Пропуск времени', value: '138' },
+ { label: 'Пророчества', value: '429' },
+ { label: 'Проститутки', value: '844' },
+ { label: 'Пространственное манипулирование', value: '375' },
+ { label: 'Прошлое играет большую роль', value: '215' },
+ { label: 'Прыжки между мирами', value: '737' },
+ { label: 'Психические силы', value: '265' },
+ { label: 'Психопаты', value: '158' },
+ { label: 'Путешествие во времени', value: '80' },
+ { label: 'Пытка', value: '168' },
+ { label: 'Рабы', value: '829' },
+ { label: 'Развод', value: '771' },
+ { label: 'Разумные предметы', value: '174' },
+ { label: 'Расизм', value: '320' },
+ { label: 'Рассказ', value: '61' },
+ { label: 'Расторжения помолвки', value: '243' },
+ { label: 'Расы зооморфов', value: '209' },
+ { label: 'Ревность', value: '717' },
+ { label: 'Редакторы', value: '684' },
+ { label: 'Реинкарнация', value: '281' },
+ { label: 'Реинкарнация в монстра', value: '204' },
+ { label: 'Реинкарнация в объект', value: '692' },
+ { label: 'Религии', value: '565' },
+ { label: 'Репортеры', value: '837' },
+ { label: 'Ресторан', value: '652' },
+ { label: 'Решительный главный герой', value: '124' },
+ { label: 'Робкий главный герой', value: '800' },
+ { label: 'Родитель одиночка', value: '687' },
+ { label: 'Родительский комплекс', value: '531' },
+ { label: 'Родословная', value: '121' },
+ { label: 'Романтический подсюжет ', value: '159' },
+ { label: 'Рост персонажа', value: '95' },
+ { label: 'Рыцари', value: '142' },
+ { label: 'Сёнэн-ай подсюжет ', value: '664' },
+ { label: 'Садистские персонажи', value: '642' },
+ { label: 'Самоотверженный главный герой', value: '748' },
+ { label: 'Самоубийства', value: '616' },
+ { label: 'Самурай', value: '646' },
+ { label: 'Сборник коротких историй', value: '456' },
+ { label: 'Связанные сюжетные линии', value: '473' },
+ { label: 'Святые', value: '761' },
+ { label: 'Священники', value: '325' },
+ { label: 'Сдержанный главный герой', value: '799' },
+ { label: 'Секретные организации', value: '331' },
+ { label: 'Секреты', value: '577' },
+ { label: 'Секс рабы', value: '830' },
+ { label: 'Семейный конфликт', value: '770' },
+ { label: 'Семь добродетелей', value: '233' },
+ { label: 'Семь смертных грехов', value: '134' },
+ { label: 'Семья', value: '251' },
+ { label: 'Серийные убийцы', value: '497' },
+ { label: 'Сестринский комплекс', value: '498' },
+ { label: 'Сила духа', value: '282' },
+ { label: 'Сила, требующая платы за пользование', value: '520' },
+ { label: 'Сильная пара', value: '109' },
+ { label: 'Сильный в сильнейшего', value: '359' },
+ { label: 'Сильный любовный интерес', value: '161' },
+ { label: 'Синдром восьмиклассника', value: '90' },
+ { label: 'Сироты', value: '214' },
+ { label: 'Система уровней', value: '198' },
+ { label: 'Системный администратор', value: '476' },
+ { label: 'Скрытие истинной личности', value: '371' },
+ { label: 'Скрытие истинных способностей', value: '252' },
+ { label: 'Скрытный главный герой', value: '133' },
+ { label: 'Скрытые способности', value: '128' },
+ { label: 'Скульпторы', value: '366' },
+ { label: 'Слабо выраженная романтическая линия', value: '213' },
+ { label: 'Слабый главный герой', value: '188' },
+ { label: 'Слепой главный герой', value: '864' },
+ { label: 'Слуги', value: '232' },
+ { label: 'Смерть', value: '49' },
+ { label: 'Смерть близких', value: '361' },
+ { label: 'Собственнические персонажи', value: '108' },
+ { label: 'Современность', value: '40' },
+ { label: 'Сожительство', value: '482' },
+ { label: 'Создание армии', value: '175' },
+ { label: 'Создание артефактов', value: '292' },
+ { label: 'Создание клана', value: '448' },
+ { label: 'Создание королевства', value: '181' },
+ { label: 'Создание навыков', value: '236' },
+ { label: 'Создание секты', value: '393' },
+ { label: 'Солдаты/Военные', value: '71' },
+ { label: 'Сон', value: '571' },
+ { label: 'Состоятельные персонажи', value: '67' },
+ { label: 'Социальная иерархия на основе силы', value: '137' },
+ { label: 'Социальные изгои', value: '480' },
+ { label: 'Спасение мира', value: '597' },
+ { label: 'Специальные способности', value: '54' },
+ { label: 'Спокойный главный герой', value: '32' },
+ { label: 'Справедливый главный герой', value: '702' },
+ { label: 'Средневековье', value: '184' },
+ { label: 'Ссорящаяся пара', value: '293' },
+ { label: 'Сталкеры', value: '689' },
+ { label: 'Старение', value: '190' },
+ { label: 'Стоические персонажи', value: '444' },
+ { label: 'Стокгольмский синдром', value: '643' },
+ { label: 'Стратег', value: '425' },
+ { label: 'Стратегические битвы', value: '160' },
+ { label: 'Стратегия', value: '1038' },
+ { label: 'Стрелки', value: '458' },
+ { label: 'Стрельба из лука', value: '383' },
+ { label: 'Студенческий совет', value: '490' },
+ { label: 'Судьба', value: '271' },
+ { label: 'Суккубы', value: '484' },
+ { label: 'Супер герои', value: '1039' },
+ { label: 'Суровая подготовка', value: '261' },
+ { label: 'Таинственная болезнь', value: '74' },
+ { label: 'Таинственное прошлое', value: '263' },
+ { label: 'Тайная личность', value: '310' },
+ { label: 'Тайные отношения', value: '812' },
+ { label: 'Танцоры', value: '840' },
+ { label: 'Телохранители', value: '452' },
+ { label: 'Тентакли', value: '693' },
+ { label: 'Террористы', value: '515' },
+ { label: 'Технологический разрыв', value: '621' },
+ { label: 'Тихие персонажи', value: '546' },
+ { label: 'Толстый главный герой', value: '299' },
+ { label: 'Торговцы', value: '416' },
+ { label: 'Травля/Буллинг', value: '89' },
+ { label: 'Травник', value: '708' },
+ { label: 'Трагическое прошлое', value: '164' },
+ { label: 'Трансплантация воспоминаний', value: '367' },
+ { label: 'Трап (Путаница с гендером персонажа)', value: '582' },
+ { label: 'Трудолюбивый главный герой', value: '37' },
+ { label: 'Тюрьма', value: '479' },
+ { label: 'Убийства', value: '84' },
+ { label: 'Убийцы', value: '248' },
+ { label: 'Убийцы драконов', value: '606' },
+ { label: 'Уверенный главный герой', value: '270' },
+ { label: 'Удачливый главный герой', value: '402' },
+ { label: 'Укротитель монстров', value: '337' },
+ { label: 'Умения из прошлой жизни', value: '280' },
+ { label: 'Умная пара', value: '493' },
+ { label: 'Умный главный герой', value: '33' },
+ { label: 'Уникальная техника Культивации', value: '254' },
+ { label: 'Уникальное оружие', value: '340' },
+ { label: 'Управление бизнесом', value: '315' },
+ { label: 'Управление временем', value: '167' },
+ { label: 'Управление кровью', value: '764' },
+ { label: 'Упрямый главный герой', value: '672' },
+ { label: 'Уродливый главный герой', value: '803' },
+ { label: 'Ускоренный рост', value: '300' },
+ { label: 'Усыновленные дети', value: '481' },
+ { label: 'Усыновленный главный герой', value: '412' },
+ { label: 'Уход за детьми', value: '398' },
+ { label: 'Учителя', value: '345' },
+ { label: 'Фамильяры', value: '541' },
+ { label: 'Фанатизм', value: '613' },
+ { label: 'Фантастические существа', value: '322' },
+ { label: 'Фанфикшн', value: '388' },
+ { label: 'Фармацевт', value: '715' },
+ { label: 'Фарминг', value: '379' },
+ { label: 'Феи', value: '210' },
+ { label: 'Фелляция', value: '584' },
+ { label: 'Фениксы', value: '374' },
+ { label: 'Фетиш груди', value: '499' },
+ { label: 'Философия', value: '87' },
+ { label: 'Фильмы', value: '403' },
+ { label: 'Флэшбэки', value: '528' },
+ { label: 'Фобии', value: '100' },
+ { label: 'Фольклор', value: '467' },
+ { label: 'Футанари', value: '568' },
+ { label: 'Футуристический сеттинг', value: '382' },
+ { label: 'Фэнтези мир', value: '126' },
+ { label: 'Хакеры', value: '399' },
+ { label: 'Харизматический герой', value: '391' },
+ { label: 'Хикикомори/Затворники', value: '462' },
+ { label: 'Хитроумный главный герой', value: '105' },
+ { label: 'Хозяин подземелий', value: '557' },
+ { label: 'Холодный главный герой', value: '259' },
+ { label: 'Хорошие отношения с семьей', value: '506' },
+ { label: 'Хранители могил', value: '68' },
+ { label: 'Целители', value: '389' },
+ { label: 'Цзянши', value: '735' },
+ { label: 'Цундэрэ', value: '445' },
+ { label: 'Чаты', value: '580' },
+ { label: 'Человеческое оружие', value: '521' },
+ { label: 'Честный главный герой', value: '240' },
+ { label: 'Читы', value: '238' },
+ { label: 'Шантаж', value: '526' },
+ { label: 'Шеф-повар', value: '239' },
+ { label: 'Шикигами', value: '543' },
+ { label: 'Школа только для девочек', value: '633' },
+ { label: 'Шота', value: '514' },
+ { label: 'Шоу-бизнес', value: '407' },
+ { label: 'Шпионы', value: '563' },
+ { label: 'Эволюция', value: '196' },
+ { label: 'Эгоистичный главный герой', value: '539' },
+ { label: 'Эйдетическая память', value: '392' },
+ { label: 'Экзорсизм', value: '504' },
+ { label: 'Экономика', value: '492' },
+ { label: 'Эксгибиционизм', value: '639' },
+ { label: 'Эксперименты с людьми', value: '129' },
+ { label: 'Элементальная магия', value: '395' },
+ { label: 'Эльфы', value: '172' },
+ { label: 'Эмоционально слабый главный герой', value: '816' },
+ { label: 'Эпизодический', value: '612' },
+ { label: 'Юный любовный интерес', value: '446' },
+ { label: 'Яды', value: '410' },
+ { label: 'Языкастые персонажи', value: '406' },
+ { label: 'Языковой барьер', value: '59' },
+ { label: 'Яндере', value: '208' },
+ { label: 'Японские силы самообороны', value: '559' },
+ { label: 'Ярко выраженная романтическая линия', value: '272' },
+ { label: '[Награжденная работа]', value: '611' },
+ { label: 'Ёкаи', value: '516' },
+ { label: '18+', value: '338' },
+ { label: 'Abusive Characters', value: '625' },
+ { label: 'Adapted to Visual Novel', value: '1046' },
+ { label: 'Adopted-lead', value: '886' },
+ { label: 'Adultery', value: '866' },
+ { label: 'Affair', value: '645' },
+ { label: 'Age-gap', value: '923' },
+ { label: 'Almost-human-lead', value: '975' },
+ { label: 'An*l', value: '780' },
+ { label: 'Androgynous-male-lead', value: '1002' },
+ { label: 'Anti-hero-lead', value: '976' },
+ { label: 'Apathetic-lead', value: '967' },
+ { label: 'Arms Dealers', value: '839' },
+ { label: 'Army-commander', value: '1003' },
+ { label: 'Artifact-refining', value: '924' },
+ { label: 'Autism', value: '855' },
+ { label: 'Awkward Protagonist', value: '669' },
+ { label: 'Awkward-lead', value: '892' },
+ { label: 'Bestiality', value: '796' },
+ { label: 'Big-breasts', value: '908' },
+ { label: 'Birth-of-a-nation', value: '1004' },
+ { label: 'Bisexual-lead', value: '1027' },
+ { label: 'Body-refining', value: '947' },
+ { label: 'Body-swap/s', value: '1036' },
+ { label: 'Boss-subordinate-relationship', value: '876' },
+ { label: 'Bride-kidnapping', value: '948' },
+ { label: 'Caring-lead', value: '879' },
+ { label: 'Cautious-lead', value: '1032' },
+ { label: 'Changed-man', value: '925' },
+ { label: 'Charismatic-lead', value: '1005' },
+ { label: 'Child-lead', value: '936' },
+ { label: 'Clever-lead', value: '880' },
+ { label: 'Clumsy Love Interests', value: '815' },
+ { label: 'Cold Love Interests', value: '651' },
+ { label: 'Coming of Age', value: '860' },
+ { label: 'Confident-lead', value: '894' },
+ { label: 'Confident-male-lead', value: '951' },
+ { label: 'Confinement', value: '767' },
+ { label: 'Conflicting Loyalties', value: '793' },
+ { label: 'Couple Growth', value: '690' },
+ { label: 'Court Official', value: '863' },
+ { label: 'Cowardly Protagonist', value: '703' },
+ { label: 'Cowardly-lead', value: '1000' },
+ { label: 'Cross-dressing', value: '250' },
+ { label: 'Cunnilingus', value: '867' },
+ { label: 'Cunning-lead', value: '952' },
+ { label: 'Cunning-male-lead', value: '953' },
+ { label: 'Curious Protagonist', value: '849' },
+ { label: 'Cute-lead', value: '887' },
+ { label: 'Dense-lead', value: '868' },
+ { label: 'Determined-lead', value: '972' },
+ { label: 'Developing-technology', value: '1006' },
+ { label: 'Devil/s', value: '1007' },
+ { label: 'Different Social Status', value: '758' },
+ { label: 'Disfigurement', value: '838' },
+ { label: 'Doting Love Interests', value: '665' },
+ { label: 'Doting Older Siblings', value: '609' },
+ { label: 'Doting Parents', value: '530' },
+ { label: 'Dungeon/s-exploring', value: '990' },
+ { label: 'Elderly Protagonist', value: '774' },
+ { label: 'Enlightenment', value: '729' },
+ { label: 'Eunuch', value: '1047' },
+ { label: 'Eye Powers', value: '386' },
+ { label: 'Family Business', value: '785' },
+ { label: 'Famous Parents', value: '790' },
+ { label: 'Famous-lead', value: '897' },
+ { label: 'Fanfic', value: '942' },
+ { label: 'Fated Lovers', value: '797' },
+ { label: 'Fellatio', value: '870' },
+ { label: 'Female-lead', value: '888' },
+ { label: 'First-time-intercourse', value: '871' },
+ { label: 'Fleet Battles', value: '836' },
+ { label: 'Forced Living Arrangements', value: '808' },
+ { label: 'Forced Marriage', value: '835' },
+ { label: 'Former Hero', value: '752' },
+ { label: 'Fujoshi', value: '1045' },
+ { label: 'Galge', value: '848' },
+ { label: 'Gambling', value: '1031' },
+ { label: 'Gamelit', value: '994' },
+ { label: 'Genderless-lead', value: '1008' },
+ { label: 'Glasses-wearing-lead', value: '995' },
+ { label: 'Guardian Relationship', value: '197' },
+ { label: 'H*ndjob', value: '629' },
+ { label: 'Half-human-lead', value: '956' },
+ { label: 'Hard-working-lead', value: '957' },
+ { label: 'Hard-working-male-lead', value: '958' },
+ { label: 'Hard-working-protagonist/s', value: '1030' },
+ { label: 'Harem-seeking-lead', value: '929' },
+ { label: 'Harem-subtext', value: '909' },
+ { label: 'Helpful Protagonist', value: '760' },
+ { label: 'Helpful-lead', value: '882' },
+ { label: 'Hidden-gem', value: '998' },
+ { label: 'High-fantasy', value: '991' },
+ { label: 'Human-becomes-demon/monster', value: '1009' },
+ { label: 'Human-nonhuman-relationship', value: '914' },
+ { label: 'Humanoid-lead', value: '915' },
+ { label: 'Imperial Harem', value: '805' },
+ { label: 'Insects', value: '831' },
+ { label: 'Interspatial-storage', value: '959' },
+ { label: 'Kind Love Interests', value: '757' },
+ { label: 'Large-number-of-skills', value: '1010' },
+ { label: 'Legendary-hero', value: '1011' },
+ { label: 'Litrpg', value: '977' },
+ { label: 'Love Rivals', value: '788' },
+ { label: 'Lovers Reunited', value: '853' },
+ { label: 'Low-fantasy', value: '1037' },
+ { label: 'Master-disciple-relationship', value: '899' },
+ { label: 'Matriarchy', value: '807' },
+ { label: 'Mature-lead', value: '900' },
+ { label: 'Mind Break', value: '862' },
+ { label: 'Mismatched Couple', value: '695' },
+ { label: 'Mob Protagonist', value: '648' },
+ { label: 'Mob-lead', value: '902' },
+ { label: 'Modern', value: '988' },
+ { label: 'Monster-pov', value: '1012' },
+ { label: 'Mpreg', value: '856' },
+ { label: 'Multiple-povs', value: '1013' },
+ { label: 'Mystery Solving', value: '710' },
+ { label: 'Naive-lead', value: '1014' },
+ { label: 'Near-death-experience', value: '996' },
+ { label: 'Neet', value: '495' },
+ { label: 'Nightmares', value: '833' },
+ { label: 'Nobility', value: '1015' },
+ { label: 'Non-human-lead', value: '978' },
+ { label: 'Non-humanoid-lead', value: '1016' },
+ { label: 'Not-so-secret-identity', value: '979' },
+ { label: 'Omegaverse', value: '857' },
+ { label: 'Online-game', value: '910' },
+ { label: 'Online-gaming', value: '911' },
+ { label: 'Outdoor Interc**rse', value: '847' },
+ { label: 'Outdoor-intercourse', value: '903' },
+ { label: 'Overprotective Siblings', value: '610' },
+ { label: 'Part-Time Job', value: '865' },
+ { label: 'Past Trauma', value: '726' },
+ { label: 'Past-memories', value: '1017' },
+ { label: 'Persistent Love Interests', value: '714' },
+ { label: 'Perverted-lead', value: '932' },
+ { label: 'Photography', value: '798' },
+ { label: 'Pill Based Cultivation', value: '279' },
+ { label: 'Pill Concocting', value: '245' },
+ { label: 'Pilots', value: '820' },
+ { label: 'Playboys', value: '795' },
+ { label: 'Playful-lead', value: '989' },
+ { label: 'Polyandry', value: '811' },
+ { label: 'Portal-fantasy-/-isekai', value: '992' },
+ { label: 'Pragmatic-lead', value: '884' },
+ { label: 'Profanity', value: '980' },
+ { label: 'Protagonist-loyal-to-love-interest', value: '905' },
+ { label: 'R-15 (Японское возрастное ограничение)', value: '230' },
+ { label: 'Rebellion', value: '834' },
+ { label: 'Reincarnated in a Game World', value: '804' },
+ { label: 'Reluctant Protagonist', value: '696' },
+ { label: 'Reverse R*pe', value: '776' },
+ { label: 'Reversible Couple', value: '854' },
+ { label: 'Ruling-class', value: '943' },
+ { label: 'S*x Friends', value: '750' },
+ { label: 'S*xual Cultivation Technique', value: '823' },
+ { label: 'Salaryman', value: '1035' },
+ { label: 'Satire', value: '981' },
+ { label: 'Schemes And Conspiracies', value: '745' },
+ { label: 'Scientist/s', value: '997' },
+ { label: 'Scientists', value: '1029' },
+ { label: 'Secret Crush', value: '827' },
+ { label: 'Seme Protagonist', value: '1034' },
+ { label: 'Seme-lead', value: '1028' },
+ { label: 'Seven-heavenly-virtues', value: '1018' },
+ { label: 'Sexual Cultivation Technique', value: '350' },
+ { label: 'Sexual-content', value: '982' },
+ { label: 'Sexuality', value: '983' },
+ { label: 'Sharing A Body', value: '814' },
+ { label: 'Shotacon', value: '858' },
+ { label: 'Shoujo-Ai Subplot', value: '777' },
+ { label: 'Sibling Rivalry', value: '766' },
+ { label: "Sibling's Care", value: '1042' },
+ { label: 'Sickly Characters', value: '787' },
+ { label: 'Skills', value: '1019' },
+ { label: 'Slave-harem', value: '1001' },
+ { label: 'Slime', value: '1020' },
+ { label: 'Smart-male-lead', value: '963' },
+ { label: 'Spirit Users', value: '739' },
+ { label: 'Straight Seme', value: '819' },
+ { label: 'Straight Uke', value: '818' },
+ { label: 'Strength-based-social-hierarchy', value: '974' },
+ { label: 'Strong-lead', value: '944' },
+ { label: 'Strong-male-lead', value: '964' },
+ { label: 'Student-teacher-relationship', value: '1026' },
+ { label: 'Suspense', value: '987' },
+ { label: 'Sword-and-sorcery', value: '875' },
+ { label: 'Threesome', value: '574' },
+ { label: 'Transformation Ability', value: '736' },
+ { label: 'Traumatising-content', value: '1040' },
+ { label: 'Underestimated-lead', value: '919' },
+ { label: 'Underestimated-male-lead', value: '966' },
+ { label: 'Unique-abilities', value: '1021' },
+ { label: 'Unique-skill', value: '1022' },
+ { label: 'Unique-skills', value: '1023' },
+ { label: 'Unlimited Flow', value: '1044' },
+ { label: 'Unrequited Love', value: '806' },
+ { label: 'Urban-fantasy', value: '1041' },
+ { label: 'Villainess Noble Girls', value: '719' },
+ { label: 'Weak-lead', value: '885' },
+ { label: 'Web-novel', value: '1024' },
+ ],
+ inputType: FilterInputs.Checkbox,
+ },
+ {
+ key: 'tags',
+ label: 'Жанры',
+ values: [
+ { label: 'Боевые искусства', value: '22' },
+ { label: 'Гарем', value: '114' },
+ { label: 'Гендер бендер', value: '246' },
+ { label: 'Дзёсэй', value: '216' },
+ { label: 'Для взрослых', value: '115' },
+ { label: 'Для взрослых', value: '258' },
+ { label: 'Драма', value: '7' },
+ { label: 'Исторический', value: '101' },
+ { label: 'Комедия', value: '17' },
+ { label: 'Лоликон', value: '638' },
+ { label: 'Магический реализм', value: '922' },
+ { label: 'Меха', value: '24' },
+ { label: 'Милитари', value: '12' },
+ { label: 'Мистика', value: '2' },
+ { label: 'Научная фантастика', value: '13' },
+ { label: 'Непристойность', value: '747' },
+ { label: 'Повседневность', value: '93' },
+ { label: 'Приключение', value: '11' },
+ { label: 'Психология', value: '18' },
+ { label: 'Романтика', value: '9' },
+ { label: 'Сёдзё', value: '15' },
+ { label: 'Сёдзё-ай', value: '23' },
+ { label: 'Сёнэн', value: '189' },
+ { label: 'Сёнэн-ай', value: '680' },
+ { label: 'Сверхъестественное', value: '20' },
+ { label: 'Спорт', value: '420' },
+ { label: 'Сэйнэн', value: '5' },
+ { label: 'Сюаньхуа', value: '242' },
+ { label: 'Сянься', value: '364' },
+ { label: 'Трагедия', value: '19' },
+ { label: 'Триллер', value: '3' },
+ { label: 'Ужасы', value: '1' },
+ { label: 'Уся', value: '720' },
+ { label: 'Фэнтези', value: '8' },
+ { label: 'Школьная жизнь', value: '21' },
+ { label: 'Экшн', value: '14' },
+ { label: 'Эччи', value: '327' },
+ { label: 'Юри', value: '691' },
+ { label: 'Яой', value: '682' },
+ { label: 'Eastern fantasy', value: '907' },
+ { label: 'Isekai', value: '999' },
+ { label: 'Video games', value: '993' },
+ ],
+ inputType: FilterInputs.Checkbox,
+ },
+];
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ version: '1.0.0',
+ site: baseUrl,
+ icon: 'src/ru/ranobehub/icon.png',
+ lang: languages.Russian,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+ filters,
+};
\ No newline at end of file
diff --git a/plugins/russian/ranoberf.js b/plugins/russian/ranoberf.js
new file mode 100644
index 0000000..eb24c41
--- /dev/null
+++ b/plugins/russian/ranoberf.js
@@ -0,0 +1,147 @@
+const cheerio = require('cheerio');
+const dayjs = require('dayjs');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+const Status = require('@libs/novelStatus');
+const FilterInputs = require('@libs/filterInputs');
+const defaultCoverUri =
+ 'https://github.com/LNReader/lnreader-sources/blob/main/icons/src/coverNotAvailable.jpg?raw=true';
+
+
+const pluginId = "RNRF";
+const sourceName = 'РанобэРФ';
+
+const baseUrl = 'https://ранобэ.рф';
+
+async function popularNovels (page, { showLatestNovels, filters }) {
+ let url = baseUrl + '/books?order=';
+ url += filters?.sort ? filters?.sort : (showLatestNovels ? 'lastPublishedChapter' : 'popular');
+ url += '&page=' + page;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+ let json = loadedCheerio('#__NEXT_DATA__').html();
+ json = JSON.parse(json);
+ let novels = [];
+
+ json.props.pageProps.totalData.items.forEach(item => {
+ const novelName = item.title;
+ const novelUrl = baseUrl + '/' + item.slug;
+ const novelCover = item?.verticalImage?.url
+ ? baseUrl + item.verticalImage.url
+ : defaultCoverUri;
+ novels.push({ name: novelName, cover: novelCover, url: novelUrl });
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const result = await fetchApi(novelUrl);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+ let json = loadedCheerio('#__NEXT_DATA__').html();
+ json = JSON.parse(json);
+
+ let novel = {
+ url: novelUrl,
+ name: json.props.pageProps.book.title,
+ cover: json.props.pageProps.book?.verticalImage?.url
+ ? baseUrl + json.props.pageProps.book.verticalImage.url
+ : defaultCoverUri,
+ summary: json.props.pageProps.book.description,
+ author: json.props.pageProps.book?.author || '',
+ genres: json.props.pageProps.book.genres.map(item => item.title).join(','),
+ status: json.props.pageProps.book.additionalInfo.includes('Активен')
+ ? Status.Ongoing
+ : Status.Completed,
+ };
+
+ let chapters = [];
+
+ json.props.pageProps.book.chapters.forEach(item => {
+ const chapterName = item.title;
+ const releaseDate = dayjs(item.publishedAt).format('LLL');
+ const chapterUrl = baseUrl + item.url;
+
+ if (!item.isDonate || item.isUserPaid) {
+ chapters.push({ name: chapterName, releaseTime: releaseDate, url: chapterUrl });
+ }
+ });
+
+ novel.chapters = chapters.reverse();
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const result = await fetchApi(chapterUrl);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+ let json = loadedCheerio('#__NEXT_DATA__').html();
+ json = JSON.parse(json);
+
+ let temp = cheerio.load(json.props.pageProps.chapter.content.text);
+
+ temp('img').each(function () {
+ if (!loadedCheerio(this).attr('src')?.startsWith('http')) {
+ let src = loadedCheerio(this).attr('src');
+ loadedCheerio(this).attr('src', baseUrl + src);
+ }
+ });
+
+ const chapterText = temp.html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = `${baseUrl}/v3/books?filter[or][0][title][like]=${searchTerm}&filter[or][1][titleEn][like]=${searchTerm}&filter[or][2][fullTitle][like]=${searchTerm}&filter[status][]=active&filter[status][]=abandoned&filter[status][]=completed&expand=verticalImage`;
+ const result = await fetchApi(url);
+ const body = await result.json();
+ let novels = [];
+
+ body.items.forEach(item => {
+ const novelName = item.title;
+ const novelUrl = baseUrl + '/' + item.slug;
+ const novelCover = item?.verticalImage?.url
+ ? baseUrl + item.verticalImage.url
+ : defaultCoverUri;
+ novels.push({ name: novelName, cover: novelCover, url: novelUrl });
+ });
+
+ return novels;
+};
+
+const filters = [
+ {
+ key: 'sort',
+ label: 'Сортировка',
+ values: [
+ { label: 'Рейтинг', value: 'popular' },
+ { label: 'Дате добавления', value: 'new' },
+ { label: 'Дате обновления', value: 'lastPublishedChapter' },
+ { label: 'Законченные', value: 'completed' },
+ ],
+ inputType: FilterInputs.Picker,
+ },
+];
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ lang: languages.Russian,
+ icon: 'src/ru/ranoberf/icon.png',
+ filters,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/spanish/.spanish b/plugins/spanish/.spanish
new file mode 100644
index 0000000..e69de29
diff --git a/plugins/spanish/hasutl.js b/plugins/spanish/hasutl.js
new file mode 100644
index 0000000..0cf9d76
--- /dev/null
+++ b/plugins/spanish/hasutl.js
@@ -0,0 +1,139 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const baseUrl = 'https://hasutl.wordpress.com/';
+
+async function popularNovels (page) {
+ let url = baseUrl + 'light-novels-activas/';
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('div.wp-block-columns').each(function () {
+ const novelName = loadedCheerio(this).find('.wp-block-button').text();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+
+ let novelUrl = loadedCheerio(this)
+ .find('.wp-block-button > a')
+ .attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {};
+
+ novel.url = url;
+
+ novel.url = novelUrl;
+
+ novel.name = loadedCheerio('.post-header').text();
+
+ novel.cover = loadedCheerio('.featured-media > img').attr('src');
+
+ let novelSummary = loadedCheerio('.post-content').find('p').html();
+ novel.summary = novelSummary;
+
+ let novelChapters = [];
+
+ loadedCheerio('.wp-block-media-text__content')
+ .find('a')
+ .each(function () {
+ const chapterName = loadedCheerio(this).text().trim();
+
+ const releaseDate = null;
+
+ let chapterUrl = loadedCheerio(this).attr('href');
+
+ const chapter = { name: chapterName, releaseTime: releaseDate, url: chapterUrl };
+
+ novelChapters.push(chapter);
+ });
+
+ novel.chapters = novelChapters;
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let chapterText = loadedCheerio('.post-content').html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = `${baseUrl}?s=${searchTerm}&post_type=wp-manga`;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.post-container ').each(function () {
+ const novelName = loadedCheerio(this).find('.post-header').text();
+ if (
+ !novelName.includes('Cap') &&
+ !novelName.includes('Vol') &&
+ !novelName.includes('Light Novels')
+ ) {
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+
+ let novelUrl = loadedCheerio(this).find('a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ }
+ });
+
+ return novels;
+};
+
+module.exports = {
+ id: "HasuTL",
+ name: 'Hasu Translations',
+ site: baseUrl,
+ version: '1.0.0',
+ lang: languages.Spanish,
+ icon: 'src/es/hasutl/icon.png',
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
diff --git a/plugins/spanish/novelasligera.js b/plugins/spanish/novelasligera.js
new file mode 100644
index 0000000..bb36648
--- /dev/null
+++ b/plugins/spanish/novelasligera.js
@@ -0,0 +1,177 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const baseUrl = 'https://novelasligera.com/';
+
+async function popularNovels (page) {
+ let url = baseUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.elementor-column').each(function () {
+ const novelName = loadedCheerio(this)
+ .find('.widget-image-caption.wp-caption-text')
+ .text();
+ if (novelName) {
+ const novelCover = loadedCheerio(this).find('a > img').attr('data-lazy-src');
+
+ let novelUrl = loadedCheerio(this).find('a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ }
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters ( novelUrl) {
+ const url = baseUrl + 'novela/' + novelUrl;
+
+ // console.log(url);
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {};
+
+ novel.url = url;
+
+ novel.name = loadedCheerio('h1').text();
+
+ novel.cover = loadedCheerio('.elementor-widget-container')
+ .find('img')
+ .attr('src');
+
+ loadedCheerio('.elementor-row')
+ .find('p')
+ .each(function () {
+ if (loadedCheerio(this).text().includes('Autor:')) {
+ novel.author = loadedCheerio(this).text().replace('Autor:', '').trim();
+ }
+ if (loadedCheerio(this).text().includes('Estado:')) {
+ novel.status = loadedCheerio(this)
+ .text()
+ .replace('Estado: ', '')
+ .trim();
+ }
+
+ if (loadedCheerio(this).text().includes('Género:')) {
+ loadedCheerio(this).find('span').remove();
+ novel.genres = loadedCheerio(this).text().replace(/,\s/g, ',');
+ }
+ });
+
+ novel.artist = null;
+
+ novel.summary = loadedCheerio(
+ '.elementor-text-editor.elementor-clearfix',
+ ).text();
+
+ let novelChapters = [];
+
+ loadedCheerio('.elementor-accordion-item').remove();
+
+ loadedCheerio('.elementor-tab-content')
+ .find('li')
+ .each(function () {
+ const chapterName = loadedCheerio(this).text();
+ const releaseDate = null;
+ const chapterUrl = loadedCheerio(this)
+ .find('a')
+ .attr('href')
+
+ const chapter = { name: chapterName, releaseTime: releaseDate, url: chapterUrl };
+
+ novelChapters.push(chapter);
+ });
+
+ novel.chapters = novelChapters;
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+ // console.log(url);
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+ loadedCheerio('.osny-nightmode.osny-nightmode--left').remove();
+ loadedCheerio('.code-block.code-block-1').remove();
+ loadedCheerio('.adsb30').remove();
+ loadedCheerio('.saboxplugin-wrap').remove();
+ loadedCheerio('.wp-post-navigation').remove();
+
+ let chapterText = loadedCheerio('.entry-content').html();
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = baseUrl + '?s=' + searchTerm + '&post_type=wp-manga';
+ // console.log(url);
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.inside-article').each(function () {
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+ let novelUrl = loadedCheerio(this).find('a').attr('href');
+
+ let novelName;
+
+ if (novelUrl) {
+ novelName = novelUrl.replace(/-/g, ' ').replace(/^./, function (x) {
+ return x.toUpperCase();
+ });
+ }
+
+ novelUrl += '/';
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ novels = [{ ...novels[1] }];
+
+ return novels;
+};
+
+module.exports = {
+ id: "ligera.com",
+ name: "Novelas Ligera",
+ site: baseUrl,
+ version: '1.0.0',
+ lang: languages.Spanish,
+ icon: 'src/es/novelasligera/icon.png',
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
diff --git a/plugins/spanish/novelawuxia.js b/plugins/spanish/novelawuxia.js
new file mode 100644
index 0000000..54b4c79
--- /dev/null
+++ b/plugins/spanish/novelawuxia.js
@@ -0,0 +1,205 @@
+const fetchApi = require('@libs/fetchApi');
+const languages = require('@libs/languages');
+const fetchFile = require('@libs/fetchFile');
+const cheerio = require('cheerio');
+
+const pluginId = "awuxia.com"
+const baseUrl = 'http://www.reinowuxia.com/';
+
+function getNovelName(y) {
+ return y.replace(/-/g, ' ').replace(/(?:^|\s)\S/g, a => a.toUpperCase());
+}
+
+async function popularNovels (page) {
+ let url = baseUrl + 'p/todas-las-novelas.html';
+
+ let headers ={
+ 'User-Agent':
+ "'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
+ };
+
+ const result = await fetchApi(url, {
+ method: 'GET',
+ headers: headers,
+ });
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.post-body.entry-content')
+ .find('a')
+ .each(function () {
+ let novelName = loadedCheerio(this)
+ .attr('href')
+ .split('/')
+ .pop()
+ .replace('.html', '');
+ novelName = getNovelName(novelName);
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+
+ let novelUrl = loadedCheerio(this).attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {};
+
+ novel.url = url;
+
+ novel.name = loadedCheerio('h1.post-title').text().trim();
+
+ novel.cover = loadedCheerio('div.separator').find('a').attr('href');
+
+ novel.artist = '';
+ novel.status = '';
+
+ loadedCheerio('div > b').each(function () {
+ const detailName = loadedCheerio(this).text();
+ let detail = loadedCheerio(this)[0].nextSibling;
+
+ if (detailName && detail) {
+ detail = detail.nodeValue;
+
+ if (detailName.includes('Autor')) {
+ novel.author = detail.replace('Autor:', '');
+ }
+
+ if (detailName.includes('Estatus')) {
+ novel.status = detail.replace('Estatus: ', '');
+ }
+ if (detailName.includes('Géneros:')) {
+ novel.genres = detail.replace('Géneros: ', '').replace(/,\s/g, ',');
+ }
+ }
+ });
+
+ let novelChapters = [];
+
+ loadedCheerio('div').each(function () {
+ const detailName = loadedCheerio(this).text();
+ if (detailName.includes('Sinopsis')) {
+ novel.summary =
+ loadedCheerio(this).next().text() !== ''
+ ? loadedCheerio(this).next().text().replace('Sinopsis', '').trim()
+ : loadedCheerio(this)
+ .next()
+ .next()
+ .text()
+ .replace('Sinopsis', '')
+ .trim();
+ }
+
+ if (detailName.includes('Lista de Capítulos')) {
+ loadedCheerio(this)
+ .find('a')
+ .each(function (res) {
+ const chapterName = loadedCheerio(this).text();
+ let chapterUrl = loadedCheerio(this).attr('href');
+ const releaseDate = null;
+
+ if (
+ chapterName &&
+ chapterUrl &&
+ !novelChapters.some(chap => chap.name === chapterName)
+ ) {
+ const chapter = {
+ name: chapterName,
+ releaseTime: releaseDate,
+ url: chapterUrl,
+ };
+
+ novelChapters.push(chapter);
+ }
+ });
+ }
+ });
+
+ novel.chapters = novelChapters;
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let chapterText = loadedCheerio('.post-body.entry-content').html();
+
+ return chapterText;
+};
+
+const searchNovels = async searchTerm => {
+ const url = `${baseUrl}search?q=${searchTerm}`;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.date-outer').each(function () {
+ let novelName = loadedCheerio(this)
+ .find('a')
+ .attr('href')
+ .split('/')
+ .pop()
+ .replace(/-capitulo(.*?).html/, '');
+
+ const novelUrl = novelName + '.html/';
+
+ novelName = getNovelName(novelName);
+
+ const exists = novels.some(novel => novel.novelName === novelName);
+
+ if (!exists) {
+ const novelCover = null;
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ }
+ });
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: "ReinoWuxia",
+ site: baseUrl,
+ version: '1.0.0',
+ icon: 'src/es/novelawuxia/icon.png',
+ lang: languages.Spanish,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/spanish/oasistranslations.js b/plugins/spanish/oasistranslations.js
new file mode 100644
index 0000000..aea7afb
--- /dev/null
+++ b/plugins/spanish/oasistranslations.js
@@ -0,0 +1,167 @@
+const fetchApi = require('@libs/fetchApi');
+const languages = require('@libs/languages');
+const fetchFile = require('@libs/fetchFile');
+const cheerio = require('cheerio');
+
+const pluginId = 'oasisTL.wp';
+const sourceName = 'Oasis Translations';
+const baseUrl = 'https://oasistranslations.wordpress.com/';
+
+async function popularNovels (page) {
+ let url = baseUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.menu-item-1819')
+ .find('.sub-menu > li')
+ .each(function () {
+ const novelName = loadedCheerio(this).text();
+ if (!novelName.match(/Activas|Finalizadas|Dropeadas/)) {
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+
+ let novelUrl = loadedCheerio(this).find('a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ }
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {};
+
+ novel.url = url;
+
+ novel.name = loadedCheerio('h1.entry-title')
+ .text()
+ .replace(/[\t\n]/g, '')
+ .trim();
+
+ novel.cover = loadedCheerio('img[loading="lazy"]').attr('src');
+
+ loadedCheerio('.entry-content > p').each(function (res) {
+ if (loadedCheerio(this).text().includes('Autor')) {
+ let details = loadedCheerio(this).html();
+ details = details.match(/<\/strong>(.|\n)*?
/g);
+ details = details.map(detail =>
+ detail.replace(/|<\/strong>|
|:\s/g, ''),
+ );
+
+ novel.genres = '';
+
+ novel.author = details[2];
+ novel.genres = details[4].replace(/\s| /g, '');
+ novel.artist = details[3];
+ }
+ });
+
+ // let novelSummary = $(this).next().html();
+ novel.summary = '';
+
+ let novelChapters = [];
+
+ // if ($(".entry-content").find("li").length) {
+ loadedCheerio('.entry-content')
+ .find('a')
+ .each(function () {
+ let chapterUrl = loadedCheerio(this).attr('href');
+
+ if (chapterUrl && chapterUrl.includes(baseUrl)) {
+ const chapterName = loadedCheerio(this).text();
+ const releaseDate = null;
+
+ const chapter = { name: chapterName, releaseTime: releaseDate, url: chapterUrl };
+
+ novelChapters.push(chapter);
+ }
+ });
+
+ novel.chapters = novelChapters;
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ loadedCheerio('div#jp-post-flair').remove();
+
+ let chapterText = loadedCheerio('.entry-content').html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ searchTerm = searchTerm.toLowerCase();
+
+ let url = baseUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+ loadedCheerio('.menu-item-1819')
+ .find('.sub-menu > li')
+ .each(function () {
+ const novelName = loadedCheerio(this).text();
+ if (!novelName.match(/Activas|Finalizadas|Dropeadas/)) {
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+
+ let novelUrl = loadedCheerio(this).find('a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ }
+ });
+
+ novels = novels.filter(novel =>
+ novel.name.toLowerCase().includes(searchTerm),
+ );
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ icon: 'src/es/oasistranslations/icon.png',
+ lang: languages.Spanish,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/spanish/skynovels.js b/plugins/spanish/skynovels.js
new file mode 100644
index 0000000..b38cc96
--- /dev/null
+++ b/plugins/spanish/skynovels.js
@@ -0,0 +1,126 @@
+const fetchApi = require('@libs/fetchApi');
+const languages = require('@libs/languages');
+const fetchFile = require('@libs/fetchFile');
+
+const baseUrl = 'https://www.skynovels.net/';
+
+async function popularNovels (page) {
+ const url = 'https://api.skynovels.net/api/novels?&q';
+
+ const result = await fetchApi(url);
+ const body = await result.json();
+
+ const novels = [];
+
+ body.novels.map(res => {
+ const novelName = res.nvl_title;
+ const novelCover =
+ 'https://api.skynovels.net/api/get-image/' + res.image + '/novels/false';
+ const novelUrl = baseUrl + 'novelas/' + res.id + '/' + res.nvl_name + '/';
+
+ const novel = { name: novelName, url: novelUrl, cover: novelCover };
+
+ novels.push(novel);
+ });
+
+ return novels ;
+};
+
+async function parseNovelAndChapters (novUrl) {
+ let novelId = novUrl.substring().split('/')[4];
+ const url = 'https://api.skynovels.net/api/novel/' + novelId + '/reading?&q';
+
+ const result = await fetchApi(url);
+ const body = await result.json();
+
+ const item = body.novel[0];
+
+ let novel = {};
+
+ novel.url = novUrl;
+
+ novel.name = item.nvl_title;
+
+ novel.cover =
+ 'https://api.skynovels.net/api/get-image/' + item.image + '/novels/false';
+
+ let genres = [];
+ item.genres.map(genre => genres.push(genre.genre_name));
+ novel.genres = genres.join(',');
+ novel.author = item.nvl_writer;
+ novel.summary = item.nvl_content;
+ novel.status = item.nvl_status;
+
+ let novelChapters = [];
+
+ item.volumes.map(volume => {
+ volume.chapters.map(chapter => {
+ const chapterName = chapter.chp_index_title;
+ const releaseDate = new Date(chapter.createdAt).toDateString();
+ const chapterUrl = novUrl + chapter.id + '/' + chapter.chp_name;
+
+ const chap = { name: chapterName, releaseTime: releaseDate, url: chapterUrl };
+
+ novelChapters.push(chap);
+ });
+ });
+
+ novel.chapters = novelChapters;
+
+ return novel;
+};
+
+async function parseChapter (chapUrl) {
+ let chapterId = chapUrl.split('/')[6];
+ const url = `https://api.skynovels.net/api/novel-chapter/${chapterId}`;
+
+ const result = await fetchApi(url);
+ const body = await result.json();
+
+ const item = body.chapter[0];
+
+ let chapterText = item.chp_content;
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ searchTerm = searchTerm.toLowerCase();
+ const url = 'https://api.skynovels.net/api/novels?&q';
+
+ const result = await fetchApi(url);
+ const body = await result.json();
+
+ let results = body.novels.filter(novel =>
+ novel.nvl_title.toLowerCase().includes(searchTerm),
+ );
+
+ const novels = [];
+
+ results.map(res => {
+ const novelName = res.nvl_title;
+ const novelCover =
+ 'https://api.skynovels.net/api/get-image/' + res.image + '/novels/false';
+ const novelUrl = baseUrl + 'novelas/' + res.id + '/' + res.nvl_name + '/';
+
+ const novel = { name: novelName, url: novelUrl, cover: novelCover };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+module.exports = {
+ id: 'skynovels.net',
+ name: "SkyNovels",
+ site: baseUrl,
+ version: '1.0.0',
+ icon: 'src/es/skynovels/icon.png',
+ lang: languages.Spanish,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/spanish/tunovelaligera.js b/plugins/spanish/tunovelaligera.js
new file mode 100644
index 0000000..1128293
--- /dev/null
+++ b/plugins/spanish/tunovelaligera.js
@@ -0,0 +1,164 @@
+const fetchApi = require('@libs/fetchApi');
+const languages = require('@libs/languages');
+const fetchFile = require('@libs/fetchFile');
+const cheerio = require('cheerio');
+const Status = require('@libs/novelStatus');
+const defaultCoverUri =
+ 'https://github.com/LNReader/lnreader-sources/blob/main/icons/src/coverNotAvailable.jpg?raw=true';
+
+const pluginId = "TNL.com";
+const sourceName = 'TuNovelaLigera';
+
+const baseUrl = 'https://tunovelaligera.com/';
+
+async function popularNovels (page) {
+ let url = baseUrl + 'novelas/page/' + page + '/?m_orderby=rating';
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.page-item-detail').each(function () {
+ const novelName = loadedCheerio(this).find('.h5 > a').text();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+
+ let novelUrl = loadedCheerio(this)
+ .find('.h5 > a')
+ .attr('href')
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {
+ url,
+ };
+
+ loadedCheerio('.manga-title-badges').remove();
+
+ novel.name = loadedCheerio('.post-title > h1').text().trim();
+
+ let novelCover = loadedCheerio('.summary_image > a > img');
+
+ novel.cover =
+ novelCover.attr('data-src') || novelCover.attr('src') || defaultCoverUri;
+
+ loadedCheerio('.post-content_item').each(function () {
+ const detailName = loadedCheerio(this)
+ .find('.summary-heading > h5')
+ .text()
+ .trim();
+ const detail = loadedCheerio(this).find('.summary-content').text().trim();
+
+ switch (detailName) {
+ case 'Generos':
+ novel.genres = detail.replace(/, /g, ',');
+ break;
+ case 'Autores':
+ novel.author = detail;
+ break;
+ case 'Estado':
+ novel.status =
+ detail.includes('OnGoing') || detail.includes('Updating')
+ ? Status.Ongoing
+ : Status.Completed;
+ break;
+ }
+ });
+
+ novel.summary = loadedCheerio('div.summary__content > p').text().trim();
+
+ let novelChapters = [];
+
+ loadedCheerio('.lcp_catlist li').each(function () {
+ const chapterName = loadedCheerio(this)
+ .find('a')
+ .text()
+ .replace(/[\t\n]/g, '')
+ .trim();
+
+ const releaseDate = loadedCheerio(this).find('span').text().trim();
+
+ let chapterUrl = loadedCheerio(this).find('a').attr('href');
+
+ novelChapters.push({ name: chapterName, releaseTime: releaseDate, url: chapterUrl });
+ });
+
+ novel.chapters = novelChapters.reverse();
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let chapterText = loadedCheerio('#hola_siguiente').next().text();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = `${baseUrl}?s=${searchTerm}&post_type=wp-manga`;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.c-tabs-item__content').each(function () {
+ const novelName = loadedCheerio(this).find('.h4 > a').text();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+
+ let novelUrl = loadedCheerio(this).find('.h4 > a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ icon: 'src/es/tunovelaligera/icon.png',
+ lang: languages.Spanish,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/spanish/yukitls.js b/plugins/spanish/yukitls.js
new file mode 100644
index 0000000..1222025
--- /dev/null
+++ b/plugins/spanish/yukitls.js
@@ -0,0 +1,183 @@
+const fetchApi = require('@libs/fetchApi');
+const languages = require('@libs/languages');
+const fetchFile = require('@libs/fetchFile');
+const cheerio = require('cheerio');
+
+const pluginId = "yuukitls.com";
+const baseUrl = 'https://yuukitls.com/';
+
+async function popularNovels (page) {
+ let url = baseUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.quadmenu-navbar-collapse ul li:nth-child(2)')
+ .find('li')
+ .each(function () {
+ const novelName = loadedCheerio(this).text().replace(/[\s\n]+/g,' ');
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+
+ let novelUrl = loadedCheerio(this).find('a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels ;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {};
+
+ novel.url = url;
+
+ novel.name = loadedCheerio('h1.entry-title')
+ .text()
+ .replace(/[\t\n]/g, '')
+ .trim();
+
+ novel.cover = loadedCheerio('img[loading="lazy"]').attr('src');
+
+ loadedCheerio('.entry-content')
+ .find('div')
+ .each(function () {
+ if (loadedCheerio(this).text().includes('Escritor:')) {
+ novel.author = loadedCheerio(this)
+ .text()
+ .replace('Escritor: ', '')
+ .trim();
+ }
+ if (loadedCheerio(this).text().includes('Ilustrador:')) {
+ novel.artist = loadedCheerio(this)
+ .text()
+ .replace('Ilustrador: ', '')
+ .trim();
+ }
+
+ if (loadedCheerio(this).text().includes('Género:')) {
+ novel.genres = loadedCheerio(this)
+ .text()
+ .replace(/Género: |\s/g, '');
+ }
+
+ if (loadedCheerio(this).text().includes('Sinopsis:')) {
+ novel.summary = loadedCheerio(this).next().text();
+ }
+ });
+
+ let novelChapters = [];
+
+ if (loadedCheerio('.entry-content').find('li').length) {
+ loadedCheerio('.entry-content')
+ .find('li')
+ .each(function () {
+ let chapterUrl = loadedCheerio(this).find('a').attr('href');
+
+ if (chapterUrl && chapterUrl.includes(baseUrl)) {
+ const chapterName = loadedCheerio(this).text();
+ const releaseDate = null;
+
+ const chapter = { name: chapterName, releaseTime: releaseDate, url: chapterUrl };
+
+ novelChapters.push(chapter);
+ }
+ });
+ } else {
+ loadedCheerio('.entry-content')
+ .find('p')
+ .each(function () {
+ let chapterUrl = loadedCheerio(this).find('a').attr('href');
+
+ if (chapterUrl && chapterUrl.includes(baseUrl)) {
+ const chapterName = loadedCheerio(this).text();
+ const releaseDate = null;
+
+ const chapter = { name: chapterName, releaseTime: releaseDate, url: chapterUrl };
+
+ novelChapters.push(chapter);
+ }
+ });
+ }
+
+ novel.chapters = novelChapters;
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+ let chapterText = loadedCheerio('.entry-content').html();
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ searchTerm = searchTerm.toLowerCase();
+
+ let url = baseUrl;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('.menu-item-2869')
+ .find('.menu-item.menu-item-type-post_type.menu-item-object-post')
+ .each(function () {
+ const novelName = loadedCheerio(this).text();
+ const novelCover = loadedCheerio(this).find('img').attr('src');
+
+ let novelUrl = loadedCheerio(this).find('a').attr('href');
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ novels = novels.filter(novel =>
+ novel.novelName.toLowerCase().includes(searchTerm),
+ );
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: "Yuuki Tls",
+ site: baseUrl,
+ version: '1.0.0',
+ icon: 'src/es/yuukitls/icon.png',
+ lang: languages.Spanish,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/turkish/.turkish b/plugins/turkish/.turkish
new file mode 100644
index 0000000..e69de29
diff --git a/plugins/turkish/epiknovel.js b/plugins/turkish/epiknovel.js
new file mode 100644
index 0000000..c36f3d4
--- /dev/null
+++ b/plugins/turkish/epiknovel.js
@@ -0,0 +1,167 @@
+const cheerio = require('cheerio');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+const languages = require('@libs/languages');
+
+const pluginId = 'epiknovel.com';
+
+const sourceName = 'EpikNovel';
+
+const baseUrl = 'https://www.epiknovel.com/';
+
+async function popularNovels (page) {
+ let url = baseUrl + 'seri-listesi?Sayfa=' + page;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('div.col-lg-12.col-md-12').each(function () {
+ const novelName = loadedCheerio(this).find('h3').text();
+ const novelCover = loadedCheerio(this).find('img').attr('data-src');
+ const novelUrl = loadedCheerio(this).find('h3 > a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ // console.log(novels);
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const url = novelUrl;
+ // console.log(url);
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novel = {url};
+
+ novel.name = loadedCheerio('h1#tables').text().trim();
+
+ novel.cover = loadedCheerio('img.manga-cover').attr('src');
+
+ novel.summary = loadedCheerio(
+ '#wrapper > div.row > div.col-md-9 > div:nth-child(6) > p:nth-child(3)',
+ )
+ .text()
+ .trim();
+
+ novel.status = loadedCheerio(
+ '#wrapper > div.row > div.col-md-9 > div.row > div.col-md-9 > h4:nth-child(3) > a',
+ )
+ .text()
+ .trim();
+
+ novel.author = loadedCheerio('#NovelInfo > p:nth-child(4)')
+ .text()
+ .replace(/Publisher:|\s/g, '')
+ .trim();
+
+ let novelChapters = [];
+
+ loadedCheerio('table').find('tr').first().remove();
+
+ loadedCheerio('table')
+ .find('tr')
+ .each(function () {
+ const releaseDate = loadedCheerio(this).find('td:nth-child(3)').text();
+
+ let chapterName = loadedCheerio(this).find('td:nth-child(1) > a').text();
+
+ if (loadedCheerio(this).find('td:nth-child(1) > span').length > 0) {
+ chapterName = '🔒 ' + chapterName;
+ }
+
+ const chapterUrl = loadedCheerio(this)
+ .find(' td:nth-child(1) > a')
+ .attr('href');
+
+ novelChapters.push({
+ name: chapterName,
+ url: chapterUrl,
+ releaseTime: releaseDate,
+ });
+ });
+
+ novel.chapters = novelChapters;
+ // console.log(novel);
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const url = chapterUrl;
+
+ // console.log(url);
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let chapterName, chapterText;
+
+ if (result.url === 'https://www.epiknovel.com/login') {
+ chapterName = '';
+ chapterText = 'Premium Chapter';
+ } else {
+ chapterName = loadedCheerio('#icerik > center > h4 > b').text();
+ chapterText = loadedCheerio('div#icerik').html();
+ }
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = baseUrl + 'seri-listesi?q=' + searchTerm;
+
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ let novels = [];
+
+ loadedCheerio('div.col-lg-12.col-md-12').each(function () {
+ const novelName = loadedCheerio(this).find('h3').text();
+ const novelCover = loadedCheerio(this).find('img').attr('data-src');
+ const novelUrl = loadedCheerio(this).find('h3 > a').attr('href');
+
+ const novel = {
+ name: novelName,
+ cover: novelCover,
+ url: novelUrl,
+ };
+
+ novels.push(novel);
+ });
+
+ return novels;
+};
+
+module.exports = {
+ id: pluginId,
+ name: sourceName,
+ site: baseUrl,
+ version: '1.0.0',
+ icon: 'src/tr/epiknovel/icon.png',
+ lang: languages.Turkish,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+ fetchImage: fetchFile,
+};
\ No newline at end of file
diff --git a/plugins/vietnamese/.vietnamese b/plugins/vietnamese/.vietnamese
new file mode 100644
index 0000000..e69de29
diff --git a/plugins/vietnamese/LNHako.js b/plugins/vietnamese/LNHako.js
new file mode 100644
index 0000000..5682a96
--- /dev/null
+++ b/plugins/vietnamese/LNHako.js
@@ -0,0 +1,199 @@
+const cheerio = require('cheerio');
+const isUrlAbsolute = require('@libs/isAbsoluteUrl');
+const languages = require('@libs/languages');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+
+const pluginId = 'ln.hako';
+const baseUrl = 'https://ln.hako.vn';
+
+async function popularNovels (page) {
+ const link = baseUrl + '/danh-sach?truyendich=1&sapxep=topthang&page=' + page;
+ const result = await fetchApi(link);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ const novels = [];
+
+ loadedCheerio('main.row > .thumb-item-flow').each(function () {
+ let url = loadedCheerio(this)
+ .find('div.thumb_attr.series-title > a')
+ .attr('href');
+
+ if (url && !isUrlAbsolute(url)) {
+ url = baseUrl + url;
+ }
+
+ if (url) {
+ const name = loadedCheerio(this).find('.series-title').text().trim();
+ let cover = loadedCheerio(this)
+ .find('.img-in-ratio')
+ .attr('data-bg');
+
+ if (cover && !isUrlAbsolute(cover)) {
+ cover = baseUrl + cover;
+ }
+
+ const novel = {
+ name,
+ url,
+ cover,
+ };
+
+ novels.push(novel);
+ }
+ });
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl){
+ const url = novelUrl;
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ let loadedCheerio = cheerio.load(body);
+
+ const novel = {
+ url,
+ chapters: [],
+ };
+
+ novel.name = loadedCheerio('.series-name').text();
+
+ const background = loadedCheerio('.series-cover > .a6-ratio > div').attr(
+ 'style',
+ );
+ const novelCover = background.substring(
+ background.indexOf('http'),
+ background.length - 2,
+ );
+
+ novel.cover = novelCover
+ ? isUrlAbsolute(novelCover)
+ ? novelCover
+ : baseUrl + novelCover
+ : '';
+
+ novel.summary = loadedCheerio('.summary-content').text().trim();
+
+ novel.author = loadedCheerio(
+ '#mainpart > div:nth-child(2) > div > div:nth-child(1) > section > main > div.top-part > div > div.col-12.col-md-9 > div.series-information > div:nth-child(2) > span.info-value > a',
+ )
+ .text()
+ .trim();
+
+ novel.genres = loadedCheerio('.series-gernes')
+ .text()
+ .trim()
+ .replaceAll(/ +/g," ")
+ .split('\n')
+ .filter(e => e.trim())
+ .join(', ');
+
+ novel.status = loadedCheerio(
+ '#mainpart > div:nth-child(2) > div > div:nth-child(1) > section > main > div.top-part > div > div.col-12.col-md-9 > div.series-information > div:nth-child(4) > span.info-value > a',
+ )
+ .text()
+ .trim();
+
+ loadedCheerio('.list-chapters li').each(function () {
+ let chapterUrl = loadedCheerio(this).find('a').attr('href');
+
+ if (chapterUrl && !isUrlAbsolute(chapterUrl)) {
+ chapterUrl = baseUrl + chapterUrl;
+ }
+
+ if (chapterUrl) {
+ const chapterName = loadedCheerio(this)
+ .find('.chapter-name')
+ .text()
+ .trim();
+ const releaseTime = loadedCheerio(this).find('.chapter-time').text();
+
+ const chapter = {
+ name: chapterName,
+ releaseTime: releaseTime,
+ url: chapterUrl,
+ };
+
+ novel.chapters.push(chapter);
+ }
+ });
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl){
+ const result = await fetchApi(chapterUrl);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ const chapterText = loadedCheerio('#chapter-content').html() || '';
+
+ return chapterText;
+};
+
+async function searchNovels (searchTerm) {
+ const url = baseUrl + '/tim-kiem?keywords=' + searchTerm;
+ const result = await fetchApi(url);
+ const body = await result.text();
+
+ const loadedCheerio = cheerio.load(body);
+
+ const novels = [];
+
+ loadedCheerio('div.row > .thumb-item-flow').each(function () {
+ let novelUrl = loadedCheerio(this)
+ .find('div.thumb_attr.series-title > a')
+ .attr('href');
+
+ if (novelUrl && !isUrlAbsolute(novelUrl)) {
+ novelUrl = baseUrl + novelUrl;
+ }
+
+ if (novelUrl) {
+ const novelName = loadedCheerio(this).find('.series-title').text();
+ let novelCover = loadedCheerio(this)
+ .find('.img-in-ratio')
+ .attr('data-bg');
+
+ if (novelCover && !isUrlAbsolute(novelCover)) {
+ novelCover = baseUrl + novelCover;
+ }
+
+ novels.push({
+ name: novelName,
+ url: novelUrl,
+ cover: novelCover,
+ });
+ }
+ });
+
+ return novels;
+};
+
+async function fetchImage (url){
+ const headers = {
+ Referer: 'https://ln.hako.vn',
+ }
+ return await fetchFile(url, {headers: headers});
+};
+
+module.exports = {
+ id: pluginId,
+ name: 'Hako',
+ version: '1.0.0',
+ icon: 'src/vi/hakolightnovel/icon.png',
+ site: baseUrl,
+ lang: languages.Vietnamese,
+ description: 'Cổng LightNovel',
+ protected: true,
+ fetchImage,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+};
\ No newline at end of file
diff --git a/scripts/json_plugins.js b/scripts/json_plugins.js
new file mode 100644
index 0000000..a789906
--- /dev/null
+++ b/scripts/json_plugins.js
@@ -0,0 +1,40 @@
+require('module-alias/register');
+require('dotenv').config();
+const fs = require('fs');
+const languages = require('@libs/languages');
+const path = require('path')
+const root = path.dirname(__dirname);
+const username = process.env.GITHUB_USERNAME;
+const repo = process.env.GITHUB_REPOSITORY;
+const branch = process.env.GITHUB_BRANCH;
+
+const githubIconsLink = `https://raw.githubusercontent.com/${username}/${repo}/${branch}/icons`;
+const githubPluginsLink = `https://raw.githubusercontent.com/${username}/${repo}/${branch}/plugins`;
+
+const json = {};
+const jsonPath = path.join(root, 'plugins', 'plugins.json');
+const jsonMinPath = path.join(root, 'plugins', 'plugins.min.json');
+
+for (let language in languages) { // language with English name
+ const langPath = path.join(root, 'plugins', language.toLowerCase());
+ if (!fs.existsSync(langPath)) continue;
+ const plugins = fs.readdirSync(langPath);
+ json[languages[language]] = [];
+ plugins.forEach(plugin => {
+ if(plugin.startsWith('.')) return;
+ const instance = require(`@plugins/${language.toLowerCase()}/${plugin.split('.')[0]}`);
+
+ const { id, name, site, lang, version, icon, description } = instance;
+ // lang: language with native name
+ const info = { id, name, site, lang, version, description }
+ info.url = `${githubPluginsLink}/${language.toLowerCase()}/${plugin}`;
+ info.iconUrl = `${githubIconsLink}/${icon}`;
+
+ json[lang].push(info);
+
+ console.log('Collected', name);
+ });
+}
+fs.writeFileSync(jsonMinPath, JSON.stringify(json));
+fs.writeFileSync(jsonPath, JSON.stringify(json, null, '\t'));
+console.log('Done ✅');
diff --git a/template.js b/template.js
new file mode 100644
index 0000000..3bab5e2
--- /dev/null
+++ b/template.js
@@ -0,0 +1,97 @@
+const cheerio = require('cheerio');
+const languages = require('@libs/languages');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+// const dayjs = require('dayjs');
+// const FilterInputs = require('@libs/filterInputs');
+// const novelStatus = require('@libs/novelStatus');
+// const isUrlAbsolute = require('@libs/isAbsoluteUrl');
+// const parseDate = require('@libs/parseDate');
+
+
+async function popularNovels (pageNo) {
+ const novels = [];
+ /*
+ Do something....
+ novel = {
+ name: '',
+ url: '', must be absolute
+ cover: '',
+ }
+ novels.push(novel);
+ */
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const novel = {
+ url: novelUrl,
+ chapters: [],
+ };
+
+ /**
+ * novel.name = '';
+ * novel.cover = '';
+ * novel.summary = '';
+ * novel.author = '';
+ * novel.artist = '';
+ * novel.status = '';
+ * novel.genres = ''; join by commas. For example: 'romcom, action, school'
+ */
+
+ /*
+ Do something....
+ chapter = {
+ name: '',
+ url: '', must be absoulute
+ releaseTime: '',
+ }
+ novel.chapters.push(chapter);
+ */
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ // Do something...
+ const chapterText = '';
+ return chapterText;
+};
+
+
+async function searchNovels (searchTerm, pageNo) {
+ const novels = [];
+ /*
+ Do something....
+ novel = {
+ name: '',
+ url: '', must be absolute
+ cover: '',
+ }
+ novels.push(novel);
+ */
+ return novels;
+};
+
+async function fetchImage (url) {
+ // Some site cant fetch images normally (maybe need some headers)
+ // Must return base64 of image
+ return await fetchFile(url, {});
+};
+
+module.exports = {
+ id, // string and must be unique
+ name: 'Source name',
+ icon, /** The relative path to the icon without @icons . For example: 'src/vi/hakolightnovel/icon.png' */
+ version, // xx.xx.xx
+ site,
+ lang: languages.English, // must be included in languages
+ description: 'This is descriptions',
+ protected: false, // true if this site protect its resources (images) and you have to define headers or smt to bypass
+ filters, // optional
+ fetchImage,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+}
\ No newline at end of file
diff --git a/template.min.js b/template.min.js
new file mode 100644
index 0000000..964c413
--- /dev/null
+++ b/template.min.js
@@ -0,0 +1,60 @@
+const cheerio = require('cheerio');
+const languages = require('@libs/languages');
+const fetchApi = require('@libs/fetchApi');
+const fetchFile = require('@libs/fetchFile');
+// const dayjs = require('dayjs');
+// const FilterInputs = require('@libs/filterInputs');
+// const novelStatus = require('@libs/novelStatus');
+// const isUrlAbsolute = require('@libs/isAbsoluteUrl');
+// const parseDate = require('@libs/parseDate');
+
+
+async function popularNovels (pageNo) {
+ const novels = [];
+
+ return novels;
+};
+
+async function parseNovelAndChapters (novelUrl) {
+ const novel = {
+ url: novelUrl,
+ chapters: [],
+ };
+
+ return novel;
+};
+
+async function parseChapter (chapterUrl) {
+ const chapterText = '';
+
+ return chapterText;
+};
+
+
+async function searchNovels (searchTerm, pageNo) {
+ const novels = [];
+
+ return novels;
+};
+
+async function fetchImage (url) {
+
+ return await fetchFile(url, {});
+};
+
+module.exports = {
+ id,
+ name,
+ icon,
+ version,
+ site,
+ lang: languages.English,
+ // description,
+ // protected,
+ // filters,
+ fetchImage,
+ popularNovels,
+ parseNovelAndChapters,
+ parseChapter,
+ searchNovels,
+}
\ No newline at end of file
diff --git a/test_web/index.html b/test_web/index.html
new file mode 100644
index 0000000..9b0d835
--- /dev/null
+++ b/test_web/index.html
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+ Testing plugin
+
+
+
+
+
+
+
+ popularNovels
+
+
+ Loading...
+
+
+
+
+
+
+
+ searchNovels
+
+
+ Loading...
+
+
+
+
+
+
+
+ parseNovelAndChapters
+
+
+ Loading...
+
+
+
+
+
+
+ parseChapter
+
+
+ Loading...
+
+
+
+
+
+
+
+
+ fetchImage
+
+
+ Loading...
+
+
+
![]()
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test_web/static/css/bootstrap.min.css b/test_web/static/css/bootstrap.min.css
new file mode 100644
index 0000000..6561b6f
--- /dev/null
+++ b/test_web/static/css/bootstrap.min.css
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v4.0.0 (https://getbootstrap.com)
+ * Copyright 2011-2018 The Bootstrap Authors
+ * Copyright 2011-2018 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-sm-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-sm-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-sm-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-sm-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-sm-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-sm-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-sm-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-sm-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-sm-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-sm-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-sm-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-sm-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-sm-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-sm-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-md-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-md-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-md-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-md-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-md-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-md-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-md-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-md-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-md-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-md-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-md-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-md-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-md-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-md-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-lg-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-lg-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-lg-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-lg-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-lg-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-lg-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-lg-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-lg-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-lg-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-lg-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-lg-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-lg-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-lg-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-lg-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-xl-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-xl-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-xl-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-xl-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-xl-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-xl-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-xl-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-xl-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-xl-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-xl-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-xl-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-xl-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-xl-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-xl-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.input-group-append>.form-control-plaintext.btn,.input-group-lg>.input-group-append>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-prepend>.form-control-plaintext.btn,.input-group-lg>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.input-group-append>.form-control-plaintext.btn,.input-group-sm>.input-group-append>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-prepend>.form-control-plaintext.btn,.input-group-sm>.input-group-prepend>.form-control-plaintext.input-group-text{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-sm>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-lg>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:calc(2.875rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(40,167,69,.8);border-radius:.2rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{background-color:#71dd8a}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(40,167,69,.25)}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label::before,.was-validated .custom-file-input:valid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,.8);border-radius:.2rem}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{background-color:#efa2a9}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label::before,.was-validated .custom-file-input:invalid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group{width:auto}.form-inline .form-check{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled).active,.btn:not(:disabled):not(.disabled):active{background-image:none}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;background-color:transparent;background-image:none;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;background-color:transparent}.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent;border-color:transparent}.btn-link.focus,.btn-link:focus{text-decoration:underline;border-color:transparent;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}.dropdown,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropup .dropdown-menu{margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;width:0;height:0;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.btn-group,.btn-group-vertical{position:relative;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-webkit-box-flex:0;-ms-flex:0 1 auto;flex:0 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after{margin-left:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control{position:relative;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file:focus,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control{margin-left:-1px}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::before{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label,.input-group>.custom-file:not(:first-child) .custom-file-label::before{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-webkit-box;display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:active~.custom-control-label::before{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{margin-bottom:0}.custom-control-label::before{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;pointer-events:none;content:"";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#dee2e6}.custom-control-label::after{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;content:"";background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:inset 0 1px 2px rgba(0,0,0,.075),0 0 5px rgba(128,189,255,.5)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-select-lg{height:calc(2.875rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:125%}.custom-file{position:relative;display:inline-block;width:100%;height:calc(2.25rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(2.25rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-control{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:focus~.custom-file-control::before{border-color:#80bdff}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(2.25rem + 2px);padding:.375rem .75rem;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(calc(2.25rem + 2px) - 1px * 2);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:1px solid #ced4da;border-radius:0 .25rem .25rem 0}.nav{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler:not(:disabled):not(.disabled){cursor:pointer}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .dropup .dropdown-menu{top:auto;bottom:100%}}.navbar-expand{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .dropup .dropdown-menu{top:auto;bottom:100%}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1 0 0%;flex:1 0 0%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-webkit-box-flex:1;-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-header,.card-group>.card:first-child .card-img-top{border-top-right-radius:0}.card-group>.card:first-child .card-footer,.card-group>.card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-header,.card-group>.card:last-child .card-img-top{border-top-left-radius:0}.card-group>.card:last-child .card-footer,.card-group>.card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:.25rem}.card-group>.card:only-child .card-header,.card-group>.card:only-child .card-img-top{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-group>.card:only-child .card-footer,.card-group>.card:only-child .card-img-bottom{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-group>.card:not(:first-child):not(:last-child):not(:only-child){border-radius:0}.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-webkit-box;display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-link:not(:disabled):not(.disabled){cursor:pointer}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#6c757d}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#545b62}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#212529;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#212529;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#212529;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#212529;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-webkit-box;display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;background-color:#007bff;transition:width .6s ease}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}.media{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.media-body{-webkit-box-flex:1;-ms-flex:1;flex:1}.list-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{z-index:1;text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:focus,.close:hover{color:#000;text-decoration:none;opacity:.75}.close:not(:disabled):not(.disabled){cursor:pointer}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.show .modal-dialog{-webkit-transform:translate(0,0);transform:translate(0,0)}.modal-dialog-centered{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-content{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:1rem;border-bottom:1px solid #e9ecef;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top] .arrow,.bs-popover-top .arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::after,.bs-popover-top .arrow::before{border-width:.5rem .5rem 0}.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::before{bottom:0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-top .arrow::after{bottom:1px;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right] .arrow,.bs-popover-right .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::after,.bs-popover-right .arrow::before{border-width:.5rem .5rem .5rem 0}.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::before{left:0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-right .arrow::after{left:1px;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom] .arrow,.bs-popover-bottom .arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::after,.bs-popover-bottom .arrow::before{border-width:0 .5rem .5rem .5rem}.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::before{top:0;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-bottom .arrow::after{top:1px;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left] .arrow,.bs-popover-left .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::after,.bs-popover-left .arrow::before{border-width:.5rem 0 .5rem .5rem}.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::before{right:0;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-left .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;transition:-webkit-transform .6s ease;transition:transform .6s ease;transition:transform .6s ease,-webkit-transform .6s ease;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{-webkit-transform:translateX(100%);transform:translateX(100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-right,.carousel-item-next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translateX(-100%);transform:translateX(-100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;-webkit-box-flex:0;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;background-color:rgba(255,255,255,.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-circle{border-radius:50%!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-sm-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-md-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-lg-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-xl-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;-webkit-clip-path:inset(50%);clip-path:inset(50%);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal;-webkit-clip-path:none;clip-path:none}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#545b62!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-muted{color:#6c757d!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}
+/*# sourceMappingURL=bootstrap.min.css.map */
\ No newline at end of file
diff --git a/test_web/static/css/index.css b/test_web/static/css/index.css
new file mode 100644
index 0000000..3322063
--- /dev/null
+++ b/test_web/static/css/index.css
@@ -0,0 +1,120 @@
+.navbar{
+ width: 1080px;
+ align-items: center;
+ padding-left: 5%;
+ justify-content: space-between;
+}
+
+.input-group{
+ width: 20rem;
+}
+
+#search-results{
+ position: absolute;
+ top: calc(100% - 0.5rem);
+ width: 15rem;
+ padding: 0.375rem 0;
+ border-radius: 5px;
+ background-color: white;
+}
+
+.btn.disabled, .btn:disabled{
+ opacity: 1;
+}
+
+#test-container{
+ align-items: center;
+ height: max-content;
+ margin-bottom: 100px;
+}
+
+
+.test-wrapper{
+ margin: 1rem;
+ padding: 0.5rem;
+ background-color: aliceblue;
+}
+
+#popularNovels, #searchNovels{
+ height: 350px;
+ min-width: 95%;
+ max-width: 95%;
+ overflow-y: hidden;
+ overflow-x: scroll;
+}
+
+#parseNovelAndChapters{
+ height: 380px;
+ min-width: 95%;
+ max-width: 95%;
+}
+
+.title{
+ font-weight: bold;
+}
+
+.spinner-border {
+ display: none;
+ width: 1rem;
+ height: 1rem;
+ vertical-align: text-bottom;
+ border: 0.25em solid currentColor;
+ border-right-color: transparent;
+ border-radius: 50%;
+ -webkit-animation: spinner-border .75s linear infinite;
+ animation: spinner-border .75s linear infinite;
+}
+
+@keyframes spinner-border{
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+
+.novel-list{
+ display: flex;
+ margin-top: 0.5rem;
+ height: 300px;
+ width: 100%;
+}
+
+.novel-item{
+ display: flex;
+ padding: 0.5rem;
+}
+
+.novel-item img {
+ max-height: 90%;
+}
+
+.novel-info{
+ width: 16rem;
+}
+
+.info-item{
+ display: flex;
+ margin-top: 5px;
+}
+
+.info-value{
+ width: 10rem;
+ padding-left: 0.25rem;
+ font-size: 0.65rem;
+ word-wrap:break-word;
+}
+
+.btn{
+ font-size: 0.75rem;
+ padding: 0.25rem 0.25rem;
+}
+
+.chapter-list{
+ position: relative;
+ display: grid;
+ min-width: 50%;
+ overflow-y: scroll;
+ overflow-x: scroll;
+ grid-template-columns: 15rem 15rem 15rem 15rem;
+ grid-gap: 0, 0;
+}
diff --git a/test_web/static/ico.png b/test_web/static/ico.png
new file mode 100644
index 0000000..d2f483c
Binary files /dev/null and b/test_web/static/ico.png differ
diff --git a/test_web/static/js/index.js b/test_web/static/js/index.js
new file mode 100644
index 0000000..3cf7825
--- /dev/null
+++ b/test_web/static/js/index.js
@@ -0,0 +1,263 @@
+var all_plugins = undefined;
+var plugin_arr = [];
+var current_array = [];
+var current_plugin_requirePath = undefined;
+
+const language_selection = $('#language');
+const plugin_search = $('#plugin');
+const search_results = $('#search-results');
+
+fetch('/all_plugins').then(res => res.json()).then(all => {
+ all_plugins = all;
+ for(let lang in all){
+ language_selection.append(``);
+ plugin_arr = plugin_arr.concat(all[lang]);
+ }
+});
+
+const display_search = (arr) => {
+ search_results.hide();
+ search_results.html('');
+ arr.slice(0, 15).forEach(plugin => {
+ search_results.append(`
+
+
+
+ `)
+ });
+ search_results.show();
+}
+
+plugin_search.focus(e => {
+ if(!all_plugins) return;
+ if(language_selection.val()){
+ current_array = all_plugins[language_selection.val()];
+ }else{
+ current_array = plugin_arr;
+ }
+ display_search(current_array);
+});
+
+plugin_search.keyup(e => {
+ display_search(current_array.filter(plg => plg.name.toLowerCase().includes(plugin_search.val())));
+});
+
+$('#clear-search').click(e => {
+ search_results.hide();
+ plugin_search.val('');
+ plugin_search.attr('data-require', '');
+})
+
+const test_plugin = (btn) => {
+ const ele = $(btn);
+ current_plugin_requirePath = ele.attr('data-require');
+ plugin_search.attr('data-require', current_plugin_requirePath);
+ plugin_search.val(ele.text().split('/')[1]);
+ search_results.hide();
+}
+
+const popularNovels = () => {
+ if(!current_plugin_requirePath) return;
+ $('#popularNovels .spinner-border').show();
+ fetch(`/popularNovels/`,{
+ method: 'POST',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify({"pluginRequirePath": current_plugin_requirePath}),
+ })
+ .then(res => res.json())
+ .then(novels => {
+ const novel_list = $('#popularNovels .novel-list');
+ novel_list.html('');
+ if(novels.error){
+ novel_list.html(novels.error);
+ }else{
+ novels.forEach(novel => {
+ novel_list.append(`
+
+

+
+
+
name
+
${novel.name?.slice(0, 50)}
+
Copy
+
+
+
url
+
${novel.url?.slice(0, 50)}
+
Copy
+
+
+
cover
+
${novel.cover?.slice(0, 50)}
+
Copy
+
+
+
+ `);
+ })
+ }
+ $('#popularNovels .spinner-border').hide();
+ });
+}
+
+const searchNovels = () => {
+ const searchTerm = $('#searchNovels input').val();
+ if(!current_plugin_requirePath || !searchTerm) return;
+ $('#searchNovels .spinner-border').show();
+ fetch(`/searchNovels/`,{
+ method: 'POST',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify({"pluginRequirePath": current_plugin_requirePath, "searchTerm": searchTerm}),
+ })
+ .then(res => res.json())
+ .then(novels => {
+ const novel_list = $('#searchNovels .novel-list');
+ novel_list.html('');
+ if(novels.error){
+ novel_list.html(novels.error);
+ }else{
+ novels.forEach(novel => {
+ novel_list.append(`
+
+

+
+
+
name
+
${novel.name?.slice(0, 50)}
+
Copy
+
+
+
url
+
${novel.url?.slice(0, 50)}
+
Copy
+
+
+
cover
+
${novel.cover?.slice(0, 50)}
+
Copy
+
+
+
+ `);
+ })
+ }
+ $('#searchNovels .spinner-border').hide();
+ });
+}
+
+const parseNovelAndChapters = () => {
+ const novelUrl = $('#parseNovelAndChapters input').val();
+ if(!current_plugin_requirePath || !novelUrl) return;
+ $('#parseNovelAndChapters .spinner-border').show();
+ fetch(`/parseNovelAndChapters/`,{
+ method: 'POST',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify({"pluginRequirePath": current_plugin_requirePath, "novelUrl": novelUrl}),
+ })
+ .then(res => res.json())
+ .then(sourceNovel => {
+ const novel_item = $('#parseNovelAndChapters .novel-list .novel-item');
+ novel_item.html(`
+
+
+
+
name
+
${sourceNovel.name?.slice(0, 50)}
+
Copy
+
+
+
url
+
${sourceNovel.url?.slice(0, 50)}
+
Copy
+
+
+
cover
+
${sourceNovel.cover?.slice(0, 50)}
+
Copy
+
+
+
summary
+
${sourceNovel.summary?.slice(0, 50)}
+
Copy
+
+
+
author
+
${sourceNovel.author}
+
Copy
+
+
+
artist
+
${sourceNovel.artist}
+
Copy
+
+
+
status
+
${sourceNovel.status}
+
Copy
+
+
+
genres
+
${sourceNovel.genres?.slice(0, 50)}
+
Copy
+
+
+ `);
+ if(sourceNovel.error){
+ novel_item.html(sourceNovel.error);
+ }else{
+ const chapter_list = $('#parseNovelAndChapters .chapter-list');
+ chapter_list.html('');
+ sourceNovel.chapters.forEach(chapter => {
+ chapter_list.append(`
+
+
${chapter.name?.slice(0, 26)}
+
Copy url
+
+ `);
+ })
+ }
+ $('#parseNovelAndChapters .spinner-border').hide();
+ });
+}
+
+const parseChapter = () => {
+ const chapterUrl = $('#parseChapter input').val();
+ if(!current_plugin_requirePath || !chapterUrl) return;
+ $('#parseChapter .spinner-border').show();
+ fetch(`/parseChapter/`,{
+ method: 'POST',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify({"pluginRequirePath": current_plugin_requirePath, "chapterUrl": chapterUrl}),
+ })
+ .then(res => res.json())
+ .then(chapterText => {
+ $('#parseChapter textarea').text(chapterText);
+ $('#parseChapter .spinner-border').hide();
+ })
+}
+
+const fetchImage = () => {
+ const url = $('#fetchImage input').val();
+ if(!current_plugin_requirePath || !url) return;
+ $('#fetchImage .spinner-border').show();
+ fetch(`/fetchImage/`,{
+ method: 'POST',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify({"pluginRequirePath": current_plugin_requirePath, "url": url}),
+ })
+ .then(res => res.json())
+ .then(base64 => {
+ $('#fetchImage img').attr("src", `data:image/jpg;base64,${base64}`);
+ $('#fetchImage .spinner-border').hide();
+ })
+}
\ No newline at end of file
diff --git a/test_web/static/js/jquery-3.6.4.min.js b/test_web/static/js/jquery-3.6.4.min.js
new file mode 100644
index 0000000..fde8714
--- /dev/null
+++ b/test_web/static/js/jquery-3.6.4.min.js
@@ -0,0 +1,2 @@
+/*! jQuery v3.6.4 | (c) OpenJS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),v={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.4",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&v(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!y||!y.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ve(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ye(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ve(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.cssHas=ce(function(){try{return C.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],y=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||y.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||y.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||y.push(".#.+[+~]"),e.querySelectorAll("\\\f"),y.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),d.cssHas||y.push(":has"),y=y.length&&new RegExp(y.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),v=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType&&e.documentElement||e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&v(p,e)?-1:t==C||t.ownerDocument==p&&v(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!y||!y.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),v.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",v.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",v.option=!!ce.lastChild;var ge={thead:[1,""],col:[2,""],tr:[2,""],td:[3,""],_default:[0,"",""]};function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var me=/<|?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),v.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(v.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return B(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=_e(v.pixelPosition,function(e,t){if(t)return t=Be(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return B(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0