├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── index.js ├── lib └── public │ └── view-source-assets │ ├── explorer.js │ ├── file-text.svg │ ├── folder-plus.svg │ ├── folder.svg │ ├── prism.css │ └── prism.js ├── package.json ├── test └── server.js ├── view-source.png └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | node_modules 3 | *.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Krasimir Tsonev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![view-source](./view-source.png) 2 | 3 | # view-source 4 | 5 | An Express.js add-on to render source code. Use it if you need to show source code of a project over the web. 6 | 7 | ## Usage 8 | 9 | Install it via `npm i view-source` (or `yarn add view-source`). Then the following: 10 | 11 | ```js 12 | const express = require('express'); 13 | const { viewSource } = require('view-source'); 14 | 15 | const app = express(); 16 | 17 | viewSource({ 18 | appTitle: 'My App Name', 19 | app, 20 | route: '/code', 21 | source: __dirname + '/../' 22 | }); 23 | ``` 24 | 25 | Where `route` is the path from which you'll access the viewer and `source` is the actual physical place where the files are located. 26 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const express = require('express'); 4 | 5 | const defaultAppTitle = 'App'; 6 | 7 | function viewSource({ app, route, source, appTitle }) { 8 | app.use(express.static(__dirname + '/lib/public', { maxAge: 604800000 })); 9 | app.use(path.join('/' + route, '@'), express.static(path.normalize(source), { maxAge: 604800000 })); 10 | 11 | const ROOT_DIR = path.normalize(source); 12 | 13 | function buildTree() { 14 | const root = { 15 | name: appTitle || defaultAppTitle, 16 | path: path.normalize(route), 17 | type: 'directory', 18 | children: [] 19 | }; 20 | 21 | function traverseDirectory(dirPath, parentNode) { 22 | const files = fs.readdirSync(dirPath); 23 | 24 | files.forEach(file => { 25 | const filePath = path.join(dirPath, file); 26 | const stats = fs.statSync(filePath); 27 | const node = { 28 | name: file, 29 | path: filePath.replace(ROOT_DIR, ''), 30 | type: stats.isDirectory() ? 'directory' : 'file', 31 | children: [] 32 | }; 33 | 34 | if (stats.isDirectory()) { 35 | traverseDirectory(filePath, node); 36 | } 37 | 38 | parentNode.children.push(node); 39 | }); 40 | } 41 | 42 | traverseDirectory(ROOT_DIR, root); 43 | 44 | return root; 45 | } 46 | 47 | const content = buildTree(route, path.normalize(source)); 48 | 49 | app.get(route, (req, res) => { 50 | res.setHeader("Content-Type", "text/html"); 51 | res.send(page( 52 | ` 53 | 58 | 59 | `, 60 | ` 61 |
62 |
63 |
64 |
65 |

