+ `
+ )
+ .join("");
+
+ // 최종 HTML 응답
+ res.send(`
+
+
+
+
+ 투표하기 - 지역 선택
+
+
+
+
투표할 지역을 선택하세요
+
+
+
+
지역
+
+
+
+ ${regionRows}
+
+
+
+
+ `);
+ });
+});
+
+// 특정 지역의 후보 페이지
+router.get("/:region", (req, res) => {
+ const region = req.params.region;
+
+ // 특정 지역의 후보 조회
+ const query = "SELECT * FROM candidates WHERE region = ?";
+ db.query(query, [region], (err, results) => {
+ if (err) {
+ return res.status(500).send("후보 조회 실패");
+ }
+
+ // 후보 목록을 HTML로 생성
+ let candidateCheckboxes = results
+ .map(
+ (candidate) => `
+
+
+
+
+ `
+ )
+ .join("");
+
+ // 최종 HTML 응답
+ res.send(`
+
+
+
+
+ ${region} 지역 투표하기
+
+
+
${region} 지역 투표하기
+
+
+
+ `);
+ });
+});
+
+// 투표 처리
+router.post("/", (req, res) => {
+ let { candidateIds } = req.body; // let으로 변경
+
+ // 후보자가 선택되지 않았거나 candidateIds가 존재하지 않을 경우 처리
+ if (!candidateIds) {
+ return res.status(400).send("후보를 선택해야 합니다.");
+ }
+
+ // 후보자가 하나만 선택된 경우에도 정상 처리
+ if (!Array.isArray(candidateIds)) {
+ candidateIds = [candidateIds]; // 배열이 아닌 경우 배열로 변환
+ }
+
+ // DB에 투표 저장 로직 추가 필요
+ // 예시: candidateIds 배열을 사용하여 DB에 투표 기록을 저장하는 로직을 추가하세요.
+
+ res.send("투표 완료");
+});
+
+module.exports = router;
diff --git a/lib_login/auth.js b/lib_login/auth.js
new file mode 100644
index 0000000..dd1906d
--- /dev/null
+++ b/lib_login/auth.js
@@ -0,0 +1,129 @@
+var express = require("express");
+var router = express.Router();
+
+var template = require("./template.js");
+var db = require("../db.js");
+
+// 로그인 화면
+router.get("/login", function (request, response) {
+ var title = "로그인";
+ var html = template.HTML(
+ title,
+ `
+
+
+Denque is a well tested, extremely fast and lightweight [double-ended queue](http://en.wikipedia.org/wiki/Double-ended_queue)
+implementation with zero dependencies and includes TypeScript types.
+
+Double-ended queues can also be used as a:
+
+- [Stack](http://en.wikipedia.org/wiki/Stack_\(abstract_data_type\))
+- [Queue](http://en.wikipedia.org/wiki/Queue_\(data_structure\))
+
+This implementation is currently the fastest available, even faster than `double-ended-queue`, see the [benchmarks](https://docs.page/invertase/denque/benchmarks).
+
+Every queue operation is done at a constant `O(1)` - including random access from `.peekAt(index)`.
+
+**Works on all node versions >= v0.10**
+
+## Quick Start
+
+Install the package:
+
+```bash
+npm install denque
+```
+
+Create and consume a queue:
+
+```js
+const Denque = require("denque");
+
+const denque = new Denque([1,2,3,4]);
+denque.shift(); // 1
+denque.pop(); // 4
+```
+
+
+See the [API reference documentation](https://docs.page/invertase/denque/api) for more examples.
+
+---
+
+## Who's using it?
+
+- [Kafka Node.js client](https://www.npmjs.com/package/kafka-node)
+- [MariaDB Node.js client](https://www.npmjs.com/package/mariadb)
+- [MongoDB Node.js client](https://www.npmjs.com/package/mongodb)
+- [MySQL Node.js client](https://www.npmjs.com/package/mysql2)
+- [Redis Node.js clients](https://www.npmjs.com/package/redis)
+
+... and [many more](https://www.npmjs.com/browse/depended/denque).
+
+
+---
+
+## License
+
+- See [LICENSE](/LICENSE)
+
+---
+
+
diff --git a/node_modules/denque/index.d.ts b/node_modules/denque/index.d.ts
new file mode 100644
index 0000000..e125dd4
--- /dev/null
+++ b/node_modules/denque/index.d.ts
@@ -0,0 +1,47 @@
+declare class Denque {
+ length: number;
+
+ constructor();
+
+ constructor(array: T[]);
+
+ constructor(array: T[], options: IDenqueOptions);
+
+ push(item: T): number;
+
+ unshift(item: T): number;
+
+ pop(): T | undefined;
+
+ shift(): T | undefined;
+
+ peekBack(): T | undefined;
+
+ peekFront(): T | undefined;
+
+ peekAt(index: number): T | undefined;
+
+ get(index: number): T | undefined;
+
+ remove(index: number, count: number): T[];
+
+ removeOne(index: number): T | undefined;
+
+ splice(index: number, count: number, ...item: T[]): T[] | undefined;
+
+ isEmpty(): boolean;
+
+ clear(): void;
+
+ size(): number;
+
+ toString(): string;
+
+ toArray(): T[];
+}
+
+interface IDenqueOptions {
+ capacity?: number
+}
+
+export = Denque;
diff --git a/node_modules/denque/index.js b/node_modules/denque/index.js
new file mode 100644
index 0000000..6b2e9d8
--- /dev/null
+++ b/node_modules/denque/index.js
@@ -0,0 +1,481 @@
+'use strict';
+
+/**
+ * Custom implementation of a double ended queue.
+ */
+function Denque(array, options) {
+ var options = options || {};
+ this._capacity = options.capacity;
+
+ this._head = 0;
+ this._tail = 0;
+
+ if (Array.isArray(array)) {
+ this._fromArray(array);
+ } else {
+ this._capacityMask = 0x3;
+ this._list = new Array(4);
+ }
+}
+
+/**
+ * --------------
+ * PUBLIC API
+ * -------------
+ */
+
+/**
+ * Returns the item at the specified index from the list.
+ * 0 is the first element, 1 is the second, and so on...
+ * Elements at negative values are that many from the end: -1 is one before the end
+ * (the last element), -2 is two before the end (one before last), etc.
+ * @param index
+ * @returns {*}
+ */
+Denque.prototype.peekAt = function peekAt(index) {
+ var i = index;
+ // expect a number or return undefined
+ if ((i !== (i | 0))) {
+ return void 0;
+ }
+ var len = this.size();
+ if (i >= len || i < -len) return undefined;
+ if (i < 0) i += len;
+ i = (this._head + i) & this._capacityMask;
+ return this._list[i];
+};
+
+/**
+ * Alias for peekAt()
+ * @param i
+ * @returns {*}
+ */
+Denque.prototype.get = function get(i) {
+ return this.peekAt(i);
+};
+
+/**
+ * Returns the first item in the list without removing it.
+ * @returns {*}
+ */
+Denque.prototype.peek = function peek() {
+ if (this._head === this._tail) return undefined;
+ return this._list[this._head];
+};
+
+/**
+ * Alias for peek()
+ * @returns {*}
+ */
+Denque.prototype.peekFront = function peekFront() {
+ return this.peek();
+};
+
+/**
+ * Returns the item that is at the back of the queue without removing it.
+ * Uses peekAt(-1)
+ */
+Denque.prototype.peekBack = function peekBack() {
+ return this.peekAt(-1);
+};
+
+/**
+ * Returns the current length of the queue
+ * @return {Number}
+ */
+Object.defineProperty(Denque.prototype, 'length', {
+ get: function length() {
+ return this.size();
+ }
+});
+
+/**
+ * Return the number of items on the list, or 0 if empty.
+ * @returns {number}
+ */
+Denque.prototype.size = function size() {
+ if (this._head === this._tail) return 0;
+ if (this._head < this._tail) return this._tail - this._head;
+ else return this._capacityMask + 1 - (this._head - this._tail);
+};
+
+/**
+ * Add an item at the beginning of the list.
+ * @param item
+ */
+Denque.prototype.unshift = function unshift(item) {
+ if (arguments.length === 0) return this.size();
+ var len = this._list.length;
+ this._head = (this._head - 1 + len) & this._capacityMask;
+ this._list[this._head] = item;
+ if (this._tail === this._head) this._growArray();
+ if (this._capacity && this.size() > this._capacity) this.pop();
+ if (this._head < this._tail) return this._tail - this._head;
+ else return this._capacityMask + 1 - (this._head - this._tail);
+};
+
+/**
+ * Remove and return the first item on the list,
+ * Returns undefined if the list is empty.
+ * @returns {*}
+ */
+Denque.prototype.shift = function shift() {
+ var head = this._head;
+ if (head === this._tail) return undefined;
+ var item = this._list[head];
+ this._list[head] = undefined;
+ this._head = (head + 1) & this._capacityMask;
+ if (head < 2 && this._tail > 10000 && this._tail <= this._list.length >>> 2) this._shrinkArray();
+ return item;
+};
+
+/**
+ * Add an item to the bottom of the list.
+ * @param item
+ */
+Denque.prototype.push = function push(item) {
+ if (arguments.length === 0) return this.size();
+ var tail = this._tail;
+ this._list[tail] = item;
+ this._tail = (tail + 1) & this._capacityMask;
+ if (this._tail === this._head) {
+ this._growArray();
+ }
+ if (this._capacity && this.size() > this._capacity) {
+ this.shift();
+ }
+ if (this._head < this._tail) return this._tail - this._head;
+ else return this._capacityMask + 1 - (this._head - this._tail);
+};
+
+/**
+ * Remove and return the last item on the list.
+ * Returns undefined if the list is empty.
+ * @returns {*}
+ */
+Denque.prototype.pop = function pop() {
+ var tail = this._tail;
+ if (tail === this._head) return undefined;
+ var len = this._list.length;
+ this._tail = (tail - 1 + len) & this._capacityMask;
+ var item = this._list[this._tail];
+ this._list[this._tail] = undefined;
+ if (this._head < 2 && tail > 10000 && tail <= len >>> 2) this._shrinkArray();
+ return item;
+};
+
+/**
+ * Remove and return the item at the specified index from the list.
+ * Returns undefined if the list is empty.
+ * @param index
+ * @returns {*}
+ */
+Denque.prototype.removeOne = function removeOne(index) {
+ var i = index;
+ // expect a number or return undefined
+ if ((i !== (i | 0))) {
+ return void 0;
+ }
+ if (this._head === this._tail) return void 0;
+ var size = this.size();
+ var len = this._list.length;
+ if (i >= size || i < -size) return void 0;
+ if (i < 0) i += size;
+ i = (this._head + i) & this._capacityMask;
+ var item = this._list[i];
+ var k;
+ if (index < size / 2) {
+ for (k = index; k > 0; k--) {
+ this._list[i] = this._list[i = (i - 1 + len) & this._capacityMask];
+ }
+ this._list[i] = void 0;
+ this._head = (this._head + 1 + len) & this._capacityMask;
+ } else {
+ for (k = size - 1 - index; k > 0; k--) {
+ this._list[i] = this._list[i = (i + 1 + len) & this._capacityMask];
+ }
+ this._list[i] = void 0;
+ this._tail = (this._tail - 1 + len) & this._capacityMask;
+ }
+ return item;
+};
+
+/**
+ * Remove number of items from the specified index from the list.
+ * Returns array of removed items.
+ * Returns undefined if the list is empty.
+ * @param index
+ * @param count
+ * @returns {array}
+ */
+Denque.prototype.remove = function remove(index, count) {
+ var i = index;
+ var removed;
+ var del_count = count;
+ // expect a number or return undefined
+ if ((i !== (i | 0))) {
+ return void 0;
+ }
+ if (this._head === this._tail) return void 0;
+ var size = this.size();
+ var len = this._list.length;
+ if (i >= size || i < -size || count < 1) return void 0;
+ if (i < 0) i += size;
+ if (count === 1 || !count) {
+ removed = new Array(1);
+ removed[0] = this.removeOne(i);
+ return removed;
+ }
+ if (i === 0 && i + count >= size) {
+ removed = this.toArray();
+ this.clear();
+ return removed;
+ }
+ if (i + count > size) count = size - i;
+ var k;
+ removed = new Array(count);
+ for (k = 0; k < count; k++) {
+ removed[k] = this._list[(this._head + i + k) & this._capacityMask];
+ }
+ i = (this._head + i) & this._capacityMask;
+ if (index + count === size) {
+ this._tail = (this._tail - count + len) & this._capacityMask;
+ for (k = count; k > 0; k--) {
+ this._list[i = (i + 1 + len) & this._capacityMask] = void 0;
+ }
+ return removed;
+ }
+ if (index === 0) {
+ this._head = (this._head + count + len) & this._capacityMask;
+ for (k = count - 1; k > 0; k--) {
+ this._list[i = (i + 1 + len) & this._capacityMask] = void 0;
+ }
+ return removed;
+ }
+ if (i < size / 2) {
+ this._head = (this._head + index + count + len) & this._capacityMask;
+ for (k = index; k > 0; k--) {
+ this.unshift(this._list[i = (i - 1 + len) & this._capacityMask]);
+ }
+ i = (this._head - 1 + len) & this._capacityMask;
+ while (del_count > 0) {
+ this._list[i = (i - 1 + len) & this._capacityMask] = void 0;
+ del_count--;
+ }
+ if (index < 0) this._tail = i;
+ } else {
+ this._tail = i;
+ i = (i + count + len) & this._capacityMask;
+ for (k = size - (count + index); k > 0; k--) {
+ this.push(this._list[i++]);
+ }
+ i = this._tail;
+ while (del_count > 0) {
+ this._list[i = (i + 1 + len) & this._capacityMask] = void 0;
+ del_count--;
+ }
+ }
+ if (this._head < 2 && this._tail > 10000 && this._tail <= len >>> 2) this._shrinkArray();
+ return removed;
+};
+
+/**
+ * Native splice implementation.
+ * Remove number of items from the specified index from the list and/or add new elements.
+ * Returns array of removed items or empty array if count == 0.
+ * Returns undefined if the list is empty.
+ *
+ * @param index
+ * @param count
+ * @param {...*} [elements]
+ * @returns {array}
+ */
+Denque.prototype.splice = function splice(index, count) {
+ var i = index;
+ // expect a number or return undefined
+ if ((i !== (i | 0))) {
+ return void 0;
+ }
+ var size = this.size();
+ if (i < 0) i += size;
+ if (i > size) return void 0;
+ if (arguments.length > 2) {
+ var k;
+ var temp;
+ var removed;
+ var arg_len = arguments.length;
+ var len = this._list.length;
+ var arguments_index = 2;
+ if (!size || i < size / 2) {
+ temp = new Array(i);
+ for (k = 0; k < i; k++) {
+ temp[k] = this._list[(this._head + k) & this._capacityMask];
+ }
+ if (count === 0) {
+ removed = [];
+ if (i > 0) {
+ this._head = (this._head + i + len) & this._capacityMask;
+ }
+ } else {
+ removed = this.remove(i, count);
+ this._head = (this._head + i + len) & this._capacityMask;
+ }
+ while (arg_len > arguments_index) {
+ this.unshift(arguments[--arg_len]);
+ }
+ for (k = i; k > 0; k--) {
+ this.unshift(temp[k - 1]);
+ }
+ } else {
+ temp = new Array(size - (i + count));
+ var leng = temp.length;
+ for (k = 0; k < leng; k++) {
+ temp[k] = this._list[(this._head + i + count + k) & this._capacityMask];
+ }
+ if (count === 0) {
+ removed = [];
+ if (i != size) {
+ this._tail = (this._head + i + len) & this._capacityMask;
+ }
+ } else {
+ removed = this.remove(i, count);
+ this._tail = (this._tail - leng + len) & this._capacityMask;
+ }
+ while (arguments_index < arg_len) {
+ this.push(arguments[arguments_index++]);
+ }
+ for (k = 0; k < leng; k++) {
+ this.push(temp[k]);
+ }
+ }
+ return removed;
+ } else {
+ return this.remove(i, count);
+ }
+};
+
+/**
+ * Soft clear - does not reset capacity.
+ */
+Denque.prototype.clear = function clear() {
+ this._list = new Array(this._list.length);
+ this._head = 0;
+ this._tail = 0;
+};
+
+/**
+ * Returns true or false whether the list is empty.
+ * @returns {boolean}
+ */
+Denque.prototype.isEmpty = function isEmpty() {
+ return this._head === this._tail;
+};
+
+/**
+ * Returns an array of all queue items.
+ * @returns {Array}
+ */
+Denque.prototype.toArray = function toArray() {
+ return this._copyArray(false);
+};
+
+/**
+ * -------------
+ * INTERNALS
+ * -------------
+ */
+
+/**
+ * Fills the queue with items from an array
+ * For use in the constructor
+ * @param array
+ * @private
+ */
+Denque.prototype._fromArray = function _fromArray(array) {
+ var length = array.length;
+ var capacity = this._nextPowerOf2(length);
+
+ this._list = new Array(capacity);
+ this._capacityMask = capacity - 1;
+ this._tail = length;
+
+ for (var i = 0; i < length; i++) this._list[i] = array[i];
+};
+
+/**
+ *
+ * @param fullCopy
+ * @param size Initialize the array with a specific size. Will default to the current list size
+ * @returns {Array}
+ * @private
+ */
+Denque.prototype._copyArray = function _copyArray(fullCopy, size) {
+ var src = this._list;
+ var capacity = src.length;
+ var length = this.length;
+ size = size | length;
+
+ // No prealloc requested and the buffer is contiguous
+ if (size == length && this._head < this._tail) {
+ // Simply do a fast slice copy
+ return this._list.slice(this._head, this._tail);
+ }
+
+ var dest = new Array(size);
+
+ var k = 0;
+ var i;
+ if (fullCopy || this._head > this._tail) {
+ for (i = this._head; i < capacity; i++) dest[k++] = src[i];
+ for (i = 0; i < this._tail; i++) dest[k++] = src[i];
+ } else {
+ for (i = this._head; i < this._tail; i++) dest[k++] = src[i];
+ }
+
+ return dest;
+}
+
+/**
+ * Grows the internal list array.
+ * @private
+ */
+Denque.prototype._growArray = function _growArray() {
+ if (this._head != 0) {
+ // double array size and copy existing data, head to end, then beginning to tail.
+ var newList = this._copyArray(true, this._list.length << 1);
+
+ this._tail = this._list.length;
+ this._head = 0;
+
+ this._list = newList;
+ } else {
+ this._tail = this._list.length;
+ this._list.length <<= 1;
+ }
+
+ this._capacityMask = (this._capacityMask << 1) | 1;
+};
+
+/**
+ * Shrinks the internal list array.
+ * @private
+ */
+Denque.prototype._shrinkArray = function _shrinkArray() {
+ this._list.length >>>= 1;
+ this._capacityMask >>>= 1;
+};
+
+/**
+ * Find the next power of 2, at least 4
+ * @private
+ * @param {number} num
+ * @returns {number}
+ */
+Denque.prototype._nextPowerOf2 = function _nextPowerOf2(num) {
+ var log2 = Math.log(num) / Math.log(2);
+ var nextPow2 = 1 << (log2 + 1);
+
+ return Math.max(nextPow2, 4);
+}
+
+module.exports = Denque;
diff --git a/node_modules/denque/package.json b/node_modules/denque/package.json
new file mode 100644
index 0000000..a635910
--- /dev/null
+++ b/node_modules/denque/package.json
@@ -0,0 +1,58 @@
+{
+ "name": "denque",
+ "version": "2.1.0",
+ "description": "The fastest javascript implementation of a double-ended queue. Used by the official Redis, MongoDB, MariaDB & MySQL libraries for Node.js and many other libraries. Maintains compatability with deque.",
+ "main": "index.js",
+ "engines": {
+ "node": ">=0.10"
+ },
+ "keywords": [
+ "data-structure",
+ "data-structures",
+ "queue",
+ "double",
+ "end",
+ "ended",
+ "deque",
+ "denque",
+ "double-ended-queue"
+ ],
+ "scripts": {
+ "test": "istanbul cover --report lcov _mocha && npm run typescript",
+ "coveralls": "cat ./coverage/lcov.info | coveralls",
+ "typescript": "tsc --project ./test/type/tsconfig.json",
+ "benchmark_thousand": "node benchmark/thousand",
+ "benchmark_2mil": "node benchmark/two_million",
+ "benchmark_splice": "node benchmark/splice",
+ "benchmark_remove": "node benchmark/remove",
+ "benchmark_removeOne": "node benchmark/removeOne",
+ "benchmark_growth": "node benchmark/growth",
+ "benchmark_toArray": "node benchmark/toArray",
+ "benchmark_fromArray": "node benchmark/fromArray"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/invertase/denque.git"
+ },
+ "license": "Apache-2.0",
+ "author": {
+ "name": "Invertase",
+ "email": "oss@invertase.io",
+ "url": "http://github.com/invertase/"
+ },
+ "contributors": [
+ "Mike Diarmid (Salakar) "
+ ],
+ "bugs": {
+ "url": "https://github.com/invertase/denque/issues"
+ },
+ "homepage": "https://docs.page/invertase/denque",
+ "devDependencies": {
+ "benchmark": "^2.1.4",
+ "codecov": "^3.8.3",
+ "double-ended-queue": "^2.1.0-0",
+ "istanbul": "^0.4.5",
+ "mocha": "^3.5.3",
+ "typescript": "^3.4.1"
+ }
+}
diff --git a/node_modules/depd/History.md b/node_modules/depd/History.md
new file mode 100644
index 0000000..cd9ebaa
--- /dev/null
+++ b/node_modules/depd/History.md
@@ -0,0 +1,103 @@
+2.0.0 / 2018-10-26
+==================
+
+ * Drop support for Node.js 0.6
+ * Replace internal `eval` usage with `Function` constructor
+ * Use instance methods on `process` to check for listeners
+
+1.1.2 / 2018-01-11
+==================
+
+ * perf: remove argument reassignment
+ * Support Node.js 0.6 to 9.x
+
+1.1.1 / 2017-07-27
+==================
+
+ * Remove unnecessary `Buffer` loading
+ * Support Node.js 0.6 to 8.x
+
+1.1.0 / 2015-09-14
+==================
+
+ * Enable strict mode in more places
+ * Support io.js 3.x
+ * Support io.js 2.x
+ * Support web browser loading
+ - Requires bundler like Browserify or webpack
+
+1.0.1 / 2015-04-07
+==================
+
+ * Fix `TypeError`s when under `'use strict'` code
+ * Fix useless type name on auto-generated messages
+ * Support io.js 1.x
+ * Support Node.js 0.12
+
+1.0.0 / 2014-09-17
+==================
+
+ * No changes
+
+0.4.5 / 2014-09-09
+==================
+
+ * Improve call speed to functions using the function wrapper
+ * Support Node.js 0.6
+
+0.4.4 / 2014-07-27
+==================
+
+ * Work-around v8 generating empty stack traces
+
+0.4.3 / 2014-07-26
+==================
+
+ * Fix exception when global `Error.stackTraceLimit` is too low
+
+0.4.2 / 2014-07-19
+==================
+
+ * Correct call site for wrapped functions and properties
+
+0.4.1 / 2014-07-19
+==================
+
+ * Improve automatic message generation for function properties
+
+0.4.0 / 2014-07-19
+==================
+
+ * Add `TRACE_DEPRECATION` environment variable
+ * Remove non-standard grey color from color output
+ * Support `--no-deprecation` argument
+ * Support `--trace-deprecation` argument
+ * Support `deprecate.property(fn, prop, message)`
+
+0.3.0 / 2014-06-16
+==================
+
+ * Add `NO_DEPRECATION` environment variable
+
+0.2.0 / 2014-06-15
+==================
+
+ * Add `deprecate.property(obj, prop, message)`
+ * Remove `supports-color` dependency for node.js 0.8
+
+0.1.0 / 2014-06-15
+==================
+
+ * Add `deprecate.function(fn, message)`
+ * Add `process.on('deprecation', fn)` emitter
+ * Automatically generate message when omitted from `deprecate()`
+
+0.0.1 / 2014-06-15
+==================
+
+ * Fix warning for dynamic calls at singe call site
+
+0.0.0 / 2014-06-15
+==================
+
+ * Initial implementation
diff --git a/node_modules/depd/LICENSE b/node_modules/depd/LICENSE
new file mode 100644
index 0000000..248de7a
--- /dev/null
+++ b/node_modules/depd/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2014-2018 Douglas Christopher Wilson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/depd/Readme.md b/node_modules/depd/Readme.md
new file mode 100644
index 0000000..043d1ca
--- /dev/null
+++ b/node_modules/depd/Readme.md
@@ -0,0 +1,280 @@
+# depd
+
+[![NPM Version][npm-version-image]][npm-url]
+[![NPM Downloads][npm-downloads-image]][npm-url]
+[![Node.js Version][node-image]][node-url]
+[![Linux Build][travis-image]][travis-url]
+[![Windows Build][appveyor-image]][appveyor-url]
+[![Coverage Status][coveralls-image]][coveralls-url]
+
+Deprecate all the things
+
+> With great modules comes great responsibility; mark things deprecated!
+
+## Install
+
+This module is installed directly using `npm`:
+
+```sh
+$ npm install depd
+```
+
+This module can also be bundled with systems like
+[Browserify](http://browserify.org/) or [webpack](https://webpack.github.io/),
+though by default this module will alter it's API to no longer display or
+track deprecations.
+
+## API
+
+
+
+```js
+var deprecate = require('depd')('my-module')
+```
+
+This library allows you to display deprecation messages to your users.
+This library goes above and beyond with deprecation warnings by
+introspection of the call stack (but only the bits that it is interested
+in).
+
+Instead of just warning on the first invocation of a deprecated
+function and never again, this module will warn on the first invocation
+of a deprecated function per unique call site, making it ideal to alert
+users of all deprecated uses across the code base, rather than just
+whatever happens to execute first.
+
+The deprecation warnings from this module also include the file and line
+information for the call into the module that the deprecated function was
+in.
+
+**NOTE** this library has a similar interface to the `debug` module, and
+this module uses the calling file to get the boundary for the call stacks,
+so you should always create a new `deprecate` object in each file and not
+within some central file.
+
+### depd(namespace)
+
+Create a new deprecate function that uses the given namespace name in the
+messages and will display the call site prior to the stack entering the
+file this function was called from. It is highly suggested you use the
+name of your module as the namespace.
+
+### deprecate(message)
+
+Call this function from deprecated code to display a deprecation message.
+This message will appear once per unique caller site. Caller site is the
+first call site in the stack in a different file from the caller of this
+function.
+
+If the message is omitted, a message is generated for you based on the site
+of the `deprecate()` call and will display the name of the function called,
+similar to the name displayed in a stack trace.
+
+### deprecate.function(fn, message)
+
+Call this function to wrap a given function in a deprecation message on any
+call to the function. An optional message can be supplied to provide a custom
+message.
+
+### deprecate.property(obj, prop, message)
+
+Call this function to wrap a given property on object in a deprecation message
+on any accessing or setting of the property. An optional message can be supplied
+to provide a custom message.
+
+The method must be called on the object where the property belongs (not
+inherited from the prototype).
+
+If the property is a data descriptor, it will be converted to an accessor
+descriptor in order to display the deprecation message.
+
+### process.on('deprecation', fn)
+
+This module will allow easy capturing of deprecation errors by emitting the
+errors as the type "deprecation" on the global `process`. If there are no
+listeners for this type, the errors are written to STDERR as normal, but if
+there are any listeners, nothing will be written to STDERR and instead only
+emitted. From there, you can write the errors in a different format or to a
+logging source.
+
+The error represents the deprecation and is emitted only once with the same
+rules as writing to STDERR. The error has the following properties:
+
+ - `message` - This is the message given by the library
+ - `name` - This is always `'DeprecationError'`
+ - `namespace` - This is the namespace the deprecation came from
+ - `stack` - This is the stack of the call to the deprecated thing
+
+Example `error.stack` output:
+
+```
+DeprecationError: my-cool-module deprecated oldfunction
+ at Object. ([eval]-wrapper:6:22)
+ at Module._compile (module.js:456:26)
+ at evalScript (node.js:532:25)
+ at startup (node.js:80:7)
+ at node.js:902:3
+```
+
+### process.env.NO_DEPRECATION
+
+As a user of modules that are deprecated, the environment variable `NO_DEPRECATION`
+is provided as a quick solution to silencing deprecation warnings from being
+output. The format of this is similar to that of `DEBUG`:
+
+```sh
+$ NO_DEPRECATION=my-module,othermod node app.js
+```
+
+This will suppress deprecations from being output for "my-module" and "othermod".
+The value is a list of comma-separated namespaces. To suppress every warning
+across all namespaces, use the value `*` for a namespace.
+
+Providing the argument `--no-deprecation` to the `node` executable will suppress
+all deprecations (only available in Node.js 0.8 or higher).
+
+**NOTE** This will not suppress the deperecations given to any "deprecation"
+event listeners, just the output to STDERR.
+
+### process.env.TRACE_DEPRECATION
+
+As a user of modules that are deprecated, the environment variable `TRACE_DEPRECATION`
+is provided as a solution to getting more detailed location information in deprecation
+warnings by including the entire stack trace. The format of this is the same as
+`NO_DEPRECATION`:
+
+```sh
+$ TRACE_DEPRECATION=my-module,othermod node app.js
+```
+
+This will include stack traces for deprecations being output for "my-module" and
+"othermod". The value is a list of comma-separated namespaces. To trace every
+warning across all namespaces, use the value `*` for a namespace.
+
+Providing the argument `--trace-deprecation` to the `node` executable will trace
+all deprecations (only available in Node.js 0.8 or higher).
+
+**NOTE** This will not trace the deperecations silenced by `NO_DEPRECATION`.
+
+## Display
+
+
+
+When a user calls a function in your library that you mark deprecated, they
+will see the following written to STDERR (in the given colors, similar colors
+and layout to the `debug` module):
+
+```
+bright cyan bright yellow
+| | reset cyan
+| | | |
+▼ ▼ ▼ ▼
+my-cool-module deprecated oldfunction [eval]-wrapper:6:22
+▲ ▲ ▲ ▲
+| | | |
+namespace | | location of mycoolmod.oldfunction() call
+ | deprecation message
+ the word "deprecated"
+```
+
+If the user redirects their STDERR to a file or somewhere that does not support
+colors, they see (similar layout to the `debug` module):
+
+```
+Sun, 15 Jun 2014 05:21:37 GMT my-cool-module deprecated oldfunction at [eval]-wrapper:6:22
+▲ ▲ ▲ ▲ ▲
+| | | | |
+timestamp of message namespace | | location of mycoolmod.oldfunction() call
+ | deprecation message
+ the word "deprecated"
+```
+
+## Examples
+
+### Deprecating all calls to a function
+
+This will display a deprecated message about "oldfunction" being deprecated
+from "my-module" on STDERR.
+
+```js
+var deprecate = require('depd')('my-cool-module')
+
+// message automatically derived from function name
+// Object.oldfunction
+exports.oldfunction = deprecate.function(function oldfunction () {
+ // all calls to function are deprecated
+})
+
+// specific message
+exports.oldfunction = deprecate.function(function () {
+ // all calls to function are deprecated
+}, 'oldfunction')
+```
+
+### Conditionally deprecating a function call
+
+This will display a deprecated message about "weirdfunction" being deprecated
+from "my-module" on STDERR when called with less than 2 arguments.
+
+```js
+var deprecate = require('depd')('my-cool-module')
+
+exports.weirdfunction = function () {
+ if (arguments.length < 2) {
+ // calls with 0 or 1 args are deprecated
+ deprecate('weirdfunction args < 2')
+ }
+}
+```
+
+When calling `deprecate` as a function, the warning is counted per call site
+within your own module, so you can display different deprecations depending
+on different situations and the users will still get all the warnings:
+
+```js
+var deprecate = require('depd')('my-cool-module')
+
+exports.weirdfunction = function () {
+ if (arguments.length < 2) {
+ // calls with 0 or 1 args are deprecated
+ deprecate('weirdfunction args < 2')
+ } else if (typeof arguments[0] !== 'string') {
+ // calls with non-string first argument are deprecated
+ deprecate('weirdfunction non-string first arg')
+ }
+}
+```
+
+### Deprecating property access
+
+This will display a deprecated message about "oldprop" being deprecated
+from "my-module" on STDERR when accessed. A deprecation will be displayed
+when setting the value and when getting the value.
+
+```js
+var deprecate = require('depd')('my-cool-module')
+
+exports.oldprop = 'something'
+
+// message automatically derives from property name
+deprecate.property(exports, 'oldprop')
+
+// explicit message
+deprecate.property(exports, 'oldprop', 'oldprop >= 0.10')
+```
+
+## License
+
+[MIT](LICENSE)
+
+[appveyor-image]: https://badgen.net/appveyor/ci/dougwilson/nodejs-depd/master?label=windows
+[appveyor-url]: https://ci.appveyor.com/project/dougwilson/nodejs-depd
+[coveralls-image]: https://badgen.net/coveralls/c/github/dougwilson/nodejs-depd/master
+[coveralls-url]: https://coveralls.io/r/dougwilson/nodejs-depd?branch=master
+[node-image]: https://badgen.net/npm/node/depd
+[node-url]: https://nodejs.org/en/download/
+[npm-downloads-image]: https://badgen.net/npm/dm/depd
+[npm-url]: https://npmjs.org/package/depd
+[npm-version-image]: https://badgen.net/npm/v/depd
+[travis-image]: https://badgen.net/travis/dougwilson/nodejs-depd/master?label=linux
+[travis-url]: https://travis-ci.org/dougwilson/nodejs-depd
diff --git a/node_modules/depd/index.js b/node_modules/depd/index.js
new file mode 100644
index 0000000..1bf2fcf
--- /dev/null
+++ b/node_modules/depd/index.js
@@ -0,0 +1,538 @@
+/*!
+ * depd
+ * Copyright(c) 2014-2018 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var relative = require('path').relative
+
+/**
+ * Module exports.
+ */
+
+module.exports = depd
+
+/**
+ * Get the path to base files on.
+ */
+
+var basePath = process.cwd()
+
+/**
+ * Determine if namespace is contained in the string.
+ */
+
+function containsNamespace (str, namespace) {
+ var vals = str.split(/[ ,]+/)
+ var ns = String(namespace).toLowerCase()
+
+ for (var i = 0; i < vals.length; i++) {
+ var val = vals[i]
+
+ // namespace contained
+ if (val && (val === '*' || val.toLowerCase() === ns)) {
+ return true
+ }
+ }
+
+ return false
+}
+
+/**
+ * Convert a data descriptor to accessor descriptor.
+ */
+
+function convertDataDescriptorToAccessor (obj, prop, message) {
+ var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
+ var value = descriptor.value
+
+ descriptor.get = function getter () { return value }
+
+ if (descriptor.writable) {
+ descriptor.set = function setter (val) { return (value = val) }
+ }
+
+ delete descriptor.value
+ delete descriptor.writable
+
+ Object.defineProperty(obj, prop, descriptor)
+
+ return descriptor
+}
+
+/**
+ * Create arguments string to keep arity.
+ */
+
+function createArgumentsString (arity) {
+ var str = ''
+
+ for (var i = 0; i < arity; i++) {
+ str += ', arg' + i
+ }
+
+ return str.substr(2)
+}
+
+/**
+ * Create stack string from stack.
+ */
+
+function createStackString (stack) {
+ var str = this.name + ': ' + this.namespace
+
+ if (this.message) {
+ str += ' deprecated ' + this.message
+ }
+
+ for (var i = 0; i < stack.length; i++) {
+ str += '\n at ' + stack[i].toString()
+ }
+
+ return str
+}
+
+/**
+ * Create deprecate for namespace in caller.
+ */
+
+function depd (namespace) {
+ if (!namespace) {
+ throw new TypeError('argument namespace is required')
+ }
+
+ var stack = getStack()
+ var site = callSiteLocation(stack[1])
+ var file = site[0]
+
+ function deprecate (message) {
+ // call to self as log
+ log.call(deprecate, message)
+ }
+
+ deprecate._file = file
+ deprecate._ignored = isignored(namespace)
+ deprecate._namespace = namespace
+ deprecate._traced = istraced(namespace)
+ deprecate._warned = Object.create(null)
+
+ deprecate.function = wrapfunction
+ deprecate.property = wrapproperty
+
+ return deprecate
+}
+
+/**
+ * Determine if event emitter has listeners of a given type.
+ *
+ * The way to do this check is done three different ways in Node.js >= 0.8
+ * so this consolidates them into a minimal set using instance methods.
+ *
+ * @param {EventEmitter} emitter
+ * @param {string} type
+ * @returns {boolean}
+ * @private
+ */
+
+function eehaslisteners (emitter, type) {
+ var count = typeof emitter.listenerCount !== 'function'
+ ? emitter.listeners(type).length
+ : emitter.listenerCount(type)
+
+ return count > 0
+}
+
+/**
+ * Determine if namespace is ignored.
+ */
+
+function isignored (namespace) {
+ if (process.noDeprecation) {
+ // --no-deprecation support
+ return true
+ }
+
+ var str = process.env.NO_DEPRECATION || ''
+
+ // namespace ignored
+ return containsNamespace(str, namespace)
+}
+
+/**
+ * Determine if namespace is traced.
+ */
+
+function istraced (namespace) {
+ if (process.traceDeprecation) {
+ // --trace-deprecation support
+ return true
+ }
+
+ var str = process.env.TRACE_DEPRECATION || ''
+
+ // namespace traced
+ return containsNamespace(str, namespace)
+}
+
+/**
+ * Display deprecation message.
+ */
+
+function log (message, site) {
+ var haslisteners = eehaslisteners(process, 'deprecation')
+
+ // abort early if no destination
+ if (!haslisteners && this._ignored) {
+ return
+ }
+
+ var caller
+ var callFile
+ var callSite
+ var depSite
+ var i = 0
+ var seen = false
+ var stack = getStack()
+ var file = this._file
+
+ if (site) {
+ // provided site
+ depSite = site
+ callSite = callSiteLocation(stack[1])
+ callSite.name = depSite.name
+ file = callSite[0]
+ } else {
+ // get call site
+ i = 2
+ depSite = callSiteLocation(stack[i])
+ callSite = depSite
+ }
+
+ // get caller of deprecated thing in relation to file
+ for (; i < stack.length; i++) {
+ caller = callSiteLocation(stack[i])
+ callFile = caller[0]
+
+ if (callFile === file) {
+ seen = true
+ } else if (callFile === this._file) {
+ file = this._file
+ } else if (seen) {
+ break
+ }
+ }
+
+ var key = caller
+ ? depSite.join(':') + '__' + caller.join(':')
+ : undefined
+
+ if (key !== undefined && key in this._warned) {
+ // already warned
+ return
+ }
+
+ this._warned[key] = true
+
+ // generate automatic message from call site
+ var msg = message
+ if (!msg) {
+ msg = callSite === depSite || !callSite.name
+ ? defaultMessage(depSite)
+ : defaultMessage(callSite)
+ }
+
+ // emit deprecation if listeners exist
+ if (haslisteners) {
+ var err = DeprecationError(this._namespace, msg, stack.slice(i))
+ process.emit('deprecation', err)
+ return
+ }
+
+ // format and write message
+ var format = process.stderr.isTTY
+ ? formatColor
+ : formatPlain
+ var output = format.call(this, msg, caller, stack.slice(i))
+ process.stderr.write(output + '\n', 'utf8')
+}
+
+/**
+ * Get call site location as array.
+ */
+
+function callSiteLocation (callSite) {
+ var file = callSite.getFileName() || ''
+ var line = callSite.getLineNumber()
+ var colm = callSite.getColumnNumber()
+
+ if (callSite.isEval()) {
+ file = callSite.getEvalOrigin() + ', ' + file
+ }
+
+ var site = [file, line, colm]
+
+ site.callSite = callSite
+ site.name = callSite.getFunctionName()
+
+ return site
+}
+
+/**
+ * Generate a default message from the site.
+ */
+
+function defaultMessage (site) {
+ var callSite = site.callSite
+ var funcName = site.name
+
+ // make useful anonymous name
+ if (!funcName) {
+ funcName = ''
+ }
+
+ var context = callSite.getThis()
+ var typeName = context && callSite.getTypeName()
+
+ // ignore useless type name
+ if (typeName === 'Object') {
+ typeName = undefined
+ }
+
+ // make useful type name
+ if (typeName === 'Function') {
+ typeName = context.name || typeName
+ }
+
+ return typeName && callSite.getMethodName()
+ ? typeName + '.' + funcName
+ : funcName
+}
+
+/**
+ * Format deprecation message without color.
+ */
+
+function formatPlain (msg, caller, stack) {
+ var timestamp = new Date().toUTCString()
+
+ var formatted = timestamp +
+ ' ' + this._namespace +
+ ' deprecated ' + msg
+
+ // add stack trace
+ if (this._traced) {
+ for (var i = 0; i < stack.length; i++) {
+ formatted += '\n at ' + stack[i].toString()
+ }
+
+ return formatted
+ }
+
+ if (caller) {
+ formatted += ' at ' + formatLocation(caller)
+ }
+
+ return formatted
+}
+
+/**
+ * Format deprecation message with color.
+ */
+
+function formatColor (msg, caller, stack) {
+ var formatted = '\x1b[36;1m' + this._namespace + '\x1b[22;39m' + // bold cyan
+ ' \x1b[33;1mdeprecated\x1b[22;39m' + // bold yellow
+ ' \x1b[0m' + msg + '\x1b[39m' // reset
+
+ // add stack trace
+ if (this._traced) {
+ for (var i = 0; i < stack.length; i++) {
+ formatted += '\n \x1b[36mat ' + stack[i].toString() + '\x1b[39m' // cyan
+ }
+
+ return formatted
+ }
+
+ if (caller) {
+ formatted += ' \x1b[36m' + formatLocation(caller) + '\x1b[39m' // cyan
+ }
+
+ return formatted
+}
+
+/**
+ * Format call site location.
+ */
+
+function formatLocation (callSite) {
+ return relative(basePath, callSite[0]) +
+ ':' + callSite[1] +
+ ':' + callSite[2]
+}
+
+/**
+ * Get the stack as array of call sites.
+ */
+
+function getStack () {
+ var limit = Error.stackTraceLimit
+ var obj = {}
+ var prep = Error.prepareStackTrace
+
+ Error.prepareStackTrace = prepareObjectStackTrace
+ Error.stackTraceLimit = Math.max(10, limit)
+
+ // capture the stack
+ Error.captureStackTrace(obj)
+
+ // slice this function off the top
+ var stack = obj.stack.slice(1)
+
+ Error.prepareStackTrace = prep
+ Error.stackTraceLimit = limit
+
+ return stack
+}
+
+/**
+ * Capture call site stack from v8.
+ */
+
+function prepareObjectStackTrace (obj, stack) {
+ return stack
+}
+
+/**
+ * Return a wrapped function in a deprecation message.
+ */
+
+function wrapfunction (fn, message) {
+ if (typeof fn !== 'function') {
+ throw new TypeError('argument fn must be a function')
+ }
+
+ var args = createArgumentsString(fn.length)
+ var stack = getStack()
+ var site = callSiteLocation(stack[1])
+
+ site.name = fn.name
+
+ // eslint-disable-next-line no-new-func
+ var deprecatedfn = new Function('fn', 'log', 'deprecate', 'message', 'site',
+ '"use strict"\n' +
+ 'return function (' + args + ') {' +
+ 'log.call(deprecate, message, site)\n' +
+ 'return fn.apply(this, arguments)\n' +
+ '}')(fn, log, this, message, site)
+
+ return deprecatedfn
+}
+
+/**
+ * Wrap property in a deprecation message.
+ */
+
+function wrapproperty (obj, prop, message) {
+ if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) {
+ throw new TypeError('argument obj must be object')
+ }
+
+ var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
+
+ if (!descriptor) {
+ throw new TypeError('must call property on owner object')
+ }
+
+ if (!descriptor.configurable) {
+ throw new TypeError('property must be configurable')
+ }
+
+ var deprecate = this
+ var stack = getStack()
+ var site = callSiteLocation(stack[1])
+
+ // set site name
+ site.name = prop
+
+ // convert data descriptor
+ if ('value' in descriptor) {
+ descriptor = convertDataDescriptorToAccessor(obj, prop, message)
+ }
+
+ var get = descriptor.get
+ var set = descriptor.set
+
+ // wrap getter
+ if (typeof get === 'function') {
+ descriptor.get = function getter () {
+ log.call(deprecate, message, site)
+ return get.apply(this, arguments)
+ }
+ }
+
+ // wrap setter
+ if (typeof set === 'function') {
+ descriptor.set = function setter () {
+ log.call(deprecate, message, site)
+ return set.apply(this, arguments)
+ }
+ }
+
+ Object.defineProperty(obj, prop, descriptor)
+}
+
+/**
+ * Create DeprecationError for deprecation
+ */
+
+function DeprecationError (namespace, message, stack) {
+ var error = new Error()
+ var stackString
+
+ Object.defineProperty(error, 'constructor', {
+ value: DeprecationError
+ })
+
+ Object.defineProperty(error, 'message', {
+ configurable: true,
+ enumerable: false,
+ value: message,
+ writable: true
+ })
+
+ Object.defineProperty(error, 'name', {
+ enumerable: false,
+ configurable: true,
+ value: 'DeprecationError',
+ writable: true
+ })
+
+ Object.defineProperty(error, 'namespace', {
+ configurable: true,
+ enumerable: false,
+ value: namespace,
+ writable: true
+ })
+
+ Object.defineProperty(error, 'stack', {
+ configurable: true,
+ enumerable: false,
+ get: function () {
+ if (stackString !== undefined) {
+ return stackString
+ }
+
+ // prepare stack trace
+ return (stackString = createStackString.call(this, stack))
+ },
+ set: function setter (val) {
+ stackString = val
+ }
+ })
+
+ return error
+}
diff --git a/node_modules/depd/lib/browser/index.js b/node_modules/depd/lib/browser/index.js
new file mode 100644
index 0000000..6be45cc
--- /dev/null
+++ b/node_modules/depd/lib/browser/index.js
@@ -0,0 +1,77 @@
+/*!
+ * depd
+ * Copyright(c) 2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module exports.
+ * @public
+ */
+
+module.exports = depd
+
+/**
+ * Create deprecate for namespace in caller.
+ */
+
+function depd (namespace) {
+ if (!namespace) {
+ throw new TypeError('argument namespace is required')
+ }
+
+ function deprecate (message) {
+ // no-op in browser
+ }
+
+ deprecate._file = undefined
+ deprecate._ignored = true
+ deprecate._namespace = namespace
+ deprecate._traced = false
+ deprecate._warned = Object.create(null)
+
+ deprecate.function = wrapfunction
+ deprecate.property = wrapproperty
+
+ return deprecate
+}
+
+/**
+ * Return a wrapped function in a deprecation message.
+ *
+ * This is a no-op version of the wrapper, which does nothing but call
+ * validation.
+ */
+
+function wrapfunction (fn, message) {
+ if (typeof fn !== 'function') {
+ throw new TypeError('argument fn must be a function')
+ }
+
+ return fn
+}
+
+/**
+ * Wrap property in a deprecation message.
+ *
+ * This is a no-op version of the wrapper, which does nothing but call
+ * validation.
+ */
+
+function wrapproperty (obj, prop, message) {
+ if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) {
+ throw new TypeError('argument obj must be object')
+ }
+
+ var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
+
+ if (!descriptor) {
+ throw new TypeError('must call property on owner object')
+ }
+
+ if (!descriptor.configurable) {
+ throw new TypeError('property must be configurable')
+ }
+}
diff --git a/node_modules/depd/package.json b/node_modules/depd/package.json
new file mode 100644
index 0000000..3857e19
--- /dev/null
+++ b/node_modules/depd/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "depd",
+ "description": "Deprecate all the things",
+ "version": "2.0.0",
+ "author": "Douglas Christopher Wilson ",
+ "license": "MIT",
+ "keywords": [
+ "deprecate",
+ "deprecated"
+ ],
+ "repository": "dougwilson/nodejs-depd",
+ "browser": "lib/browser/index.js",
+ "devDependencies": {
+ "benchmark": "2.1.4",
+ "beautify-benchmark": "0.2.4",
+ "eslint": "5.7.0",
+ "eslint-config-standard": "12.0.0",
+ "eslint-plugin-import": "2.14.0",
+ "eslint-plugin-markdown": "1.0.0-beta.7",
+ "eslint-plugin-node": "7.0.1",
+ "eslint-plugin-promise": "4.0.1",
+ "eslint-plugin-standard": "4.0.0",
+ "istanbul": "0.4.5",
+ "mocha": "5.2.0",
+ "safe-buffer": "5.1.2",
+ "uid-safe": "2.1.5"
+ },
+ "files": [
+ "lib/",
+ "History.md",
+ "LICENSE",
+ "index.js",
+ "Readme.md"
+ ],
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "scripts": {
+ "bench": "node benchmark/index.js",
+ "lint": "eslint --plugin markdown --ext js,md .",
+ "test": "mocha --reporter spec --bail test/",
+ "test-ci": "istanbul cover --print=none node_modules/mocha/bin/_mocha -- --reporter spec test/ && istanbul report lcovonly text-summary",
+ "test-cov": "istanbul cover --print=none node_modules/mocha/bin/_mocha -- --reporter dot test/ && istanbul report lcov text-summary"
+ }
+}
diff --git a/node_modules/destroy/LICENSE b/node_modules/destroy/LICENSE
new file mode 100644
index 0000000..0e2c35f
--- /dev/null
+++ b/node_modules/destroy/LICENSE
@@ -0,0 +1,23 @@
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Jonathan Ong me@jongleberry.com
+Copyright (c) 2015-2022 Douglas Christopher Wilson doug@somethingdoug.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/node_modules/destroy/README.md b/node_modules/destroy/README.md
new file mode 100644
index 0000000..e7701ae
--- /dev/null
+++ b/node_modules/destroy/README.md
@@ -0,0 +1,63 @@
+# destroy
+
+[![NPM version][npm-image]][npm-url]
+[![Build Status][github-actions-ci-image]][github-actions-ci-url]
+[![Test coverage][coveralls-image]][coveralls-url]
+[![License][license-image]][license-url]
+[![Downloads][downloads-image]][downloads-url]
+
+Destroy a stream.
+
+This module is meant to ensure a stream gets destroyed, handling different APIs
+and Node.js bugs.
+
+## API
+
+```js
+var destroy = require('destroy')
+```
+
+### destroy(stream [, suppress])
+
+Destroy the given stream, and optionally suppress any future `error` events.
+
+In most cases, this is identical to a simple `stream.destroy()` call. The rules
+are as follows for a given stream:
+
+ 1. If the `stream` is an instance of `ReadStream`, then call `stream.destroy()`
+ and add a listener to the `open` event to call `stream.close()` if it is
+ fired. This is for a Node.js bug that will leak a file descriptor if
+ `.destroy()` is called before `open`.
+ 2. If the `stream` is an instance of a zlib stream, then call `stream.destroy()`
+ and close the underlying zlib handle if open, otherwise call `stream.close()`.
+ This is for consistency across Node.js versions and a Node.js bug that will
+ leak a native zlib handle.
+ 3. If the `stream` is not an instance of `Stream`, then nothing happens.
+ 4. If the `stream` has a `.destroy()` method, then call it.
+
+The function returns the `stream` passed in as the argument.
+
+## Example
+
+```js
+var destroy = require('destroy')
+
+var fs = require('fs')
+var stream = fs.createReadStream('package.json')
+
+// ... and later
+destroy(stream)
+```
+
+[npm-image]: https://img.shields.io/npm/v/destroy.svg?style=flat-square
+[npm-url]: https://npmjs.org/package/destroy
+[github-tag]: http://img.shields.io/github/tag/stream-utils/destroy.svg?style=flat-square
+[github-url]: https://github.com/stream-utils/destroy/tags
+[coveralls-image]: https://img.shields.io/coveralls/stream-utils/destroy.svg?style=flat-square
+[coveralls-url]: https://coveralls.io/r/stream-utils/destroy?branch=master
+[license-image]: http://img.shields.io/npm/l/destroy.svg?style=flat-square
+[license-url]: LICENSE.md
+[downloads-image]: http://img.shields.io/npm/dm/destroy.svg?style=flat-square
+[downloads-url]: https://npmjs.org/package/destroy
+[github-actions-ci-image]: https://img.shields.io/github/workflow/status/stream-utils/destroy/ci/master?label=ci&style=flat-square
+[github-actions-ci-url]: https://github.com/stream-utils/destroy/actions/workflows/ci.yml
diff --git a/node_modules/destroy/index.js b/node_modules/destroy/index.js
new file mode 100644
index 0000000..7fd5c09
--- /dev/null
+++ b/node_modules/destroy/index.js
@@ -0,0 +1,209 @@
+/*!
+ * destroy
+ * Copyright(c) 2014 Jonathan Ong
+ * Copyright(c) 2015-2022 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var EventEmitter = require('events').EventEmitter
+var ReadStream = require('fs').ReadStream
+var Stream = require('stream')
+var Zlib = require('zlib')
+
+/**
+ * Module exports.
+ * @public
+ */
+
+module.exports = destroy
+
+/**
+ * Destroy the given stream, and optionally suppress any future `error` events.
+ *
+ * @param {object} stream
+ * @param {boolean} suppress
+ * @public
+ */
+
+function destroy (stream, suppress) {
+ if (isFsReadStream(stream)) {
+ destroyReadStream(stream)
+ } else if (isZlibStream(stream)) {
+ destroyZlibStream(stream)
+ } else if (hasDestroy(stream)) {
+ stream.destroy()
+ }
+
+ if (isEventEmitter(stream) && suppress) {
+ stream.removeAllListeners('error')
+ stream.addListener('error', noop)
+ }
+
+ return stream
+}
+
+/**
+ * Destroy a ReadStream.
+ *
+ * @param {object} stream
+ * @private
+ */
+
+function destroyReadStream (stream) {
+ stream.destroy()
+
+ if (typeof stream.close === 'function') {
+ // node.js core bug work-around
+ stream.on('open', onOpenClose)
+ }
+}
+
+/**
+ * Close a Zlib stream.
+ *
+ * Zlib streams below Node.js 4.5.5 have a buggy implementation
+ * of .close() when zlib encountered an error.
+ *
+ * @param {object} stream
+ * @private
+ */
+
+function closeZlibStream (stream) {
+ if (stream._hadError === true) {
+ var prop = stream._binding === null
+ ? '_binding'
+ : '_handle'
+
+ stream[prop] = {
+ close: function () { this[prop] = null }
+ }
+ }
+
+ stream.close()
+}
+
+/**
+ * Destroy a Zlib stream.
+ *
+ * Zlib streams don't have a destroy function in Node.js 6. On top of that
+ * simply calling destroy on a zlib stream in Node.js 8+ will result in a
+ * memory leak. So until that is fixed, we need to call both close AND destroy.
+ *
+ * PR to fix memory leak: https://github.com/nodejs/node/pull/23734
+ *
+ * In Node.js 6+8, it's important that destroy is called before close as the
+ * stream would otherwise emit the error 'zlib binding closed'.
+ *
+ * @param {object} stream
+ * @private
+ */
+
+function destroyZlibStream (stream) {
+ if (typeof stream.destroy === 'function') {
+ // node.js core bug work-around
+ // istanbul ignore if: node.js 0.8
+ if (stream._binding) {
+ // node.js < 0.10.0
+ stream.destroy()
+ if (stream._processing) {
+ stream._needDrain = true
+ stream.once('drain', onDrainClearBinding)
+ } else {
+ stream._binding.clear()
+ }
+ } else if (stream._destroy && stream._destroy !== Stream.Transform.prototype._destroy) {
+ // node.js >= 12, ^11.1.0, ^10.15.1
+ stream.destroy()
+ } else if (stream._destroy && typeof stream.close === 'function') {
+ // node.js 7, 8
+ stream.destroyed = true
+ stream.close()
+ } else {
+ // fallback
+ // istanbul ignore next
+ stream.destroy()
+ }
+ } else if (typeof stream.close === 'function') {
+ // node.js < 8 fallback
+ closeZlibStream(stream)
+ }
+}
+
+/**
+ * Determine if stream has destroy.
+ * @private
+ */
+
+function hasDestroy (stream) {
+ return stream instanceof Stream &&
+ typeof stream.destroy === 'function'
+}
+
+/**
+ * Determine if val is EventEmitter.
+ * @private
+ */
+
+function isEventEmitter (val) {
+ return val instanceof EventEmitter
+}
+
+/**
+ * Determine if stream is fs.ReadStream stream.
+ * @private
+ */
+
+function isFsReadStream (stream) {
+ return stream instanceof ReadStream
+}
+
+/**
+ * Determine if stream is Zlib stream.
+ * @private
+ */
+
+function isZlibStream (stream) {
+ return stream instanceof Zlib.Gzip ||
+ stream instanceof Zlib.Gunzip ||
+ stream instanceof Zlib.Deflate ||
+ stream instanceof Zlib.DeflateRaw ||
+ stream instanceof Zlib.Inflate ||
+ stream instanceof Zlib.InflateRaw ||
+ stream instanceof Zlib.Unzip
+}
+
+/**
+ * No-op function.
+ * @private
+ */
+
+function noop () {}
+
+/**
+ * On drain handler to clear binding.
+ * @private
+ */
+
+// istanbul ignore next: node.js 0.8
+function onDrainClearBinding () {
+ this._binding.clear()
+}
+
+/**
+ * On open handler to close stream.
+ * @private
+ */
+
+function onOpenClose () {
+ if (typeof this.fd === 'number') {
+ // actually close down the fd
+ this.close()
+ }
+}
diff --git a/node_modules/destroy/package.json b/node_modules/destroy/package.json
new file mode 100644
index 0000000..c85e438
--- /dev/null
+++ b/node_modules/destroy/package.json
@@ -0,0 +1,48 @@
+{
+ "name": "destroy",
+ "description": "destroy a stream if possible",
+ "version": "1.2.0",
+ "author": {
+ "name": "Jonathan Ong",
+ "email": "me@jongleberry.com",
+ "url": "http://jongleberry.com",
+ "twitter": "https://twitter.com/jongleberry"
+ },
+ "contributors": [
+ "Douglas Christopher Wilson "
+ ],
+ "license": "MIT",
+ "repository": "stream-utils/destroy",
+ "devDependencies": {
+ "eslint": "7.32.0",
+ "eslint-config-standard": "14.1.1",
+ "eslint-plugin-import": "2.25.4",
+ "eslint-plugin-node": "11.1.0",
+ "eslint-plugin-promise": "5.2.0",
+ "eslint-plugin-standard": "4.1.0",
+ "mocha": "9.2.2",
+ "nyc": "15.1.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ },
+ "scripts": {
+ "lint": "eslint .",
+ "test": "mocha --reporter spec",
+ "test-ci": "nyc --reporter=lcovonly --reporter=text npm test",
+ "test-cov": "nyc --reporter=html --reporter=text npm test"
+ },
+ "files": [
+ "index.js",
+ "LICENSE"
+ ],
+ "keywords": [
+ "stream",
+ "streams",
+ "destroy",
+ "cleanup",
+ "leak",
+ "fd"
+ ]
+}
diff --git a/node_modules/ecdsa-sig-formatter/CODEOWNERS b/node_modules/ecdsa-sig-formatter/CODEOWNERS
new file mode 100644
index 0000000..4451d3d
--- /dev/null
+++ b/node_modules/ecdsa-sig-formatter/CODEOWNERS
@@ -0,0 +1 @@
+* @omsmith
diff --git a/node_modules/ecdsa-sig-formatter/LICENSE b/node_modules/ecdsa-sig-formatter/LICENSE
new file mode 100644
index 0000000..8754ed6
--- /dev/null
+++ b/node_modules/ecdsa-sig-formatter/LICENSE
@@ -0,0 +1,201 @@
+Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2015 D2L Corporation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/node_modules/ecdsa-sig-formatter/README.md b/node_modules/ecdsa-sig-formatter/README.md
new file mode 100644
index 0000000..daa95d6
--- /dev/null
+++ b/node_modules/ecdsa-sig-formatter/README.md
@@ -0,0 +1,65 @@
+# ecdsa-sig-formatter
+
+[](https://travis-ci.org/Brightspace/node-ecdsa-sig-formatter) [](https://coveralls.io/r/Brightspace/node-ecdsa-sig-formatter)
+
+Translate between JOSE and ASN.1/DER encodings for ECDSA signatures
+
+## Install
+```sh
+npm install ecdsa-sig-formatter --save
+```
+
+## Usage
+```js
+var format = require('ecdsa-sig-formatter');
+
+var derSignature = '..'; // asn.1/DER encoded ecdsa signature
+
+var joseSignature = format.derToJose(derSignature);
+
+```
+
+### API
+
+---
+
+#### `.derToJose(Buffer|String signature, String alg)` -> `String`
+
+Convert the ASN.1/DER encoded signature to a JOSE-style concatenated signature.
+Returns a _base64 url_ encoded `String`.
+
+* If _signature_ is a `String`, it should be _base64_ encoded
+* _alg_ must be one of _ES256_, _ES384_ or _ES512_
+
+---
+
+#### `.joseToDer(Buffer|String signature, String alg)` -> `Buffer`
+
+Convert the JOSE-style concatenated signature to an ASN.1/DER encoded
+signature. Returns a `Buffer`
+
+* If _signature_ is a `String`, it should be _base64 url_ encoded
+* _alg_ must be one of _ES256_, _ES384_ or _ES512_
+
+## Contributing
+
+1. **Fork** the repository. Committing directly against this repository is
+ highly discouraged.
+
+2. Make your modifications in a branch, updating and writing new unit tests
+ as necessary in the `spec` directory.
+
+3. Ensure that all tests pass with `npm test`
+
+4. `rebase` your changes against master. *Do not merge*.
+
+5. Submit a pull request to this repository. Wait for tests to run and someone
+ to chime in.
+
+### Code Style
+
+This repository is configured with [EditorConfig][EditorConfig] and
+[ESLint][ESLint] rules.
+
+[EditorConfig]: http://editorconfig.org/
+[ESLint]: http://eslint.org
diff --git a/node_modules/ecdsa-sig-formatter/package.json b/node_modules/ecdsa-sig-formatter/package.json
new file mode 100644
index 0000000..6fb5ebf
--- /dev/null
+++ b/node_modules/ecdsa-sig-formatter/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "ecdsa-sig-formatter",
+ "version": "1.0.11",
+ "description": "Translate ECDSA signatures between ASN.1/DER and JOSE-style concatenation",
+ "main": "src/ecdsa-sig-formatter.js",
+ "scripts": {
+ "check-style": "eslint .",
+ "pretest": "npm run check-style",
+ "test": "istanbul cover --root src _mocha -- spec",
+ "report-cov": "cat ./coverage/lcov.info | coveralls"
+ },
+ "typings": "./src/ecdsa-sig-formatter.d.ts",
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@github.com/Brightspace/node-ecdsa-sig-formatter.git"
+ },
+ "keywords": [
+ "ecdsa",
+ "der",
+ "asn.1",
+ "jwt",
+ "jwa",
+ "jsonwebtoken",
+ "jose"
+ ],
+ "author": "D2L Corporation",
+ "license": "Apache-2.0",
+ "bugs": {
+ "url": "https://github.com/Brightspace/node-ecdsa-sig-formatter/issues"
+ },
+ "homepage": "https://github.com/Brightspace/node-ecdsa-sig-formatter#readme",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "devDependencies": {
+ "bench": "^0.3.6",
+ "chai": "^3.5.0",
+ "coveralls": "^2.11.9",
+ "eslint": "^2.12.0",
+ "eslint-config-brightspace": "^0.2.1",
+ "istanbul": "^0.4.3",
+ "jwk-to-pem": "^1.2.5",
+ "mocha": "^2.5.3",
+ "native-crypto": "^1.7.0"
+ }
+}
diff --git a/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.d.ts b/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.d.ts
new file mode 100644
index 0000000..9693aa0
--- /dev/null
+++ b/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.d.ts
@@ -0,0 +1,17 @@
+///
+
+declare module "ecdsa-sig-formatter" {
+ /**
+ * Convert the ASN.1/DER encoded signature to a JOSE-style concatenated signature. Returns a base64 url encoded String.
+ * If signature is a String, it should be base64 encoded
+ * alg must be one of ES256, ES384 or ES512
+ */
+ export function derToJose(signature: Buffer | string, alg: string): string;
+
+ /**
+ * Convert the JOSE-style concatenated signature to an ASN.1/DER encoded signature. Returns a Buffer
+ * If signature is a String, it should be base64 url encoded
+ * alg must be one of ES256, ES384 or ES512
+ */
+ export function joseToDer(signature: Buffer | string, alg: string): Buffer
+}
diff --git a/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.js b/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.js
new file mode 100644
index 0000000..38eeb9b
--- /dev/null
+++ b/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.js
@@ -0,0 +1,187 @@
+'use strict';
+
+var Buffer = require('safe-buffer').Buffer;
+
+var getParamBytesForAlg = require('./param-bytes-for-alg');
+
+var MAX_OCTET = 0x80,
+ CLASS_UNIVERSAL = 0,
+ PRIMITIVE_BIT = 0x20,
+ TAG_SEQ = 0x10,
+ TAG_INT = 0x02,
+ ENCODED_TAG_SEQ = (TAG_SEQ | PRIMITIVE_BIT) | (CLASS_UNIVERSAL << 6),
+ ENCODED_TAG_INT = TAG_INT | (CLASS_UNIVERSAL << 6);
+
+function base64Url(base64) {
+ return base64
+ .replace(/=/g, '')
+ .replace(/\+/g, '-')
+ .replace(/\//g, '_');
+}
+
+function signatureAsBuffer(signature) {
+ if (Buffer.isBuffer(signature)) {
+ return signature;
+ } else if ('string' === typeof signature) {
+ return Buffer.from(signature, 'base64');
+ }
+
+ throw new TypeError('ECDSA signature must be a Base64 string or a Buffer');
+}
+
+function derToJose(signature, alg) {
+ signature = signatureAsBuffer(signature);
+ var paramBytes = getParamBytesForAlg(alg);
+
+ // the DER encoded param should at most be the param size, plus a padding
+ // zero, since due to being a signed integer
+ var maxEncodedParamLength = paramBytes + 1;
+
+ var inputLength = signature.length;
+
+ var offset = 0;
+ if (signature[offset++] !== ENCODED_TAG_SEQ) {
+ throw new Error('Could not find expected "seq"');
+ }
+
+ var seqLength = signature[offset++];
+ if (seqLength === (MAX_OCTET | 1)) {
+ seqLength = signature[offset++];
+ }
+
+ if (inputLength - offset < seqLength) {
+ throw new Error('"seq" specified length of "' + seqLength + '", only "' + (inputLength - offset) + '" remaining');
+ }
+
+ if (signature[offset++] !== ENCODED_TAG_INT) {
+ throw new Error('Could not find expected "int" for "r"');
+ }
+
+ var rLength = signature[offset++];
+
+ if (inputLength - offset - 2 < rLength) {
+ throw new Error('"r" specified length of "' + rLength + '", only "' + (inputLength - offset - 2) + '" available');
+ }
+
+ if (maxEncodedParamLength < rLength) {
+ throw new Error('"r" specified length of "' + rLength + '", max of "' + maxEncodedParamLength + '" is acceptable');
+ }
+
+ var rOffset = offset;
+ offset += rLength;
+
+ if (signature[offset++] !== ENCODED_TAG_INT) {
+ throw new Error('Could not find expected "int" for "s"');
+ }
+
+ var sLength = signature[offset++];
+
+ if (inputLength - offset !== sLength) {
+ throw new Error('"s" specified length of "' + sLength + '", expected "' + (inputLength - offset) + '"');
+ }
+
+ if (maxEncodedParamLength < sLength) {
+ throw new Error('"s" specified length of "' + sLength + '", max of "' + maxEncodedParamLength + '" is acceptable');
+ }
+
+ var sOffset = offset;
+ offset += sLength;
+
+ if (offset !== inputLength) {
+ throw new Error('Expected to consume entire buffer, but "' + (inputLength - offset) + '" bytes remain');
+ }
+
+ var rPadding = paramBytes - rLength,
+ sPadding = paramBytes - sLength;
+
+ var dst = Buffer.allocUnsafe(rPadding + rLength + sPadding + sLength);
+
+ for (offset = 0; offset < rPadding; ++offset) {
+ dst[offset] = 0;
+ }
+ signature.copy(dst, offset, rOffset + Math.max(-rPadding, 0), rOffset + rLength);
+
+ offset = paramBytes;
+
+ for (var o = offset; offset < o + sPadding; ++offset) {
+ dst[offset] = 0;
+ }
+ signature.copy(dst, offset, sOffset + Math.max(-sPadding, 0), sOffset + sLength);
+
+ dst = dst.toString('base64');
+ dst = base64Url(dst);
+
+ return dst;
+}
+
+function countPadding(buf, start, stop) {
+ var padding = 0;
+ while (start + padding < stop && buf[start + padding] === 0) {
+ ++padding;
+ }
+
+ var needsSign = buf[start + padding] >= MAX_OCTET;
+ if (needsSign) {
+ --padding;
+ }
+
+ return padding;
+}
+
+function joseToDer(signature, alg) {
+ signature = signatureAsBuffer(signature);
+ var paramBytes = getParamBytesForAlg(alg);
+
+ var signatureBytes = signature.length;
+ if (signatureBytes !== paramBytes * 2) {
+ throw new TypeError('"' + alg + '" signatures must be "' + paramBytes * 2 + '" bytes, saw "' + signatureBytes + '"');
+ }
+
+ var rPadding = countPadding(signature, 0, paramBytes);
+ var sPadding = countPadding(signature, paramBytes, signature.length);
+ var rLength = paramBytes - rPadding;
+ var sLength = paramBytes - sPadding;
+
+ var rsBytes = 1 + 1 + rLength + 1 + 1 + sLength;
+
+ var shortLength = rsBytes < MAX_OCTET;
+
+ var dst = Buffer.allocUnsafe((shortLength ? 2 : 3) + rsBytes);
+
+ var offset = 0;
+ dst[offset++] = ENCODED_TAG_SEQ;
+ if (shortLength) {
+ // Bit 8 has value "0"
+ // bits 7-1 give the length.
+ dst[offset++] = rsBytes;
+ } else {
+ // Bit 8 of first octet has value "1"
+ // bits 7-1 give the number of additional length octets.
+ dst[offset++] = MAX_OCTET | 1;
+ // length, base 256
+ dst[offset++] = rsBytes & 0xff;
+ }
+ dst[offset++] = ENCODED_TAG_INT;
+ dst[offset++] = rLength;
+ if (rPadding < 0) {
+ dst[offset++] = 0;
+ offset += signature.copy(dst, offset, 0, paramBytes);
+ } else {
+ offset += signature.copy(dst, offset, rPadding, paramBytes);
+ }
+ dst[offset++] = ENCODED_TAG_INT;
+ dst[offset++] = sLength;
+ if (sPadding < 0) {
+ dst[offset++] = 0;
+ signature.copy(dst, offset, paramBytes);
+ } else {
+ signature.copy(dst, offset, paramBytes + sPadding);
+ }
+
+ return dst;
+}
+
+module.exports = {
+ derToJose: derToJose,
+ joseToDer: joseToDer
+};
diff --git a/node_modules/ecdsa-sig-formatter/src/param-bytes-for-alg.js b/node_modules/ecdsa-sig-formatter/src/param-bytes-for-alg.js
new file mode 100644
index 0000000..9fe67ac
--- /dev/null
+++ b/node_modules/ecdsa-sig-formatter/src/param-bytes-for-alg.js
@@ -0,0 +1,23 @@
+'use strict';
+
+function getParamSize(keySize) {
+ var result = ((keySize / 8) | 0) + (keySize % 8 === 0 ? 0 : 1);
+ return result;
+}
+
+var paramBytesForAlg = {
+ ES256: getParamSize(256),
+ ES384: getParamSize(384),
+ ES512: getParamSize(521)
+};
+
+function getParamBytesForAlg(alg) {
+ var paramBytes = paramBytesForAlg[alg];
+ if (paramBytes) {
+ return paramBytes;
+ }
+
+ throw new Error('Unknown algorithm "' + alg + '"');
+}
+
+module.exports = getParamBytesForAlg;
diff --git a/node_modules/ee-first/LICENSE b/node_modules/ee-first/LICENSE
new file mode 100644
index 0000000..a7ae8ee
--- /dev/null
+++ b/node_modules/ee-first/LICENSE
@@ -0,0 +1,22 @@
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Jonathan Ong me@jongleberry.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/node_modules/ee-first/README.md b/node_modules/ee-first/README.md
new file mode 100644
index 0000000..cbd2478
--- /dev/null
+++ b/node_modules/ee-first/README.md
@@ -0,0 +1,80 @@
+# EE First
+
+[![NPM version][npm-image]][npm-url]
+[![Build status][travis-image]][travis-url]
+[![Test coverage][coveralls-image]][coveralls-url]
+[![License][license-image]][license-url]
+[![Downloads][downloads-image]][downloads-url]
+[![Gittip][gittip-image]][gittip-url]
+
+Get the first event in a set of event emitters and event pairs,
+then clean up after itself.
+
+## Install
+
+```sh
+$ npm install ee-first
+```
+
+## API
+
+```js
+var first = require('ee-first')
+```
+
+### first(arr, listener)
+
+Invoke `listener` on the first event from the list specified in `arr`. `arr` is
+an array of arrays, with each array in the format `[ee, ...event]`. `listener`
+will be called only once, the first time any of the given events are emitted. If
+`error` is one of the listened events, then if that fires first, the `listener`
+will be given the `err` argument.
+
+The `listener` is invoked as `listener(err, ee, event, args)`, where `err` is the
+first argument emitted from an `error` event, if applicable; `ee` is the event
+emitter that fired; `event` is the string event name that fired; and `args` is an
+array of the arguments that were emitted on the event.
+
+```js
+var ee1 = new EventEmitter()
+var ee2 = new EventEmitter()
+
+first([
+ [ee1, 'close', 'end', 'error'],
+ [ee2, 'error']
+], function (err, ee, event, args) {
+ // listener invoked
+})
+```
+
+#### .cancel()
+
+The group of listeners can be cancelled before being invoked and have all the event
+listeners removed from the underlying event emitters.
+
+```js
+var thunk = first([
+ [ee1, 'close', 'end', 'error'],
+ [ee2, 'error']
+], function (err, ee, event, args) {
+ // listener invoked
+})
+
+// cancel and clean up
+thunk.cancel()
+```
+
+[npm-image]: https://img.shields.io/npm/v/ee-first.svg?style=flat-square
+[npm-url]: https://npmjs.org/package/ee-first
+[github-tag]: http://img.shields.io/github/tag/jonathanong/ee-first.svg?style=flat-square
+[github-url]: https://github.com/jonathanong/ee-first/tags
+[travis-image]: https://img.shields.io/travis/jonathanong/ee-first.svg?style=flat-square
+[travis-url]: https://travis-ci.org/jonathanong/ee-first
+[coveralls-image]: https://img.shields.io/coveralls/jonathanong/ee-first.svg?style=flat-square
+[coveralls-url]: https://coveralls.io/r/jonathanong/ee-first?branch=master
+[license-image]: http://img.shields.io/npm/l/ee-first.svg?style=flat-square
+[license-url]: LICENSE.md
+[downloads-image]: http://img.shields.io/npm/dm/ee-first.svg?style=flat-square
+[downloads-url]: https://npmjs.org/package/ee-first
+[gittip-image]: https://img.shields.io/gittip/jonathanong.svg?style=flat-square
+[gittip-url]: https://www.gittip.com/jonathanong/
diff --git a/node_modules/ee-first/index.js b/node_modules/ee-first/index.js
new file mode 100644
index 0000000..501287c
--- /dev/null
+++ b/node_modules/ee-first/index.js
@@ -0,0 +1,95 @@
+/*!
+ * ee-first
+ * Copyright(c) 2014 Jonathan Ong
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module exports.
+ * @public
+ */
+
+module.exports = first
+
+/**
+ * Get the first event in a set of event emitters and event pairs.
+ *
+ * @param {array} stuff
+ * @param {function} done
+ * @public
+ */
+
+function first(stuff, done) {
+ if (!Array.isArray(stuff))
+ throw new TypeError('arg must be an array of [ee, events...] arrays')
+
+ var cleanups = []
+
+ for (var i = 0; i < stuff.length; i++) {
+ var arr = stuff[i]
+
+ if (!Array.isArray(arr) || arr.length < 2)
+ throw new TypeError('each array member must be [ee, events...]')
+
+ var ee = arr[0]
+
+ for (var j = 1; j < arr.length; j++) {
+ var event = arr[j]
+ var fn = listener(event, callback)
+
+ // listen to the event
+ ee.on(event, fn)
+ // push this listener to the list of cleanups
+ cleanups.push({
+ ee: ee,
+ event: event,
+ fn: fn,
+ })
+ }
+ }
+
+ function callback() {
+ cleanup()
+ done.apply(null, arguments)
+ }
+
+ function cleanup() {
+ var x
+ for (var i = 0; i < cleanups.length; i++) {
+ x = cleanups[i]
+ x.ee.removeListener(x.event, x.fn)
+ }
+ }
+
+ function thunk(fn) {
+ done = fn
+ }
+
+ thunk.cancel = cleanup
+
+ return thunk
+}
+
+/**
+ * Create the event listener.
+ * @private
+ */
+
+function listener(event, done) {
+ return function onevent(arg1) {
+ var args = new Array(arguments.length)
+ var ee = this
+ var err = event === 'error'
+ ? arg1
+ : null
+
+ // copy args to prevent arguments escaping scope
+ for (var i = 0; i < args.length; i++) {
+ args[i] = arguments[i]
+ }
+
+ done(err, ee, event, args)
+ }
+}
diff --git a/node_modules/ee-first/package.json b/node_modules/ee-first/package.json
new file mode 100644
index 0000000..b6d0b7d
--- /dev/null
+++ b/node_modules/ee-first/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "ee-first",
+ "description": "return the first event in a set of ee/event pairs",
+ "version": "1.1.1",
+ "author": {
+ "name": "Jonathan Ong",
+ "email": "me@jongleberry.com",
+ "url": "http://jongleberry.com",
+ "twitter": "https://twitter.com/jongleberry"
+ },
+ "contributors": [
+ "Douglas Christopher Wilson "
+ ],
+ "license": "MIT",
+ "repository": "jonathanong/ee-first",
+ "devDependencies": {
+ "istanbul": "0.3.9",
+ "mocha": "2.2.5"
+ },
+ "files": [
+ "index.js",
+ "LICENSE"
+ ],
+ "scripts": {
+ "test": "mocha --reporter spec --bail --check-leaks test/",
+ "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
+ "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
+ }
+}
diff --git a/node_modules/encodeurl/LICENSE b/node_modules/encodeurl/LICENSE
new file mode 100644
index 0000000..8812229
--- /dev/null
+++ b/node_modules/encodeurl/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2016 Douglas Christopher Wilson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/encodeurl/README.md b/node_modules/encodeurl/README.md
new file mode 100644
index 0000000..3842493
--- /dev/null
+++ b/node_modules/encodeurl/README.md
@@ -0,0 +1,109 @@
+# Encode URL
+
+Encode a URL to a percent-encoded form, excluding already-encoded sequences.
+
+## Installation
+
+```sh
+npm install encodeurl
+```
+
+## API
+
+```js
+var encodeUrl = require('encodeurl')
+```
+
+### encodeUrl(url)
+
+Encode a URL to a percent-encoded form, excluding already-encoded sequences.
+
+This function accepts a URL and encodes all the non-URL code points (as UTF-8 byte sequences). It will not encode the "%" character unless it is not part of a valid sequence (`%20` will be left as-is, but `%foo` will be encoded as `%25foo`).
+
+This encode is meant to be "safe" and does not throw errors. It will try as hard as it can to properly encode the given URL, including replacing any raw, unpaired surrogate pairs with the Unicode replacement character prior to encoding.
+
+## Examples
+
+### Encode a URL containing user-controlled data
+
+```js
+var encodeUrl = require('encodeurl')
+var escapeHtml = require('escape-html')
+
+http.createServer(function onRequest (req, res) {
+ // get encoded form of inbound url
+ var url = encodeUrl(req.url)
+
+ // create html message
+ var body = '
Location ' + escapeHtml(url) + ' not found
'
+
+ // send a 404
+ res.statusCode = 404
+ res.setHeader('Content-Type', 'text/html; charset=UTF-8')
+ res.setHeader('Content-Length', String(Buffer.byteLength(body, 'utf-8')))
+ res.end(body, 'utf-8')
+})
+```
+
+### Encode a URL for use in a header field
+
+```js
+var encodeUrl = require('encodeurl')
+var escapeHtml = require('escape-html')
+var url = require('url')
+
+http.createServer(function onRequest (req, res) {
+ // parse inbound url
+ var href = url.parse(req)
+
+ // set new host for redirect
+ href.host = 'localhost'
+ href.protocol = 'https:'
+ href.slashes = true
+
+ // create location header
+ var location = encodeUrl(url.format(href))
+
+ // create html message
+ var body = '
Redirecting to new site: ' + escapeHtml(location) + '
'
+
+ // send a 301
+ res.statusCode = 301
+ res.setHeader('Content-Type', 'text/html; charset=UTF-8')
+ res.setHeader('Content-Length', String(Buffer.byteLength(body, 'utf-8')))
+ res.setHeader('Location', location)
+ res.end(body, 'utf-8')
+})
+```
+
+## Similarities
+
+This function is _similar_ to the intrinsic function `encodeURI`. However, it will not encode:
+
+* The `\`, `^`, or `|` characters
+* The `%` character when it's part of a valid sequence
+* `[` and `]` (for IPv6 hostnames)
+* Replaces raw, unpaired surrogate pairs with the Unicode replacement character
+
+As a result, the encoding aligns closely with the behavior in the [WHATWG URL specification][whatwg-url]. However, this package only encodes strings and does not do any URL parsing or formatting.
+
+It is expected that any output from `new URL(url)` will not change when used with this package, as the output has already been encoded. Additionally, if we were to encode before `new URL(url)`, we do not expect the before and after encoded formats to be parsed any differently.
+
+## Testing
+
+```sh
+$ npm test
+$ npm run lint
+```
+
+## References
+
+- [RFC 3986: Uniform Resource Identifier (URI): Generic Syntax][rfc-3986]
+- [WHATWG URL Living Standard][whatwg-url]
+
+[rfc-3986]: https://tools.ietf.org/html/rfc3986
+[whatwg-url]: https://url.spec.whatwg.org/
+
+## License
+
+[MIT](LICENSE)
diff --git a/node_modules/encodeurl/index.js b/node_modules/encodeurl/index.js
new file mode 100644
index 0000000..a49ee5a
--- /dev/null
+++ b/node_modules/encodeurl/index.js
@@ -0,0 +1,60 @@
+/*!
+ * encodeurl
+ * Copyright(c) 2016 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module exports.
+ * @public
+ */
+
+module.exports = encodeUrl
+
+/**
+ * RegExp to match non-URL code points, *after* encoding (i.e. not including "%")
+ * and including invalid escape sequences.
+ * @private
+ */
+
+var ENCODE_CHARS_REGEXP = /(?:[^\x21\x23-\x3B\x3D\x3F-\x5F\x61-\x7A\x7C\x7E]|%(?:[^0-9A-Fa-f]|[0-9A-Fa-f][^0-9A-Fa-f]|$))+/g
+
+/**
+ * RegExp to match unmatched surrogate pair.
+ * @private
+ */
+
+var UNMATCHED_SURROGATE_PAIR_REGEXP = /(^|[^\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uD800-\uDBFF]([^\uDC00-\uDFFF]|$)/g
+
+/**
+ * String to replace unmatched surrogate pair with.
+ * @private
+ */
+
+var UNMATCHED_SURROGATE_PAIR_REPLACE = '$1\uFFFD$2'
+
+/**
+ * Encode a URL to a percent-encoded form, excluding already-encoded sequences.
+ *
+ * This function will take an already-encoded URL and encode all the non-URL
+ * code points. This function will not encode the "%" character unless it is
+ * not part of a valid sequence (`%20` will be left as-is, but `%foo` will
+ * be encoded as `%25foo`).
+ *
+ * This encode is meant to be "safe" and does not throw errors. It will try as
+ * hard as it can to properly encode the given URL, including replacing any raw,
+ * unpaired surrogate pairs with the Unicode replacement character prior to
+ * encoding.
+ *
+ * @param {string} url
+ * @return {string}
+ * @public
+ */
+
+function encodeUrl (url) {
+ return String(url)
+ .replace(UNMATCHED_SURROGATE_PAIR_REGEXP, UNMATCHED_SURROGATE_PAIR_REPLACE)
+ .replace(ENCODE_CHARS_REGEXP, encodeURI)
+}
diff --git a/node_modules/encodeurl/package.json b/node_modules/encodeurl/package.json
new file mode 100644
index 0000000..3133822
--- /dev/null
+++ b/node_modules/encodeurl/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "encodeurl",
+ "description": "Encode a URL to a percent-encoded form, excluding already-encoded sequences",
+ "version": "2.0.0",
+ "contributors": [
+ "Douglas Christopher Wilson "
+ ],
+ "license": "MIT",
+ "keywords": [
+ "encode",
+ "encodeurl",
+ "url"
+ ],
+ "repository": "pillarjs/encodeurl",
+ "devDependencies": {
+ "eslint": "5.11.1",
+ "eslint-config-standard": "12.0.0",
+ "eslint-plugin-import": "2.14.0",
+ "eslint-plugin-node": "7.0.1",
+ "eslint-plugin-promise": "4.0.1",
+ "eslint-plugin-standard": "4.0.0",
+ "istanbul": "0.4.5",
+ "mocha": "2.5.3"
+ },
+ "files": [
+ "LICENSE",
+ "HISTORY.md",
+ "README.md",
+ "index.js"
+ ],
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "scripts": {
+ "lint": "eslint .",
+ "test": "mocha --reporter spec --bail --check-leaks test/",
+ "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
+ "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
+ }
+}
diff --git a/node_modules/es-define-property/.eslintrc b/node_modules/es-define-property/.eslintrc
new file mode 100644
index 0000000..46f3b12
--- /dev/null
+++ b/node_modules/es-define-property/.eslintrc
@@ -0,0 +1,13 @@
+{
+ "root": true,
+
+ "extends": "@ljharb",
+
+ "rules": {
+ "new-cap": ["error", {
+ "capIsNewExceptions": [
+ "GetIntrinsic",
+ ],
+ }],
+ },
+}
diff --git a/node_modules/es-define-property/.github/FUNDING.yml b/node_modules/es-define-property/.github/FUNDING.yml
new file mode 100644
index 0000000..4445451
--- /dev/null
+++ b/node_modules/es-define-property/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: [ljharb]
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: npm/es-define-property
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with a single custom sponsorship URL
diff --git a/node_modules/es-define-property/.nycrc b/node_modules/es-define-property/.nycrc
new file mode 100644
index 0000000..bdd626c
--- /dev/null
+++ b/node_modules/es-define-property/.nycrc
@@ -0,0 +1,9 @@
+{
+ "all": true,
+ "check-coverage": false,
+ "reporter": ["text-summary", "text", "html", "json"],
+ "exclude": [
+ "coverage",
+ "test"
+ ]
+}
diff --git a/node_modules/es-define-property/CHANGELOG.md b/node_modules/es-define-property/CHANGELOG.md
new file mode 100644
index 0000000..4dce2ec
--- /dev/null
+++ b/node_modules/es-define-property/CHANGELOG.md
@@ -0,0 +1,15 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## v1.0.0 - 2024-02-12
+
+### Commits
+
+- Initial implementation, tests, readme, types [`3e154e1`](https://github.com/ljharb/es-define-property/commit/3e154e11a2fee09127220f5e503bf2c0a31dd480)
+- Initial commit [`07d98de`](https://github.com/ljharb/es-define-property/commit/07d98de34a4dc31ff5e83a37c0c3f49e0d85cd50)
+- npm init [`c4eb634`](https://github.com/ljharb/es-define-property/commit/c4eb6348b0d3886aac36cef34ad2ee0665ea6f3e)
+- Only apps should have lockfiles [`7af86ec`](https://github.com/ljharb/es-define-property/commit/7af86ec1d311ec0b17fdfe616a25f64276903856)
diff --git a/node_modules/es-define-property/LICENSE b/node_modules/es-define-property/LICENSE
new file mode 100644
index 0000000..f82f389
--- /dev/null
+++ b/node_modules/es-define-property/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Jordan Harband
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/node_modules/es-define-property/README.md b/node_modules/es-define-property/README.md
new file mode 100644
index 0000000..9b291bd
--- /dev/null
+++ b/node_modules/es-define-property/README.md
@@ -0,0 +1,49 @@
+# es-define-property [![Version Badge][npm-version-svg]][package-url]
+
+[![github actions][actions-image]][actions-url]
+[![coverage][codecov-image]][codecov-url]
+[![License][license-image]][license-url]
+[![Downloads][downloads-image]][downloads-url]
+
+[![npm badge][npm-badge-png]][package-url]
+
+`Object.defineProperty`, but not IE 8's broken one.
+
+## Example
+
+```js
+const assert = require('assert');
+
+const $defineProperty = require('es-define-property');
+
+if ($defineProperty) {
+ assert.equal($defineProperty, Object.defineProperty);
+} else if (Object.defineProperty) {
+ assert.equal($defineProperty, false, 'this is IE 8');
+} else {
+ assert.equal($defineProperty, false, 'this is an ES3 engine');
+}
+```
+
+## Tests
+Simply clone the repo, `npm install`, and run `npm test`
+
+## Security
+
+Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report.
+
+[package-url]: https://npmjs.org/package/es-define-property
+[npm-version-svg]: https://versionbadg.es/ljharb/es-define-property.svg
+[deps-svg]: https://david-dm.org/ljharb/es-define-property.svg
+[deps-url]: https://david-dm.org/ljharb/es-define-property
+[dev-deps-svg]: https://david-dm.org/ljharb/es-define-property/dev-status.svg
+[dev-deps-url]: https://david-dm.org/ljharb/es-define-property#info=devDependencies
+[npm-badge-png]: https://nodei.co/npm/es-define-property.png?downloads=true&stars=true
+[license-image]: https://img.shields.io/npm/l/es-define-property.svg
+[license-url]: LICENSE
+[downloads-image]: https://img.shields.io/npm/dm/es-define-property.svg
+[downloads-url]: https://npm-stat.com/charts.html?package=es-define-property
+[codecov-image]: https://codecov.io/gh/ljharb/es-define-property/branch/main/graphs/badge.svg
+[codecov-url]: https://app.codecov.io/gh/ljharb/es-define-property/
+[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/es-define-property
+[actions-url]: https://github.com/ljharb/es-define-property/actions
diff --git a/node_modules/es-define-property/index.d.ts b/node_modules/es-define-property/index.d.ts
new file mode 100644
index 0000000..6012247
--- /dev/null
+++ b/node_modules/es-define-property/index.d.ts
@@ -0,0 +1,3 @@
+declare const defineProperty: false | typeof Object.defineProperty;
+
+export = defineProperty;
\ No newline at end of file
diff --git a/node_modules/es-define-property/index.js b/node_modules/es-define-property/index.js
new file mode 100644
index 0000000..f32737d
--- /dev/null
+++ b/node_modules/es-define-property/index.js
@@ -0,0 +1,16 @@
+'use strict';
+
+var GetIntrinsic = require('get-intrinsic');
+
+/** @type {import('.')} */
+var $defineProperty = GetIntrinsic('%Object.defineProperty%', true) || false;
+if ($defineProperty) {
+ try {
+ $defineProperty({}, 'a', { value: 1 });
+ } catch (e) {
+ // IE 8 has a broken defineProperty
+ $defineProperty = false;
+ }
+}
+
+module.exports = $defineProperty;
diff --git a/node_modules/es-define-property/package.json b/node_modules/es-define-property/package.json
new file mode 100644
index 0000000..45bc90f
--- /dev/null
+++ b/node_modules/es-define-property/package.json
@@ -0,0 +1,81 @@
+{
+ "name": "es-define-property",
+ "version": "1.0.0",
+ "description": "`Object.defineProperty`, but not IE 8's broken one.",
+ "main": "index.js",
+ "types": "./index.d.ts",
+ "exports": {
+ ".": "./index.js",
+ "./package.json": "./package.json"
+ },
+ "sideEffects": false,
+ "scripts": {
+ "prepack": "npmignore --auto --commentLines=autogenerated",
+ "prepublish": "not-in-publish || npm run prepublishOnly",
+ "prepublishOnly": "safe-publish-latest",
+ "prelint": "evalmd README.md",
+ "lint": "eslint --ext=js,mjs .",
+ "postlint": "tsc -p .",
+ "pretest": "npm run lint",
+ "tests-only": "nyc tape 'test/**/*.js'",
+ "test": "npm run tests-only",
+ "posttest": "aud --production",
+ "version": "auto-changelog && git add CHANGELOG.md",
+ "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\""
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/ljharb/es-define-property.git"
+ },
+ "keywords": [
+ "javascript",
+ "ecmascript",
+ "object",
+ "define",
+ "property",
+ "defineProperty",
+ "Object.defineProperty"
+ ],
+ "author": "Jordan Harband ",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/ljharb/es-define-property/issues"
+ },
+ "homepage": "https://github.com/ljharb/es-define-property#readme",
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "devDependencies": {
+ "@ljharb/eslint-config": "^21.1.0",
+ "@types/get-intrinsic": "^1.2.2",
+ "@types/gopd": "^1.0.3",
+ "@types/tape": "^5.6.4",
+ "aud": "^2.0.4",
+ "auto-changelog": "^2.4.0",
+ "eslint": "^8.8.0",
+ "evalmd": "^0.0.19",
+ "gopd": "^1.0.1",
+ "in-publish": "^2.0.1",
+ "npmignore": "^0.3.1",
+ "nyc": "^10.3.2",
+ "safe-publish-latest": "^2.0.0",
+ "tape": "^5.7.4",
+ "typescript": "next"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "auto-changelog": {
+ "output": "CHANGELOG.md",
+ "template": "keepachangelog",
+ "unreleased": false,
+ "commitLimit": false,
+ "backfillLimit": false,
+ "hideCredit": true
+ },
+ "publishConfig": {
+ "ignore": [
+ ".github/workflows"
+ ]
+ }
+}
diff --git a/node_modules/es-define-property/test/index.js b/node_modules/es-define-property/test/index.js
new file mode 100644
index 0000000..dbc054e
--- /dev/null
+++ b/node_modules/es-define-property/test/index.js
@@ -0,0 +1,55 @@
+'use strict';
+
+var $defineProperty = require('../');
+
+var test = require('tape');
+var gOPD = require('gopd');
+
+test('defineProperty: supported', { skip: !$defineProperty }, function (t) {
+ t.plan(4);
+
+ t.equal(typeof $defineProperty, 'function', 'defineProperty is supported');
+ if ($defineProperty && gOPD) { // this `if` check is just to shut TS up
+ var o = { a: 1 };
+
+ $defineProperty(o, 'b', { enumerable: true, value: 2 });
+ t.deepEqual(
+ gOPD(o, 'b'),
+ {
+ configurable: false,
+ enumerable: true,
+ value: 2,
+ writable: false
+ },
+ 'property descriptor is as expected'
+ );
+
+ $defineProperty(o, 'c', { enumerable: false, value: 3, writable: true });
+ t.deepEqual(
+ gOPD(o, 'c'),
+ {
+ configurable: false,
+ enumerable: false,
+ value: 3,
+ writable: true
+ },
+ 'property descriptor is as expected'
+ );
+ }
+
+ t.equal($defineProperty, Object.defineProperty, 'defineProperty is Object.defineProperty');
+
+ t.end();
+});
+
+test('defineProperty: not supported', { skip: !!$defineProperty }, function (t) {
+ t.notOk($defineProperty, 'defineProperty is not supported');
+
+ t.match(
+ typeof $defineProperty,
+ /^(?:undefined|boolean)$/,
+ '`typeof defineProperty` is `undefined` or `boolean`'
+ );
+
+ t.end();
+});
diff --git a/node_modules/es-define-property/tsconfig.json b/node_modules/es-define-property/tsconfig.json
new file mode 100644
index 0000000..fdfa155
--- /dev/null
+++ b/node_modules/es-define-property/tsconfig.json
@@ -0,0 +1,50 @@
+{
+ "compilerOptions": {
+ /* Visit https://aka.ms/tsconfig.json to read more about this file */
+
+ /* Projects */
+
+ /* Language and Environment */
+ "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
+ "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
+ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
+
+ /* Modules */
+ "module": "commonjs", /* Specify what module code is generated. */
+ // "rootDir": "./", /* Specify the root folder within your source files. */
+ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
+ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
+ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
+ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
+ // "typeRoots": ["types"], /* Specify multiple folders that act like `./node_modules/@types`. */
+ "resolveJsonModule": true, /* Enable importing .json files. */
+ // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
+
+ /* JavaScript Support */
+ "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
+ "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
+ "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
+
+ /* Emit */
+ "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+ "declarationMap": true, /* Create sourcemaps for d.ts files. */
+ "noEmit": true, /* Disable emitting files from a compilation. */
+
+ /* Interop Constraints */
+ "allowSyntheticDefaultImports": true, /* Allow `import x from y` when a module doesn't have a default export. */
+ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
+ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
+
+ /* Type Checking */
+ "strict": true, /* Enable all strict type-checking options. */
+
+ /* Completeness */
+ // "skipLibCheck": true /* Skip type checking all .d.ts files. */
+ },
+ "exclude": [
+ "coverage",
+ "test/list-exports"
+ ],
+}
diff --git a/node_modules/es-errors/.eslintrc b/node_modules/es-errors/.eslintrc
new file mode 100644
index 0000000..3b5d9e9
--- /dev/null
+++ b/node_modules/es-errors/.eslintrc
@@ -0,0 +1,5 @@
+{
+ "root": true,
+
+ "extends": "@ljharb",
+}
diff --git a/node_modules/es-errors/.github/FUNDING.yml b/node_modules/es-errors/.github/FUNDING.yml
new file mode 100644
index 0000000..f1b8805
--- /dev/null
+++ b/node_modules/es-errors/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: [ljharb]
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: npm/es-errors
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with a single custom sponsorship URL
diff --git a/node_modules/es-errors/CHANGELOG.md b/node_modules/es-errors/CHANGELOG.md
new file mode 100644
index 0000000..204a9e9
--- /dev/null
+++ b/node_modules/es-errors/CHANGELOG.md
@@ -0,0 +1,40 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [v1.3.0](https://github.com/ljharb/es-errors/compare/v1.2.1...v1.3.0) - 2024-02-05
+
+### Commits
+
+- [New] add `EvalError` and `URIError` [`1927627`](https://github.com/ljharb/es-errors/commit/1927627ba68cb6c829d307231376c967db53acdf)
+
+## [v1.2.1](https://github.com/ljharb/es-errors/compare/v1.2.0...v1.2.1) - 2024-02-04
+
+### Commits
+
+- [Fix] add missing `exports` entry [`5bb5f28`](https://github.com/ljharb/es-errors/commit/5bb5f280f98922701109d6ebb82eea2257cecc7e)
+
+## [v1.2.0](https://github.com/ljharb/es-errors/compare/v1.1.0...v1.2.0) - 2024-02-04
+
+### Commits
+
+- [New] add `ReferenceError` [`6d8cf5b`](https://github.com/ljharb/es-errors/commit/6d8cf5bbb6f3f598d02cf6f30e468ba2caa8e143)
+
+## [v1.1.0](https://github.com/ljharb/es-errors/compare/v1.0.0...v1.1.0) - 2024-02-04
+
+### Commits
+
+- [New] add base Error [`2983ab6`](https://github.com/ljharb/es-errors/commit/2983ab65f7bc5441276cb021dc3aa03c78881698)
+
+## v1.0.0 - 2024-02-03
+
+### Commits
+
+- Initial implementation, tests, readme, type [`8f47631`](https://github.com/ljharb/es-errors/commit/8f476317e9ad76f40ad648081829b1a1a3a1288b)
+- Initial commit [`ea5d099`](https://github.com/ljharb/es-errors/commit/ea5d099ef18e550509ab9e2be000526afd81c385)
+- npm init [`6f5ebf9`](https://github.com/ljharb/es-errors/commit/6f5ebf9cead474dadd72b9e63dad315820a089ae)
+- Only apps should have lockfiles [`e1a0aeb`](https://github.com/ljharb/es-errors/commit/e1a0aeb7b80f5cfc56be54d6b2100e915d47def8)
+- [meta] add `sideEffects` flag [`a9c7d46`](https://github.com/ljharb/es-errors/commit/a9c7d460a492f1d8a241c836bc25a322a19cc043)
diff --git a/node_modules/es-errors/LICENSE b/node_modules/es-errors/LICENSE
new file mode 100644
index 0000000..f82f389
--- /dev/null
+++ b/node_modules/es-errors/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Jordan Harband
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/node_modules/es-errors/README.md b/node_modules/es-errors/README.md
new file mode 100644
index 0000000..8dbfacf
--- /dev/null
+++ b/node_modules/es-errors/README.md
@@ -0,0 +1,55 @@
+# es-errors [![Version Badge][npm-version-svg]][package-url]
+
+[![github actions][actions-image]][actions-url]
+[![coverage][codecov-image]][codecov-url]
+[![License][license-image]][license-url]
+[![Downloads][downloads-image]][downloads-url]
+
+[![npm badge][npm-badge-png]][package-url]
+
+A simple cache for a few of the JS Error constructors.
+
+## Example
+
+```js
+const assert = require('assert');
+
+const Base = require('es-errors');
+const Eval = require('es-errors/eval');
+const Range = require('es-errors/range');
+const Ref = require('es-errors/ref');
+const Syntax = require('es-errors/syntax');
+const Type = require('es-errors/type');
+const URI = require('es-errors/uri');
+
+assert.equal(Base, Error);
+assert.equal(Eval, EvalError);
+assert.equal(Range, RangeError);
+assert.equal(Ref, ReferenceError);
+assert.equal(Syntax, SyntaxError);
+assert.equal(Type, TypeError);
+assert.equal(URI, URIError);
+```
+
+## Tests
+Simply clone the repo, `npm install`, and run `npm test`
+
+## Security
+
+Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report.
+
+[package-url]: https://npmjs.org/package/es-errors
+[npm-version-svg]: https://versionbadg.es/ljharb/es-errors.svg
+[deps-svg]: https://david-dm.org/ljharb/es-errors.svg
+[deps-url]: https://david-dm.org/ljharb/es-errors
+[dev-deps-svg]: https://david-dm.org/ljharb/es-errors/dev-status.svg
+[dev-deps-url]: https://david-dm.org/ljharb/es-errors#info=devDependencies
+[npm-badge-png]: https://nodei.co/npm/es-errors.png?downloads=true&stars=true
+[license-image]: https://img.shields.io/npm/l/es-errors.svg
+[license-url]: LICENSE
+[downloads-image]: https://img.shields.io/npm/dm/es-errors.svg
+[downloads-url]: https://npm-stat.com/charts.html?package=es-errors
+[codecov-image]: https://codecov.io/gh/ljharb/es-errors/branch/main/graphs/badge.svg
+[codecov-url]: https://app.codecov.io/gh/ljharb/es-errors/
+[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/es-errors
+[actions-url]: https://github.com/ljharb/es-errors/actions
diff --git a/node_modules/es-errors/eval.d.ts b/node_modules/es-errors/eval.d.ts
new file mode 100644
index 0000000..e4210e0
--- /dev/null
+++ b/node_modules/es-errors/eval.d.ts
@@ -0,0 +1,3 @@
+declare const EvalError: EvalErrorConstructor;
+
+export = EvalError;
diff --git a/node_modules/es-errors/eval.js b/node_modules/es-errors/eval.js
new file mode 100644
index 0000000..725ccb6
--- /dev/null
+++ b/node_modules/es-errors/eval.js
@@ -0,0 +1,4 @@
+'use strict';
+
+/** @type {import('./eval')} */
+module.exports = EvalError;
diff --git a/node_modules/es-errors/index.d.ts b/node_modules/es-errors/index.d.ts
new file mode 100644
index 0000000..69bdbc9
--- /dev/null
+++ b/node_modules/es-errors/index.d.ts
@@ -0,0 +1,3 @@
+declare const Error: ErrorConstructor;
+
+export = Error;
diff --git a/node_modules/es-errors/index.js b/node_modules/es-errors/index.js
new file mode 100644
index 0000000..cc0c521
--- /dev/null
+++ b/node_modules/es-errors/index.js
@@ -0,0 +1,4 @@
+'use strict';
+
+/** @type {import('.')} */
+module.exports = Error;
diff --git a/node_modules/es-errors/package.json b/node_modules/es-errors/package.json
new file mode 100644
index 0000000..ff8c2a5
--- /dev/null
+++ b/node_modules/es-errors/package.json
@@ -0,0 +1,80 @@
+{
+ "name": "es-errors",
+ "version": "1.3.0",
+ "description": "A simple cache for a few of the JS Error constructors.",
+ "main": "index.js",
+ "exports": {
+ ".": "./index.js",
+ "./eval": "./eval.js",
+ "./range": "./range.js",
+ "./ref": "./ref.js",
+ "./syntax": "./syntax.js",
+ "./type": "./type.js",
+ "./uri": "./uri.js",
+ "./package.json": "./package.json"
+ },
+ "sideEffects": false,
+ "scripts": {
+ "prepack": "npmignore --auto --commentLines=autogenerated",
+ "prepublishOnly": "safe-publish-latest",
+ "prepublish": "not-in-publish || npm run prepublishOnly",
+ "pretest": "npm run lint",
+ "test": "npm run tests-only",
+ "tests-only": "nyc tape 'test/**/*.js'",
+ "posttest": "aud --production",
+ "prelint": "evalmd README.md",
+ "lint": "eslint --ext=js,mjs .",
+ "postlint": "tsc -p . && eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git' | grep -v dist/)",
+ "version": "auto-changelog && git add CHANGELOG.md",
+ "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\""
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/ljharb/es-errors.git"
+ },
+ "keywords": [
+ "javascript",
+ "ecmascript",
+ "error",
+ "typeerror",
+ "syntaxerror",
+ "rangeerror"
+ ],
+ "author": "Jordan Harband ",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/ljharb/es-errors/issues"
+ },
+ "homepage": "https://github.com/ljharb/es-errors#readme",
+ "devDependencies": {
+ "@ljharb/eslint-config": "^21.1.0",
+ "@types/tape": "^5.6.4",
+ "aud": "^2.0.4",
+ "auto-changelog": "^2.4.0",
+ "eclint": "^2.8.1",
+ "eslint": "^8.8.0",
+ "evalmd": "^0.0.19",
+ "in-publish": "^2.0.1",
+ "npmignore": "^0.3.1",
+ "nyc": "^10.3.2",
+ "safe-publish-latest": "^2.0.0",
+ "tape": "^5.7.4",
+ "typescript": "next"
+ },
+ "auto-changelog": {
+ "output": "CHANGELOG.md",
+ "template": "keepachangelog",
+ "unreleased": false,
+ "commitLimit": false,
+ "backfillLimit": false,
+ "hideCredit": true
+ },
+ "publishConfig": {
+ "ignore": [
+ ".github/workflows"
+ ]
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+}
diff --git a/node_modules/es-errors/range.d.ts b/node_modules/es-errors/range.d.ts
new file mode 100644
index 0000000..3a12e86
--- /dev/null
+++ b/node_modules/es-errors/range.d.ts
@@ -0,0 +1,3 @@
+declare const RangeError: RangeErrorConstructor;
+
+export = RangeError;
diff --git a/node_modules/es-errors/range.js b/node_modules/es-errors/range.js
new file mode 100644
index 0000000..2044fe0
--- /dev/null
+++ b/node_modules/es-errors/range.js
@@ -0,0 +1,4 @@
+'use strict';
+
+/** @type {import('./range')} */
+module.exports = RangeError;
diff --git a/node_modules/es-errors/ref.d.ts b/node_modules/es-errors/ref.d.ts
new file mode 100644
index 0000000..a13107e
--- /dev/null
+++ b/node_modules/es-errors/ref.d.ts
@@ -0,0 +1,3 @@
+declare const ReferenceError: ReferenceErrorConstructor;
+
+export = ReferenceError;
diff --git a/node_modules/es-errors/ref.js b/node_modules/es-errors/ref.js
new file mode 100644
index 0000000..d7c430f
--- /dev/null
+++ b/node_modules/es-errors/ref.js
@@ -0,0 +1,4 @@
+'use strict';
+
+/** @type {import('./ref')} */
+module.exports = ReferenceError;
diff --git a/node_modules/es-errors/syntax.d.ts b/node_modules/es-errors/syntax.d.ts
new file mode 100644
index 0000000..6a0c53c
--- /dev/null
+++ b/node_modules/es-errors/syntax.d.ts
@@ -0,0 +1,3 @@
+declare const SyntaxError: SyntaxErrorConstructor;
+
+export = SyntaxError;
diff --git a/node_modules/es-errors/syntax.js b/node_modules/es-errors/syntax.js
new file mode 100644
index 0000000..5f5fdde
--- /dev/null
+++ b/node_modules/es-errors/syntax.js
@@ -0,0 +1,4 @@
+'use strict';
+
+/** @type {import('./syntax')} */
+module.exports = SyntaxError;
diff --git a/node_modules/es-errors/test/index.js b/node_modules/es-errors/test/index.js
new file mode 100644
index 0000000..1ff0277
--- /dev/null
+++ b/node_modules/es-errors/test/index.js
@@ -0,0 +1,19 @@
+'use strict';
+
+var test = require('tape');
+
+var E = require('../');
+var R = require('../range');
+var Ref = require('../ref');
+var S = require('../syntax');
+var T = require('../type');
+
+test('errors', function (t) {
+ t.equal(E, Error);
+ t.equal(R, RangeError);
+ t.equal(Ref, ReferenceError);
+ t.equal(S, SyntaxError);
+ t.equal(T, TypeError);
+
+ t.end();
+});
diff --git a/node_modules/es-errors/tsconfig.json b/node_modules/es-errors/tsconfig.json
new file mode 100644
index 0000000..99dfeb6
--- /dev/null
+++ b/node_modules/es-errors/tsconfig.json
@@ -0,0 +1,49 @@
+{
+ "compilerOptions": {
+ /* Visit https://aka.ms/tsconfig.json to read more about this file */
+
+ /* Projects */
+
+ /* Language and Environment */
+ "target": "es5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
+ "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
+ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
+
+ /* Modules */
+ "module": "commonjs", /* Specify what module code is generated. */
+ // "rootDir": "./", /* Specify the root folder within your source files. */
+ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
+ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
+ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
+ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
+ // "typeRoots": ["types"], /* Specify multiple folders that act like `./node_modules/@types`. */
+ "resolveJsonModule": true, /* Enable importing .json files. */
+ // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
+
+ /* JavaScript Support */
+ "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
+ "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
+ "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
+
+ /* Emit */
+ "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+ "declarationMap": true, /* Create sourcemaps for d.ts files. */
+ "noEmit": true, /* Disable emitting files from a compilation. */
+
+ /* Interop Constraints */
+ "allowSyntheticDefaultImports": true, /* Allow `import x from y` when a module doesn't have a default export. */
+ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
+ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
+
+ /* Type Checking */
+ "strict": true, /* Enable all strict type-checking options. */
+
+ /* Completeness */
+ // "skipLibCheck": true /* Skip type checking all .d.ts files. */
+ },
+ "exclude": [
+ "coverage",
+ ],
+}
diff --git a/node_modules/es-errors/type.d.ts b/node_modules/es-errors/type.d.ts
new file mode 100644
index 0000000..576fb51
--- /dev/null
+++ b/node_modules/es-errors/type.d.ts
@@ -0,0 +1,3 @@
+declare const TypeError: TypeErrorConstructor
+
+export = TypeError;
diff --git a/node_modules/es-errors/type.js b/node_modules/es-errors/type.js
new file mode 100644
index 0000000..9769e44
--- /dev/null
+++ b/node_modules/es-errors/type.js
@@ -0,0 +1,4 @@
+'use strict';
+
+/** @type {import('./type')} */
+module.exports = TypeError;
diff --git a/node_modules/es-errors/uri.d.ts b/node_modules/es-errors/uri.d.ts
new file mode 100644
index 0000000..c3261c9
--- /dev/null
+++ b/node_modules/es-errors/uri.d.ts
@@ -0,0 +1,3 @@
+declare const URIError: URIErrorConstructor;
+
+export = URIError;
diff --git a/node_modules/es-errors/uri.js b/node_modules/es-errors/uri.js
new file mode 100644
index 0000000..e9cd1c7
--- /dev/null
+++ b/node_modules/es-errors/uri.js
@@ -0,0 +1,4 @@
+'use strict';
+
+/** @type {import('./uri')} */
+module.exports = URIError;
diff --git a/node_modules/escape-html/LICENSE b/node_modules/escape-html/LICENSE
new file mode 100644
index 0000000..2e70de9
--- /dev/null
+++ b/node_modules/escape-html/LICENSE
@@ -0,0 +1,24 @@
+(The MIT License)
+
+Copyright (c) 2012-2013 TJ Holowaychuk
+Copyright (c) 2015 Andreas Lubbe
+Copyright (c) 2015 Tiancheng "Timothy" Gu
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/escape-html/Readme.md b/node_modules/escape-html/Readme.md
new file mode 100644
index 0000000..653d9ea
--- /dev/null
+++ b/node_modules/escape-html/Readme.md
@@ -0,0 +1,43 @@
+
+# escape-html
+
+ Escape string for use in HTML
+
+## Example
+
+```js
+var escape = require('escape-html');
+var html = escape('foo & bar');
+// -> foo & bar
+```
+
+## Benchmark
+
+```
+$ npm run-script bench
+
+> escape-html@1.0.3 bench nodejs-escape-html
+> node benchmark/index.js
+
+
+ http_parser@1.0
+ node@0.10.33
+ v8@3.14.5.9
+ ares@1.9.0-DEV
+ uv@0.10.29
+ zlib@1.2.3
+ modules@11
+ openssl@1.0.1j
+
+ 1 test completed.
+ 2 tests completed.
+ 3 tests completed.
+
+ no special characters x 19,435,271 ops/sec ±0.85% (187 runs sampled)
+ single special character x 6,132,421 ops/sec ±0.67% (194 runs sampled)
+ many special characters x 3,175,826 ops/sec ±0.65% (193 runs sampled)
+```
+
+## License
+
+ MIT
\ No newline at end of file
diff --git a/node_modules/escape-html/index.js b/node_modules/escape-html/index.js
new file mode 100644
index 0000000..bf9e226
--- /dev/null
+++ b/node_modules/escape-html/index.js
@@ -0,0 +1,78 @@
+/*!
+ * escape-html
+ * Copyright(c) 2012-2013 TJ Holowaychuk
+ * Copyright(c) 2015 Andreas Lubbe
+ * Copyright(c) 2015 Tiancheng "Timothy" Gu
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Module variables.
+ * @private
+ */
+
+var matchHtmlRegExp = /["'&<>]/;
+
+/**
+ * Module exports.
+ * @public
+ */
+
+module.exports = escapeHtml;
+
+/**
+ * Escape special characters in the given string of html.
+ *
+ * @param {string} string The string to escape for inserting into HTML
+ * @return {string}
+ * @public
+ */
+
+function escapeHtml(string) {
+ var str = '' + string;
+ var match = matchHtmlRegExp.exec(str);
+
+ if (!match) {
+ return str;
+ }
+
+ var escape;
+ var html = '';
+ var index = 0;
+ var lastIndex = 0;
+
+ for (index = match.index; index < str.length; index++) {
+ switch (str.charCodeAt(index)) {
+ case 34: // "
+ escape = '"';
+ break;
+ case 38: // &
+ escape = '&';
+ break;
+ case 39: // '
+ escape = ''';
+ break;
+ case 60: // <
+ escape = '<';
+ break;
+ case 62: // >
+ escape = '>';
+ break;
+ default:
+ continue;
+ }
+
+ if (lastIndex !== index) {
+ html += str.substring(lastIndex, index);
+ }
+
+ lastIndex = index + 1;
+ html += escape;
+ }
+
+ return lastIndex !== index
+ ? html + str.substring(lastIndex, index)
+ : html;
+}
diff --git a/node_modules/escape-html/package.json b/node_modules/escape-html/package.json
new file mode 100644
index 0000000..57ec7bd
--- /dev/null
+++ b/node_modules/escape-html/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "escape-html",
+ "description": "Escape string for use in HTML",
+ "version": "1.0.3",
+ "license": "MIT",
+ "keywords": [
+ "escape",
+ "html",
+ "utility"
+ ],
+ "repository": "component/escape-html",
+ "devDependencies": {
+ "benchmark": "1.0.0",
+ "beautify-benchmark": "0.2.4"
+ },
+ "files": [
+ "LICENSE",
+ "Readme.md",
+ "index.js"
+ ],
+ "scripts": {
+ "bench": "node benchmark/index.js"
+ }
+}
diff --git a/node_modules/etag/HISTORY.md b/node_modules/etag/HISTORY.md
new file mode 100644
index 0000000..222b293
--- /dev/null
+++ b/node_modules/etag/HISTORY.md
@@ -0,0 +1,83 @@
+1.8.1 / 2017-09-12
+==================
+
+ * perf: replace regular expression with substring
+
+1.8.0 / 2017-02-18
+==================
+
+ * Use SHA1 instead of MD5 for ETag hashing
+ - Improves performance for larger entities
+ - Works with FIPS 140-2 OpenSSL configuration
+
+1.7.0 / 2015-06-08
+==================
+
+ * Always include entity length in ETags for hash length extensions
+ * Generate non-Stats ETags using MD5 only (no longer CRC32)
+ * Improve stat performance by removing hashing
+ * Remove base64 padding in ETags to shorten
+ * Use MD5 instead of MD4 in weak ETags over 1KB
+
+1.6.0 / 2015-05-10
+==================
+
+ * Improve support for JXcore
+ * Remove requirement of `atime` in the stats object
+ * Support "fake" stats objects in environments without `fs`
+
+1.5.1 / 2014-11-19
+==================
+
+ * deps: crc@3.2.1
+ - Minor fixes
+
+1.5.0 / 2014-10-14
+==================
+
+ * Improve string performance
+ * Slightly improve speed for weak ETags over 1KB
+
+1.4.0 / 2014-09-21
+==================
+
+ * Support "fake" stats objects
+ * Support Node.js 0.6
+
+1.3.1 / 2014-09-14
+==================
+
+ * Use the (new and improved) `crc` for crc32
+
+1.3.0 / 2014-08-29
+==================
+
+ * Default strings to strong ETags
+ * Improve speed for weak ETags over 1KB
+
+1.2.1 / 2014-08-29
+==================
+
+ * Use the (much faster) `buffer-crc32` for crc32
+
+1.2.0 / 2014-08-24
+==================
+
+ * Add support for file stat objects
+
+1.1.0 / 2014-08-24
+==================
+
+ * Add fast-path for empty entity
+ * Add weak ETag generation
+ * Shrink size of generated ETags
+
+1.0.1 / 2014-08-24
+==================
+
+ * Fix behavior of string containing Unicode
+
+1.0.0 / 2014-05-18
+==================
+
+ * Initial release
diff --git a/node_modules/etag/LICENSE b/node_modules/etag/LICENSE
new file mode 100644
index 0000000..cab251c
--- /dev/null
+++ b/node_modules/etag/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2014-2016 Douglas Christopher Wilson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/etag/README.md b/node_modules/etag/README.md
new file mode 100644
index 0000000..09c2169
--- /dev/null
+++ b/node_modules/etag/README.md
@@ -0,0 +1,159 @@
+# etag
+
+[![NPM Version][npm-image]][npm-url]
+[![NPM Downloads][downloads-image]][downloads-url]
+[![Node.js Version][node-version-image]][node-version-url]
+[![Build Status][travis-image]][travis-url]
+[![Test Coverage][coveralls-image]][coveralls-url]
+
+Create simple HTTP ETags
+
+This module generates HTTP ETags (as defined in RFC 7232) for use in
+HTTP responses.
+
+## Installation
+
+This is a [Node.js](https://nodejs.org/en/) module available through the
+[npm registry](https://www.npmjs.com/). Installation is done using the
+[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
+
+```sh
+$ npm install etag
+```
+
+## API
+
+
+
+```js
+var etag = require('etag')
+```
+
+### etag(entity, [options])
+
+Generate a strong ETag for the given entity. This should be the complete
+body of the entity. Strings, `Buffer`s, and `fs.Stats` are accepted. By
+default, a strong ETag is generated except for `fs.Stats`, which will
+generate a weak ETag (this can be overwritten by `options.weak`).
+
+
+
+```js
+res.setHeader('ETag', etag(body))
+```
+
+#### Options
+
+`etag` accepts these properties in the options object.
+
+##### weak
+
+Specifies if the generated ETag will include the weak validator mark (that
+is, the leading `W/`). The actual entity tag is the same. The default value
+is `false`, unless the `entity` is `fs.Stats`, in which case it is `true`.
+
+## Testing
+
+```sh
+$ npm test
+```
+
+## Benchmark
+
+```bash
+$ npm run-script bench
+
+> etag@1.8.1 bench nodejs-etag
+> node benchmark/index.js
+
+ http_parser@2.7.0
+ node@6.11.1
+ v8@5.1.281.103
+ uv@1.11.0
+ zlib@1.2.11
+ ares@1.10.1-DEV
+ icu@58.2
+ modules@48
+ openssl@1.0.2k
+
+> node benchmark/body0-100b.js
+
+ 100B body
+
+ 4 tests completed.
+
+ buffer - strong x 258,647 ops/sec ±1.07% (180 runs sampled)
+ buffer - weak x 263,812 ops/sec ±0.61% (184 runs sampled)
+ string - strong x 259,955 ops/sec ±1.19% (185 runs sampled)
+ string - weak x 264,356 ops/sec ±1.09% (184 runs sampled)
+
+> node benchmark/body1-1kb.js
+
+ 1KB body
+
+ 4 tests completed.
+
+ buffer - strong x 189,018 ops/sec ±1.12% (182 runs sampled)
+ buffer - weak x 190,586 ops/sec ±0.81% (186 runs sampled)
+ string - strong x 144,272 ops/sec ±0.96% (188 runs sampled)
+ string - weak x 145,380 ops/sec ±1.43% (187 runs sampled)
+
+> node benchmark/body2-5kb.js
+
+ 5KB body
+
+ 4 tests completed.
+
+ buffer - strong x 92,435 ops/sec ±0.42% (188 runs sampled)
+ buffer - weak x 92,373 ops/sec ±0.58% (189 runs sampled)
+ string - strong x 48,850 ops/sec ±0.56% (186 runs sampled)
+ string - weak x 49,380 ops/sec ±0.56% (190 runs sampled)
+
+> node benchmark/body3-10kb.js
+
+ 10KB body
+
+ 4 tests completed.
+
+ buffer - strong x 55,989 ops/sec ±0.93% (188 runs sampled)
+ buffer - weak x 56,148 ops/sec ±0.55% (190 runs sampled)
+ string - strong x 27,345 ops/sec ±0.43% (188 runs sampled)
+ string - weak x 27,496 ops/sec ±0.45% (190 runs sampled)
+
+> node benchmark/body4-100kb.js
+
+ 100KB body
+
+ 4 tests completed.
+
+ buffer - strong x 7,083 ops/sec ±0.22% (190 runs sampled)
+ buffer - weak x 7,115 ops/sec ±0.26% (191 runs sampled)
+ string - strong x 3,068 ops/sec ±0.34% (190 runs sampled)
+ string - weak x 3,096 ops/sec ±0.35% (190 runs sampled)
+
+> node benchmark/stats.js
+
+ stat
+
+ 4 tests completed.
+
+ real - strong x 871,642 ops/sec ±0.34% (189 runs sampled)
+ real - weak x 867,613 ops/sec ±0.39% (190 runs sampled)
+ fake - strong x 401,051 ops/sec ±0.40% (189 runs sampled)
+ fake - weak x 400,100 ops/sec ±0.47% (188 runs sampled)
+```
+
+## License
+
+[MIT](LICENSE)
+
+[npm-image]: https://img.shields.io/npm/v/etag.svg
+[npm-url]: https://npmjs.org/package/etag
+[node-version-image]: https://img.shields.io/node/v/etag.svg
+[node-version-url]: https://nodejs.org/en/download/
+[travis-image]: https://img.shields.io/travis/jshttp/etag/master.svg
+[travis-url]: https://travis-ci.org/jshttp/etag
+[coveralls-image]: https://img.shields.io/coveralls/jshttp/etag/master.svg
+[coveralls-url]: https://coveralls.io/r/jshttp/etag?branch=master
+[downloads-image]: https://img.shields.io/npm/dm/etag.svg
+[downloads-url]: https://npmjs.org/package/etag
diff --git a/node_modules/etag/index.js b/node_modules/etag/index.js
new file mode 100644
index 0000000..2a585c9
--- /dev/null
+++ b/node_modules/etag/index.js
@@ -0,0 +1,131 @@
+/*!
+ * etag
+ * Copyright(c) 2014-2016 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module exports.
+ * @public
+ */
+
+module.exports = etag
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var crypto = require('crypto')
+var Stats = require('fs').Stats
+
+/**
+ * Module variables.
+ * @private
+ */
+
+var toString = Object.prototype.toString
+
+/**
+ * Generate an entity tag.
+ *
+ * @param {Buffer|string} entity
+ * @return {string}
+ * @private
+ */
+
+function entitytag (entity) {
+ if (entity.length === 0) {
+ // fast-path empty
+ return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"'
+ }
+
+ // compute hash of entity
+ var hash = crypto
+ .createHash('sha1')
+ .update(entity, 'utf8')
+ .digest('base64')
+ .substring(0, 27)
+
+ // compute length of entity
+ var len = typeof entity === 'string'
+ ? Buffer.byteLength(entity, 'utf8')
+ : entity.length
+
+ return '"' + len.toString(16) + '-' + hash + '"'
+}
+
+/**
+ * Create a simple ETag.
+ *
+ * @param {string|Buffer|Stats} entity
+ * @param {object} [options]
+ * @param {boolean} [options.weak]
+ * @return {String}
+ * @public
+ */
+
+function etag (entity, options) {
+ if (entity == null) {
+ throw new TypeError('argument entity is required')
+ }
+
+ // support fs.Stats object
+ var isStats = isstats(entity)
+ var weak = options && typeof options.weak === 'boolean'
+ ? options.weak
+ : isStats
+
+ // validate argument
+ if (!isStats && typeof entity !== 'string' && !Buffer.isBuffer(entity)) {
+ throw new TypeError('argument entity must be string, Buffer, or fs.Stats')
+ }
+
+ // generate entity tag
+ var tag = isStats
+ ? stattag(entity)
+ : entitytag(entity)
+
+ return weak
+ ? 'W/' + tag
+ : tag
+}
+
+/**
+ * Determine if object is a Stats object.
+ *
+ * @param {object} obj
+ * @return {boolean}
+ * @api private
+ */
+
+function isstats (obj) {
+ // genuine fs.Stats
+ if (typeof Stats === 'function' && obj instanceof Stats) {
+ return true
+ }
+
+ // quack quack
+ return obj && typeof obj === 'object' &&
+ 'ctime' in obj && toString.call(obj.ctime) === '[object Date]' &&
+ 'mtime' in obj && toString.call(obj.mtime) === '[object Date]' &&
+ 'ino' in obj && typeof obj.ino === 'number' &&
+ 'size' in obj && typeof obj.size === 'number'
+}
+
+/**
+ * Generate a tag for a stat.
+ *
+ * @param {object} stat
+ * @return {string}
+ * @private
+ */
+
+function stattag (stat) {
+ var mtime = stat.mtime.getTime().toString(16)
+ var size = stat.size.toString(16)
+
+ return '"' + size + '-' + mtime + '"'
+}
diff --git a/node_modules/etag/package.json b/node_modules/etag/package.json
new file mode 100644
index 0000000..b06ab80
--- /dev/null
+++ b/node_modules/etag/package.json
@@ -0,0 +1,47 @@
+{
+ "name": "etag",
+ "description": "Create simple HTTP ETags",
+ "version": "1.8.1",
+ "contributors": [
+ "Douglas Christopher Wilson ",
+ "David Björklund "
+ ],
+ "license": "MIT",
+ "keywords": [
+ "etag",
+ "http",
+ "res"
+ ],
+ "repository": "jshttp/etag",
+ "devDependencies": {
+ "beautify-benchmark": "0.2.4",
+ "benchmark": "2.1.4",
+ "eslint": "3.19.0",
+ "eslint-config-standard": "10.2.1",
+ "eslint-plugin-import": "2.7.0",
+ "eslint-plugin-markdown": "1.0.0-beta.6",
+ "eslint-plugin-node": "5.1.1",
+ "eslint-plugin-promise": "3.5.0",
+ "eslint-plugin-standard": "3.0.1",
+ "istanbul": "0.4.5",
+ "mocha": "1.21.5",
+ "safe-buffer": "5.1.1",
+ "seedrandom": "2.4.3"
+ },
+ "files": [
+ "LICENSE",
+ "HISTORY.md",
+ "README.md",
+ "index.js"
+ ],
+ "engines": {
+ "node": ">= 0.6"
+ },
+ "scripts": {
+ "bench": "node benchmark/index.js",
+ "lint": "eslint --plugin markdown --ext js,md .",
+ "test": "mocha --reporter spec --bail --check-leaks test/",
+ "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
+ "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
+ }
+}
diff --git a/node_modules/express-session/HISTORY.md b/node_modules/express-session/HISTORY.md
new file mode 100644
index 0000000..57c68d3
--- /dev/null
+++ b/node_modules/express-session/HISTORY.md
@@ -0,0 +1,470 @@
+1.18.1 / 2024-10-08
+==========
+
+ * deps: cookie@0.7.2
+ - Fix object assignment of `hasOwnProperty`
+ * deps: cookie@0.7.1
+ - Allow leading dot for domain
+ - Although not permitted in the spec, some users expect this to work and user agents ignore the leading dot according to spec
+ - Add fast path for `serialize` without options, use `obj.hasOwnProperty` when parsing
+ * deps: cookie@0.7.0
+ - perf: parse cookies ~10% faster
+ - fix: narrow the validation of cookies to match RFC6265
+ - fix: add `main` to `package.json` for rspack
+
+1.18.0 / 2024-01-28
+===================
+
+ * Add debug log for pathname mismatch
+ * Add `partitioned` to `cookie` options
+ * Add `priority` to `cookie` options
+ * Fix handling errors from setting cookie
+ * Support any type in `secret` that `crypto.createHmac` supports
+ * deps: cookie@0.6.0
+ - Fix `expires` option to reject invalid dates
+ - perf: improve default decode speed
+ - perf: remove slow string split in parse
+ * deps: cookie-signature@1.0.7
+
+1.17.3 / 2022-05-11
+===================
+
+ * Fix resaving already-saved new session at end of request
+ * deps: cookie@0.4.2
+
+1.17.2 / 2021-05-19
+===================
+
+ * Fix `res.end` patch to always commit headers
+ * deps: cookie@0.4.1
+ * deps: safe-buffer@5.2.1
+
+1.17.1 / 2020-04-16
+===================
+
+ * Fix internal method wrapping error on failed reloads
+
+1.17.0 / 2019-10-10
+===================
+
+ * deps: cookie@0.4.0
+ - Add `SameSite=None` support
+ * deps: safe-buffer@5.2.0
+
+1.16.2 / 2019-06-12
+===================
+
+ * Fix restoring `cookie.originalMaxAge` when store returns `Date`
+ * deps: parseurl@~1.3.3
+
+1.16.1 / 2019-04-11
+===================
+
+ * Fix error passing `data` option to `Cookie` constructor
+ * Fix uncaught error from bad session data
+
+1.16.0 / 2019-04-10
+===================
+
+ * Catch invalid `cookie.maxAge` value earlier
+ * Deprecate setting `cookie.maxAge` to a `Date` object
+ * Fix issue where `resave: false` may not save altered sessions
+ * Remove `utils-merge` dependency
+ * Use `safe-buffer` for improved Buffer API
+ * Use `Set-Cookie` as cookie header name for compatibility
+ * deps: depd@~2.0.0
+ - Replace internal `eval` usage with `Function` constructor
+ - Use instance methods on `process` to check for listeners
+ - perf: remove argument reassignment
+ * deps: on-headers@~1.0.2
+ - Fix `res.writeHead` patch missing return value
+
+1.15.6 / 2017-09-26
+===================
+
+ * deps: debug@2.6.9
+ * deps: parseurl@~1.3.2
+ - perf: reduce overhead for full URLs
+ - perf: unroll the "fast-path" `RegExp`
+ * deps: uid-safe@~2.1.5
+ - perf: remove only trailing `=`
+ * deps: utils-merge@1.0.1
+
+1.15.5 / 2017-08-02
+===================
+
+ * Fix `TypeError` when `req.url` is an empty string
+ * deps: depd@~1.1.1
+ - Remove unnecessary `Buffer` loading
+
+1.15.4 / 2017-07-18
+===================
+
+ * deps: debug@2.6.8
+
+1.15.3 / 2017-05-17
+===================
+
+ * deps: debug@2.6.7
+ - deps: ms@2.0.0
+
+1.15.2 / 2017-03-26
+===================
+
+ * deps: debug@2.6.3
+ - Fix `DEBUG_MAX_ARRAY_LENGTH`
+ * deps: uid-safe@~2.1.4
+ - Remove `base64-url` dependency
+
+1.15.1 / 2017-02-10
+===================
+
+ * deps: debug@2.6.1
+ - Fix deprecation messages in WebStorm and other editors
+ - Undeprecate `DEBUG_FD` set to `1` or `2`
+
+1.15.0 / 2017-01-22
+===================
+
+ * Fix detecting modified session when session contains "cookie" property
+ * Fix resaving already-saved reloaded session at end of request
+ * deps: crc@3.4.4
+ - perf: use `Buffer.from` when available
+ * deps: debug@2.6.0
+ - Allow colors in workers
+ - Deprecated `DEBUG_FD` environment variable
+ - Use same color for same namespace
+ - Fix error when running under React Native
+ - deps: ms@0.7.2
+ * perf: remove unreachable branch in set-cookie method
+
+1.14.2 / 2016-10-30
+===================
+
+ * deps: crc@3.4.1
+ - Fix deprecation warning in Node.js 7.x
+ * deps: uid-safe@~2.1.3
+ - deps: base64-url@1.3.3
+
+1.14.1 / 2016-08-24
+===================
+
+ * Fix not always resetting session max age before session save
+ * Fix the cookie `sameSite` option to actually alter the `Set-Cookie`
+ * deps: uid-safe@~2.1.2
+ - deps: base64-url@1.3.2
+
+1.14.0 / 2016-07-01
+===================
+
+ * Correctly inherit from `EventEmitter` class in `Store` base class
+ * Fix issue where `Set-Cookie` `Expires` was not always updated
+ * Methods are no longer enumerable on `req.session` object
+ * deps: cookie@0.3.1
+ - Add `sameSite` option
+ - Improve error message when `encode` is not a function
+ - Improve error message when `expires` is not a `Date`
+ - perf: enable strict mode
+ - perf: use for loop in parse
+ - perf: use string concatination for serialization
+ * deps: parseurl@~1.3.1
+ - perf: enable strict mode
+ * deps: uid-safe@~2.1.1
+ - Use `random-bytes` for byte source
+ - deps: base64-url@1.2.2
+ * perf: enable strict mode
+ * perf: remove argument reassignment
+
+1.13.0 / 2016-01-10
+===================
+
+ * Fix `rolling: true` to not set cookie when no session exists
+ - Better `saveUninitialized: false` + `rolling: true` behavior
+ * deps: crc@3.4.0
+
+1.12.1 / 2015-10-29
+===================
+
+ * deps: cookie@0.2.3
+ - Fix cookie `Max-Age` to never be a floating point number
+
+1.12.0 / 2015-10-25
+===================
+
+ * Support the value `'auto'` in the `cookie.secure` option
+ * deps: cookie@0.2.2
+ - Throw on invalid values provided to `serialize`
+ * deps: depd@~1.1.0
+ - Enable strict mode in more places
+ - Support web browser loading
+ * deps: on-headers@~1.0.1
+ - perf: enable strict mode
+
+1.11.3 / 2015-05-22
+===================
+
+ * deps: cookie@0.1.3
+ - Slight optimizations
+ * deps: crc@3.3.0
+
+1.11.2 / 2015-05-10
+===================
+
+ * deps: debug@~2.2.0
+ - deps: ms@0.7.1
+ * deps: uid-safe@~2.0.0
+
+1.11.1 / 2015-04-08
+===================
+
+ * Fix mutating `options.secret` value
+
+1.11.0 / 2015-04-07
+===================
+
+ * Support an array in `secret` option for key rotation
+ * deps: depd@~1.0.1
+
+1.10.4 / 2015-03-15
+===================
+
+ * deps: debug@~2.1.3
+ - Fix high intensity foreground color for bold
+ - deps: ms@0.7.0
+
+1.10.3 / 2015-02-16
+===================
+
+ * deps: cookie-signature@1.0.6
+ * deps: uid-safe@1.1.0
+ - Use `crypto.randomBytes`, if available
+ - deps: base64-url@1.2.1
+
+1.10.2 / 2015-01-31
+===================
+
+ * deps: uid-safe@1.0.3
+ - Fix error branch that would throw
+ - deps: base64-url@1.2.0
+
+1.10.1 / 2015-01-08
+===================
+
+ * deps: uid-safe@1.0.2
+ - Remove dependency on `mz`
+
+1.10.0 / 2015-01-05
+===================
+
+ * Add `store.touch` interface for session stores
+ * Fix `MemoryStore` expiration with `resave: false`
+ * deps: debug@~2.1.1
+
+1.9.3 / 2014-12-02
+==================
+
+ * Fix error when `req.sessionID` contains a non-string value
+
+1.9.2 / 2014-11-22
+==================
+
+ * deps: crc@3.2.1
+ - Minor fixes
+
+1.9.1 / 2014-10-22
+==================
+
+ * Remove unnecessary empty write call
+ - Fixes Node.js 0.11.14 behavior change
+ - Helps work-around Node.js 0.10.1 zlib bug
+
+1.9.0 / 2014-09-16
+==================
+
+ * deps: debug@~2.1.0
+ - Implement `DEBUG_FD` env variable support
+ * deps: depd@~1.0.0
+
+1.8.2 / 2014-09-15
+==================
+
+ * Use `crc` instead of `buffer-crc32` for speed
+ * deps: depd@0.4.5
+
+1.8.1 / 2014-09-08
+==================
+
+ * Keep `req.session.save` non-enumerable
+ * Prevent session prototype methods from being overwritten
+
+1.8.0 / 2014-09-07
+==================
+
+ * Do not resave already-saved session at end of request
+ * deps: cookie-signature@1.0.5
+ * deps: debug@~2.0.0
+
+1.7.6 / 2014-08-18
+==================
+
+ * Fix exception on `res.end(null)` calls
+
+1.7.5 / 2014-08-10
+==================
+
+ * Fix parsing original URL
+ * deps: on-headers@~1.0.0
+ * deps: parseurl@~1.3.0
+
+1.7.4 / 2014-08-05
+==================
+
+ * Fix response end delay for non-chunked responses
+
+1.7.3 / 2014-08-05
+==================
+
+ * Fix `res.end` patch to call correct upstream `res.write`
+
+1.7.2 / 2014-07-27
+==================
+
+ * deps: depd@0.4.4
+ - Work-around v8 generating empty stack traces
+
+1.7.1 / 2014-07-26
+==================
+
+ * deps: depd@0.4.3
+ - Fix exception when global `Error.stackTraceLimit` is too low
+
+1.7.0 / 2014-07-22
+==================
+
+ * Improve session-ending error handling
+ - Errors are passed to `next(err)` instead of `console.error`
+ * deps: debug@1.0.4
+ * deps: depd@0.4.2
+ - Add `TRACE_DEPRECATION` environment variable
+ - Remove non-standard grey color from color output
+ - Support `--no-deprecation` argument
+ - Support `--trace-deprecation` argument
+
+1.6.5 / 2014-07-11
+==================
+
+ * Do not require `req.originalUrl`
+ * deps: debug@1.0.3
+ - Add support for multiple wildcards in namespaces
+
+1.6.4 / 2014-07-07
+==================
+
+ * Fix blank responses for stores with synchronous operations
+
+1.6.3 / 2014-07-04
+==================
+
+ * Fix resave deprecation message
+
+1.6.2 / 2014-07-04
+==================
+
+ * Fix confusing option deprecation messages
+
+1.6.1 / 2014-06-28
+==================
+
+ * Fix saveUninitialized deprecation message
+
+1.6.0 / 2014-06-28
+==================
+
+ * Add deprecation message to undefined `resave` option
+ * Add deprecation message to undefined `saveUninitialized` option
+ * Fix `res.end` patch to return correct value
+ * Fix `res.end` patch to handle multiple `res.end` calls
+ * Reject cookies with missing signatures
+
+1.5.2 / 2014-06-26
+==================
+
+ * deps: cookie-signature@1.0.4
+ - fix for timing attacks
+
+1.5.1 / 2014-06-21
+==================
+
+ * Move hard-to-track-down `req.secret` deprecation message
+
+1.5.0 / 2014-06-19
+==================
+
+ * Debug name is now "express-session"
+ * Deprecate integration with `cookie-parser` middleware
+ * Deprecate looking for secret in `req.secret`
+ * Directly read cookies; `cookie-parser` no longer required
+ * Directly set cookies; `res.cookie` no longer required
+ * Generate session IDs with `uid-safe`, faster and even less collisions
+
+1.4.0 / 2014-06-17
+==================
+
+ * Add `genid` option to generate custom session IDs
+ * Add `saveUninitialized` option to control saving uninitialized sessions
+ * Add `unset` option to control unsetting `req.session`
+ * Generate session IDs with `rand-token` by default; reduce collisions
+ * deps: buffer-crc32@0.2.3
+
+1.3.1 / 2014-06-14
+==================
+
+ * Add description in package for npmjs.org listing
+
+1.3.0 / 2014-06-14
+==================
+
+ * Integrate with express "trust proxy" by default
+ * deps: debug@1.0.2
+
+1.2.1 / 2014-05-27
+==================
+
+ * Fix `resave` such that `resave: true` works
+
+1.2.0 / 2014-05-19
+==================
+
+ * Add `resave` option to control saving unmodified sessions
+
+1.1.0 / 2014-05-12
+==================
+
+ * Add `name` option; replacement for `key` option
+ * Use `setImmediate` in MemoryStore for node.js >= 0.10
+
+1.0.4 / 2014-04-27
+==================
+
+ * deps: debug@0.8.1
+
+1.0.3 / 2014-04-19
+==================
+
+ * Use `res.cookie()` instead of `res.setHeader()`
+ * deps: cookie@0.1.2
+
+1.0.2 / 2014-02-23
+==================
+
+ * Add missing dependency to `package.json`
+
+1.0.1 / 2014-02-15
+==================
+
+ * Add missing dependencies to `package.json`
+
+1.0.0 / 2014-02-15
+==================
+
+ * Genesis from `connect`
diff --git a/node_modules/express-session/LICENSE b/node_modules/express-session/LICENSE
new file mode 100644
index 0000000..9b59ff8
--- /dev/null
+++ b/node_modules/express-session/LICENSE
@@ -0,0 +1,24 @@
+(The MIT License)
+
+Copyright (c) 2010 Sencha Inc.
+Copyright (c) 2011 TJ Holowaychuk
+Copyright (c) 2014-2015 Douglas Christopher Wilson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/express-session/README.md b/node_modules/express-session/README.md
new file mode 100644
index 0000000..65a37e6
--- /dev/null
+++ b/node_modules/express-session/README.md
@@ -0,0 +1,1032 @@
+# express-session
+
+[![NPM Version][npm-version-image]][npm-url]
+[![NPM Downloads][npm-downloads-image]][node-url]
+[![Build Status][ci-image]][ci-url]
+[![Test Coverage][coveralls-image]][coveralls-url]
+
+## Installation
+
+This is a [Node.js](https://nodejs.org/en/) module available through the
+[npm registry](https://www.npmjs.com/). Installation is done using the
+[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
+
+```sh
+$ npm install express-session
+```
+
+## API
+
+```js
+var session = require('express-session')
+```
+
+### session(options)
+
+Create a session middleware with the given `options`.
+
+**Note** Session data is _not_ saved in the cookie itself, just the session ID.
+Session data is stored server-side.
+
+**Note** Since version 1.5.0, the [`cookie-parser` middleware](https://www.npmjs.com/package/cookie-parser)
+no longer needs to be used for this module to work. This module now directly reads
+and writes cookies on `req`/`res`. Using `cookie-parser` may result in issues
+if the `secret` is not the same between this module and `cookie-parser`.
+
+**Warning** The default server-side session storage, `MemoryStore`, is _purposely_
+not designed for a production environment. It will leak memory under most
+conditions, does not scale past a single process, and is meant for debugging and
+developing.
+
+For a list of stores, see [compatible session stores](#compatible-session-stores).
+
+#### Options
+
+`express-session` accepts these properties in the options object.
+
+##### cookie
+
+Settings object for the session ID cookie. The default value is
+`{ path: '/', httpOnly: true, secure: false, maxAge: null }`.
+
+The following are options that can be set in this object.
+
+##### cookie.domain
+
+Specifies the value for the `Domain` `Set-Cookie` attribute. By default, no domain
+is set, and most clients will consider the cookie to apply to only the current
+domain.
+
+##### cookie.expires
+
+Specifies the `Date` object to be the value for the `Expires` `Set-Cookie` attribute.
+By default, no expiration is set, and most clients will consider this a
+"non-persistent cookie" and will delete it on a condition like exiting a web browser
+application.
+
+**Note** If both `expires` and `maxAge` are set in the options, then the last one
+defined in the object is what is used.
+
+**Note** The `expires` option should not be set directly; instead only use the `maxAge`
+option.
+
+##### cookie.httpOnly
+
+Specifies the `boolean` value for the `HttpOnly` `Set-Cookie` attribute. When truthy,
+the `HttpOnly` attribute is set, otherwise it is not. By default, the `HttpOnly`
+attribute is set.
+
+**Note** be careful when setting this to `true`, as compliant clients will not allow
+client-side JavaScript to see the cookie in `document.cookie`.
+
+##### cookie.maxAge
+
+Specifies the `number` (in milliseconds) to use when calculating the `Expires`
+`Set-Cookie` attribute. This is done by taking the current server time and adding
+`maxAge` milliseconds to the value to calculate an `Expires` datetime. By default,
+no maximum age is set.
+
+**Note** If both `expires` and `maxAge` are set in the options, then the last one
+defined in the object is what is used.
+
+##### cookie.partitioned
+
+Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](rfc-cutler-httpbis-partitioned-cookies)
+attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not.
+By default, the `Partitioned` attribute is not set.
+
+**Note** This is an attribute that has not yet been fully standardized, and may
+change in the future. This also means many clients may ignore this attribute until
+they understand it.
+
+More information about can be found in [the proposal](https://github.com/privacycg/CHIPS).
+
+##### cookie.path
+
+Specifies the value for the `Path` `Set-Cookie`. By default, this is set to `'/'`, which
+is the root path of the domain.
+
+##### cookie.priority
+
+Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-4.1].
+
+ - `'low'` will set the `Priority` attribute to `Low`.
+ - `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set.
+ - `'high'` will set the `Priority` attribute to `High`.
+
+More information about the different priority levels can be found in
+[the specification][rfc-west-cookie-priority-00-4.1].
+
+**Note** This is an attribute that has not yet been fully standardized, and may change in the future.
+This also means many clients may ignore this attribute until they understand it.
+
+##### cookie.sameSite
+
+Specifies the `boolean` or `string` to be the value for the `SameSite` `Set-Cookie` attribute.
+By default, this is `false`.
+
+ - `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
+ - `false` will not set the `SameSite` attribute.
+ - `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement.
+ - `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.
+ - `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
+
+More information about the different enforcement levels can be found in
+[the specification][rfc-6265bis-03-4.1.2.7].
+
+**Note** This is an attribute that has not yet been fully standardized, and may change in
+the future. This also means many clients may ignore this attribute until they understand it.
+
+**Note** There is a [draft spec](https://tools.ietf.org/html/draft-west-cookie-incrementalism-01)
+that requires that the `Secure` attribute be set to `true` when the `SameSite` attribute has been
+set to `'none'`. Some web browsers or other clients may be adopting this specification.
+
+##### cookie.secure
+
+Specifies the `boolean` value for the `Secure` `Set-Cookie` attribute. When truthy,
+the `Secure` attribute is set, otherwise it is not. By default, the `Secure`
+attribute is not set.
+
+**Note** be careful when setting this to `true`, as compliant clients will not send
+the cookie back to the server in the future if the browser does not have an HTTPS
+connection.
+
+Please note that `secure: true` is a **recommended** option. However, it requires
+an https-enabled website, i.e., HTTPS is necessary for secure cookies. If `secure`
+is set, and you access your site over HTTP, the cookie will not be set. If you
+have your node.js behind a proxy and are using `secure: true`, you need to set
+"trust proxy" in express:
+
+```js
+var app = express()
+app.set('trust proxy', 1) // trust first proxy
+app.use(session({
+ secret: 'keyboard cat',
+ resave: false,
+ saveUninitialized: true,
+ cookie: { secure: true }
+}))
+```
+
+For using secure cookies in production, but allowing for testing in development,
+the following is an example of enabling this setup based on `NODE_ENV` in express:
+
+```js
+var app = express()
+var sess = {
+ secret: 'keyboard cat',
+ cookie: {}
+}
+
+if (app.get('env') === 'production') {
+ app.set('trust proxy', 1) // trust first proxy
+ sess.cookie.secure = true // serve secure cookies
+}
+
+app.use(session(sess))
+```
+
+The `cookie.secure` option can also be set to the special value `'auto'` to have
+this setting automatically match the determined security of the connection. Be
+careful when using this setting if the site is available both as HTTP and HTTPS,
+as once the cookie is set on HTTPS, it will no longer be visible over HTTP. This
+is useful when the Express `"trust proxy"` setting is properly setup to simplify
+development vs production configuration.
+
+##### genid
+
+Function to call to generate a new session ID. Provide a function that returns
+a string that will be used as a session ID. The function is given `req` as the
+first argument if you want to use some value attached to `req` when generating
+the ID.
+
+The default value is a function which uses the `uid-safe` library to generate IDs.
+
+**NOTE** be careful to generate unique IDs so your sessions do not conflict.
+
+```js
+app.use(session({
+ genid: function(req) {
+ return genuuid() // use UUIDs for session IDs
+ },
+ secret: 'keyboard cat'
+}))
+```
+
+##### name
+
+The name of the session ID cookie to set in the response (and read from in the
+request).
+
+The default value is `'connect.sid'`.
+
+**Note** if you have multiple apps running on the same hostname (this is just
+the name, i.e. `localhost` or `127.0.0.1`; different schemes and ports do not
+name a different hostname), then you need to separate the session cookies from
+each other. The simplest method is to simply set different `name`s per app.
+
+##### proxy
+
+Trust the reverse proxy when setting secure cookies (via the "X-Forwarded-Proto"
+header).
+
+The default value is `undefined`.
+
+ - `true` The "X-Forwarded-Proto" header will be used.
+ - `false` All headers are ignored and the connection is considered secure only
+ if there is a direct TLS/SSL connection.
+ - `undefined` Uses the "trust proxy" setting from express
+
+##### resave
+
+Forces the session to be saved back to the session store, even if the session
+was never modified during the request. Depending on your store this may be
+necessary, but it can also create race conditions where a client makes two
+parallel requests to your server and changes made to the session in one
+request may get overwritten when the other request ends, even if it made no
+changes (this behavior also depends on what store you're using).
+
+The default value is `true`, but using the default has been deprecated,
+as the default will change in the future. Please research into this setting
+and choose what is appropriate to your use-case. Typically, you'll want
+`false`.
+
+How do I know if this is necessary for my store? The best way to know is to
+check with your store if it implements the `touch` method. If it does, then
+you can safely set `resave: false`. If it does not implement the `touch`
+method and your store sets an expiration date on stored sessions, then you
+likely need `resave: true`.
+
+##### rolling
+
+Force the session identifier cookie to be set on every response. The expiration
+is reset to the original [`maxAge`](#cookiemaxage), resetting the expiration
+countdown.
+
+The default value is `false`.
+
+With this enabled, the session identifier cookie will expire in
+[`maxAge`](#cookiemaxage) since the last response was sent instead of in
+[`maxAge`](#cookiemaxage) since the session was last modified by the server.
+
+This is typically used in conjuction with short, non-session-length
+[`maxAge`](#cookiemaxage) values to provide a quick timeout of the session data
+with reduced potential of it occurring during on going server interactions.
+
+**Note** When this option is set to `true` but the `saveUninitialized` option is
+set to `false`, the cookie will not be set on a response with an uninitialized
+session. This option only modifies the behavior when an existing session was
+loaded for the request.
+
+##### saveUninitialized
+
+Forces a session that is "uninitialized" to be saved to the store. A session is
+uninitialized when it is new but not modified. Choosing `false` is useful for
+implementing login sessions, reducing server storage usage, or complying with
+laws that require permission before setting a cookie. Choosing `false` will also
+help with race conditions where a client makes multiple parallel requests
+without a session.
+
+The default value is `true`, but using the default has been deprecated, as the
+default will change in the future. Please research into this setting and
+choose what is appropriate to your use-case.
+
+**Note** if you are using Session in conjunction with PassportJS, Passport
+will add an empty Passport object to the session for use after a user is
+authenticated, which will be treated as a modification to the session, causing
+it to be saved. *This has been fixed in PassportJS 0.3.0*
+
+##### secret
+
+**Required option**
+
+This is the secret used to sign the session ID cookie. The secret can be any type
+of value that is supported by Node.js `crypto.createHmac` (like a string or a
+`Buffer`). This can be either a single secret, or an array of multiple secrets. If
+an array of secrets is provided, only the first element will be used to sign the
+session ID cookie, while all the elements will be considered when verifying the
+signature in requests. The secret itself should be not easily parsed by a human and
+would best be a random set of characters. A best practice may include:
+
+ - The use of environment variables to store the secret, ensuring the secret itself
+ does not exist in your repository.
+ - Periodic updates of the secret, while ensuring the previous secret is in the
+ array.
+
+Using a secret that cannot be guessed will reduce the ability to hijack a session to
+only guessing the session ID (as determined by the `genid` option).
+
+Changing the secret value will invalidate all existing sessions. In order to rotate
+the secret without invalidating sessions, provide an array of secrets, with the new
+secret as first element of the array, and including previous secrets as the later
+elements.
+
+**Note** HMAC-256 is used to sign the session ID. For this reason, the secret should
+contain at least 32 bytes of entropy.
+
+##### store
+
+The session store instance, defaults to a new `MemoryStore` instance.
+
+##### unset
+
+Control the result of unsetting `req.session` (through `delete`, setting to `null`,
+etc.).
+
+The default value is `'keep'`.
+
+ - `'destroy'` The session will be destroyed (deleted) when the response ends.
+ - `'keep'` The session in the store will be kept, but modifications made during
+ the request are ignored and not saved.
+
+### req.session
+
+To store or access session data, simply use the request property `req.session`,
+which is (generally) serialized as JSON by the store, so nested objects
+are typically fine. For example below is a user-specific view counter:
+
+```js
+// Use the session middleware
+app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
+
+// Access the session as req.session
+app.get('/', function(req, res, next) {
+ if (req.session.views) {
+ req.session.views++
+ res.setHeader('Content-Type', 'text/html')
+ res.write('
')
+ res.end()
+ } else {
+ req.session.views = 1
+ res.end('welcome to the session demo. refresh!')
+ }
+})
+```
+
+#### Session.regenerate(callback)
+
+To regenerate the session simply invoke the method. Once complete,
+a new SID and `Session` instance will be initialized at `req.session`
+and the `callback` will be invoked.
+
+```js
+req.session.regenerate(function(err) {
+ // will have a new session here
+})
+```
+
+#### Session.destroy(callback)
+
+Destroys the session and will unset the `req.session` property.
+Once complete, the `callback` will be invoked.
+
+```js
+req.session.destroy(function(err) {
+ // cannot access session here
+})
+```
+
+#### Session.reload(callback)
+
+Reloads the session data from the store and re-populates the
+`req.session` object. Once complete, the `callback` will be invoked.
+
+```js
+req.session.reload(function(err) {
+ // session updated
+})
+```
+
+#### Session.save(callback)
+
+Save the session back to the store, replacing the contents on the store with the
+contents in memory (though a store may do something else--consult the store's
+documentation for exact behavior).
+
+This method is automatically called at the end of the HTTP response if the
+session data has been altered (though this behavior can be altered with various
+options in the middleware constructor). Because of this, typically this method
+does not need to be called.
+
+There are some cases where it is useful to call this method, for example,
+redirects, long-lived requests or in WebSockets.
+
+```js
+req.session.save(function(err) {
+ // session saved
+})
+```
+
+#### Session.touch()
+
+Updates the `.maxAge` property. Typically this is
+not necessary to call, as the session middleware does this for you.
+
+### req.session.id
+
+Each session has a unique ID associated with it. This property is an
+alias of [`req.sessionID`](#reqsessionid-1) and cannot be modified.
+It has been added to make the session ID accessible from the `session`
+object.
+
+### req.session.cookie
+
+Each session has a unique cookie object accompany it. This allows
+you to alter the session cookie per visitor. For example we can
+set `req.session.cookie.expires` to `false` to enable the cookie
+to remain for only the duration of the user-agent.
+
+#### Cookie.maxAge
+
+Alternatively `req.session.cookie.maxAge` will return the time
+remaining in milliseconds, which we may also re-assign a new value
+to adjust the `.expires` property appropriately. The following
+are essentially equivalent
+
+```js
+var hour = 3600000
+req.session.cookie.expires = new Date(Date.now() + hour)
+req.session.cookie.maxAge = hour
+```
+
+For example when `maxAge` is set to `60000` (one minute), and 30 seconds
+has elapsed it will return `30000` until the current request has completed,
+at which time `req.session.touch()` is called to reset
+`req.session.cookie.maxAge` to its original value.
+
+```js
+req.session.cookie.maxAge // => 30000
+```
+
+#### Cookie.originalMaxAge
+
+The `req.session.cookie.originalMaxAge` property returns the original
+`maxAge` (time-to-live), in milliseconds, of the session cookie.
+
+### req.sessionID
+
+To get the ID of the loaded session, access the request property
+`req.sessionID`. This is simply a read-only value set when a session
+is loaded/created.
+
+## Session Store Implementation
+
+Every session store _must_ be an `EventEmitter` and implement specific
+methods. The following methods are the list of **required**, **recommended**,
+and **optional**.
+
+ * Required methods are ones that this module will always call on the store.
+ * Recommended methods are ones that this module will call on the store if
+ available.
+ * Optional methods are ones this module does not call at all, but helps
+ present uniform stores to users.
+
+For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo.
+
+### store.all(callback)
+
+**Optional**
+
+This optional method is used to get all sessions in the store as an array. The
+`callback` should be called as `callback(error, sessions)`.
+
+### store.destroy(sid, callback)
+
+**Required**
+
+This required method is used to destroy/delete a session from the store given
+a session ID (`sid`). The `callback` should be called as `callback(error)` once
+the session is destroyed.
+
+### store.clear(callback)
+
+**Optional**
+
+This optional method is used to delete all sessions from the store. The
+`callback` should be called as `callback(error)` once the store is cleared.
+
+### store.length(callback)
+
+**Optional**
+
+This optional method is used to get the count of all sessions in the store.
+The `callback` should be called as `callback(error, len)`.
+
+### store.get(sid, callback)
+
+**Required**
+
+This required method is used to get a session from the store given a session
+ID (`sid`). The `callback` should be called as `callback(error, session)`.
+
+The `session` argument should be a session if found, otherwise `null` or
+`undefined` if the session was not found (and there was no error). A special
+case is made when `error.code === 'ENOENT'` to act like `callback(null, null)`.
+
+### store.set(sid, session, callback)
+
+**Required**
+
+This required method is used to upsert a session into the store given a
+session ID (`sid`) and session (`session`) object. The callback should be
+called as `callback(error)` once the session has been set in the store.
+
+### store.touch(sid, session, callback)
+
+**Recommended**
+
+This recommended method is used to "touch" a given session given a
+session ID (`sid`) and session (`session`) object. The `callback` should be
+called as `callback(error)` once the session has been touched.
+
+This is primarily used when the store will automatically delete idle sessions
+and this method is used to signal to the store the given session is active,
+potentially resetting the idle timer.
+
+## Compatible Session Stores
+
+The following modules implement a session store that is compatible with this
+module. Please make a PR to add additional modules :)
+
+[![★][aerospike-session-store-image] aerospike-session-store][aerospike-session-store-url] A session store using [Aerospike](http://www.aerospike.com/).
+
+[aerospike-session-store-url]: https://www.npmjs.com/package/aerospike-session-store
+[aerospike-session-store-image]: https://badgen.net/github/stars/aerospike/aerospike-session-store-expressjs?label=%E2%98%85
+
+[![★][better-sqlite3-session-store-image] better-sqlite3-session-store][better-sqlite3-session-store-url] A session store based on [better-sqlite3](https://github.com/JoshuaWise/better-sqlite3).
+
+[better-sqlite3-session-store-url]: https://www.npmjs.com/package/better-sqlite3-session-store
+[better-sqlite3-session-store-image]: https://badgen.net/github/stars/timdaub/better-sqlite3-session-store?label=%E2%98%85
+
+[![★][cassandra-store-image] cassandra-store][cassandra-store-url] An Apache Cassandra-based session store.
+
+[cassandra-store-url]: https://www.npmjs.com/package/cassandra-store
+[cassandra-store-image]: https://badgen.net/github/stars/webcc/cassandra-store?label=%E2%98%85
+
+[![★][cluster-store-image] cluster-store][cluster-store-url] A wrapper for using in-process / embedded
+stores - such as SQLite (via knex), leveldb, files, or memory - with node cluster (desirable for Raspberry Pi 2
+and other multi-core embedded devices).
+
+[cluster-store-url]: https://www.npmjs.com/package/cluster-store
+[cluster-store-image]: https://badgen.net/github/stars/coolaj86/cluster-store?label=%E2%98%85
+
+[![★][connect-arango-image] connect-arango][connect-arango-url] An ArangoDB-based session store.
+
+[connect-arango-url]: https://www.npmjs.com/package/connect-arango
+[connect-arango-image]: https://badgen.net/github/stars/AlexanderArvidsson/connect-arango?label=%E2%98%85
+
+[![★][connect-azuretables-image] connect-azuretables][connect-azuretables-url] An [Azure Table Storage](https://azure.microsoft.com/en-gb/services/storage/tables/)-based session store.
+
+[connect-azuretables-url]: https://www.npmjs.com/package/connect-azuretables
+[connect-azuretables-image]: https://badgen.net/github/stars/mike-goodwin/connect-azuretables?label=%E2%98%85
+
+[![★][connect-cloudant-store-image] connect-cloudant-store][connect-cloudant-store-url] An [IBM Cloudant](https://cloudant.com/)-based session store.
+
+[connect-cloudant-store-url]: https://www.npmjs.com/package/connect-cloudant-store
+[connect-cloudant-store-image]: https://badgen.net/github/stars/adriantanasa/connect-cloudant-store?label=%E2%98%85
+
+[![★][connect-cosmosdb-image] connect-cosmosdb][connect-cosmosdb-url] An Azure [Cosmos DB](https://azure.microsoft.com/en-us/products/cosmos-db/)-based session store.
+
+[connect-cosmosdb-url]: https://www.npmjs.com/package/connect-cosmosdb
+[connect-cosmosdb-image]: https://badgen.net/github/stars/thekillingspree/connect-cosmosdb?label=%E2%98%85
+
+[![★][connect-couchbase-image] connect-couchbase][connect-couchbase-url] A [couchbase](http://www.couchbase.com/)-based session store.
+
+[connect-couchbase-url]: https://www.npmjs.com/package/connect-couchbase
+[connect-couchbase-image]: https://badgen.net/github/stars/christophermina/connect-couchbase?label=%E2%98%85
+
+[![★][connect-datacache-image] connect-datacache][connect-datacache-url] An [IBM Bluemix Data Cache](http://www.ibm.com/cloud-computing/bluemix/)-based session store.
+
+[connect-datacache-url]: https://www.npmjs.com/package/connect-datacache
+[connect-datacache-image]: https://badgen.net/github/stars/adriantanasa/connect-datacache?label=%E2%98%85
+
+[![★][@google-cloud/connect-datastore-image] @google-cloud/connect-datastore][@google-cloud/connect-datastore-url] A [Google Cloud Datastore](https://cloud.google.com/datastore/docs/concepts/overview)-based session store.
+
+[@google-cloud/connect-datastore-url]: https://www.npmjs.com/package/@google-cloud/connect-datastore
+[@google-cloud/connect-datastore-image]: https://badgen.net/github/stars/GoogleCloudPlatform/cloud-datastore-session-node?label=%E2%98%85
+
+[![★][connect-db2-image] connect-db2][connect-db2-url] An IBM DB2-based session store built using [ibm_db](https://www.npmjs.com/package/ibm_db) module.
+
+[connect-db2-url]: https://www.npmjs.com/package/connect-db2
+[connect-db2-image]: https://badgen.net/github/stars/wallali/connect-db2?label=%E2%98%85
+
+[![★][connect-dynamodb-image] connect-dynamodb][connect-dynamodb-url] A DynamoDB-based session store.
+
+[connect-dynamodb-url]: https://www.npmjs.com/package/connect-dynamodb
+[connect-dynamodb-image]: https://badgen.net/github/stars/ca98am79/connect-dynamodb?label=%E2%98%85
+
+[![★][@google-cloud/connect-firestore-image] @google-cloud/connect-firestore][@google-cloud/connect-firestore-url] A [Google Cloud Firestore](https://cloud.google.com/firestore/docs/overview)-based session store.
+
+[@google-cloud/connect-firestore-url]: https://www.npmjs.com/package/@google-cloud/connect-firestore
+[@google-cloud/connect-firestore-image]: https://badgen.net/github/stars/googleapis/nodejs-firestore-session?label=%E2%98%85
+
+[![★][connect-hazelcast-image] connect-hazelcast][connect-hazelcast-url] Hazelcast session store for Connect and Express.
+
+[connect-hazelcast-url]: https://www.npmjs.com/package/connect-hazelcast
+[connect-hazelcast-image]: https://badgen.net/github/stars/huseyinbabal/connect-hazelcast?label=%E2%98%85
+
+[![★][connect-loki-image] connect-loki][connect-loki-url] A Loki.js-based session store.
+
+[connect-loki-url]: https://www.npmjs.com/package/connect-loki
+[connect-loki-image]: https://badgen.net/github/stars/Requarks/connect-loki?label=%E2%98%85
+
+[![★][connect-lowdb-image] connect-lowdb][connect-lowdb-url] A lowdb-based session store.
+
+[connect-lowdb-url]: https://www.npmjs.com/package/connect-lowdb
+[connect-lowdb-image]: https://badgen.net/github/stars/travishorn/connect-lowdb?label=%E2%98%85
+
+[![★][connect-memcached-image] connect-memcached][connect-memcached-url] A memcached-based session store.
+
+[connect-memcached-url]: https://www.npmjs.com/package/connect-memcached
+[connect-memcached-image]: https://badgen.net/github/stars/balor/connect-memcached?label=%E2%98%85
+
+[![★][connect-memjs-image] connect-memjs][connect-memjs-url] A memcached-based session store using
+[memjs](https://www.npmjs.com/package/memjs) as the memcached client.
+
+[connect-memjs-url]: https://www.npmjs.com/package/connect-memjs
+[connect-memjs-image]: https://badgen.net/github/stars/liamdon/connect-memjs?label=%E2%98%85
+
+[![★][connect-ml-image] connect-ml][connect-ml-url] A MarkLogic Server-based session store.
+
+[connect-ml-url]: https://www.npmjs.com/package/connect-ml
+[connect-ml-image]: https://badgen.net/github/stars/bluetorch/connect-ml?label=%E2%98%85
+
+[![★][connect-monetdb-image] connect-monetdb][connect-monetdb-url] A MonetDB-based session store.
+
+[connect-monetdb-url]: https://www.npmjs.com/package/connect-monetdb
+[connect-monetdb-image]: https://badgen.net/github/stars/MonetDB/npm-connect-monetdb?label=%E2%98%85
+
+[![★][connect-mongo-image] connect-mongo][connect-mongo-url] A MongoDB-based session store.
+
+[connect-mongo-url]: https://www.npmjs.com/package/connect-mongo
+[connect-mongo-image]: https://badgen.net/github/stars/kcbanner/connect-mongo?label=%E2%98%85
+
+[![★][connect-mongodb-session-image] connect-mongodb-session][connect-mongodb-session-url] Lightweight MongoDB-based session store built and maintained by MongoDB.
+
+[connect-mongodb-session-url]: https://www.npmjs.com/package/connect-mongodb-session
+[connect-mongodb-session-image]: https://badgen.net/github/stars/mongodb-js/connect-mongodb-session?label=%E2%98%85
+
+[![★][connect-mssql-v2-image] connect-mssql-v2][connect-mssql-v2-url] A Microsoft SQL Server-based session store based on [connect-mssql](https://www.npmjs.com/package/connect-mssql).
+
+[connect-mssql-v2-url]: https://www.npmjs.com/package/connect-mssql-v2
+[connect-mssql-v2-image]: https://badgen.net/github/stars/jluboff/connect-mssql-v2?label=%E2%98%85
+
+[![★][connect-neo4j-image] connect-neo4j][connect-neo4j-url] A [Neo4j](https://neo4j.com)-based session store.
+
+[connect-neo4j-url]: https://www.npmjs.com/package/connect-neo4j
+[connect-neo4j-image]: https://badgen.net/github/stars/MaxAndersson/connect-neo4j?label=%E2%98%85
+
+[![★][connect-ottoman-image] connect-ottoman][connect-ottoman-url] A [couchbase ottoman](http://www.couchbase.com/)-based session store.
+
+[connect-ottoman-url]: https://www.npmjs.com/package/connect-ottoman
+[connect-ottoman-image]: https://badgen.net/github/stars/noiissyboy/connect-ottoman?label=%E2%98%85
+
+[![★][connect-pg-simple-image] connect-pg-simple][connect-pg-simple-url] A PostgreSQL-based session store.
+
+[connect-pg-simple-url]: https://www.npmjs.com/package/connect-pg-simple
+[connect-pg-simple-image]: https://badgen.net/github/stars/voxpelli/node-connect-pg-simple?label=%E2%98%85
+
+[![★][connect-redis-image] connect-redis][connect-redis-url] A Redis-based session store.
+
+[connect-redis-url]: https://www.npmjs.com/package/connect-redis
+[connect-redis-image]: https://badgen.net/github/stars/tj/connect-redis?label=%E2%98%85
+
+[![★][connect-session-firebase-image] connect-session-firebase][connect-session-firebase-url] A session store based on the [Firebase Realtime Database](https://firebase.google.com/docs/database/)
+
+[connect-session-firebase-url]: https://www.npmjs.com/package/connect-session-firebase
+[connect-session-firebase-image]: https://badgen.net/github/stars/benweier/connect-session-firebase?label=%E2%98%85
+
+[![★][connect-session-knex-image] connect-session-knex][connect-session-knex-url] A session store using
+[Knex.js](http://knexjs.org/), which is a SQL query builder for PostgreSQL, MySQL, MariaDB, SQLite3, and Oracle.
+
+[connect-session-knex-url]: https://www.npmjs.com/package/connect-session-knex
+[connect-session-knex-image]: https://badgen.net/github/stars/llambda/connect-session-knex?label=%E2%98%85
+
+[![★][connect-session-sequelize-image] connect-session-sequelize][connect-session-sequelize-url] A session store using
+[Sequelize.js](http://sequelizejs.com/), which is a Node.js / io.js ORM for PostgreSQL, MySQL, SQLite and MSSQL.
+
+[connect-session-sequelize-url]: https://www.npmjs.com/package/connect-session-sequelize
+[connect-session-sequelize-image]: https://badgen.net/github/stars/mweibel/connect-session-sequelize?label=%E2%98%85
+
+[![★][connect-sqlite3-image] connect-sqlite3][connect-sqlite3-url] A [SQLite3](https://github.com/mapbox/node-sqlite3) session store modeled after the TJ's `connect-redis` store.
+
+[connect-sqlite3-url]: https://www.npmjs.com/package/connect-sqlite3
+[connect-sqlite3-image]: https://badgen.net/github/stars/rawberg/connect-sqlite3?label=%E2%98%85
+
+[![★][connect-typeorm-image] connect-typeorm][connect-typeorm-url] A [TypeORM](https://github.com/typeorm/typeorm)-based session store.
+
+[connect-typeorm-url]: https://www.npmjs.com/package/connect-typeorm
+[connect-typeorm-image]: https://badgen.net/github/stars/makepost/connect-typeorm?label=%E2%98%85
+
+[![★][couchdb-expression-image] couchdb-expression][couchdb-expression-url] A [CouchDB](https://couchdb.apache.org/)-based session store.
+
+[couchdb-expression-url]: https://www.npmjs.com/package/couchdb-expression
+[couchdb-expression-image]: https://badgen.net/github/stars/tkshnwesper/couchdb-expression?label=%E2%98%85
+
+[![★][dynamodb-store-image] dynamodb-store][dynamodb-store-url] A DynamoDB-based session store.
+
+[dynamodb-store-url]: https://www.npmjs.com/package/dynamodb-store
+[dynamodb-store-image]: https://badgen.net/github/stars/rafaelrpinto/dynamodb-store?label=%E2%98%85
+
+[![★][dynamodb-store-v3-image] dynamodb-store-v3][dynamodb-store-v3-url] Implementation of a session store using DynamoDB backed by the [AWS SDK for JavaScript v3](https://github.com/aws/aws-sdk-js-v3).
+
+[dynamodb-store-v3-url]: https://www.npmjs.com/package/dynamodb-store-v3
+[dynamodb-store-v3-image]: https://badgen.net/github/stars/FryDay/dynamodb-store-v3?label=%E2%98%85
+
+[![★][express-etcd-image] express-etcd][express-etcd-url] An [etcd](https://github.com/stianeikeland/node-etcd) based session store.
+
+[express-etcd-url]: https://www.npmjs.com/package/express-etcd
+[express-etcd-image]: https://badgen.net/github/stars/gildean/express-etcd?label=%E2%98%85
+
+[![★][express-mysql-session-image] express-mysql-session][express-mysql-session-url] A session store using native
+[MySQL](https://www.mysql.com/) via the [node-mysql](https://github.com/felixge/node-mysql) module.
+
+[express-mysql-session-url]: https://www.npmjs.com/package/express-mysql-session
+[express-mysql-session-image]: https://badgen.net/github/stars/chill117/express-mysql-session?label=%E2%98%85
+
+[![★][express-nedb-session-image] express-nedb-session][express-nedb-session-url] A NeDB-based session store.
+
+[express-nedb-session-url]: https://www.npmjs.com/package/express-nedb-session
+[express-nedb-session-image]: https://badgen.net/github/stars/louischatriot/express-nedb-session?label=%E2%98%85
+
+[![★][express-oracle-session-image] express-oracle-session][express-oracle-session-url] A session store using native
+[oracle](https://www.oracle.com/) via the [node-oracledb](https://www.npmjs.com/package/oracledb) module.
+
+[express-oracle-session-url]: https://www.npmjs.com/package/express-oracle-session
+[express-oracle-session-image]: https://badgen.net/github/stars/slumber86/express-oracle-session?label=%E2%98%85
+
+[![★][express-session-cache-manager-image] express-session-cache-manager][express-session-cache-manager-url]
+A store that implements [cache-manager](https://www.npmjs.com/package/cache-manager), which supports
+a [variety of storage types](https://www.npmjs.com/package/cache-manager#store-engines).
+
+[express-session-cache-manager-url]: https://www.npmjs.com/package/express-session-cache-manager
+[express-session-cache-manager-image]: https://badgen.net/github/stars/theogravity/express-session-cache-manager?label=%E2%98%85
+
+[![★][express-session-etcd3-image] express-session-etcd3][express-session-etcd3-url] An [etcd3](https://github.com/mixer/etcd3) based session store.
+
+[express-session-etcd3-url]: https://www.npmjs.com/package/express-session-etcd3
+[express-session-etcd3-image]: https://badgen.net/github/stars/willgm/express-session-etcd3?label=%E2%98%85
+
+[![★][express-session-level-image] express-session-level][express-session-level-url] A [LevelDB](https://github.com/Level/levelup) based session store.
+
+[express-session-level-url]: https://www.npmjs.com/package/express-session-level
+[express-session-level-image]: https://badgen.net/github/stars/tgohn/express-session-level?label=%E2%98%85
+
+[![★][express-session-rsdb-image] express-session-rsdb][express-session-rsdb-url] Session store based on Rocket-Store: A very simple, super fast and yet powerfull, flat file database.
+
+[express-session-rsdb-url]: https://www.npmjs.com/package/express-session-rsdb
+[express-session-rsdb-image]: https://badgen.net/github/stars/paragi/express-session-rsdb?label=%E2%98%85
+
+[![★][express-sessions-image] express-sessions][express-sessions-url] A session store supporting both MongoDB and Redis.
+
+[express-sessions-url]: https://www.npmjs.com/package/express-sessions
+[express-sessions-image]: https://badgen.net/github/stars/konteck/express-sessions?label=%E2%98%85
+
+[![★][firestore-store-image] firestore-store][firestore-store-url] A [Firestore](https://github.com/hendrysadrak/firestore-store)-based session store.
+
+[firestore-store-url]: https://www.npmjs.com/package/firestore-store
+[firestore-store-image]: https://badgen.net/github/stars/hendrysadrak/firestore-store?label=%E2%98%85
+
+[![★][fortune-session-image] fortune-session][fortune-session-url] A [Fortune.js](https://github.com/fortunejs/fortune)
+based session store. Supports all backends supported by Fortune (MongoDB, Redis, Postgres, NeDB).
+
+[fortune-session-url]: https://www.npmjs.com/package/fortune-session
+[fortune-session-image]: https://badgen.net/github/stars/aliceklipper/fortune-session?label=%E2%98%85
+
+[![★][hazelcast-store-image] hazelcast-store][hazelcast-store-url] A Hazelcast-based session store built on the [Hazelcast Node Client](https://www.npmjs.com/package/hazelcast-client).
+
+[hazelcast-store-url]: https://www.npmjs.com/package/hazelcast-store
+[hazelcast-store-image]: https://badgen.net/github/stars/jackspaniel/hazelcast-store?label=%E2%98%85
+
+[![★][level-session-store-image] level-session-store][level-session-store-url] A LevelDB-based session store.
+
+[level-session-store-url]: https://www.npmjs.com/package/level-session-store
+[level-session-store-image]: https://badgen.net/github/stars/toddself/level-session-store?label=%E2%98%85
+
+[![★][lowdb-session-store-image] lowdb-session-store][lowdb-session-store-url] A [lowdb](https://www.npmjs.com/package/lowdb)-based session store.
+
+[lowdb-session-store-url]: https://www.npmjs.com/package/lowdb-session-store
+[lowdb-session-store-image]: https://badgen.net/github/stars/fhellwig/lowdb-session-store?label=%E2%98%85
+
+[![★][medea-session-store-image] medea-session-store][medea-session-store-url] A Medea-based session store.
+
+[medea-session-store-url]: https://www.npmjs.com/package/medea-session-store
+[medea-session-store-image]: https://badgen.net/github/stars/BenjaminVadant/medea-session-store?label=%E2%98%85
+
+[![★][memorystore-image] memorystore][memorystore-url] A memory session store made for production.
+
+[memorystore-url]: https://www.npmjs.com/package/memorystore
+[memorystore-image]: https://badgen.net/github/stars/roccomuso/memorystore?label=%E2%98%85
+
+[![★][mssql-session-store-image] mssql-session-store][mssql-session-store-url] A SQL Server-based session store.
+
+[mssql-session-store-url]: https://www.npmjs.com/package/mssql-session-store
+[mssql-session-store-image]: https://badgen.net/github/stars/jwathen/mssql-session-store?label=%E2%98%85
+
+[![★][nedb-session-store-image] nedb-session-store][nedb-session-store-url] An alternate NeDB-based (either in-memory or file-persisted) session store.
+
+[nedb-session-store-url]: https://www.npmjs.com/package/nedb-session-store
+[nedb-session-store-image]: https://badgen.net/github/stars/JamesMGreene/nedb-session-store?label=%E2%98%85
+
+[![★][@quixo3/prisma-session-store-image] @quixo3/prisma-session-store][@quixo3/prisma-session-store-url] A session store for the [Prisma Framework](https://www.prisma.io).
+
+[@quixo3/prisma-session-store-url]: https://www.npmjs.com/package/@quixo3/prisma-session-store
+[@quixo3/prisma-session-store-image]: https://badgen.net/github/stars/kleydon/prisma-session-store?label=%E2%98%85
+
+[![★][restsession-image] restsession][restsession-url] Store sessions utilizing a RESTful API
+
+[restsession-url]: https://www.npmjs.com/package/restsession
+[restsession-image]: https://badgen.net/github/stars/jankal/restsession?label=%E2%98%85
+
+[![★][sequelstore-connect-image] sequelstore-connect][sequelstore-connect-url] A session store using [Sequelize.js](http://sequelizejs.com/).
+
+[sequelstore-connect-url]: https://www.npmjs.com/package/sequelstore-connect
+[sequelstore-connect-image]: https://badgen.net/github/stars/MattMcFarland/sequelstore-connect?label=%E2%98%85
+
+[![★][session-file-store-image] session-file-store][session-file-store-url] A file system-based session store.
+
+[session-file-store-url]: https://www.npmjs.com/package/session-file-store
+[session-file-store-image]: https://badgen.net/github/stars/valery-barysok/session-file-store?label=%E2%98%85
+
+[![★][session-pouchdb-store-image] session-pouchdb-store][session-pouchdb-store-url] Session store for PouchDB / CouchDB. Accepts embedded, custom, or remote PouchDB instance and realtime synchronization.
+
+[session-pouchdb-store-url]: https://www.npmjs.com/package/session-pouchdb-store
+[session-pouchdb-store-image]: https://badgen.net/github/stars/solzimer/session-pouchdb-store?label=%E2%98%85
+
+[![★][@cyclic.sh/session-store-image] @cyclic.sh/session-store][@cyclic.sh/session-store-url] A DynamoDB-based session store for [Cyclic.sh](https://www.cyclic.sh/) apps.
+
+[@cyclic.sh/session-store-url]: https://www.npmjs.com/package/@cyclic.sh/session-store
+[@cyclic.sh/session-store-image]: https://badgen.net/github/stars/cyclic-software/session-store?label=%E2%98%85
+
+[![★][@databunker/session-store-image] @databunker/session-store][@databunker/session-store-url] A [Databunker](https://databunker.org/)-based encrypted session store.
+
+[@databunker/session-store-url]: https://www.npmjs.com/package/@databunker/session-store
+[@databunker/session-store-image]: https://badgen.net/github/stars/securitybunker/databunker-session-store?label=%E2%98%85
+
+[![★][sessionstore-image] sessionstore][sessionstore-url] A session store that works with various databases.
+
+[sessionstore-url]: https://www.npmjs.com/package/sessionstore
+[sessionstore-image]: https://badgen.net/github/stars/adrai/sessionstore?label=%E2%98%85
+
+[![★][tch-nedb-session-image] tch-nedb-session][tch-nedb-session-url] A file system session store based on NeDB.
+
+[tch-nedb-session-url]: https://www.npmjs.com/package/tch-nedb-session
+[tch-nedb-session-image]: https://badgen.net/github/stars/tomaschyly/NeDBSession?label=%E2%98%85
+
+## Examples
+
+### View counter
+
+A simple example using `express-session` to store page views for a user.
+
+```js
+var express = require('express')
+var parseurl = require('parseurl')
+var session = require('express-session')
+
+var app = express()
+
+app.use(session({
+ secret: 'keyboard cat',
+ resave: false,
+ saveUninitialized: true
+}))
+
+app.use(function (req, res, next) {
+ if (!req.session.views) {
+ req.session.views = {}
+ }
+
+ // get the url pathname
+ var pathname = parseurl(req).pathname
+
+ // count the views
+ req.session.views[pathname] = (req.session.views[pathname] || 0) + 1
+
+ next()
+})
+
+app.get('/foo', function (req, res, next) {
+ res.send('you viewed this page ' + req.session.views['/foo'] + ' times')
+})
+
+app.get('/bar', function (req, res, next) {
+ res.send('you viewed this page ' + req.session.views['/bar'] + ' times')
+})
+
+app.listen(3000)
+```
+
+### User login
+
+A simple example using `express-session` to keep a user log in session.
+
+```js
+var escapeHtml = require('escape-html')
+var express = require('express')
+var session = require('express-session')
+
+var app = express()
+
+app.use(session({
+ secret: 'keyboard cat',
+ resave: false,
+ saveUninitialized: true
+}))
+
+// middleware to test if authenticated
+function isAuthenticated (req, res, next) {
+ if (req.session.user) next()
+ else next('route')
+}
+
+app.get('/', isAuthenticated, function (req, res) {
+ // this is only called when there is an authentication user due to isAuthenticated
+ res.send('hello, ' + escapeHtml(req.session.user) + '!' +
+ ' Logout')
+})
+
+app.get('/', function (req, res) {
+ res.send('')
+})
+
+app.post('/login', express.urlencoded({ extended: false }), function (req, res) {
+ // login logic to validate req.body.user and req.body.pass
+ // would be implemented here. for this example any combo works
+
+ // regenerate the session, which is good practice to help
+ // guard against forms of session fixation
+ req.session.regenerate(function (err) {
+ if (err) next(err)
+
+ // store user information in session, typically a user id
+ req.session.user = req.body.user
+
+ // save the session before redirection to ensure page
+ // load does not happen before session is saved
+ req.session.save(function (err) {
+ if (err) return next(err)
+ res.redirect('/')
+ })
+ })
+})
+
+app.get('/logout', function (req, res, next) {
+ // logout logic
+
+ // clear the user from the session object and save.
+ // this will ensure that re-using the old session id
+ // does not have a logged in user
+ req.session.user = null
+ req.session.save(function (err) {
+ if (err) next(err)
+
+ // regenerate the session, which is good practice to help
+ // guard against forms of session fixation
+ req.session.regenerate(function (err) {
+ if (err) next(err)
+ res.redirect('/')
+ })
+ })
+})
+
+app.listen(3000)
+```
+
+## Debugging
+
+This module uses the [debug](https://www.npmjs.com/package/debug) module
+internally to log information about session operations.
+
+To see all the internal logs, set the `DEBUG` environment variable to
+`express-session` when launching your app (`npm start`, in this example):
+
+```sh
+$ DEBUG=express-session npm start
+```
+
+On Windows, use the corresponding command;
+
+```sh
+> set DEBUG=express-session & npm start
+```
+
+## License
+
+[MIT](LICENSE)
+
+[rfc-6265bis-03-4.1.2.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7
+[rfc-cutler-httpbis-partitioned-cookies]: https://tools.ietf.org/html/draft-cutler-httpbis-partitioned-cookies/
+[rfc-west-cookie-priority-00-4.1]: https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1
+[ci-image]: https://badgen.net/github/checks/expressjs/session/master?label=ci
+[ci-url]: https://github.com/expressjs/session/actions?query=workflow%3Aci
+[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/session/master
+[coveralls-url]: https://coveralls.io/r/expressjs/session?branch=master
+[node-url]: https://nodejs.org/en/download
+[npm-downloads-image]: https://badgen.net/npm/dm/express-session
+[npm-url]: https://npmjs.org/package/express-session
+[npm-version-image]: https://badgen.net/npm/v/express-session
diff --git a/node_modules/express-session/index.js b/node_modules/express-session/index.js
new file mode 100644
index 0000000..d41b237
--- /dev/null
+++ b/node_modules/express-session/index.js
@@ -0,0 +1,693 @@
+/*!
+ * express-session
+ * Copyright(c) 2010 Sencha Inc.
+ * Copyright(c) 2011 TJ Holowaychuk
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var Buffer = require('safe-buffer').Buffer
+var cookie = require('cookie');
+var crypto = require('crypto')
+var debug = require('debug')('express-session');
+var deprecate = require('depd')('express-session');
+var onHeaders = require('on-headers')
+var parseUrl = require('parseurl');
+var signature = require('cookie-signature')
+var uid = require('uid-safe').sync
+
+var Cookie = require('./session/cookie')
+var MemoryStore = require('./session/memory')
+var Session = require('./session/session')
+var Store = require('./session/store')
+
+// environment
+
+var env = process.env.NODE_ENV;
+
+/**
+ * Expose the middleware.
+ */
+
+exports = module.exports = session;
+
+/**
+ * Expose constructors.
+ */
+
+exports.Store = Store;
+exports.Cookie = Cookie;
+exports.Session = Session;
+exports.MemoryStore = MemoryStore;
+
+/**
+ * Warning message for `MemoryStore` usage in production.
+ * @private
+ */
+
+var warning = 'Warning: connect.session() MemoryStore is not\n'
+ + 'designed for a production environment, as it will leak\n'
+ + 'memory, and will not scale past a single process.';
+
+/**
+ * Node.js 0.8+ async implementation.
+ * @private
+ */
+
+/* istanbul ignore next */
+var defer = typeof setImmediate === 'function'
+ ? setImmediate
+ : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
+
+/**
+ * Setup session store with the given `options`.
+ *
+ * @param {Object} [options]
+ * @param {Object} [options.cookie] Options for cookie
+ * @param {Function} [options.genid]
+ * @param {String} [options.name=connect.sid] Session ID cookie name
+ * @param {Boolean} [options.proxy]
+ * @param {Boolean} [options.resave] Resave unmodified sessions back to the store
+ * @param {Boolean} [options.rolling] Enable/disable rolling session expiration
+ * @param {Boolean} [options.saveUninitialized] Save uninitialized sessions to the store
+ * @param {String|Array} [options.secret] Secret for signing session ID
+ * @param {Object} [options.store=MemoryStore] Session store
+ * @param {String} [options.unset]
+ * @return {Function} middleware
+ * @public
+ */
+
+function session(options) {
+ var opts = options || {}
+
+ // get the cookie options
+ var cookieOptions = opts.cookie || {}
+
+ // get the session id generate function
+ var generateId = opts.genid || generateSessionId
+
+ // get the session cookie name
+ var name = opts.name || opts.key || 'connect.sid'
+
+ // get the session store
+ var store = opts.store || new MemoryStore()
+
+ // get the trust proxy setting
+ var trustProxy = opts.proxy
+
+ // get the resave session option
+ var resaveSession = opts.resave;
+
+ // get the rolling session option
+ var rollingSessions = Boolean(opts.rolling)
+
+ // get the save uninitialized session option
+ var saveUninitializedSession = opts.saveUninitialized
+
+ // get the cookie signing secret
+ var secret = opts.secret
+
+ if (typeof generateId !== 'function') {
+ throw new TypeError('genid option must be a function');
+ }
+
+ if (resaveSession === undefined) {
+ deprecate('undefined resave option; provide resave option');
+ resaveSession = true;
+ }
+
+ if (saveUninitializedSession === undefined) {
+ deprecate('undefined saveUninitialized option; provide saveUninitialized option');
+ saveUninitializedSession = true;
+ }
+
+ if (opts.unset && opts.unset !== 'destroy' && opts.unset !== 'keep') {
+ throw new TypeError('unset option must be "destroy" or "keep"');
+ }
+
+ // TODO: switch to "destroy" on next major
+ var unsetDestroy = opts.unset === 'destroy'
+
+ if (Array.isArray(secret) && secret.length === 0) {
+ throw new TypeError('secret option array must contain one or more strings');
+ }
+
+ if (secret && !Array.isArray(secret)) {
+ secret = [secret];
+ }
+
+ if (!secret) {
+ deprecate('req.secret; provide secret option');
+ }
+
+ // notify user that this store is not
+ // meant for a production environment
+ /* istanbul ignore next: not tested */
+ if (env === 'production' && store instanceof MemoryStore) {
+ console.warn(warning);
+ }
+
+ // generates the new session
+ store.generate = function(req){
+ req.sessionID = generateId(req);
+ req.session = new Session(req);
+ req.session.cookie = new Cookie(cookieOptions);
+
+ if (cookieOptions.secure === 'auto') {
+ req.session.cookie.secure = issecure(req, trustProxy);
+ }
+ };
+
+ var storeImplementsTouch = typeof store.touch === 'function';
+
+ // register event listeners for the store to track readiness
+ var storeReady = true
+ store.on('disconnect', function ondisconnect() {
+ storeReady = false
+ })
+ store.on('connect', function onconnect() {
+ storeReady = true
+ })
+
+ return function session(req, res, next) {
+ // self-awareness
+ if (req.session) {
+ next()
+ return
+ }
+
+ // Handle connection as if there is no session if
+ // the store has temporarily disconnected etc
+ if (!storeReady) {
+ debug('store is disconnected')
+ next()
+ return
+ }
+
+ // pathname mismatch
+ var originalPath = parseUrl.original(req).pathname || '/'
+ if (originalPath.indexOf(cookieOptions.path || '/') !== 0) {
+ debug('pathname mismatch')
+ next()
+ return
+ }
+
+ // ensure a secret is available or bail
+ if (!secret && !req.secret) {
+ next(new Error('secret option required for sessions'));
+ return;
+ }
+
+ // backwards compatibility for signed cookies
+ // req.secret is passed from the cookie parser middleware
+ var secrets = secret || [req.secret];
+
+ var originalHash;
+ var originalId;
+ var savedHash;
+ var touched = false
+
+ // expose store
+ req.sessionStore = store;
+
+ // get the session ID from the cookie
+ var cookieId = req.sessionID = getcookie(req, name, secrets);
+
+ // set-cookie
+ onHeaders(res, function(){
+ if (!req.session) {
+ debug('no session');
+ return;
+ }
+
+ if (!shouldSetCookie(req)) {
+ return;
+ }
+
+ // only send secure cookies via https
+ if (req.session.cookie.secure && !issecure(req, trustProxy)) {
+ debug('not secured');
+ return;
+ }
+
+ if (!touched) {
+ // touch session
+ req.session.touch()
+ touched = true
+ }
+
+ // set cookie
+ try {
+ setcookie(res, name, req.sessionID, secrets[0], req.session.cookie.data)
+ } catch (err) {
+ defer(next, err)
+ }
+ });
+
+ // proxy end() to commit the session
+ var _end = res.end;
+ var _write = res.write;
+ var ended = false;
+ res.end = function end(chunk, encoding) {
+ if (ended) {
+ return false;
+ }
+
+ ended = true;
+
+ var ret;
+ var sync = true;
+
+ function writeend() {
+ if (sync) {
+ ret = _end.call(res, chunk, encoding);
+ sync = false;
+ return;
+ }
+
+ _end.call(res);
+ }
+
+ function writetop() {
+ if (!sync) {
+ return ret;
+ }
+
+ if (!res._header) {
+ res._implicitHeader()
+ }
+
+ if (chunk == null) {
+ ret = true;
+ return ret;
+ }
+
+ var contentLength = Number(res.getHeader('Content-Length'));
+
+ if (!isNaN(contentLength) && contentLength > 0) {
+ // measure chunk
+ chunk = !Buffer.isBuffer(chunk)
+ ? Buffer.from(chunk, encoding)
+ : chunk;
+ encoding = undefined;
+
+ if (chunk.length !== 0) {
+ debug('split response');
+ ret = _write.call(res, chunk.slice(0, chunk.length - 1));
+ chunk = chunk.slice(chunk.length - 1, chunk.length);
+ return ret;
+ }
+ }
+
+ ret = _write.call(res, chunk, encoding);
+ sync = false;
+
+ return ret;
+ }
+
+ if (shouldDestroy(req)) {
+ // destroy session
+ debug('destroying');
+ store.destroy(req.sessionID, function ondestroy(err) {
+ if (err) {
+ defer(next, err);
+ }
+
+ debug('destroyed');
+ writeend();
+ });
+
+ return writetop();
+ }
+
+ // no session to save
+ if (!req.session) {
+ debug('no session');
+ return _end.call(res, chunk, encoding);
+ }
+
+ if (!touched) {
+ // touch session
+ req.session.touch()
+ touched = true
+ }
+
+ if (shouldSave(req)) {
+ req.session.save(function onsave(err) {
+ if (err) {
+ defer(next, err);
+ }
+
+ writeend();
+ });
+
+ return writetop();
+ } else if (storeImplementsTouch && shouldTouch(req)) {
+ // store implements touch method
+ debug('touching');
+ store.touch(req.sessionID, req.session, function ontouch(err) {
+ if (err) {
+ defer(next, err);
+ }
+
+ debug('touched');
+ writeend();
+ });
+
+ return writetop();
+ }
+
+ return _end.call(res, chunk, encoding);
+ };
+
+ // generate the session
+ function generate() {
+ store.generate(req);
+ originalId = req.sessionID;
+ originalHash = hash(req.session);
+ wrapmethods(req.session);
+ }
+
+ // inflate the session
+ function inflate (req, sess) {
+ store.createSession(req, sess)
+ originalId = req.sessionID
+ originalHash = hash(sess)
+
+ if (!resaveSession) {
+ savedHash = originalHash
+ }
+
+ wrapmethods(req.session)
+ }
+
+ function rewrapmethods (sess, callback) {
+ return function () {
+ if (req.session !== sess) {
+ wrapmethods(req.session)
+ }
+
+ callback.apply(this, arguments)
+ }
+ }
+
+ // wrap session methods
+ function wrapmethods(sess) {
+ var _reload = sess.reload
+ var _save = sess.save;
+
+ function reload(callback) {
+ debug('reloading %s', this.id)
+ _reload.call(this, rewrapmethods(this, callback))
+ }
+
+ function save() {
+ debug('saving %s', this.id);
+ savedHash = hash(this);
+ _save.apply(this, arguments);
+ }
+
+ Object.defineProperty(sess, 'reload', {
+ configurable: true,
+ enumerable: false,
+ value: reload,
+ writable: true
+ })
+
+ Object.defineProperty(sess, 'save', {
+ configurable: true,
+ enumerable: false,
+ value: save,
+ writable: true
+ });
+ }
+
+ // check if session has been modified
+ function isModified(sess) {
+ return originalId !== sess.id || originalHash !== hash(sess);
+ }
+
+ // check if session has been saved
+ function isSaved(sess) {
+ return originalId === sess.id && savedHash === hash(sess);
+ }
+
+ // determine if session should be destroyed
+ function shouldDestroy(req) {
+ return req.sessionID && unsetDestroy && req.session == null;
+ }
+
+ // determine if session should be saved to store
+ function shouldSave(req) {
+ // cannot set cookie without a session ID
+ if (typeof req.sessionID !== 'string') {
+ debug('session ignored because of bogus req.sessionID %o', req.sessionID);
+ return false;
+ }
+
+ return !saveUninitializedSession && !savedHash && cookieId !== req.sessionID
+ ? isModified(req.session)
+ : !isSaved(req.session)
+ }
+
+ // determine if session should be touched
+ function shouldTouch(req) {
+ // cannot set cookie without a session ID
+ if (typeof req.sessionID !== 'string') {
+ debug('session ignored because of bogus req.sessionID %o', req.sessionID);
+ return false;
+ }
+
+ return cookieId === req.sessionID && !shouldSave(req);
+ }
+
+ // determine if cookie should be set on response
+ function shouldSetCookie(req) {
+ // cannot set cookie without a session ID
+ if (typeof req.sessionID !== 'string') {
+ return false;
+ }
+
+ return cookieId !== req.sessionID
+ ? saveUninitializedSession || isModified(req.session)
+ : rollingSessions || req.session.cookie.expires != null && isModified(req.session);
+ }
+
+ // generate a session if the browser doesn't send a sessionID
+ if (!req.sessionID) {
+ debug('no SID sent, generating session');
+ generate();
+ next();
+ return;
+ }
+
+ // generate the session object
+ debug('fetching %s', req.sessionID);
+ store.get(req.sessionID, function(err, sess){
+ // error handling
+ if (err && err.code !== 'ENOENT') {
+ debug('error %j', err);
+ next(err)
+ return
+ }
+
+ try {
+ if (err || !sess) {
+ debug('no session found')
+ generate()
+ } else {
+ debug('session found')
+ inflate(req, sess)
+ }
+ } catch (e) {
+ next(e)
+ return
+ }
+
+ next()
+ });
+ };
+};
+
+/**
+ * Generate a session ID for a new session.
+ *
+ * @return {String}
+ * @private
+ */
+
+function generateSessionId(sess) {
+ return uid(24);
+}
+
+/**
+ * Get the session ID cookie from request.
+ *
+ * @return {string}
+ * @private
+ */
+
+function getcookie(req, name, secrets) {
+ var header = req.headers.cookie;
+ var raw;
+ var val;
+
+ // read from cookie header
+ if (header) {
+ var cookies = cookie.parse(header);
+
+ raw = cookies[name];
+
+ if (raw) {
+ if (raw.substr(0, 2) === 's:') {
+ val = unsigncookie(raw.slice(2), secrets);
+
+ if (val === false) {
+ debug('cookie signature invalid');
+ val = undefined;
+ }
+ } else {
+ debug('cookie unsigned')
+ }
+ }
+ }
+
+ // back-compat read from cookieParser() signedCookies data
+ if (!val && req.signedCookies) {
+ val = req.signedCookies[name];
+
+ if (val) {
+ deprecate('cookie should be available in req.headers.cookie');
+ }
+ }
+
+ // back-compat read from cookieParser() cookies data
+ if (!val && req.cookies) {
+ raw = req.cookies[name];
+
+ if (raw) {
+ if (raw.substr(0, 2) === 's:') {
+ val = unsigncookie(raw.slice(2), secrets);
+
+ if (val) {
+ deprecate('cookie should be available in req.headers.cookie');
+ }
+
+ if (val === false) {
+ debug('cookie signature invalid');
+ val = undefined;
+ }
+ } else {
+ debug('cookie unsigned')
+ }
+ }
+ }
+
+ return val;
+}
+
+/**
+ * Hash the given `sess` object omitting changes to `.cookie`.
+ *
+ * @param {Object} sess
+ * @return {String}
+ * @private
+ */
+
+function hash(sess) {
+ // serialize
+ var str = JSON.stringify(sess, function (key, val) {
+ // ignore sess.cookie property
+ if (this === sess && key === 'cookie') {
+ return
+ }
+
+ return val
+ })
+
+ // hash
+ return crypto
+ .createHash('sha1')
+ .update(str, 'utf8')
+ .digest('hex')
+}
+
+/**
+ * Determine if request is secure.
+ *
+ * @param {Object} req
+ * @param {Boolean} [trustProxy]
+ * @return {Boolean}
+ * @private
+ */
+
+function issecure(req, trustProxy) {
+ // socket is https server
+ if (req.connection && req.connection.encrypted) {
+ return true;
+ }
+
+ // do not trust proxy
+ if (trustProxy === false) {
+ return false;
+ }
+
+ // no explicit trust; try req.secure from express
+ if (trustProxy !== true) {
+ return req.secure === true
+ }
+
+ // read the proto from x-forwarded-proto header
+ var header = req.headers['x-forwarded-proto'] || '';
+ var index = header.indexOf(',');
+ var proto = index !== -1
+ ? header.substr(0, index).toLowerCase().trim()
+ : header.toLowerCase().trim()
+
+ return proto === 'https';
+}
+
+/**
+ * Set cookie on response.
+ *
+ * @private
+ */
+
+function setcookie(res, name, val, secret, options) {
+ var signed = 's:' + signature.sign(val, secret);
+ var data = cookie.serialize(name, signed, options);
+
+ debug('set-cookie %s', data);
+
+ var prev = res.getHeader('Set-Cookie') || []
+ var header = Array.isArray(prev) ? prev.concat(data) : [prev, data];
+
+ res.setHeader('Set-Cookie', header)
+}
+
+/**
+ * Verify and decode the given `val` with `secrets`.
+ *
+ * @param {String} val
+ * @param {Array} secrets
+ * @returns {String|Boolean}
+ * @private
+ */
+function unsigncookie(val, secrets) {
+ for (var i = 0; i < secrets.length; i++) {
+ var result = signature.unsign(val, secrets[i]);
+
+ if (result !== false) {
+ return result;
+ }
+ }
+
+ return false;
+}
diff --git a/node_modules/express-session/node_modules/cookie-signature/History.md b/node_modules/express-session/node_modules/cookie-signature/History.md
new file mode 100644
index 0000000..bcf8cc9
--- /dev/null
+++ b/node_modules/express-session/node_modules/cookie-signature/History.md
@@ -0,0 +1,42 @@
+1.0.7 / 2023-04-12
+==================
+
+* backport the buffer support from the 1.2.x release branch (thanks @FadhiliNjagi!)
+
+1.0.6 / 2015-02-03
+==================
+
+* use `npm test` instead of `make test` to run tests
+* clearer assertion messages when checking input
+
+1.0.5 / 2014-09-05
+==================
+
+* add license to package.json
+
+1.0.4 / 2014-06-25
+==================
+
+ * corrected avoidance of timing attacks (thanks @tenbits!)
+
+1.0.3 / 2014-01-28
+==================
+
+ * [incorrect] fix for timing attacks
+
+1.0.2 / 2014-01-28
+==================
+
+ * fix missing repository warning
+ * fix typo in test
+
+1.0.1 / 2013-04-15
+==================
+
+ * Revert "Changed underlying HMAC algo. to sha512."
+ * Revert "Fix for timing attacks on MAC verification."
+
+0.0.1 / 2010-01-03
+==================
+
+ * Initial release
diff --git a/node_modules/express-session/node_modules/cookie-signature/Readme.md b/node_modules/express-session/node_modules/cookie-signature/Readme.md
new file mode 100644
index 0000000..2559e84
--- /dev/null
+++ b/node_modules/express-session/node_modules/cookie-signature/Readme.md
@@ -0,0 +1,42 @@
+
+# cookie-signature
+
+ Sign and unsign cookies.
+
+## Example
+
+```js
+var cookie = require('cookie-signature');
+
+var val = cookie.sign('hello', 'tobiiscool');
+val.should.equal('hello.DGDUkGlIkCzPz+C0B064FNgHdEjox7ch8tOBGslZ5QI');
+
+var val = cookie.sign('hello', 'tobiiscool');
+cookie.unsign(val, 'tobiiscool').should.equal('hello');
+cookie.unsign(val, 'luna').should.be.false;
+```
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2012 LearnBoost <tj@learnboost.com>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/node_modules/express-session/node_modules/cookie-signature/index.js b/node_modules/express-session/node_modules/cookie-signature/index.js
new file mode 100644
index 0000000..336d487
--- /dev/null
+++ b/node_modules/express-session/node_modules/cookie-signature/index.js
@@ -0,0 +1,51 @@
+/**
+ * Module dependencies.
+ */
+
+var crypto = require('crypto');
+
+/**
+ * Sign the given `val` with `secret`.
+ *
+ * @param {String} val
+ * @param {String|NodeJS.ArrayBufferView|crypto.KeyObject} secret
+ * @return {String}
+ * @api private
+ */
+
+exports.sign = function(val, secret){
+ if ('string' !== typeof val) throw new TypeError("Cookie value must be provided as a string.");
+ if (null == secret) throw new TypeError("Secret key must be provided.");
+ return val + '.' + crypto
+ .createHmac('sha256', secret)
+ .update(val)
+ .digest('base64')
+ .replace(/\=+$/, '');
+};
+
+/**
+ * Unsign and decode the given `val` with `secret`,
+ * returning `false` if the signature is invalid.
+ *
+ * @param {String} val
+ * @param {String|NodeJS.ArrayBufferView|crypto.KeyObject} secret
+ * @return {String|Boolean}
+ * @api private
+ */
+
+exports.unsign = function(val, secret){
+ if ('string' !== typeof val) throw new TypeError("Signed cookie string must be provided.");
+ if (null == secret) throw new TypeError("Secret key must be provided.");
+ var str = val.slice(0, val.lastIndexOf('.'))
+ , mac = exports.sign(str, secret);
+
+ return sha1(mac) == sha1(val) ? str : false;
+};
+
+/**
+ * Private
+ */
+
+function sha1(str){
+ return crypto.createHash('sha1').update(str).digest('hex');
+}
diff --git a/node_modules/express-session/node_modules/cookie-signature/package.json b/node_modules/express-session/node_modules/cookie-signature/package.json
new file mode 100644
index 0000000..738487b
--- /dev/null
+++ b/node_modules/express-session/node_modules/cookie-signature/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "cookie-signature",
+ "version": "1.0.7",
+ "description": "Sign and unsign cookies",
+ "keywords": ["cookie", "sign", "unsign"],
+ "author": "TJ Holowaychuk ",
+ "license": "MIT",
+ "repository": { "type": "git", "url": "https://github.com/visionmedia/node-cookie-signature.git"},
+ "dependencies": {},
+ "devDependencies": {
+ "mocha": "*",
+ "should": "*"
+ },
+ "scripts": {
+ "test": "mocha --require should --reporter spec"
+ },
+ "main": "index"
+}
\ No newline at end of file
diff --git a/node_modules/express-session/node_modules/cookie/LICENSE b/node_modules/express-session/node_modules/cookie/LICENSE
new file mode 100644
index 0000000..058b6b4
--- /dev/null
+++ b/node_modules/express-session/node_modules/cookie/LICENSE
@@ -0,0 +1,24 @@
+(The MIT License)
+
+Copyright (c) 2012-2014 Roman Shtylman
+Copyright (c) 2015 Douglas Christopher Wilson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/node_modules/express-session/node_modules/cookie/README.md b/node_modules/express-session/node_modules/cookie/README.md
new file mode 100644
index 0000000..71fdac1
--- /dev/null
+++ b/node_modules/express-session/node_modules/cookie/README.md
@@ -0,0 +1,317 @@
+# cookie
+
+[![NPM Version][npm-version-image]][npm-url]
+[![NPM Downloads][npm-downloads-image]][npm-url]
+[![Node.js Version][node-image]][node-url]
+[![Build Status][ci-image]][ci-url]
+[![Coverage Status][coveralls-image]][coveralls-url]
+
+Basic HTTP cookie parser and serializer for HTTP servers.
+
+## Installation
+
+This is a [Node.js](https://nodejs.org/en/) module available through the
+[npm registry](https://www.npmjs.com/). Installation is done using the
+[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
+
+```sh
+$ npm install cookie
+```
+
+## API
+
+```js
+var cookie = require('cookie');
+```
+
+### cookie.parse(str, options)
+
+Parse an HTTP `Cookie` header string and returning an object of all cookie name-value pairs.
+The `str` argument is the string representing a `Cookie` header value and `options` is an
+optional object containing additional parsing options.
+
+```js
+var cookies = cookie.parse('foo=bar; equation=E%3Dmc%5E2');
+// { foo: 'bar', equation: 'E=mc^2' }
+```
+
+#### Options
+
+`cookie.parse` accepts these properties in the options object.
+
+##### decode
+
+Specifies a function that will be used to decode a cookie's value. Since the value of a cookie
+has a limited character set (and must be a simple string), this function can be used to decode
+a previously-encoded cookie value into a JavaScript string or other object.
+
+The default function is the global `decodeURIComponent`, which will decode any URL-encoded
+sequences into their byte representations.
+
+**note** if an error is thrown from this function, the original, non-decoded cookie value will
+be returned as the cookie's value.
+
+### cookie.serialize(name, value, options)
+
+Serialize a cookie name-value pair into a `Set-Cookie` header string. The `name` argument is the
+name for the cookie, the `value` argument is the value to set the cookie to, and the `options`
+argument is an optional object containing additional serialization options.
+
+```js
+var setCookie = cookie.serialize('foo', 'bar');
+// foo=bar
+```
+
+#### Options
+
+`cookie.serialize` accepts these properties in the options object.
+
+##### domain
+
+Specifies the value for the [`Domain` `Set-Cookie` attribute][rfc-6265-5.2.3]. By default, no
+domain is set, and most clients will consider the cookie to apply to only the current domain.
+
+##### encode
+
+Specifies a function that will be used to encode a cookie's value. Since value of a cookie
+has a limited character set (and must be a simple string), this function can be used to encode
+a value into a string suited for a cookie's value.
+
+The default function is the global `encodeURIComponent`, which will encode a JavaScript string
+into UTF-8 byte sequences and then URL-encode any that fall outside of the cookie range.
+
+##### expires
+
+Specifies the `Date` object to be the value for the [`Expires` `Set-Cookie` attribute][rfc-6265-5.2.1].
+By default, no expiration is set, and most clients will consider this a "non-persistent cookie" and
+will delete it on a condition like exiting a web browser application.
+
+**note** the [cookie storage model specification][rfc-6265-5.3] states that if both `expires` and
+`maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this,
+so if both are set, they should point to the same date and time.
+
+##### httpOnly
+
+Specifies the `boolean` value for the [`HttpOnly` `Set-Cookie` attribute][rfc-6265-5.2.6]. When truthy,
+the `HttpOnly` attribute is set, otherwise it is not. By default, the `HttpOnly` attribute is not set.
+
+**note** be careful when setting this to `true`, as compliant clients will not allow client-side
+JavaScript to see the cookie in `document.cookie`.
+
+##### maxAge
+
+Specifies the `number` (in seconds) to be the value for the [`Max-Age` `Set-Cookie` attribute][rfc-6265-5.2.2].
+The given number will be converted to an integer by rounding down. By default, no maximum age is set.
+
+**note** the [cookie storage model specification][rfc-6265-5.3] states that if both `expires` and
+`maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this,
+so if both are set, they should point to the same date and time.
+
+##### partitioned
+
+Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](rfc-cutler-httpbis-partitioned-cookies)
+attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not. By default, the
+`Partitioned` attribute is not set.
+
+**note** This is an attribute that has not yet been fully standardized, and may change in the future.
+This also means many clients may ignore this attribute until they understand it.
+
+More information about can be found in [the proposal](https://github.com/privacycg/CHIPS).
+
+##### path
+
+Specifies the value for the [`Path` `Set-Cookie` attribute][rfc-6265-5.2.4]. By default, the path
+is considered the ["default path"][rfc-6265-5.1.4].
+
+##### priority
+
+Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-4.1].
+
+ - `'low'` will set the `Priority` attribute to `Low`.
+ - `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set.
+ - `'high'` will set the `Priority` attribute to `High`.
+
+More information about the different priority levels can be found in
+[the specification][rfc-west-cookie-priority-00-4.1].
+
+**note** This is an attribute that has not yet been fully standardized, and may change in the future.
+This also means many clients may ignore this attribute until they understand it.
+
+##### sameSite
+
+Specifies the `boolean` or `string` to be the value for the [`SameSite` `Set-Cookie` attribute][rfc-6265bis-09-5.4.7].
+
+ - `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
+ - `false` will not set the `SameSite` attribute.
+ - `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement.
+ - `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.
+ - `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
+
+More information about the different enforcement levels can be found in
+[the specification][rfc-6265bis-09-5.4.7].
+
+**note** This is an attribute that has not yet been fully standardized, and may change in the future.
+This also means many clients may ignore this attribute until they understand it.
+
+##### secure
+
+Specifies the `boolean` value for the [`Secure` `Set-Cookie` attribute][rfc-6265-5.2.5]. When truthy,
+the `Secure` attribute is set, otherwise it is not. By default, the `Secure` attribute is not set.
+
+**note** be careful when setting this to `true`, as compliant clients will not send the cookie back to
+the server in the future if the browser does not have an HTTPS connection.
+
+## Example
+
+The following example uses this module in conjunction with the Node.js core HTTP server
+to prompt a user for their name and display it back on future visits.
+
+```js
+var cookie = require('cookie');
+var escapeHtml = require('escape-html');
+var http = require('http');
+var url = require('url');
+
+function onRequest(req, res) {
+ // Parse the query string
+ var query = url.parse(req.url, true, true).query;
+
+ if (query && query.name) {
+ // Set a new cookie with the name
+ res.setHeader('Set-Cookie', cookie.serialize('name', String(query.name), {
+ httpOnly: true,
+ maxAge: 60 * 60 * 24 * 7 // 1 week
+ }));
+
+ // Redirect back after setting cookie
+ res.statusCode = 302;
+ res.setHeader('Location', req.headers.referer || '/');
+ res.end();
+ return;
+ }
+
+ // Parse the cookies on the request
+ var cookies = cookie.parse(req.headers.cookie || '');
+
+ // Get the visitor name set in the cookie
+ var name = cookies.name;
+
+ res.setHeader('Content-Type', 'text/html; charset=UTF-8');
+
+ if (name) {
+ res.write('
Welcome back, ' + escapeHtml(name) + '!
');
+ } else {
+ res.write('
Hello, new visitor!
');
+ }
+
+ res.write('');
+}
+
+http.createServer(onRequest).listen(3000);
+```
+
+## Testing
+
+```sh
+$ npm test
+```
+
+## Benchmark
+
+```
+$ npm run bench
+
+> cookie@0.5.0 bench
+> node benchmark/index.js
+
+ node@18.18.2
+ acorn@8.10.0
+ ada@2.6.0
+ ares@1.19.1
+ brotli@1.0.9
+ cldr@43.1
+ icu@73.2
+ llhttp@6.0.11
+ modules@108
+ napi@9
+ nghttp2@1.57.0
+ nghttp3@0.7.0
+ ngtcp2@0.8.1
+ openssl@3.0.10+quic
+ simdutf@3.2.14
+ tz@2023c
+ undici@5.26.3
+ unicode@15.0
+ uv@1.44.2
+ uvwasi@0.0.18
+ v8@10.2.154.26-node.26
+ zlib@1.2.13.1-motley
+
+> node benchmark/parse-top.js
+
+ cookie.parse - top sites
+
+ 14 tests completed.
+
+ parse accounts.google.com x 2,588,913 ops/sec ±0.74% (186 runs sampled)
+ parse apple.com x 2,370,002 ops/sec ±0.69% (186 runs sampled)
+ parse cloudflare.com x 2,213,102 ops/sec ±0.88% (188 runs sampled)
+ parse docs.google.com x 2,194,157 ops/sec ±1.03% (184 runs sampled)
+ parse drive.google.com x 2,265,084 ops/sec ±0.79% (187 runs sampled)
+ parse en.wikipedia.org x 457,099 ops/sec ±0.81% (186 runs sampled)
+ parse linkedin.com x 504,407 ops/sec ±0.89% (186 runs sampled)
+ parse maps.google.com x 1,230,959 ops/sec ±0.98% (186 runs sampled)
+ parse microsoft.com x 926,294 ops/sec ±0.88% (184 runs sampled)
+ parse play.google.com x 2,311,338 ops/sec ±0.83% (185 runs sampled)
+ parse support.google.com x 1,508,850 ops/sec ±0.86% (186 runs sampled)
+ parse www.google.com x 1,022,582 ops/sec ±1.32% (182 runs sampled)
+ parse youtu.be x 332,136 ops/sec ±1.02% (185 runs sampled)
+ parse youtube.com x 323,833 ops/sec ±0.77% (183 runs sampled)
+
+> node benchmark/parse.js
+
+ cookie.parse - generic
+
+ 6 tests completed.
+
+ simple x 3,214,032 ops/sec ±1.61% (183 runs sampled)
+ decode x 587,237 ops/sec ±1.16% (187 runs sampled)
+ unquote x 2,954,618 ops/sec ±1.35% (183 runs sampled)
+ duplicates x 857,008 ops/sec ±0.89% (187 runs sampled)
+ 10 cookies x 292,133 ops/sec ±0.89% (187 runs sampled)
+ 100 cookies x 22,610 ops/sec ±0.68% (187 runs sampled)
+```
+
+## References
+
+- [RFC 6265: HTTP State Management Mechanism][rfc-6265]
+- [Same-site Cookies][rfc-6265bis-09-5.4.7]
+
+[rfc-cutler-httpbis-partitioned-cookies]: https://tools.ietf.org/html/draft-cutler-httpbis-partitioned-cookies/
+[rfc-west-cookie-priority-00-4.1]: https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1
+[rfc-6265bis-09-5.4.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7
+[rfc-6265]: https://tools.ietf.org/html/rfc6265
+[rfc-6265-5.1.4]: https://tools.ietf.org/html/rfc6265#section-5.1.4
+[rfc-6265-5.2.1]: https://tools.ietf.org/html/rfc6265#section-5.2.1
+[rfc-6265-5.2.2]: https://tools.ietf.org/html/rfc6265#section-5.2.2
+[rfc-6265-5.2.3]: https://tools.ietf.org/html/rfc6265#section-5.2.3
+[rfc-6265-5.2.4]: https://tools.ietf.org/html/rfc6265#section-5.2.4
+[rfc-6265-5.2.5]: https://tools.ietf.org/html/rfc6265#section-5.2.5
+[rfc-6265-5.2.6]: https://tools.ietf.org/html/rfc6265#section-5.2.6
+[rfc-6265-5.3]: https://tools.ietf.org/html/rfc6265#section-5.3
+
+## License
+
+[MIT](LICENSE)
+
+[ci-image]: https://badgen.net/github/checks/jshttp/cookie/master?label=ci
+[ci-url]: https://github.com/jshttp/cookie/actions/workflows/ci.yml
+[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/cookie/master
+[coveralls-url]: https://coveralls.io/r/jshttp/cookie?branch=master
+[node-image]: https://badgen.net/npm/node/cookie
+[node-url]: https://nodejs.org/en/download
+[npm-downloads-image]: https://badgen.net/npm/dm/cookie
+[npm-url]: https://npmjs.org/package/cookie
+[npm-version-image]: https://badgen.net/npm/v/cookie
diff --git a/node_modules/express-session/node_modules/cookie/SECURITY.md b/node_modules/express-session/node_modules/cookie/SECURITY.md
new file mode 100644
index 0000000..fd4a6c5
--- /dev/null
+++ b/node_modules/express-session/node_modules/cookie/SECURITY.md
@@ -0,0 +1,25 @@
+# Security Policies and Procedures
+
+## Reporting a Bug
+
+The `cookie` team and community take all security bugs seriously. Thank
+you for improving the security of the project. We appreciate your efforts and
+responsible disclosure and will make every effort to acknowledge your
+contributions.
+
+Report security bugs by emailing the current owner(s) of `cookie`. This
+information can be found in the npm registry using the command
+`npm owner ls cookie`.
+If unsure or unable to get the information from the above, open an issue
+in the [project issue tracker](https://github.com/jshttp/cookie/issues)
+asking for the current contact information.
+
+To ensure the timely response to your report, please ensure that the entirety
+of the report is contained within the email body and not solely behind a web
+link or an attachment.
+
+At least one owner will acknowledge your email within 48 hours, and will send a
+more detailed response within 48 hours indicating the next steps in handling
+your report. After the initial reply to your report, the owners will
+endeavor to keep you informed of the progress towards a fix and full
+announcement, and may ask for additional information or guidance.
diff --git a/node_modules/express-session/node_modules/cookie/index.js b/node_modules/express-session/node_modules/cookie/index.js
new file mode 100644
index 0000000..acd5acd
--- /dev/null
+++ b/node_modules/express-session/node_modules/cookie/index.js
@@ -0,0 +1,335 @@
+/*!
+ * cookie
+ * Copyright(c) 2012-2014 Roman Shtylman
+ * Copyright(c) 2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Module exports.
+ * @public
+ */
+
+exports.parse = parse;
+exports.serialize = serialize;
+
+/**
+ * Module variables.
+ * @private
+ */
+
+var __toString = Object.prototype.toString
+var __hasOwnProperty = Object.prototype.hasOwnProperty
+
+/**
+ * RegExp to match cookie-name in RFC 6265 sec 4.1.1
+ * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2
+ * which has been replaced by the token definition in RFC 7230 appendix B.
+ *
+ * cookie-name = token
+ * token = 1*tchar
+ * tchar = "!" / "#" / "$" / "%" / "&" / "'" /
+ * "*" / "+" / "-" / "." / "^" / "_" /
+ * "`" / "|" / "~" / DIGIT / ALPHA
+ */
+
+var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
+
+/**
+ * RegExp to match cookie-value in RFC 6265 sec 4.1.1
+ *
+ * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
+ * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
+ * ; US-ASCII characters excluding CTLs,
+ * ; whitespace DQUOTE, comma, semicolon,
+ * ; and backslash
+ */
+
+var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/;
+
+/**
+ * RegExp to match domain-value in RFC 6265 sec 4.1.1
+ *
+ * domain-value =
+ * ; defined in [RFC1034], Section 3.5, as
+ * ; enhanced by [RFC1123], Section 2.1
+ * = | "."
+ * = [ [ ] ]
+ * Labels must be 63 characters or less.
+ * 'let-dig' not 'letter' in the first char, per RFC1123
+ * = |
+ * = | "-"
+ * = |
+ * = any one of the 52 alphabetic characters A through Z in
+ * upper case and a through z in lower case
+ * = any one of the ten digits 0 through 9
+ *
+ * Keep support for leading dot: https://github.com/jshttp/cookie/issues/173
+ *
+ * > (Note that a leading %x2E ("."), if present, is ignored even though that
+ * character is not permitted, but a trailing %x2E ("."), if present, will
+ * cause the user agent to ignore the attribute.)
+ */
+
+var domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
+
+/**
+ * RegExp to match path-value in RFC 6265 sec 4.1.1
+ *
+ * path-value =
+ * CHAR = %x01-7F
+ * ; defined in RFC 5234 appendix B.1
+ */
+
+var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/;
+
+/**
+ * Parse a cookie header.
+ *
+ * Parse the given cookie header string into an object
+ * The object has the various cookies as keys(names) => values
+ *
+ * @param {string} str
+ * @param {object} [opt]
+ * @return {object}
+ * @public
+ */
+
+function parse(str, opt) {
+ if (typeof str !== 'string') {
+ throw new TypeError('argument str must be a string');
+ }
+
+ var obj = {};
+ var len = str.length;
+ // RFC 6265 sec 4.1.1, RFC 2616 2.2 defines a cookie name consists of one char minimum, plus '='.
+ if (len < 2) return obj;
+
+ var dec = (opt && opt.decode) || decode;
+ var index = 0;
+ var eqIdx = 0;
+ var endIdx = 0;
+
+ do {
+ eqIdx = str.indexOf('=', index);
+ if (eqIdx === -1) break; // No more cookie pairs.
+
+ endIdx = str.indexOf(';', index);
+
+ if (endIdx === -1) {
+ endIdx = len;
+ } else if (eqIdx > endIdx) {
+ // backtrack on prior semicolon
+ index = str.lastIndexOf(';', eqIdx - 1) + 1;
+ continue;
+ }
+
+ var keyStartIdx = startIndex(str, index, eqIdx);
+ var keyEndIdx = endIndex(str, eqIdx, keyStartIdx);
+ var key = str.slice(keyStartIdx, keyEndIdx);
+
+ // only assign once
+ if (!__hasOwnProperty.call(obj, key)) {
+ var valStartIdx = startIndex(str, eqIdx + 1, endIdx);
+ var valEndIdx = endIndex(str, endIdx, valStartIdx);
+
+ if (str.charCodeAt(valStartIdx) === 0x22 /* " */ && str.charCodeAt(valEndIdx - 1) === 0x22 /* " */) {
+ valStartIdx++;
+ valEndIdx--;
+ }
+
+ var val = str.slice(valStartIdx, valEndIdx);
+ obj[key] = tryDecode(val, dec);
+ }
+
+ index = endIdx + 1
+ } while (index < len);
+
+ return obj;
+}
+
+function startIndex(str, index, max) {
+ do {
+ var code = str.charCodeAt(index);
+ if (code !== 0x20 /* */ && code !== 0x09 /* \t */) return index;
+ } while (++index < max);
+ return max;
+}
+
+function endIndex(str, index, min) {
+ while (index > min) {
+ var code = str.charCodeAt(--index);
+ if (code !== 0x20 /* */ && code !== 0x09 /* \t */) return index + 1;
+ }
+ return min;
+}
+
+/**
+ * Serialize data into a cookie header.
+ *
+ * Serialize a name value pair into a cookie string suitable for
+ * http headers. An optional options object specifies cookie parameters.
+ *
+ * serialize('foo', 'bar', { httpOnly: true })
+ * => "foo=bar; httpOnly"
+ *
+ * @param {string} name
+ * @param {string} val
+ * @param {object} [opt]
+ * @return {string}
+ * @public
+ */
+
+function serialize(name, val, opt) {
+ var enc = (opt && opt.encode) || encodeURIComponent;
+
+ if (typeof enc !== 'function') {
+ throw new TypeError('option encode is invalid');
+ }
+
+ if (!cookieNameRegExp.test(name)) {
+ throw new TypeError('argument name is invalid');
+ }
+
+ var value = enc(val);
+
+ if (!cookieValueRegExp.test(value)) {
+ throw new TypeError('argument val is invalid');
+ }
+
+ var str = name + '=' + value;
+ if (!opt) return str;
+
+ if (null != opt.maxAge) {
+ var maxAge = Math.floor(opt.maxAge);
+
+ if (!isFinite(maxAge)) {
+ throw new TypeError('option maxAge is invalid')
+ }
+
+ str += '; Max-Age=' + maxAge;
+ }
+
+ if (opt.domain) {
+ if (!domainValueRegExp.test(opt.domain)) {
+ throw new TypeError('option domain is invalid');
+ }
+
+ str += '; Domain=' + opt.domain;
+ }
+
+ if (opt.path) {
+ if (!pathValueRegExp.test(opt.path)) {
+ throw new TypeError('option path is invalid');
+ }
+
+ str += '; Path=' + opt.path;
+ }
+
+ if (opt.expires) {
+ var expires = opt.expires
+
+ if (!isDate(expires) || isNaN(expires.valueOf())) {
+ throw new TypeError('option expires is invalid');
+ }
+
+ str += '; Expires=' + expires.toUTCString()
+ }
+
+ if (opt.httpOnly) {
+ str += '; HttpOnly';
+ }
+
+ if (opt.secure) {
+ str += '; Secure';
+ }
+
+ if (opt.partitioned) {
+ str += '; Partitioned'
+ }
+
+ if (opt.priority) {
+ var priority = typeof opt.priority === 'string'
+ ? opt.priority.toLowerCase() : opt.priority;
+
+ switch (priority) {
+ case 'low':
+ str += '; Priority=Low'
+ break
+ case 'medium':
+ str += '; Priority=Medium'
+ break
+ case 'high':
+ str += '; Priority=High'
+ break
+ default:
+ throw new TypeError('option priority is invalid')
+ }
+ }
+
+ if (opt.sameSite) {
+ var sameSite = typeof opt.sameSite === 'string'
+ ? opt.sameSite.toLowerCase() : opt.sameSite;
+
+ switch (sameSite) {
+ case true:
+ str += '; SameSite=Strict';
+ break;
+ case 'lax':
+ str += '; SameSite=Lax';
+ break;
+ case 'strict':
+ str += '; SameSite=Strict';
+ break;
+ case 'none':
+ str += '; SameSite=None';
+ break;
+ default:
+ throw new TypeError('option sameSite is invalid');
+ }
+ }
+
+ return str;
+}
+
+/**
+ * URL-decode string value. Optimized to skip native call when no %.
+ *
+ * @param {string} str
+ * @returns {string}
+ */
+
+function decode (str) {
+ return str.indexOf('%') !== -1
+ ? decodeURIComponent(str)
+ : str
+}
+
+/**
+ * Determine if value is a Date.
+ *
+ * @param {*} val
+ * @private
+ */
+
+function isDate (val) {
+ return __toString.call(val) === '[object Date]';
+}
+
+/**
+ * Try decoding a string using a decoding function.
+ *
+ * @param {string} str
+ * @param {function} decode
+ * @private
+ */
+
+function tryDecode(str, decode) {
+ try {
+ return decode(str);
+ } catch (e) {
+ return str;
+ }
+}
diff --git a/node_modules/express-session/node_modules/cookie/package.json b/node_modules/express-session/node_modules/cookie/package.json
new file mode 100644
index 0000000..22e3f92
--- /dev/null
+++ b/node_modules/express-session/node_modules/cookie/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "cookie",
+ "description": "HTTP server cookie parsing and serialization",
+ "version": "0.7.2",
+ "author": "Roman Shtylman ",
+ "contributors": [
+ "Douglas Christopher Wilson "
+ ],
+ "license": "MIT",
+ "keywords": [
+ "cookie",
+ "cookies"
+ ],
+ "repository": "jshttp/cookie",
+ "devDependencies": {
+ "beautify-benchmark": "0.2.4",
+ "benchmark": "2.1.4",
+ "eslint": "8.53.0",
+ "eslint-plugin-markdown": "3.0.1",
+ "mocha": "10.2.0",
+ "nyc": "15.1.0",
+ "safe-buffer": "5.2.1",
+ "top-sites": "1.1.194"
+ },
+ "files": [
+ "HISTORY.md",
+ "LICENSE",
+ "README.md",
+ "SECURITY.md",
+ "index.js"
+ ],
+ "main": "index.js",
+ "engines": {
+ "node": ">= 0.6"
+ },
+ "scripts": {
+ "bench": "node benchmark/index.js",
+ "lint": "eslint .",
+ "test": "mocha --reporter spec --bail --check-leaks test/",
+ "test-ci": "nyc --reporter=lcov --reporter=text npm test",
+ "test-cov": "nyc --reporter=html --reporter=text npm test",
+ "update-bench": "node scripts/update-benchmark.js"
+ }
+}
diff --git a/node_modules/express-session/package.json b/node_modules/express-session/package.json
new file mode 100644
index 0000000..e332243
--- /dev/null
+++ b/node_modules/express-session/package.json
@@ -0,0 +1,47 @@
+{
+ "name": "express-session",
+ "version": "1.18.1",
+ "description": "Simple session middleware for Express",
+ "author": "TJ Holowaychuk (http://tjholowaychuk.com)",
+ "contributors": [
+ "Douglas Christopher Wilson ",
+ "Joe Wagner "
+ ],
+ "repository": "expressjs/session",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "0.7.2",
+ "cookie-signature": "1.0.7",
+ "debug": "2.6.9",
+ "depd": "~2.0.0",
+ "on-headers": "~1.0.2",
+ "parseurl": "~1.3.3",
+ "safe-buffer": "5.2.1",
+ "uid-safe": "~2.1.5"
+ },
+ "devDependencies": {
+ "after": "0.8.2",
+ "cookie-parser": "1.4.6",
+ "eslint": "8.56.0",
+ "eslint-plugin-markdown": "3.0.1",
+ "express": "4.17.3",
+ "mocha": "10.2.0",
+ "nyc": "15.1.0",
+ "supertest": "6.3.4"
+ },
+ "files": [
+ "session/",
+ "HISTORY.md",
+ "index.js"
+ ],
+ "engines": {
+ "node": ">= 0.8.0"
+ },
+ "scripts": {
+ "lint": "eslint . && node ./scripts/lint-readme.js",
+ "test": "mocha --require test/support/env --check-leaks --bail --no-exit --reporter spec test/",
+ "test-ci": "nyc --reporter=lcov --reporter=text npm test",
+ "test-cov": "nyc npm test",
+ "version": "node scripts/version-history.js && git add HISTORY.md"
+ }
+}
diff --git a/node_modules/express-session/session/cookie.js b/node_modules/express-session/session/cookie.js
new file mode 100644
index 0000000..8bb5907
--- /dev/null
+++ b/node_modules/express-session/session/cookie.js
@@ -0,0 +1,152 @@
+/*!
+ * Connect - session - Cookie
+ * Copyright(c) 2010 Sencha Inc.
+ * Copyright(c) 2011 TJ Holowaychuk
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+
+var cookie = require('cookie')
+var deprecate = require('depd')('express-session')
+
+/**
+ * Initialize a new `Cookie` with the given `options`.
+ *
+ * @param {IncomingMessage} req
+ * @param {Object} options
+ * @api private
+ */
+
+var Cookie = module.exports = function Cookie(options) {
+ this.path = '/';
+ this.maxAge = null;
+ this.httpOnly = true;
+
+ if (options) {
+ if (typeof options !== 'object') {
+ throw new TypeError('argument options must be a object')
+ }
+
+ for (var key in options) {
+ if (key !== 'data') {
+ this[key] = options[key]
+ }
+ }
+ }
+
+ if (this.originalMaxAge === undefined || this.originalMaxAge === null) {
+ this.originalMaxAge = this.maxAge
+ }
+};
+
+/*!
+ * Prototype.
+ */
+
+Cookie.prototype = {
+
+ /**
+ * Set expires `date`.
+ *
+ * @param {Date} date
+ * @api public
+ */
+
+ set expires(date) {
+ this._expires = date;
+ this.originalMaxAge = this.maxAge;
+ },
+
+ /**
+ * Get expires `date`.
+ *
+ * @return {Date}
+ * @api public
+ */
+
+ get expires() {
+ return this._expires;
+ },
+
+ /**
+ * Set expires via max-age in `ms`.
+ *
+ * @param {Number} ms
+ * @api public
+ */
+
+ set maxAge(ms) {
+ if (ms && typeof ms !== 'number' && !(ms instanceof Date)) {
+ throw new TypeError('maxAge must be a number or Date')
+ }
+
+ if (ms instanceof Date) {
+ deprecate('maxAge as Date; pass number of milliseconds instead')
+ }
+
+ this.expires = typeof ms === 'number'
+ ? new Date(Date.now() + ms)
+ : ms;
+ },
+
+ /**
+ * Get expires max-age in `ms`.
+ *
+ * @return {Number}
+ * @api public
+ */
+
+ get maxAge() {
+ return this.expires instanceof Date
+ ? this.expires.valueOf() - Date.now()
+ : this.expires;
+ },
+
+ /**
+ * Return cookie data object.
+ *
+ * @return {Object}
+ * @api private
+ */
+
+ get data() {
+ return {
+ originalMaxAge: this.originalMaxAge,
+ partitioned: this.partitioned,
+ priority: this.priority
+ , expires: this._expires
+ , secure: this.secure
+ , httpOnly: this.httpOnly
+ , domain: this.domain
+ , path: this.path
+ , sameSite: this.sameSite
+ }
+ },
+
+ /**
+ * Return a serialized cookie string.
+ *
+ * @return {String}
+ * @api public
+ */
+
+ serialize: function(name, val){
+ return cookie.serialize(name, val, this.data);
+ },
+
+ /**
+ * Return JSON representation of this cookie.
+ *
+ * @return {Object}
+ * @api private
+ */
+
+ toJSON: function(){
+ return this.data;
+ }
+};
diff --git a/node_modules/express-session/session/memory.js b/node_modules/express-session/session/memory.js
new file mode 100644
index 0000000..11ed686
--- /dev/null
+++ b/node_modules/express-session/session/memory.js
@@ -0,0 +1,187 @@
+/*!
+ * express-session
+ * Copyright(c) 2010 Sencha Inc.
+ * Copyright(c) 2011 TJ Holowaychuk
+ * Copyright(c) 2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var Store = require('./store')
+var util = require('util')
+
+/**
+ * Shim setImmediate for node.js < 0.10
+ * @private
+ */
+
+/* istanbul ignore next */
+var defer = typeof setImmediate === 'function'
+ ? setImmediate
+ : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
+
+/**
+ * Module exports.
+ */
+
+module.exports = MemoryStore
+
+/**
+ * A session store in memory.
+ * @public
+ */
+
+function MemoryStore() {
+ Store.call(this)
+ this.sessions = Object.create(null)
+}
+
+/**
+ * Inherit from Store.
+ */
+
+util.inherits(MemoryStore, Store)
+
+/**
+ * Get all active sessions.
+ *
+ * @param {function} callback
+ * @public
+ */
+
+MemoryStore.prototype.all = function all(callback) {
+ var sessionIds = Object.keys(this.sessions)
+ var sessions = Object.create(null)
+
+ for (var i = 0; i < sessionIds.length; i++) {
+ var sessionId = sessionIds[i]
+ var session = getSession.call(this, sessionId)
+
+ if (session) {
+ sessions[sessionId] = session;
+ }
+ }
+
+ callback && defer(callback, null, sessions)
+}
+
+/**
+ * Clear all sessions.
+ *
+ * @param {function} callback
+ * @public
+ */
+
+MemoryStore.prototype.clear = function clear(callback) {
+ this.sessions = Object.create(null)
+ callback && defer(callback)
+}
+
+/**
+ * Destroy the session associated with the given session ID.
+ *
+ * @param {string} sessionId
+ * @public
+ */
+
+MemoryStore.prototype.destroy = function destroy(sessionId, callback) {
+ delete this.sessions[sessionId]
+ callback && defer(callback)
+}
+
+/**
+ * Fetch session by the given session ID.
+ *
+ * @param {string} sessionId
+ * @param {function} callback
+ * @public
+ */
+
+MemoryStore.prototype.get = function get(sessionId, callback) {
+ defer(callback, null, getSession.call(this, sessionId))
+}
+
+/**
+ * Commit the given session associated with the given sessionId to the store.
+ *
+ * @param {string} sessionId
+ * @param {object} session
+ * @param {function} callback
+ * @public
+ */
+
+MemoryStore.prototype.set = function set(sessionId, session, callback) {
+ this.sessions[sessionId] = JSON.stringify(session)
+ callback && defer(callback)
+}
+
+/**
+ * Get number of active sessions.
+ *
+ * @param {function} callback
+ * @public
+ */
+
+MemoryStore.prototype.length = function length(callback) {
+ this.all(function (err, sessions) {
+ if (err) return callback(err)
+ callback(null, Object.keys(sessions).length)
+ })
+}
+
+/**
+ * Touch the given session object associated with the given session ID.
+ *
+ * @param {string} sessionId
+ * @param {object} session
+ * @param {function} callback
+ * @public
+ */
+
+MemoryStore.prototype.touch = function touch(sessionId, session, callback) {
+ var currentSession = getSession.call(this, sessionId)
+
+ if (currentSession) {
+ // update expiration
+ currentSession.cookie = session.cookie
+ this.sessions[sessionId] = JSON.stringify(currentSession)
+ }
+
+ callback && defer(callback)
+}
+
+/**
+ * Get session from the store.
+ * @private
+ */
+
+function getSession(sessionId) {
+ var sess = this.sessions[sessionId]
+
+ if (!sess) {
+ return
+ }
+
+ // parse
+ sess = JSON.parse(sess)
+
+ if (sess.cookie) {
+ var expires = typeof sess.cookie.expires === 'string'
+ ? new Date(sess.cookie.expires)
+ : sess.cookie.expires
+
+ // destroy expired session
+ if (expires && expires <= Date.now()) {
+ delete this.sessions[sessionId]
+ return
+ }
+ }
+
+ return sess
+}
diff --git a/node_modules/express-session/session/session.js b/node_modules/express-session/session/session.js
new file mode 100644
index 0000000..fee7608
--- /dev/null
+++ b/node_modules/express-session/session/session.js
@@ -0,0 +1,143 @@
+/*!
+ * Connect - session - Session
+ * Copyright(c) 2010 Sencha Inc.
+ * Copyright(c) 2011 TJ Holowaychuk
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Expose Session.
+ */
+
+module.exports = Session;
+
+/**
+ * Create a new `Session` with the given request and `data`.
+ *
+ * @param {IncomingRequest} req
+ * @param {Object} data
+ * @api private
+ */
+
+function Session(req, data) {
+ Object.defineProperty(this, 'req', { value: req });
+ Object.defineProperty(this, 'id', { value: req.sessionID });
+
+ if (typeof data === 'object' && data !== null) {
+ // merge data into this, ignoring prototype properties
+ for (var prop in data) {
+ if (!(prop in this)) {
+ this[prop] = data[prop]
+ }
+ }
+ }
+}
+
+/**
+ * Update reset `.cookie.maxAge` to prevent
+ * the cookie from expiring when the
+ * session is still active.
+ *
+ * @return {Session} for chaining
+ * @api public
+ */
+
+defineMethod(Session.prototype, 'touch', function touch() {
+ return this.resetMaxAge();
+});
+
+/**
+ * Reset `.maxAge` to `.originalMaxAge`.
+ *
+ * @return {Session} for chaining
+ * @api public
+ */
+
+defineMethod(Session.prototype, 'resetMaxAge', function resetMaxAge() {
+ this.cookie.maxAge = this.cookie.originalMaxAge;
+ return this;
+});
+
+/**
+ * Save the session data with optional callback `fn(err)`.
+ *
+ * @param {Function} fn
+ * @return {Session} for chaining
+ * @api public
+ */
+
+defineMethod(Session.prototype, 'save', function save(fn) {
+ this.req.sessionStore.set(this.id, this, fn || function(){});
+ return this;
+});
+
+/**
+ * Re-loads the session data _without_ altering
+ * the maxAge properties. Invokes the callback `fn(err)`,
+ * after which time if no exception has occurred the
+ * `req.session` property will be a new `Session` object,
+ * although representing the same session.
+ *
+ * @param {Function} fn
+ * @return {Session} for chaining
+ * @api public
+ */
+
+defineMethod(Session.prototype, 'reload', function reload(fn) {
+ var req = this.req
+ var store = this.req.sessionStore
+
+ store.get(this.id, function(err, sess){
+ if (err) return fn(err);
+ if (!sess) return fn(new Error('failed to load session'));
+ store.createSession(req, sess);
+ fn();
+ });
+ return this;
+});
+
+/**
+ * Destroy `this` session.
+ *
+ * @param {Function} fn
+ * @return {Session} for chaining
+ * @api public
+ */
+
+defineMethod(Session.prototype, 'destroy', function destroy(fn) {
+ delete this.req.session;
+ this.req.sessionStore.destroy(this.id, fn);
+ return this;
+});
+
+/**
+ * Regenerate this request's session.
+ *
+ * @param {Function} fn
+ * @return {Session} for chaining
+ * @api public
+ */
+
+defineMethod(Session.prototype, 'regenerate', function regenerate(fn) {
+ this.req.sessionStore.regenerate(this.req, fn);
+ return this;
+});
+
+/**
+ * Helper function for creating a method on a prototype.
+ *
+ * @param {Object} obj
+ * @param {String} name
+ * @param {Function} fn
+ * @private
+ */
+function defineMethod(obj, name, fn) {
+ Object.defineProperty(obj, name, {
+ configurable: true,
+ enumerable: false,
+ value: fn,
+ writable: true
+ });
+};
diff --git a/node_modules/express-session/session/store.js b/node_modules/express-session/session/store.js
new file mode 100644
index 0000000..3793877
--- /dev/null
+++ b/node_modules/express-session/session/store.js
@@ -0,0 +1,102 @@
+/*!
+ * Connect - session - Store
+ * Copyright(c) 2010 Sencha Inc.
+ * Copyright(c) 2011 TJ Holowaychuk
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var Cookie = require('./cookie')
+var EventEmitter = require('events').EventEmitter
+var Session = require('./session')
+var util = require('util')
+
+/**
+ * Module exports.
+ * @public
+ */
+
+module.exports = Store
+
+/**
+ * Abstract base class for session stores.
+ * @public
+ */
+
+function Store () {
+ EventEmitter.call(this)
+}
+
+/**
+ * Inherit from EventEmitter.
+ */
+
+util.inherits(Store, EventEmitter)
+
+/**
+ * Re-generate the given requests's session.
+ *
+ * @param {IncomingRequest} req
+ * @return {Function} fn
+ * @api public
+ */
+
+Store.prototype.regenerate = function(req, fn){
+ var self = this;
+ this.destroy(req.sessionID, function(err){
+ self.generate(req);
+ fn(err);
+ });
+};
+
+/**
+ * Load a `Session` instance via the given `sid`
+ * and invoke the callback `fn(err, sess)`.
+ *
+ * @param {String} sid
+ * @param {Function} fn
+ * @api public
+ */
+
+Store.prototype.load = function(sid, fn){
+ var self = this;
+ this.get(sid, function(err, sess){
+ if (err) return fn(err);
+ if (!sess) return fn();
+ var req = { sessionID: sid, sessionStore: self };
+ fn(null, self.createSession(req, sess))
+ });
+};
+
+/**
+ * Create session from JSON `sess` data.
+ *
+ * @param {IncomingRequest} req
+ * @param {Object} sess
+ * @return {Session}
+ * @api private
+ */
+
+Store.prototype.createSession = function(req, sess){
+ var expires = sess.cookie.expires
+ var originalMaxAge = sess.cookie.originalMaxAge
+
+ sess.cookie = new Cookie(sess.cookie);
+
+ if (typeof expires === 'string') {
+ // convert expires to a Date object
+ sess.cookie.expires = new Date(expires)
+ }
+
+ // keep originalMaxAge intact
+ sess.cookie.originalMaxAge = originalMaxAge
+
+ req.session = new Session(req, sess);
+ return req.session;
+};
diff --git a/node_modules/express/History.md b/node_modules/express/History.md
new file mode 100644
index 0000000..924f105
--- /dev/null
+++ b/node_modules/express/History.md
@@ -0,0 +1,3647 @@
+4.21.1 / 2024-10-08
+==========
+
+* Backported a fix for [CVE-2024-47764](https://nvd.nist.gov/vuln/detail/CVE-2024-47764)
+
+4.21.0 / 2024-09-11
+==========
+
+ * Deprecate `res.location("back")` and `res.redirect("back")` magic string
+ * deps: serve-static@1.16.2
+ * includes send@0.19.0
+ * deps: finalhandler@1.3.1
+ * deps: qs@6.13.0
+
+4.20.0 / 2024-09-10
+==========
+ * deps: serve-static@0.16.0
+ * Remove link renderization in html while redirecting
+ * deps: send@0.19.0
+ * Remove link renderization in html while redirecting
+ * deps: body-parser@0.6.0
+ * add `depth` option to customize the depth level in the parser
+ * IMPORTANT: The default `depth` level for parsing URL-encoded data is now `32` (previously was `Infinity`)
+ * Remove link renderization in html while using `res.redirect`
+ * deps: path-to-regexp@0.1.10
+ - Adds support for named matching groups in the routes using a regex
+ - Adds backtracking protection to parameters without regexes defined
+ * deps: encodeurl@~2.0.0
+ - Removes encoding of `\`, `|`, and `^` to align better with URL spec
+ * Deprecate passing `options.maxAge` and `options.expires` to `res.clearCookie`
+ - Will be ignored in v5, clearCookie will set a cookie with an expires in the past to instruct clients to delete the cookie
+
+4.19.2 / 2024-03-25
+==========
+
+ * Improved fix for open redirect allow list bypass
+
+4.19.1 / 2024-03-20
+==========
+
+ * Allow passing non-strings to res.location with new encoding handling checks
+
+4.19.0 / 2024-03-20
+==========
+
+ * Prevent open redirect allow list bypass due to encodeurl
+ * deps: cookie@0.6.0
+
+4.18.3 / 2024-02-29
+==========
+
+ * Fix routing requests without method
+ * deps: body-parser@1.20.2
+ - Fix strict json error message on Node.js 19+
+ - deps: content-type@~1.0.5
+ - deps: raw-body@2.5.2
+ * deps: cookie@0.6.0
+ - Add `partitioned` option
+
+4.18.2 / 2022-10-08
+===================
+
+ * Fix regression routing a large stack in a single route
+ * deps: body-parser@1.20.1
+ - deps: qs@6.11.0
+ - perf: remove unnecessary object clone
+ * deps: qs@6.11.0
+
+4.18.1 / 2022-04-29
+===================
+
+ * Fix hanging on large stack of sync routes
+
+4.18.0 / 2022-04-25
+===================
+
+ * Add "root" option to `res.download`
+ * Allow `options` without `filename` in `res.download`
+ * Deprecate string and non-integer arguments to `res.status`
+ * Fix behavior of `null`/`undefined` as `maxAge` in `res.cookie`
+ * Fix handling very large stacks of sync middleware
+ * Ignore `Object.prototype` values in settings through `app.set`/`app.get`
+ * Invoke `default` with same arguments as types in `res.format`
+ * Support proper 205 responses using `res.send`
+ * Use `http-errors` for `res.format` error
+ * deps: body-parser@1.20.0
+ - Fix error message for json parse whitespace in `strict`
+ - Fix internal error when inflated body exceeds limit
+ - Prevent loss of async hooks context
+ - Prevent hanging when request already read
+ - deps: depd@2.0.0
+ - deps: http-errors@2.0.0
+ - deps: on-finished@2.4.1
+ - deps: qs@6.10.3
+ - deps: raw-body@2.5.1
+ * deps: cookie@0.5.0
+ - Add `priority` option
+ - Fix `expires` option to reject invalid dates
+ * deps: depd@2.0.0
+ - Replace internal `eval` usage with `Function` constructor
+ - Use instance methods on `process` to check for listeners
+ * deps: finalhandler@1.2.0
+ - Remove set content headers that break response
+ - deps: on-finished@2.4.1
+ - deps: statuses@2.0.1
+ * deps: on-finished@2.4.1
+ - Prevent loss of async hooks context
+ * deps: qs@6.10.3
+ * deps: send@0.18.0
+ - Fix emitted 416 error missing headers property
+ - Limit the headers removed for 304 response
+ - deps: depd@2.0.0
+ - deps: destroy@1.2.0
+ - deps: http-errors@2.0.0
+ - deps: on-finished@2.4.1
+ - deps: statuses@2.0.1
+ * deps: serve-static@1.15.0
+ - deps: send@0.18.0
+ * deps: statuses@2.0.1
+ - Remove code 306
+ - Rename `425 Unordered Collection` to standard `425 Too Early`
+
+4.17.3 / 2022-02-16
+===================
+
+ * deps: accepts@~1.3.8
+ - deps: mime-types@~2.1.34
+ - deps: negotiator@0.6.3
+ * deps: body-parser@1.19.2
+ - deps: bytes@3.1.2
+ - deps: qs@6.9.7
+ - deps: raw-body@2.4.3
+ * deps: cookie@0.4.2
+ * deps: qs@6.9.7
+ * Fix handling of `__proto__` keys
+ * pref: remove unnecessary regexp for trust proxy
+
+4.17.2 / 2021-12-16
+===================
+
+ * Fix handling of `undefined` in `res.jsonp`
+ * Fix handling of `undefined` when `"json escape"` is enabled
+ * Fix incorrect middleware execution with unanchored `RegExp`s
+ * Fix `res.jsonp(obj, status)` deprecation message
+ * Fix typo in `res.is` JSDoc
+ * deps: body-parser@1.19.1
+ - deps: bytes@3.1.1
+ - deps: http-errors@1.8.1
+ - deps: qs@6.9.6
+ - deps: raw-body@2.4.2
+ - deps: safe-buffer@5.2.1
+ - deps: type-is@~1.6.18
+ * deps: content-disposition@0.5.4
+ - deps: safe-buffer@5.2.1
+ * deps: cookie@0.4.1
+ - Fix `maxAge` option to reject invalid values
+ * deps: proxy-addr@~2.0.7
+ - Use `req.socket` over deprecated `req.connection`
+ - deps: forwarded@0.2.0
+ - deps: ipaddr.js@1.9.1
+ * deps: qs@6.9.6
+ * deps: safe-buffer@5.2.1
+ * deps: send@0.17.2
+ - deps: http-errors@1.8.1
+ - deps: ms@2.1.3
+ - pref: ignore empty http tokens
+ * deps: serve-static@1.14.2
+ - deps: send@0.17.2
+ * deps: setprototypeof@1.2.0
+
+4.17.1 / 2019-05-25
+===================
+
+ * Revert "Improve error message for `null`/`undefined` to `res.status`"
+
+4.17.0 / 2019-05-16
+===================
+
+ * Add `express.raw` to parse bodies into `Buffer`
+ * Add `express.text` to parse bodies into string
+ * Improve error message for non-strings to `res.sendFile`
+ * Improve error message for `null`/`undefined` to `res.status`
+ * Support multiple hosts in `X-Forwarded-Host`
+ * deps: accepts@~1.3.7
+ * deps: body-parser@1.19.0
+ - Add encoding MIK
+ - Add petabyte (`pb`) support
+ - Fix parsing array brackets after index
+ - deps: bytes@3.1.0
+ - deps: http-errors@1.7.2
+ - deps: iconv-lite@0.4.24
+ - deps: qs@6.7.0
+ - deps: raw-body@2.4.0
+ - deps: type-is@~1.6.17
+ * deps: content-disposition@0.5.3
+ * deps: cookie@0.4.0
+ - Add `SameSite=None` support
+ * deps: finalhandler@~1.1.2
+ - Set stricter `Content-Security-Policy` header
+ - deps: parseurl@~1.3.3
+ - deps: statuses@~1.5.0
+ * deps: parseurl@~1.3.3
+ * deps: proxy-addr@~2.0.5
+ - deps: ipaddr.js@1.9.0
+ * deps: qs@6.7.0
+ - Fix parsing array brackets after index
+ * deps: range-parser@~1.2.1
+ * deps: send@0.17.1
+ - Set stricter CSP header in redirect & error responses
+ - deps: http-errors@~1.7.2
+ - deps: mime@1.6.0
+ - deps: ms@2.1.1
+ - deps: range-parser@~1.2.1
+ - deps: statuses@~1.5.0
+ - perf: remove redundant `path.normalize` call
+ * deps: serve-static@1.14.1
+ - Set stricter CSP header in redirect response
+ - deps: parseurl@~1.3.3
+ - deps: send@0.17.1
+ * deps: setprototypeof@1.1.1
+ * deps: statuses@~1.5.0
+ - Add `103 Early Hints`
+ * deps: type-is@~1.6.18
+ - deps: mime-types@~2.1.24
+ - perf: prevent internal `throw` on invalid type
+
+4.16.4 / 2018-10-10
+===================
+
+ * Fix issue where `"Request aborted"` may be logged in `res.sendfile`
+ * Fix JSDoc for `Router` constructor
+ * deps: body-parser@1.18.3
+ - Fix deprecation warnings on Node.js 10+
+ - Fix stack trace for strict json parse error
+ - deps: depd@~1.1.2
+ - deps: http-errors@~1.6.3
+ - deps: iconv-lite@0.4.23
+ - deps: qs@6.5.2
+ - deps: raw-body@2.3.3
+ - deps: type-is@~1.6.16
+ * deps: proxy-addr@~2.0.4
+ - deps: ipaddr.js@1.8.0
+ * deps: qs@6.5.2
+ * deps: safe-buffer@5.1.2
+
+4.16.3 / 2018-03-12
+===================
+
+ * deps: accepts@~1.3.5
+ - deps: mime-types@~2.1.18
+ * deps: depd@~1.1.2
+ - perf: remove argument reassignment
+ * deps: encodeurl@~1.0.2
+ - Fix encoding `%` as last character
+ * deps: finalhandler@1.1.1
+ - Fix 404 output for bad / missing pathnames
+ - deps: encodeurl@~1.0.2
+ - deps: statuses@~1.4.0
+ * deps: proxy-addr@~2.0.3
+ - deps: ipaddr.js@1.6.0
+ * deps: send@0.16.2
+ - Fix incorrect end tag in default error & redirects
+ - deps: depd@~1.1.2
+ - deps: encodeurl@~1.0.2
+ - deps: statuses@~1.4.0
+ * deps: serve-static@1.13.2
+ - Fix incorrect end tag in redirects
+ - deps: encodeurl@~1.0.2
+ - deps: send@0.16.2
+ * deps: statuses@~1.4.0
+ * deps: type-is@~1.6.16
+ - deps: mime-types@~2.1.18
+
+4.16.2 / 2017-10-09
+===================
+
+ * Fix `TypeError` in `res.send` when given `Buffer` and `ETag` header set
+ * perf: skip parsing of entire `X-Forwarded-Proto` header
+
+4.16.1 / 2017-09-29
+===================
+
+ * deps: send@0.16.1
+ * deps: serve-static@1.13.1
+ - Fix regression when `root` is incorrectly set to a file
+ - deps: send@0.16.1
+
+4.16.0 / 2017-09-28
+===================
+
+ * Add `"json escape"` setting for `res.json` and `res.jsonp`
+ * Add `express.json` and `express.urlencoded` to parse bodies
+ * Add `options` argument to `res.download`
+ * Improve error message when autoloading invalid view engine
+ * Improve error messages when non-function provided as middleware
+ * Skip `Buffer` encoding when not generating ETag for small response
+ * Use `safe-buffer` for improved Buffer API
+ * deps: accepts@~1.3.4
+ - deps: mime-types@~2.1.16
+ * deps: content-type@~1.0.4
+ - perf: remove argument reassignment
+ - perf: skip parameter parsing when no parameters
+ * deps: etag@~1.8.1
+ - perf: replace regular expression with substring
+ * deps: finalhandler@1.1.0
+ - Use `res.headersSent` when available
+ * deps: parseurl@~1.3.2
+ - perf: reduce overhead for full URLs
+ - perf: unroll the "fast-path" `RegExp`
+ * deps: proxy-addr@~2.0.2
+ - Fix trimming leading / trailing OWS in `X-Forwarded-For`
+ - deps: forwarded@~0.1.2
+ - deps: ipaddr.js@1.5.2
+ - perf: reduce overhead when no `X-Forwarded-For` header
+ * deps: qs@6.5.1
+ - Fix parsing & compacting very deep objects
+ * deps: send@0.16.0
+ - Add 70 new types for file extensions
+ - Add `immutable` option
+ - Fix missing `