66 |
67 |
68 |
69 |
70 | ` 71 | )) 72 | }); 73 | } 74 | 75 | function page(head = '', content = '') { 76 | return ` 77 | 78 | 79 | 80 | ${head} 81 | 82 | 83 | 104 | 105 | 106 | ${content} 107 | 108 | 109 | `; 110 | } 111 | 112 | module.exports = { 113 | viewSource 114 | } -------------------------------------------------------------------------------- /lib/public/view-source-assets/explorer.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('load', () => { 2 | const tree = JSON.parse(JSON.stringify(TREE)); 3 | 4 | function renderTreeItem(item) { 5 | const icon = item.type === 'directory' ? 6 | item.open ? 'folder.svg' : 'folder-plus.svg' : 7 | 'file-text.svg'; 8 | const action = item.type === 'directory' ? 9 | `changeOpenFlag('${item.path}', ${!item.open})` : 10 | `openFile('${item.path}')`; 11 | return ` 12 |
13 | 14 | ${item.name} 15 | 16 | ${item.open ? item.children.map(i => renderTreeItem(i)).join('') : ''} 17 |
18 | `; 19 | } 20 | function renderTree() { 21 | document.querySelector('#tree').innerHTML = ` 22 |
23 | ${renderTreeItem(tree)} 24 |
25 | ` 26 | } 27 | function renderCode(code, ext = 'js') { 28 | document.querySelector('#code').innerHTML = ` 29 |
${encodeHTMLTags(code)}
30 | `; 31 | setTimeout(() => Prism.highlightAll(), 10); 32 | } 33 | function renderPath(text) { 34 | document.querySelector('#path').innerHTML = '⇢ ' + text; 35 | } 36 | function findItem(treeItem, itemPath) { 37 | if (treeItem.path === itemPath) { 38 | return treeItem; 39 | } else { 40 | for (let i = 0; i < (treeItem.children || []).length; i++) { 41 | const item = findItem(treeItem.children[i], itemPath); 42 | if (item) { 43 | return item; 44 | } 45 | } 46 | } 47 | } 48 | function encodeHTMLTags(code) { 49 | return code.replace(//g, '>'); 50 | } 51 | window.changeOpenFlag = (itemPath, value) => { 52 | const item = findItem(tree, itemPath); 53 | if (item) { 54 | item.open = value; 55 | } else { 56 | console.error(`Item ${itemPath} not found!`); 57 | } 58 | renderTree(); 59 | } 60 | window.openFile = async (itemPath) => { 61 | const ext = itemPath.split('.').pop().toLowerCase(); 62 | renderPath(itemPath); 63 | renderCode(`Loading ${itemPath} ...`, ext); 64 | const res = await fetch((ROUTE + itemPath).replace(/\/\//g, '/')); 65 | const code = await res.text(); 66 | renderCode(code, ext); 67 | } 68 | 69 | tree.open = true; 70 | renderTree(); 71 | renderCode(`// ${NAME} project`) 72 | }); -------------------------------------------------------------------------------- /lib/public/view-source-assets/file-text.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/public/view-source-assets/folder-plus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/public/view-source-assets/folder.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/public/view-source-assets/prism.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.29.0 2 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+abap+abnf+actionscript+ada+agda+al+antlr4+apacheconf+apex+apl+applescript+aql+arduino+arff+armasm+arturo+asciidoc+aspnet+asm6502+asmatmel+autohotkey+autoit+avisynth+avro-idl+awk+bash+basic+batch+bbcode+bbj+bicep+birb+bison+bnf+bqn+brainfuck+brightscript+bro+bsl+c+csharp+cpp+cfscript+chaiscript+cil+cilkc+cilkcpp+clojure+cmake+cobol+coffeescript+concurnas+csp+cooklang+coq+crystal+css-extras+csv+cue+cypher+d+dart+dataweave+dax+dhall+diff+django+dns-zone-file+docker+dot+ebnf+editorconfig+eiffel+ejs+elixir+elm+etlua+erb+erlang+excel-formula+fsharp+factor+false+firestore-security-rules+flow+fortran+ftl+gml+gap+gcode+gdscript+gedcom+gettext+gherkin+git+glsl+gn+linker-script+go+go-module+gradle+graphql+groovy+haml+handlebars+haskell+haxe+hcl+hlsl+hoon+http+hpkp+hsts+ichigojam+icon+icu-message-format+idris+ignore+inform7+ini+io+j+java+javadoc+javadoclike+javastacktrace+jexl+jolie+jq+jsdoc+js-extras+json+json5+jsonp+jsstacktrace+js-templates+julia+keepalived+keyman+kotlin+kumir+kusto+latex+latte+less+lilypond+liquid+lisp+livescript+llvm+log+lolcode+lua+magma+makefile+markdown+markup-templating+mata+matlab+maxscript+mel+mermaid+metafont+mizar+mongodb+monkey+moonscript+n1ql+n4js+nand2tetris-hdl+naniscript+nasm+neon+nevod+nginx+nim+nix+nsis+objectivec+ocaml+odin+opencl+openqasm+oz+parigp+parser+pascal+pascaligo+psl+pcaxis+peoplecode+perl+php+phpdoc+php-extras+plant-uml+plsql+powerquery+powershell+processing+prolog+promql+properties+protobuf+pug+puppet+pure+purebasic+purescript+python+qsharp+q+qml+qore+r+racket+cshtml+jsx+tsx+reason+regex+rego+renpy+rescript+rest+rip+roboconf+robotframework+ruby+rust+sas+sass+scss+scala+scheme+shell-session+smali+smalltalk+smarty+sml+solidity+solution-file+soy+sparql+splunk-spl+sqf+sql+squirrel+stan+stata+iecst+stylus+supercollider+swift+systemd+t4-templating+t4-cs+t4-vb+tap+tcl+tt2+textile+toml+tremor+turtle+twig+typescript+typoscript+unrealscript+uorazor+uri+v+vala+vbnet+velocity+verilog+vhdl+vim+visual-basic+warpscript+wasm+web-idl+wgsl+wiki+wolfram+wren+xeora+xml-doc+xojo+xquery+yaml+yang+zig */ 3 | code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help} 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "view-source", 3 | "version": "0.3.2", 4 | "description": "An Express.js middleware/handler to render source code", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node ./test/server.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/krasimir/view-source.git" 12 | }, 13 | "keywords": [ 14 | "express", 15 | "view", 16 | "source" 17 | ], 18 | "author": "Krasimir Tsonev", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/krasimir/view-source/issues" 22 | }, 23 | "homepage": "https://github.com/krasimir/view-source#readme", 24 | "dependencies": { 25 | "express": "4.18.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const { viewSource } = require('../index'); 3 | 4 | const app = express(); 5 | 6 | viewSource({ 7 | app, 8 | route: '/code', 9 | source: __dirname + '/../' 10 | }); 11 | 12 | app.get('*', (req, res) => { 13 | res.send('view-source'); 14 | }); 15 | 16 | const port = process.env.PORT || 8080; 17 | app.listen(port, () => { 18 | console.log(`Listening on port ${port}`); 19 | }); -------------------------------------------------------------------------------- /view-source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/view-source/1716c357f6b1e5b6fc7b249fd2a1abe93548d66a/view-source.png -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | accepts@~1.3.8: 6 | version "1.3.8" 7 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" 8 | integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== 9 | dependencies: 10 | mime-types "~2.1.34" 11 | negotiator "0.6.3" 12 | 13 | array-flatten@1.1.1: 14 | version "1.1.1" 15 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 16 | integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== 17 | 18 | body-parser@1.20.1: 19 | version "1.20.1" 20 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" 21 | integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== 22 | dependencies: 23 | bytes "3.1.2" 24 | content-type "~1.0.4" 25 | debug "2.6.9" 26 | depd "2.0.0" 27 | destroy "1.2.0" 28 | http-errors "2.0.0" 29 | iconv-lite "0.4.24" 30 | on-finished "2.4.1" 31 | qs "6.11.0" 32 | raw-body "2.5.1" 33 | type-is "~1.6.18" 34 | unpipe "1.0.0" 35 | 36 | bytes@3.1.2: 37 | version "3.1.2" 38 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" 39 | integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== 40 | 41 | call-bind@^1.0.0: 42 | version "1.0.2" 43 | resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" 44 | integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== 45 | dependencies: 46 | function-bind "^1.1.1" 47 | get-intrinsic "^1.0.2" 48 | 49 | content-disposition@0.5.4: 50 | version "0.5.4" 51 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" 52 | integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== 53 | dependencies: 54 | safe-buffer "5.2.1" 55 | 56 | content-type@~1.0.4: 57 | version "1.0.5" 58 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" 59 | integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== 60 | 61 | cookie-signature@1.0.6: 62 | version "1.0.6" 63 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 64 | integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== 65 | 66 | cookie@0.5.0: 67 | version "0.5.0" 68 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" 69 | integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== 70 | 71 | debug@2.6.9: 72 | version "2.6.9" 73 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 74 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 75 | dependencies: 76 | ms "2.0.0" 77 | 78 | depd@2.0.0: 79 | version "2.0.0" 80 | resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" 81 | integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== 82 | 83 | destroy@1.2.0: 84 | version "1.2.0" 85 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" 86 | integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== 87 | 88 | ee-first@1.1.1: 89 | version "1.1.1" 90 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 91 | integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== 92 | 93 | encodeurl@~1.0.2: 94 | version "1.0.2" 95 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 96 | integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== 97 | 98 | escape-html@~1.0.3: 99 | version "1.0.3" 100 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 101 | integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== 102 | 103 | etag@~1.8.1: 104 | version "1.8.1" 105 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 106 | integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== 107 | 108 | express@4.18.2: 109 | version "4.18.2" 110 | resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" 111 | integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== 112 | dependencies: 113 | accepts "~1.3.8" 114 | array-flatten "1.1.1" 115 | body-parser "1.20.1" 116 | content-disposition "0.5.4" 117 | content-type "~1.0.4" 118 | cookie "0.5.0" 119 | cookie-signature "1.0.6" 120 | debug "2.6.9" 121 | depd "2.0.0" 122 | encodeurl "~1.0.2" 123 | escape-html "~1.0.3" 124 | etag "~1.8.1" 125 | finalhandler "1.2.0" 126 | fresh "0.5.2" 127 | http-errors "2.0.0" 128 | merge-descriptors "1.0.1" 129 | methods "~1.1.2" 130 | on-finished "2.4.1" 131 | parseurl "~1.3.3" 132 | path-to-regexp "0.1.7" 133 | proxy-addr "~2.0.7" 134 | qs "6.11.0" 135 | range-parser "~1.2.1" 136 | safe-buffer "5.2.1" 137 | send "0.18.0" 138 | serve-static "1.15.0" 139 | setprototypeof "1.2.0" 140 | statuses "2.0.1" 141 | type-is "~1.6.18" 142 | utils-merge "1.0.1" 143 | vary "~1.1.2" 144 | 145 | finalhandler@1.2.0: 146 | version "1.2.0" 147 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" 148 | integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== 149 | dependencies: 150 | debug "2.6.9" 151 | encodeurl "~1.0.2" 152 | escape-html "~1.0.3" 153 | on-finished "2.4.1" 154 | parseurl "~1.3.3" 155 | statuses "2.0.1" 156 | unpipe "~1.0.0" 157 | 158 | forwarded@0.2.0: 159 | version "0.2.0" 160 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" 161 | integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== 162 | 163 | fresh@0.5.2: 164 | version "0.5.2" 165 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 166 | integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== 167 | 168 | function-bind@^1.1.1: 169 | version "1.1.1" 170 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 171 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 172 | 173 | get-intrinsic@^1.0.2: 174 | version "1.2.1" 175 | resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" 176 | integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== 177 | dependencies: 178 | function-bind "^1.1.1" 179 | has "^1.0.3" 180 | has-proto "^1.0.1" 181 | has-symbols "^1.0.3" 182 | 183 | has-proto@^1.0.1: 184 | version "1.0.1" 185 | resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" 186 | integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== 187 | 188 | has-symbols@^1.0.3: 189 | version "1.0.3" 190 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" 191 | integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== 192 | 193 | has@^1.0.3: 194 | version "1.0.3" 195 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 196 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 197 | dependencies: 198 | function-bind "^1.1.1" 199 | 200 | http-errors@2.0.0: 201 | version "2.0.0" 202 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" 203 | integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== 204 | dependencies: 205 | depd "2.0.0" 206 | inherits "2.0.4" 207 | setprototypeof "1.2.0" 208 | statuses "2.0.1" 209 | toidentifier "1.0.1" 210 | 211 | iconv-lite@0.4.24: 212 | version "0.4.24" 213 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 214 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 215 | dependencies: 216 | safer-buffer ">= 2.1.2 < 3" 217 | 218 | inherits@2.0.4: 219 | version "2.0.4" 220 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 221 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 222 | 223 | ipaddr.js@1.9.1: 224 | version "1.9.1" 225 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" 226 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== 227 | 228 | media-typer@0.3.0: 229 | version "0.3.0" 230 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 231 | integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== 232 | 233 | merge-descriptors@1.0.1: 234 | version "1.0.1" 235 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 236 | integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== 237 | 238 | methods@~1.1.2: 239 | version "1.1.2" 240 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 241 | integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== 242 | 243 | mime-db@1.52.0: 244 | version "1.52.0" 245 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" 246 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 247 | 248 | mime-types@~2.1.24, mime-types@~2.1.34: 249 | version "2.1.35" 250 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" 251 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 252 | dependencies: 253 | mime-db "1.52.0" 254 | 255 | mime@1.6.0: 256 | version "1.6.0" 257 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 258 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 259 | 260 | ms@2.0.0: 261 | version "2.0.0" 262 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 263 | integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== 264 | 265 | ms@2.1.3: 266 | version "2.1.3" 267 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 268 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 269 | 270 | negotiator@0.6.3: 271 | version "0.6.3" 272 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" 273 | integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== 274 | 275 | object-inspect@^1.9.0: 276 | version "1.12.3" 277 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" 278 | integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== 279 | 280 | on-finished@2.4.1: 281 | version "2.4.1" 282 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" 283 | integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== 284 | dependencies: 285 | ee-first "1.1.1" 286 | 287 | parseurl@~1.3.3: 288 | version "1.3.3" 289 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 290 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 291 | 292 | path-to-regexp@0.1.7: 293 | version "0.1.7" 294 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 295 | integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== 296 | 297 | proxy-addr@~2.0.7: 298 | version "2.0.7" 299 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" 300 | integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== 301 | dependencies: 302 | forwarded "0.2.0" 303 | ipaddr.js "1.9.1" 304 | 305 | qs@6.11.0: 306 | version "6.11.0" 307 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" 308 | integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== 309 | dependencies: 310 | side-channel "^1.0.4" 311 | 312 | range-parser@~1.2.1: 313 | version "1.2.1" 314 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 315 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 316 | 317 | raw-body@2.5.1: 318 | version "2.5.1" 319 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" 320 | integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== 321 | dependencies: 322 | bytes "3.1.2" 323 | http-errors "2.0.0" 324 | iconv-lite "0.4.24" 325 | unpipe "1.0.0" 326 | 327 | safe-buffer@5.2.1: 328 | version "5.2.1" 329 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 330 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 331 | 332 | "safer-buffer@>= 2.1.2 < 3": 333 | version "2.1.2" 334 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 335 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 336 | 337 | send@0.18.0: 338 | version "0.18.0" 339 | resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" 340 | integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== 341 | dependencies: 342 | debug "2.6.9" 343 | depd "2.0.0" 344 | destroy "1.2.0" 345 | encodeurl "~1.0.2" 346 | escape-html "~1.0.3" 347 | etag "~1.8.1" 348 | fresh "0.5.2" 349 | http-errors "2.0.0" 350 | mime "1.6.0" 351 | ms "2.1.3" 352 | on-finished "2.4.1" 353 | range-parser "~1.2.1" 354 | statuses "2.0.1" 355 | 356 | serve-static@1.15.0: 357 | version "1.15.0" 358 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" 359 | integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== 360 | dependencies: 361 | encodeurl "~1.0.2" 362 | escape-html "~1.0.3" 363 | parseurl "~1.3.3" 364 | send "0.18.0" 365 | 366 | setprototypeof@1.2.0: 367 | version "1.2.0" 368 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" 369 | integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== 370 | 371 | side-channel@^1.0.4: 372 | version "1.0.4" 373 | resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" 374 | integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== 375 | dependencies: 376 | call-bind "^1.0.0" 377 | get-intrinsic "^1.0.2" 378 | object-inspect "^1.9.0" 379 | 380 | statuses@2.0.1: 381 | version "2.0.1" 382 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" 383 | integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== 384 | 385 | toidentifier@1.0.1: 386 | version "1.0.1" 387 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" 388 | integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== 389 | 390 | type-is@~1.6.18: 391 | version "1.6.18" 392 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 393 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 394 | dependencies: 395 | media-typer "0.3.0" 396 | mime-types "~2.1.24" 397 | 398 | unpipe@1.0.0, unpipe@~1.0.0: 399 | version "1.0.0" 400 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 401 | integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== 402 | 403 | utils-merge@1.0.1: 404 | version "1.0.1" 405 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 406 | integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== 407 | 408 | vary@~1.1.2: 409 | version "1.1.2" 410 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 411 | integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== 412 | --------------------------------------------------------------------------------