diff --git a/package.json b/package.json index 16d69e7702..a9298f4111 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "workspaces": [ "packages/rrweb", "packages/rrweb-snapshot", - "packages/rrweb-player" + "packages/rrweb-player", + "packages/rrdom" ], "devDependencies": { "lerna": "^4.0.0" diff --git a/packages/rrdom/.gitignore b/packages/rrdom/.gitignore new file mode 100644 index 0000000000..fb77b328d4 --- /dev/null +++ b/packages/rrdom/.gitignore @@ -0,0 +1,4 @@ +dist +es +lib +typings diff --git a/packages/rrdom/.vscode/extensions.json b/packages/rrdom/.vscode/extensions.json new file mode 100644 index 0000000000..bd47279fb1 --- /dev/null +++ b/packages/rrdom/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["orta.vscode-jest"] +} diff --git a/packages/rrdom/.vscode/launch.json b/packages/rrdom/.vscode/launch.json new file mode 100644 index 0000000000..25d2357c25 --- /dev/null +++ b/packages/rrdom/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + "configurations": [ + { + "type": "node", + "name": "vscode-jest-tests", + "request": "launch", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "disableOptimisticBPs": true, + "cwd": "${workspaceFolder}", + "runtimeExecutable": "yarn", + "args": ["test", "--runInBand", "--watchAll=false"] + } + ] +} diff --git a/packages/rrdom/.vscode/settings.json b/packages/rrdom/.vscode/settings.json new file mode 100644 index 0000000000..634876effc --- /dev/null +++ b/packages/rrdom/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "jest.jestCommandLine": "yarn test" +} diff --git a/packages/rrdom/jest.config.js b/packages/rrdom/jest.config.js new file mode 100644 index 0000000000..e86e13bab9 --- /dev/null +++ b/packages/rrdom/jest.config.js @@ -0,0 +1,5 @@ +/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', +}; diff --git a/packages/rrdom/package.json b/packages/rrdom/package.json new file mode 100644 index 0000000000..abad628442 --- /dev/null +++ b/packages/rrdom/package.json @@ -0,0 +1,44 @@ +{ + "name": "rrdom", + "version": "0.0.0", + "scripts": { + "dev": "rollup -c -w", + "bundle": "rollup --config", + "bundle:es-only": "cross-env ES_ONLY=true rollup --config", + "test": "jest", + "prepublish": "npm run bundle" + }, + "keywords": [ + "rrweb", + "rrdom" + ], + "license": "MIT", + "main": "lib/rrdom.js", + "module": "es/rrdom.js", + "typings": "es", + "unpkg": "dist/rrdom.js", + "files": [ + "dist", + "lib", + "es", + "typings" + ], + "devDependencies": { + "@rollup/plugin-commonjs": "^20.0.0", + "@rollup/plugin-node-resolve": "^13.0.4", + "@types/cssom": "^0.4.1", + "@types/jest": "^27.0.1", + "@types/nwsapi": "^2.2.2", + "jest": "^27.1.1", + "rollup": "^2.56.3", + "rollup-plugin-terser": "^7.0.2", + "rollup-plugin-typescript2": "^0.30.0", + "rrweb-snapshot": "^1.1.8", + "ts-jest": "^27.0.5", + "typescript": "^3.9.5" + }, + "dependencies": { + "cssom": "^0.5.0", + "nwsapi": "^2.2.0" + } +} diff --git a/packages/rrdom/rollup.config.js b/packages/rrdom/rollup.config.js new file mode 100644 index 0000000000..80baed3473 --- /dev/null +++ b/packages/rrdom/rollup.config.js @@ -0,0 +1,103 @@ +import resolve from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import { terser } from 'rollup-plugin-terser'; +import typescript from 'rollup-plugin-typescript2'; +import pkg from './package.json'; + +function toMinPath(path) { + return path.replace(/\.js$/, '.min.js'); +} + +const basePlugins = [ + resolve({ browser: true }), + commonjs(), + typescript({ + tsconfigOverride: { compilerOptions: { module: 'ESNext' } }, + }), +]; + +const baseConfigs = [ + { + input: './src/index.ts', + name: pkg.name, + path: pkg.name, + }, + { + input: './src/document-nodejs.ts', + name: 'RRDocument', + path: 'document-nodejs', + }, +]; + +let configs = []; +let extraConfigs = []; +for (let config of baseConfigs) { + configs.push( + // ES module + { + input: config.input, + plugins: basePlugins, + output: [ + { + format: 'esm', + file: pkg.module.replace(pkg.name, config.path), + }, + ], + }, + ); + extraConfigs.push( + // browser + { + input: config.input, + plugins: basePlugins, + output: [ + { + name: config.name, + format: 'iife', + file: pkg.unpkg.replace(pkg.name, config.path), + }, + ], + }, + { + input: config.input, + plugins: basePlugins.concat(terser()), + output: [ + { + name: config.name, + format: 'iife', + file: toMinPath(pkg.unpkg).replace(pkg.name, config.path), + sourcemap: true, + }, + ], + }, + // CommonJS + { + input: config.input, + plugins: basePlugins, + output: [ + { + format: 'cjs', + file: pkg.main.replace(pkg.name, config.path), + }, + ], + }, + // ES module (packed) + { + input: config.input, + plugins: basePlugins.concat(terser()), + output: [ + { + format: 'esm', + file: toMinPath(pkg.module).replace(pkg.name, config.path), + sourcemap: true, + }, + ], + }, + ); +} + +if (!process.env.ES_ONLY) { + configs.push(...extraConfigs); +} + +export default configs; diff --git a/packages/rrdom/src/document-nodejs.ts b/packages/rrdom/src/document-nodejs.ts new file mode 100644 index 0000000000..aff8d90512 --- /dev/null +++ b/packages/rrdom/src/document-nodejs.ts @@ -0,0 +1,787 @@ +import { INode, NodeType, serializedNodeWithId } from 'rrweb-snapshot'; +import { NWSAPI } from 'nwsapi'; +import { parseCSSText, camelize, toCSSText } from './style'; +const nwsapi = require('nwsapi'); +const cssom = require('cssom'); + +export abstract class RRNode { + __sn: serializedNodeWithId | undefined; + children: Array = []; + parentElement: RRElement | null = null; + parentNode: RRNode | null = null; + ownerDocument: RRDocument | null = null; + ELEMENT_NODE = 1; + TEXT_NODE = 3; + + get firstChild() { + return this.children[0]; + } + + get nodeType() { + if (this instanceof RRDocument) return NodeType.Document; + if (this instanceof RRDocumentType) return NodeType.DocumentType; + if (this instanceof RRElement) return NodeType.Element; + if (this instanceof RRText) return NodeType.Text; + if (this instanceof RRCDATASection) return NodeType.CDATA; + if (this instanceof RRComment) return NodeType.Comment; + } + + get childNodes() { + return this.children; + } + + appendChild(newChild: RRNode): RRNode { + throw new Error( + `RRDomException: Failed to execute 'appendChild' on 'RRNode': This RRNode type does not support this method.`, + ); + } + + insertBefore(newChild: RRNode, refChild: RRNode | null): RRNode { + throw new Error( + `RRDomException: Failed to execute 'insertBefore' on 'RRNode': This RRNode type does not support this method.`, + ); + } + + contains(node: RRNode) { + if (node === this) return true; + for (const child of this.children) { + if (child.contains(node)) return true; + } + return false; + } + + removeChild(node: RRNode) { + const indexOfChild = this.children.indexOf(node); + if (indexOfChild !== -1) { + this.children.splice(indexOfChild, 1); + node.parentElement = null; + node.parentNode = null; + } + } + + toString(nodeName?: string) { + return `${JSON.stringify(this.__sn?.id) || ''} ${nodeName}`; + } +} + +export class RRWindow { + scrollLeft = 0; + scrollTop = 0; + scrollTo(options?: ScrollToOptions) { + if (!options) return; + if (typeof options.left === 'number') this.scrollLeft = options.left; + if (typeof options.top === 'number') this.scrollTop = options.top; + } +} + +export class RRDocument extends RRNode { + private mirror: Map = new Map(); + private _nwsapi: NWSAPI; + get nwsapi() { + if (!this._nwsapi) { + this._nwsapi = nwsapi({ + document: (this as unknown) as Document, + DOMException: (null as unknown) as new ( + message?: string, + name?: string, + ) => DOMException, + }); + this._nwsapi.configure({ + LOGERRORS: false, + IDS_DUPES: true, + MIXEDCASE: true, + }); + } + return this._nwsapi; + } + + get documentElement(): RRElement { + return this.children.find( + (node) => node instanceof RRElement && node.tagName === 'HTML', + ) as RRElement; + } + + get body() { + return ( + this.documentElement?.children.find( + (node) => node instanceof RRElement && node.tagName === 'BODY', + ) || null + ); + } + + get head() { + return ( + this.documentElement?.children.find( + (node) => node instanceof RRElement && node.tagName === 'HEAD', + ) || null + ); + } + + get implementation() { + return this; + } + + get firstElementChild() { + return this.documentElement; + } + + appendChild(childNode: RRNode) { + const nodeType = childNode.nodeType; + if (nodeType === NodeType.Element || nodeType === NodeType.DocumentType) { + if (this.children.some((s) => s.nodeType === nodeType)) { + throw new Error( + `RRDomException: Failed to execute 'appendChild' on 'RRNode': Only one ${ + nodeType === NodeType.Element ? 'RRElement' : 'RRDoctype' + } on RRDocument allowed.`, + ); + } + } + childNode.parentElement = null; + childNode.parentNode = this; + childNode.ownerDocument = this; + this.children.push(childNode); + return childNode; + } + + insertBefore(newChild: RRNode, refChild: RRNode | null) { + if (refChild === null) return this.appendChild(newChild); + const childIndex = this.children.indexOf(refChild); + if (childIndex == -1) + throw new Error( + "Failed to execute 'insertBefore' on 'RRNode': The RRNode before which the new node is to be inserted is not a child of this RRNode.", + ); + this.children.splice(childIndex, 0, newChild); + newChild.parentElement = null; + newChild.parentNode = this; + newChild.ownerDocument = this; + return newChild; + } + + querySelectorAll(selectors: string): RRNode[] { + return (this.nwsapi.select(selectors) as unknown) as RRNode[]; + } + + getElementsByTagName(tagName: string): RRElement[] { + if (this.documentElement) + return (this.documentElement as RRElement).getElementsByTagName(tagName); + return []; + } + + getElementsByClassName(className: string): RRElement[] { + if (this.documentElement) + return (this.documentElement as RRElement).getElementsByClassName( + className, + ); + return []; + } + + getElementById(elementId: string): RRElement | null { + if (this.documentElement) + return (this.documentElement as RRElement).getElementById(elementId); + return null; + } + + createDocument( + _namespace: string | null, + _qualifiedName: string | null, + _doctype?: DocumentType | null, + ) { + return new RRDocument(); + } + + createDocumentType( + qualifiedName: string, + publicId: string, + systemId: string, + ) { + const documentTypeNode = new RRDocumentType( + qualifiedName, + publicId, + systemId, + ); + documentTypeNode.ownerDocument = this; + return documentTypeNode; + } + + createElement( + tagName: K, + ): RRElementType; + createElement(tagName: string): RRElement; + createElement(tagName: string) { + const upperTagName = tagName.toUpperCase(); + let element; + switch (upperTagName) { + case 'AUDIO': + case 'VIDEO': + element = new RRMediaElement(upperTagName); + break; + case 'IFRAME': + element = new RRIframeElement(upperTagName); + break; + case 'IMG': + element = new RRImageElement('IMG'); + break; + case 'CANVAS': + element = new RRCanvasElement('CANVAS'); + break; + case 'STYLE': + element = new RRStyleElement('STYLE'); + break; + default: + element = new RRElement(upperTagName); + break; + } + element.ownerDocument = this; + return element; + } + + createElementNS( + _namespaceURI: 'http://www.w3.org/2000/svg', + qualifiedName: string, + ) { + return this.createElement(qualifiedName as keyof HTMLElementTagNameMap); + } + + createComment(data: string) { + const commentNode = new RRComment(data); + commentNode.ownerDocument = this; + return commentNode; + } + + createCDATASection(data: string) { + const sectionNode = new RRCDATASection(data); + sectionNode.ownerDocument = this; + return sectionNode; + } + + createTextNode(data: string) { + const textNode = new RRText(data); + textNode.ownerDocument = this; + return textNode; + } + + /** + * This does come with some side effects. For example: + * 1. All event listeners currently registered on the document, nodes inside the document, or the document's window are removed. + * 2. All existing nodes are removed from the document. + */ + open() { + this.children = []; + } + + close() {} + + buildFromDom(dom: Document) { + let notSerializedId = -1; + const NodeTypeMap: Record = {}; + NodeTypeMap[document.DOCUMENT_NODE] = NodeType.Document; + NodeTypeMap[document.DOCUMENT_TYPE_NODE] = NodeType.DocumentType; + NodeTypeMap[document.ELEMENT_NODE] = NodeType.Element; + NodeTypeMap[document.TEXT_NODE] = NodeType.Text; + NodeTypeMap[document.CDATA_SECTION_NODE] = NodeType.CDATA; + NodeTypeMap[document.COMMENT_NODE] = NodeType.Comment; + + function getValidTagName(element: HTMLElement): string { + if (element instanceof HTMLFormElement) { + return 'FORM'; + } + return element.tagName.toUpperCase().trim(); + } + + const walk = function (node: INode) { + let serializedNodeWithId = node.__sn; + let rrNode: RRNode; + if (!serializedNodeWithId) { + serializedNodeWithId = { + type: NodeTypeMap[node.nodeType], + textContent: '', + id: notSerializedId, + }; + notSerializedId -= 1; + node.__sn = serializedNodeWithId; + } + if (!this.mirror.has(serializedNodeWithId.id)) { + switch (node.nodeType) { + case node.DOCUMENT_NODE: + if ( + serializedNodeWithId.rootId && + serializedNodeWithId.rootId !== serializedNodeWithId.id + ) + rrNode = this.createDocument(); + else rrNode = this; + break; + case node.DOCUMENT_TYPE_NODE: + const documentType = (node as unknown) as DocumentType; + rrNode = this.createDocumentType( + documentType.name, + documentType.publicId, + documentType.systemId, + ); + break; + case node.ELEMENT_NODE: + const elementNode = (node as unknown) as HTMLElement; + const tagName = getValidTagName(elementNode); + rrNode = this.createElement(tagName); + const rrElement = rrNode as RRElement; + for (const { name, value } of Array.from(elementNode.attributes)) { + rrElement.attributes[name] = value; + } + // form fields + if ( + tagName === 'INPUT' || + tagName === 'TEXTAREA' || + tagName === 'SELECT' + ) { + const value = (elementNode as + | HTMLInputElement + | HTMLTextAreaElement).value; + if ( + ['RADIO', 'CHECKBOX', 'SUBMIT', 'BUTTON'].includes( + rrElement.attributes.type as string, + ) && + value + ) { + rrElement.attributes.value = value; + } else if ((elementNode as HTMLInputElement).checked) { + rrElement.attributes.checked = (elementNode as HTMLInputElement).checked; + } + } + if (tagName === 'OPTION') { + const selectValue = (elementNode as HTMLOptionElement) + .parentElement; + if ( + rrElement.attributes.value === + (selectValue as HTMLSelectElement).value + ) { + rrElement.attributes.selected = (elementNode as HTMLOptionElement).selected; + } + } + // canvas image data + if (tagName === 'CANVAS') { + rrElement.attributes.rr_dataURL = (elementNode as HTMLCanvasElement).toDataURL(); + } + // media elements + if (tagName === 'AUDIO' || tagName === 'VIDEO') { + const rrMediaElement = rrElement as RRMediaElement; + rrMediaElement.paused = (elementNode as HTMLMediaElement).paused; + rrMediaElement.currentTime = (elementNode as HTMLMediaElement).currentTime; + } + // scroll + if (elementNode.scrollLeft) { + rrElement.scrollLeft = elementNode.scrollLeft; + } + if (elementNode.scrollTop) { + rrElement.scrollTop = elementNode.scrollTop; + } + break; + case node.TEXT_NODE: + rrNode = this.createTextNode( + ((node as unknown) as Text).textContent, + ); + break; + case node.CDATA_SECTION_NODE: + rrNode = this.createCDATASection(); + break; + case node.COMMENT_NODE: + rrNode = this.createComment( + ((node as unknown) as Comment).textContent || '', + ); + break; + default: + return; + } + rrNode.__sn = serializedNodeWithId; + this.mirror.set(serializedNodeWithId.id, rrNode); + } else { + rrNode = this.mirror.get(serializedNodeWithId.id); + rrNode.parentElement = null; + rrNode.parentNode = null; + rrNode.children = []; + } + const parentNode = node.parentElement || node.parentNode; + if (parentNode) { + const parentSN = ((parentNode as unknown) as INode).__sn; + const parentRRNode = this.mirror.get(parentSN.id); + parentRRNode.appendChild(rrNode); + rrNode.parentNode = parentRRNode; + rrNode.parentElement = + parentRRNode instanceof RRElement ? parentRRNode : null; + } + + if ( + serializedNodeWithId.type === NodeType.Document || + serializedNodeWithId.type === NodeType.Element + ) { + node.childNodes.forEach((node) => walk((node as unknown) as INode)); + } + }.bind(this); + + if (dom) { + this.destroyTree(); + walk((dom as unknown) as INode); + } + } + + destroyTree() { + this.children = []; + this.mirror.clear(); + } + + toString() { + return super.toString('RRDocument'); + } +} + +export class RRDocumentType extends RRNode { + readonly name: string; + readonly publicId: string; + readonly systemId: string; + + constructor(qualifiedName: string, publicId: string, systemId: string) { + super(); + this.name = qualifiedName; + this.publicId = publicId; + this.systemId = systemId; + } + + toString() { + return super.toString('RRDocumentType'); + } +} + +export class RRElement extends RRNode { + tagName: string; + attributes: Record = {}; + scrollLeft: number = 0; + scrollTop: number = 0; + shadowRoot: RRElement | null = null; + + constructor(tagName: string) { + super(); + this.tagName = tagName; + } + + get classList() { + return new ClassList( + this.attributes.class as string | undefined, + (newClassName) => { + this.attributes.class = newClassName; + }, + ); + } + + get id() { + return this.attributes.id; + } + + get className() { + return this.attributes.class || ''; + } + + get textContent() { + return ''; + } + + set textContent(newText: string) {} + + get style() { + const style = (this.attributes.style + ? parseCSSText(this.attributes.style as string) + : {}) as Record & { + setProperty: ( + name: string, + value: string | null, + priority?: string | null, + ) => void; + }; + style.setProperty = (name: string, value: string | null) => { + const normalizedName = camelize(name); + if (!value) delete style[normalizedName]; + else style[normalizedName] = value; + this.attributes.style = toCSSText(style); + }; + // This is used to bypass the smoothscroll polyfill in rrweb player. + style.scrollBehavior = ''; + return style; + } + + get firstElementChild(): RRElement | null { + for (let child of this.children) + if (child instanceof RRElement) return child; + return null; + } + + get nextElementSibling(): RRElement | null { + let parentNode = this.parentNode; + if (!parentNode) return null; + const siblings = parentNode.children; + let index = siblings.indexOf(this); + for (let i = index + 1; i < siblings.length; i++) + if (siblings[i] instanceof RRElement) return siblings[i] as RRElement; + return null; + } + + getAttribute(name: string) { + let upperName = name && name.toLowerCase(); + if (upperName in this.attributes) return this.attributes[upperName]; + return null; + } + + setAttribute(name: string, attribute: string) { + this.attributes[name.toLowerCase()] = attribute; + } + + hasAttribute(name: string) { + return (name && name.toLowerCase()) in this.attributes; + } + + setAttributeNS( + _namespace: string | null, + qualifiedName: string, + value: string, + ): void { + this.setAttribute(qualifiedName, value); + } + + removeAttribute(name: string) { + delete this.attributes[name]; + } + + appendChild(newChild: RRNode): RRNode { + this.children.push(newChild); + newChild.parentNode = this; + newChild.parentElement = this; + newChild.ownerDocument = this.ownerDocument; + return newChild; + } + + insertBefore(newChild: RRNode, refChild: RRNode | null): RRNode { + if (refChild === null) return this.appendChild(newChild); + const childIndex = this.children.indexOf(refChild); + if (childIndex == -1) + throw new Error( + "Failed to execute 'insertBefore' on 'RRNode': The RRNode before which the new node is to be inserted is not a child of this RRNode.", + ); + this.children.splice(childIndex, 0, newChild); + newChild.parentElement = null; + newChild.parentNode = this; + newChild.ownerDocument = this.ownerDocument; + return newChild; + } + + querySelectorAll(selectors: string): RRNode[] { + if (this.ownerDocument !== null) { + return (this.ownerDocument.nwsapi.select( + selectors, + (this as unknown) as Element, + ) as unknown) as RRNode[]; + } + return []; + } + + getElementById(elementId: string): RRElement | null { + if (this instanceof RRElement && this.id === elementId) return this; + for (const child of this.children) { + if (child instanceof RRElement) { + const result = child.getElementById(elementId); + if (result !== null) return result; + } + } + return null; + } + + getElementsByClassName(className: string): RRElement[] { + let elements: RRElement[] = []; + const queryClassList = new ClassList(className); + // Make sure this element has all queried class names. + if ( + this instanceof RRElement && + queryClassList.filter((queriedClassName) => + this.classList.some((name) => name === queriedClassName), + ).length == queryClassList.length + ) + elements.push(this); + for (const child of this.children) { + if (child instanceof RRElement) + elements = elements.concat(child.getElementsByClassName(className)); + } + return elements; + } + + getElementsByTagName(tagName: string): RRElement[] { + let elements: RRElement[] = []; + const normalizedTagName = tagName.toUpperCase(); + if (this instanceof RRElement && this.tagName === normalizedTagName) + elements.push(this); + for (const child of this.children) { + if (child instanceof RRElement) + elements = elements.concat(child.getElementsByTagName(tagName)); + } + return elements; + } + + dispatchEvent(_event: Event) { + return true; + } + + /** + * Creates a shadow root for element and returns it. + */ + attachShadow(init: ShadowRootInit): RRElement { + this.shadowRoot = init.mode === 'open' ? this : null; + return this; + } + + toString() { + let attributeString = ''; + for (let attribute in this.attributes) { + attributeString += `${attribute}="${this.attributes[attribute]}" `; + } + return `${super.toString(this.tagName)} ${attributeString}`; + } +} + +export class RRImageElement extends RRElement { + src: string; + width: number; + height: number; + onload: ((this: GlobalEventHandlers, ev: Event) => any) | null; +} + +export class RRMediaElement extends RRElement { + currentTime: number = 0; + paused: boolean = true; + async play() { + this.paused = false; + } + async pause() { + this.paused = true; + } +} + +export class RRCanvasElement extends RRElement { + /** + * This is just a dummy implementation to prevent rrweb replayer from drawing mouse tail. If further analysis of canvas is needed, we may implement it with node-canvas. + */ + getContext(): CanvasRenderingContext2D | null { + return null; + } +} + +export class RRStyleElement extends RRElement { + private _sheet: CSSStyleSheet | null = null; + + get sheet() { + if (!this._sheet) { + let result = ''; + for (let child of this.childNodes) + if (child.nodeType === NodeType.Text) + result += (child as RRText).textContent; + this._sheet = cssom.parse(result); + } + return this._sheet; + } +} + +export class RRIframeElement extends RRElement { + width: string = ''; + height: string = ''; + src: string = ''; + contentDocument: RRDocument = new RRDocument(); + contentWindow: RRWindow = new RRWindow(); + + constructor(tagName: string) { + super(tagName); + const htmlElement = this.contentDocument.createElement('HTML'); + this.contentDocument.appendChild(htmlElement); + htmlElement.appendChild(this.contentDocument.createElement('HEAD')); + htmlElement.appendChild(this.contentDocument.createElement('BODY')); + } +} + +export class RRText extends RRNode { + textContent: string; + + constructor(data: string) { + super(); + this.textContent = data; + } + + toString() { + return `${super.toString('RRText')} text=${JSON.stringify( + this.textContent, + )}`; + } +} + +export class RRComment extends RRNode { + data: string; + + constructor(data: string) { + super(); + this.data = data; + } + + toString() { + return `${super.toString('RRComment')} data=${JSON.stringify(this.data)}`; + } +} +export class RRCDATASection extends RRNode { + data: string; + + constructor(data: string) { + super(); + this.data = data; + } + + toString() { + return `${super.toString('RRCDATASection')} data=${JSON.stringify( + this.data, + )}`; + } +} + +interface RRElementTagNameMap { + img: RRImageElement; + audio: RRMediaElement; + video: RRMediaElement; +} + +type RRElementType< + K extends keyof HTMLElementTagNameMap +> = K extends keyof RRElementTagNameMap ? RRElementTagNameMap[K] : RRElement; + +class ClassList extends Array { + private onChange: ((newClassText: string) => void) | undefined; + + constructor( + classText?: string, + onChange?: ((newClassText: string) => void) | undefined, + ) { + super(); + if (classText) { + const classes = classText.trim().split(/\s+/); + super.push(...classes); + } + this.onChange = onChange; + } + + add = (...classNames: string[]) => { + for (const item of classNames) { + const className = String(item); + if (super.indexOf(className) >= 0) continue; + super.push(className); + } + this.onChange && this.onChange(super.join(' ')); + }; + + remove = (...classNames: string[]) => { + for (const item of classNames) { + const className = String(item); + const index = super.indexOf(className); + if (index < 0) continue; + super.splice(index, 1); + } + this.onChange && this.onChange(super.join(' ')); + }; +} diff --git a/packages/rrdom/src/index.ts b/packages/rrdom/src/index.ts new file mode 100644 index 0000000000..ac14bf73a4 --- /dev/null +++ b/packages/rrdom/src/index.ts @@ -0,0 +1,13 @@ +import { + polyfillPerformance, + polyfillRAF, + polyfillEvent, + polyfillNode, + polyfillDocument, +} from './polyfill'; +polyfillPerformance(); +polyfillRAF(); +polyfillEvent(); +polyfillNode(); +polyfillDocument(); +export * from './document-nodejs'; diff --git a/packages/rrdom/src/polyfill.ts b/packages/rrdom/src/polyfill.ts new file mode 100644 index 0000000000..271af35f56 --- /dev/null +++ b/packages/rrdom/src/polyfill.ts @@ -0,0 +1,87 @@ +import { RRDocument, RRNode } from './document-nodejs'; + +/** + * Polyfill the performance for nodejs. + */ +export function polyfillPerformance() { + if (typeof window !== 'undefined' || 'performance' in global) return; + ((global as Window & typeof globalThis) + .performance as unknown) = require('perf_hooks').performance; +} + +/** + * Polyfill requestAnimationFrame and cancelAnimationFrame for nodejs. + */ +export function polyfillRAF() { + if (typeof window !== 'undefined' || 'requestAnimationFrame' in global) + return; + + const FPS = 60, + INTERVAL = 1_000 / FPS; + let timeoutHandle: NodeJS.Timeout | null = null, + rafCount = 0, + requests = Object.create(null); + + function onFrameTimer() { + const currentRequests = requests; + requests = Object.create(null); + timeoutHandle = null; + Object.keys(currentRequests).forEach(function (id) { + const request = currentRequests[id]; + if (request) request(Date.now()); + }); + } + + function requestAnimationFrame(callback: (timestamp: number) => void) { + const cbHandle = ++rafCount; + requests[cbHandle] = callback; + if (timeoutHandle === null) + timeoutHandle = setTimeout(onFrameTimer, INTERVAL); + return cbHandle; + } + + function cancelAnimationFrame(handleId: number) { + delete requests[handleId]; + if (Object.keys(requests).length === 0 && timeoutHandle !== null) { + clearTimeout(timeoutHandle); + timeoutHandle = null; + } + } + + (global as Window & + typeof globalThis).requestAnimationFrame = requestAnimationFrame; + (global as Window & + typeof globalThis).cancelAnimationFrame = cancelAnimationFrame; +} + +/** + * Try to polyfill Event type. + * The implementation of Event so far is empty because rrweb doesn't strongly depend on it in nodejs mode. + * Note: The Event class is available through the global object from nodejs v15.0.0. + */ +export function polyfillEvent() { + if (typeof Event !== 'undefined') return; + (global.Event as unknown) = function () {}; +} + +/** + * Polyfill Node type with RRNode for nodejs. + */ +export function polyfillNode() { + if (typeof Node !== 'undefined') return; + (global.Node as unknown) = RRNode; +} + +/** + * Polyfill document object with RRDocument for nodejs. + */ +export function polyfillDocument() { + if (typeof document !== 'undefined') return; + const rrdom = new RRDocument(); + (() => { + rrdom.appendChild(rrdom.createElement('html')); + rrdom.documentElement.appendChild(rrdom.createElement('head')); + rrdom.documentElement.appendChild(rrdom.createElement('body')); + })(); + global.document = (rrdom as unknown) as Document; +} diff --git a/packages/rrdom/src/style.ts b/packages/rrdom/src/style.ts new file mode 100644 index 0000000000..1e49b83619 --- /dev/null +++ b/packages/rrdom/src/style.ts @@ -0,0 +1,40 @@ +export function parseCSSText(cssText: string): Record { + const res: Record = {}; + const listDelimiter = /;(?![^(]*\))/g; + const propertyDelimiter = /:(.+)/; + cssText.split(listDelimiter).forEach(function (item) { + if (item) { + const tmp = item.split(propertyDelimiter); + tmp.length > 1 && (res[camelize(tmp[0].trim())] = tmp[1].trim()); + } + }); + return res; + } + + export function toCSSText(style: Record): string { + const properties = []; + for (let name in style) { + const value = style[name]; + if (typeof value !== 'string') continue; + const normalizedName = hyphenate(name); + properties.push(`${normalizedName}:${value};`); + } + return properties.join(' '); + } + + /** + * Camelize a hyphen-delimited string. + */ + const camelizeRE = /-(\w)/g; + export const camelize = (str: string): string => { + return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); + }; + + /** + * Hyphenate a camelCase string. + */ + const hyphenateRE = /\B([A-Z])/g; + export const hyphenate = (str: string): string => { + return str.replace(hyphenateRE, '-$1').toLowerCase(); + }; + \ No newline at end of file diff --git a/packages/rrdom/test/__snapshots__/document-nodejs.test.ts.snap b/packages/rrdom/test/__snapshots__/document-nodejs.test.ts.snap new file mode 100644 index 0000000000..04748dd7a8 --- /dev/null +++ b/packages/rrdom/test/__snapshots__/document-nodejs.test.ts.snap @@ -0,0 +1,48 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`RRDocument for nodejs environment buildFromDom should create an RRDocument from a html document 1`] = ` +"-1 RRDocument + -2 RRDocumentType + -3 HTML lang=\\"en\\" + -4 HEAD + -5 RRText text=\\"\\\\n \\" + -6 META charset=\\"UTF-8\\" + -7 RRText text=\\"\\\\n \\" + -8 META name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" + -9 RRText text=\\"\\\\n \\" + -10 TITLE + -11 RRText text=\\"Main\\" + -12 RRText text=\\"\\\\n \\" + -13 LINK rel=\\"stylesheet\\" href=\\"somelink\\" + -14 RRText text=\\"\\\\n \\" + -15 STYLE + -16 RRText text=\\"\\\\n h1 {\\\\n color: 'black';\\\\n }\\\\n .blocks {\\\\n padding: 0;\\\\n }\\\\n .blocks1 {\\\\n margin: 0;\\\\n }\\\\n #block1 {\\\\n width: 100px;\\\\n height: 200px;\\\\n }\\\\n @import url(\\\\\\"main.css\\\\\\");\\\\n \\" + -17 RRText text=\\"\\\\n \\" + -18 RRText text=\\"\\\\n \\" + -19 BODY + -20 RRText text=\\"\\\\n \\" + -21 H1 + -22 RRText text=\\"This is a h1 heading\\" + -23 RRText text=\\"\\\\n \\" + -24 H1 style=\\"font-size: 16px\\" + -25 RRText text=\\"This is a h1 heading with styles\\" + -26 RRText text=\\"\\\\n \\" + -27 DIV id=\\"block1\\" class=\\"blocks blocks1\\" + -28 RRText text=\\"\\\\n \\" + -29 DIV id=\\"block2\\" class=\\"blocks blocks1 :hover\\" + -30 RRText text=\\"\\\\n Text 1\\\\n \\" + -31 DIV id=\\"block3\\" + -32 RRText text=\\"\\\\n \\" + -33 P + -34 RRText text=\\"This is a paragraph\\" + -35 RRText text=\\"\\\\n \\" + -36 BUTTON + -37 RRText text=\\"button1\\" + -38 RRText text=\\"\\\\n \\" + -39 RRText text=\\"\\\\n Text 2\\\\n \\" + -40 RRText text=\\"\\\\n \\" + -41 IMG src=\\"somelink\\" alt=\\"This is an image\\" + -42 RRText text=\\"\\\\n \\" + -43 RRText text=\\"\\\\n \\\\n\\\\n\\" +" +`; diff --git a/packages/rrdom/test/document-nodejs.test.ts b/packages/rrdom/test/document-nodejs.test.ts new file mode 100644 index 0000000000..774b7250dc --- /dev/null +++ b/packages/rrdom/test/document-nodejs.test.ts @@ -0,0 +1,259 @@ +/** + * @jest-environment jsdom + */ +import * as fs from 'fs'; +import * as path from 'path'; +import { RRDocument, RRElement, RRStyleElement } from '../src/document-nodejs'; +import { printRRDom } from './util'; + +describe('RRDocument for nodejs environment', () => { + describe('buildFromDom', () => { + it('should create an RRDocument from a html document', () => { + // setup document + document.write(getHtml('main.html')); + + // create RRDocument from document + const rrdoc = new RRDocument(); + rrdoc.buildFromDom(document); + expect(printRRDom(rrdoc)).toMatchSnapshot(); + }); + }); + + describe('RRDocument API', () => { + let rrdom: RRDocument; + beforeAll(() => { + // initialize rrdom + document.write(getHtml('main.html')); + rrdom = new RRDocument(); + rrdom.buildFromDom(document); + }); + + it('get className', () => { + expect(rrdom.getElementsByTagName('DIV')[0].className).toEqual( + 'blocks blocks1', + ); + expect(rrdom.getElementsByTagName('DIV')[1].className).toEqual( + 'blocks blocks1 :hover', + ); + }); + + it('get id', () => { + expect(rrdom.getElementsByTagName('DIV')[0].id).toEqual('block1'); + expect(rrdom.getElementsByTagName('DIV')[1].id).toEqual('block2'); + expect(rrdom.getElementsByTagName('DIV')[2].id).toEqual('block3'); + }); + + it('get attribute name', () => { + expect( + rrdom.getElementsByTagName('DIV')[0].getAttribute('class'), + ).toEqual('blocks blocks1'); + expect( + rrdom.getElementsByTagName('dIv')[0].getAttribute('cLaSs'), + ).toEqual('blocks blocks1'); + expect(rrdom.getElementsByTagName('DIV')[0].getAttribute('id')).toEqual( + 'block1', + ); + expect(rrdom.getElementsByTagName('div')[0].getAttribute('iD')).toEqual( + 'block1', + ); + expect( + rrdom.getElementsByTagName('p')[0].getAttribute('class'), + ).toBeNull(); + }); + + it('get firstElementChild', () => { + expect(rrdom.firstElementChild).toBeDefined(); + expect(rrdom.firstElementChild.tagName).toEqual('HTML'); + + const div1 = rrdom.getElementById('block1'); + expect(div1).toBeDefined(); + expect(div1!.firstElementChild).toBeDefined(); + expect(div1!.firstElementChild!.id).toEqual('block2'); + const div2 = div1!.firstElementChild; + expect(div2!.firstElementChild!.id).toEqual('block3'); + }); + + it('get nextElementSibling', () => { + expect(rrdom.documentElement.firstElementChild).not.toBeNull(); + expect(rrdom.documentElement.firstElementChild!.tagName).toEqual('HEAD'); + expect( + rrdom.documentElement.firstElementChild!.nextElementSibling, + ).not.toBeNull(); + expect( + rrdom.documentElement.firstElementChild!.nextElementSibling!.tagName, + ).toEqual('BODY'); + expect( + rrdom.documentElement.firstElementChild!.nextElementSibling! + .nextElementSibling, + ).toBeNull(); + + expect(rrdom.getElementsByTagName('h1').length).toEqual(2); + const element1 = rrdom.getElementsByTagName('h1')[0]; + const element2 = rrdom.getElementsByTagName('h1')[1]; + expect(element1.tagName).toEqual('H1'); + expect(element2.tagName).toEqual('H1'); + expect(element1.nextElementSibling).toEqual(element2); + expect(element2.nextElementSibling).not.toBeNull(); + expect(element2.nextElementSibling!.id).toEqual('block1'); + expect(element2.nextElementSibling!.nextElementSibling).toBeNull(); + }); + + it('getElementsByTagName', () => { + for (let tagname of [ + 'HTML', + 'BODY', + 'HEAD', + 'STYLE', + 'META', + 'TITLE', + 'SCRIPT', + 'LINK', + 'DIV', + 'H1', + 'P', + 'BUTTON', + 'IMG', + 'CANVAS', + ]) { + const expectedResult = document.getElementsByTagName(tagname).length; + expect(rrdom.getElementsByTagName(tagname).length).toEqual( + expectedResult, + ); + expect( + rrdom.getElementsByTagName(tagname.toLowerCase()).length, + ).toEqual(expectedResult); + for (let node of rrdom.getElementsByTagName(tagname)) { + expect(node.tagName).toEqual(tagname); + } + } + }); + + it('getElementsByClassName', () => { + for (let className of [ + 'blocks', + 'blocks1', + ':hover', + 'blocks1 blocks', + 'blocks blocks1', + ':hover blocks1', + ':hover blocks1 blocks', + ':hover blocks1 block', + ]) { + const msg = `queried class name: '${className}'`; + expect({ + message: msg, + result: rrdom.getElementsByClassName(className).length, + }).toEqual({ + message: msg, + result: document.getElementsByClassName(className).length, + }); + } + }); + + it('getElementById', () => { + for (let elementId of ['block1', 'block2', 'block3']) { + expect(rrdom.getElementById(elementId)).not.toBeNull(); + expect(rrdom.getElementById(elementId)!.id).toEqual(elementId); + } + for (let elementId of ['block', 'blocks', 'blocks1']) + expect(rrdom.getElementById(elementId)).toBeNull(); + }); + + it('querySelectorAll querying tag name', () => { + expect(rrdom.querySelectorAll('H1')).toHaveLength(2); + expect(rrdom.querySelectorAll('H1')[0]).toBeInstanceOf(RRElement); + expect((rrdom.querySelectorAll('H1')[0] as RRElement).tagName).toEqual( + 'H1', + ); + expect(rrdom.querySelectorAll('H1')[1]).toBeInstanceOf(RRElement); + expect((rrdom.querySelectorAll('H1')[1] as RRElement).tagName).toEqual( + 'H1', + ); + }); + + it('querySelectorAll querying class name', () => { + for (let className of [ + '.blocks', + '.blocks1', + '.\\:hover', + '.blocks1.blocks', + '.blocks.blocks1', + '.\\:hover.blocks1', + '.\\:hover.blocks1.blocks', + '.\\:hover.blocks1.block', + ]) { + const msg = `queried class name: '${className}'`; + expect({ + message: msg, + result: rrdom.querySelectorAll(className).length, + }).toEqual({ + message: msg, + result: document.querySelectorAll(className).length, + }); + } + for (let element of rrdom.querySelectorAll('.\\:hover')) { + expect(element).toBeInstanceOf(RRElement); + expect((element as RRElement).classList).toContain(':hover'); + } + }); + + it('querySelectorAll querying id', () => { + for (let query of ['#block1', '#block2', '#block3']) { + expect(rrdom.querySelectorAll(query).length).toEqual(1); + const targetElement = rrdom.querySelectorAll(query)[0] as RRElement; + expect(targetElement.id).toEqual(query.substring(1, query.length)); + } + for (let query of ['#block', '#blocks', '#block1#block2']) + expect(rrdom.querySelectorAll(query).length).toEqual(0); + }); + + it('querySelectorAll', () => { + expect(rrdom.querySelectorAll('link[rel="stylesheet"]').length).toEqual( + 1, + ); + const targetLink = rrdom.querySelectorAll( + 'link[rel="stylesheet"]', + )[0] as RRElement; + expect(targetLink.tagName).toEqual('LINK'); + expect(targetLink.getAttribute('rel')).toEqual('stylesheet'); + + expect(rrdom.querySelectorAll('.blocks#block1').length).toEqual(1); + expect(rrdom.querySelectorAll('.blocks#block3').length).toEqual(0); + }); + + it('style element', () => { + expect(rrdom.getElementsByTagName('style').length).not.toEqual(0); + expect(rrdom.getElementsByTagName('style')[0].tagName).toEqual('STYLE'); + const styleElement = rrdom.getElementsByTagName( + 'style', + )[0] as RRStyleElement; + expect(styleElement.sheet).toBeDefined(); + expect(styleElement.sheet!.cssRules).toBeDefined(); + expect(styleElement.sheet!.cssRules.length).toEqual(5); + const rules = styleElement.sheet!.cssRules; + expect(rules[0].cssText).toEqual(`h1 {color: 'black';}`); + expect(rules[1].cssText).toEqual(`.blocks {padding: 0;}`); + expect(rules[2].cssText).toEqual(`.blocks1 {margin: 0;}`); + expect(rules[3].cssText).toEqual( + `#block1 {width: 100px; height: 200px;}`, + ); + expect(rules[4].cssText).toEqual(`@import url(main.css);`); + expect((rules[4] as CSSImportRule).href).toEqual('main.css'); + + expect(styleElement.sheet!.insertRule).toBeDefined(); + const newRule = "p {color: 'black';}"; + styleElement.sheet!.insertRule(newRule, 5); + expect(rules[5].cssText).toEqual(newRule); + + expect(styleElement.sheet!.deleteRule).toBeDefined(); + styleElement.sheet!.deleteRule(5); + expect(rules[5]).toBeUndefined(); + expect(rules[4].cssText).toEqual(`@import url(main.css);`); + }); + }); +}); + +function getHtml(fileName: string) { + const filePath = path.resolve(__dirname, `./html/${fileName}`); + return fs.readFileSync(filePath, 'utf8'); +} diff --git a/packages/rrdom/test/html/main.html b/packages/rrdom/test/html/main.html new file mode 100644 index 0000000000..c9603b3066 --- /dev/null +++ b/packages/rrdom/test/html/main.html @@ -0,0 +1,40 @@ + + + + + + Main + + + + +

This is a h1 heading

+

This is a h1 heading with styles

+
+
+ Text 1 +
+

This is a paragraph

+ +
+ Text 2 +
+ This is an image +
+ + diff --git a/packages/rrdom/test/polyfill.test.ts b/packages/rrdom/test/polyfill.test.ts new file mode 100644 index 0000000000..6222f7de3f --- /dev/null +++ b/packages/rrdom/test/polyfill.test.ts @@ -0,0 +1,83 @@ +import { RRDocument, RRNode } from '../src/document-nodejs'; +import { + polyfillPerformance, + polyfillRAF, + polyfillEvent, + polyfillNode, + polyfillDocument, +} from '../src/polyfill'; + +describe('polyfill for nodejs', () => { + it('should polyfill performance api', () => { + expect(global.performance).toBeUndefined(); + polyfillPerformance(); + expect(global.performance).toBeDefined(); + expect(performance).toBeDefined(); + expect(performance.now).toBeDefined(); + expect(performance.now()).toBeCloseTo( + require('perf_hooks').performance.now(), + 1e-10, + ); + }); + + it('should polyfill requestAnimationFrame', () => { + expect(global.requestAnimationFrame).toBeUndefined(); + expect(global.cancelAnimationFrame).toBeUndefined(); + polyfillRAF(); + expect(global.requestAnimationFrame).toBeDefined(); + expect(global.cancelAnimationFrame).toBeDefined(); + expect(requestAnimationFrame).toBeDefined(); + expect(cancelAnimationFrame).toBeDefined(); + + jest.useFakeTimers(); + const AnimationTime = 1_000; // target animation time(unit: ms) + const startTime = Date.now(); + let frameCount = 0; + const rafCallback1 = () => { + const currentTime = Date.now(); + frameCount++; + if (currentTime - startTime < AnimationTime) { + requestAnimationFrame(rafCallback1); + } else { + expect(frameCount).toBeGreaterThanOrEqual(55); + expect(frameCount).toBeLessThanOrEqual(65); + } + }; + requestAnimationFrame(rafCallback1); + // Fast-forward until all timers have been executed + jest.runAllTimers(); + + let rafHandle; + const rafCallback2 = () => { + rafHandle = requestAnimationFrame(rafCallback2); + }; + rafHandle = requestAnimationFrame(rafCallback2); + + // If this function doesn't work, recursive function will never end. + cancelAnimationFrame(rafHandle); + jest.runAllTimers(); + jest.useRealTimers(); + }); + + it('should polyfill Event type', () => { + polyfillEvent(); + expect(global.Event).toBeDefined(); + expect(Event).toBeDefined(); + }); + + it('should polyfill Node type', () => { + expect(global.Node).toBeUndefined(); + polyfillNode(); + expect(global.Node).toBeDefined(); + expect(Node).toBeDefined(); + expect(Node).toEqual(RRNode); + }); + + it('should polyfill document object', () => { + expect(global.document).toBeUndefined(); + polyfillDocument(); + expect(global.document).toBeDefined(); + expect(document).toBeDefined(); + expect(document).toBeInstanceOf(RRDocument); + }); +}); diff --git a/packages/rrdom/test/util.ts b/packages/rrdom/test/util.ts new file mode 100644 index 0000000000..09b860fee0 --- /dev/null +++ b/packages/rrdom/test/util.ts @@ -0,0 +1,19 @@ +import { RRIframeElement, RRNode } from '../src/document-nodejs'; + +/** + * Print the RRDom as a string. + * @param rootNode the root node of the RRDom tree + * @returns printed string + */ +export function printRRDom(rootNode: RRNode) { + return walk(rootNode, ''); +} + +function walk(node: RRNode, blankSpace: string) { + let printText = `${blankSpace}${node.toString()}\n`; + for (const child of node.childNodes) + printText += walk(child, blankSpace + ' '); + if (node instanceof RRIframeElement) + printText += walk(node.contentDocument, blankSpace + ' '); + return printText; +} diff --git a/packages/rrdom/tsconfig.json b/packages/rrdom/tsconfig.json new file mode 100644 index 0000000000..15e1aac33c --- /dev/null +++ b/packages/rrdom/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "noImplicitAny": true, + "strictNullChecks": true, + "removeComments": true, + "preserveConstEnums": true, + "sourceMap": true, + "rootDir": "src", + "outDir": "build", + "lib": ["es6", "dom"], + "skipLibCheck": true, + "declaration": true + }, + "compileOnSave": true, + "exclude": ["test"], + "include": ["src", "test.d.ts"] +} diff --git a/yarn.lock b/yarn.lock index fe25937f5e..ee156c2731 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,11 +16,23 @@ dependencies: "@babel/highlight" "^7.14.5" +"@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + "@babel/compat-data@^7.15.0": version "7.15.0" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== +"@babel/compat-data@^7.16.4": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" + integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== + "@babel/core@^7.1.0", "@babel/core@^7.7.2", "@babel/core@^7.7.5": version "7.15.5" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.5.tgz#f8ed9ace730722544609f90c9bb49162dc3bf5b9" @@ -42,6 +54,27 @@ semver "^6.3.0" source-map "^0.5.0" +"@babel/core@^7.12.3", "@babel/core@^7.8.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.7.tgz#db990f931f6d40cb9b87a0dc7d2adc749f1dcbcf" + integrity sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.7" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helpers" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + "@babel/generator@^7.15.4", "@babel/generator@^7.7.2": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.4.tgz#85acb159a267ca6324f9793986991ee2022a05b0" @@ -51,6 +84,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.7.tgz#b42bf46a3079fa65e1544135f32e7958f048adbb" + integrity sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg== + dependencies: + "@babel/types" "^7.16.7" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/helper-compilation-targets@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz#cf6d94f30fbefc139123e27dd6b02f65aeedb7b9" @@ -61,6 +103,23 @@ browserslist "^4.16.6" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" + integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== + dependencies: + "@babel/compat-data" "^7.16.4" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.17.5" + semver "^6.3.0" + +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-function-name@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz#845744dafc4381a4a5fb6afa6c3d36f98a787ebc" @@ -70,6 +129,15 @@ "@babel/template" "^7.15.4" "@babel/types" "^7.15.4" +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== + dependencies: + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/helper-get-function-arity@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz#098818934a137fce78b536a3e015864be1e2879b" @@ -77,6 +145,13 @@ dependencies: "@babel/types" "^7.15.4" +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-hoist-variables@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz#09993a3259c0e918f99d104261dfdfc033f178df" @@ -84,6 +159,13 @@ dependencies: "@babel/types" "^7.15.4" +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-member-expression-to-functions@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz#bfd34dc9bba9824a4658b0317ec2fd571a51e6ef" @@ -98,6 +180,13 @@ dependencies: "@babel/types" "^7.15.4" +"@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-module-transforms@^7.15.4": version "7.15.7" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz#7da80c8cbc1f02655d83f8b79d25866afe50d226" @@ -112,6 +201,20 @@ "@babel/traverse" "^7.15.4" "@babel/types" "^7.15.6" +"@babel/helper-module-transforms@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz#7665faeb721a01ca5327ddc6bba15a5cb34b6a41" + integrity sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/helper-optimise-call-expression@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz#f310a5121a3b9cc52d9ab19122bd729822dee171" @@ -141,6 +244,13 @@ dependencies: "@babel/types" "^7.15.4" +"@babel/helper-simple-access@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" + integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-split-export-declaration@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz#aecab92dcdbef6a10aa3b62ab204b085f776e257" @@ -148,6 +258,13 @@ dependencies: "@babel/types" "^7.15.4" +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-validator-identifier@^7.14.5": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.8.tgz#32be33a756f29e278a0d644fa08a2c9e0f88a34c" @@ -158,11 +275,21 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + "@babel/helper-validator-option@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + "@babel/helpers@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.4.tgz#5f40f02050a3027121a3cf48d497c05c555eaf43" @@ -172,6 +299,15 @@ "@babel/traverse" "^7.15.4" "@babel/types" "^7.15.4" +"@babel/helpers@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.7.tgz#7e3504d708d50344112767c3542fc5e357fffefc" + integrity sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw== + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" @@ -181,11 +317,25 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.7.tgz#81a01d7d675046f0d96f82450d9d9578bdfd6b0b" + integrity sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.15.4", "@babel/parser@^7.15.5", "@babel/parser@^7.7.2": version "7.15.7" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.7.tgz#0c3ed4a2eb07b165dfa85b3cc45c727334c4edae" integrity sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g== +"@babel/parser@^7.14.7", "@babel/parser@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.7.tgz#d372dda9c89fcec340a82630a9f533f2fe15877e" + integrity sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA== + "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" @@ -286,6 +436,15 @@ "@babel/parser" "^7.15.4" "@babel/types" "^7.15.4" +"@babel/template@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/traverse@^7.1.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.7.2": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" @@ -301,6 +460,22 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.7.tgz#dac01236a72c2560073658dd1a285fe4e0865d76" + integrity sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + debug "^4.1.0" + globals "^11.1.0" + "@babel/types@^7.0.0", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.3.0", "@babel/types@^7.3.3": version "7.15.6" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.6.tgz#99abdc48218b2881c058dd0a7ab05b99c9be758f" @@ -309,6 +484,14 @@ "@babel/helper-validator-identifier" "^7.14.9" to-fast-properties "^2.0.0" +"@babel/types@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.7.tgz#4ed19d51f840ed4bd5645be6ce40775fecf03159" + integrity sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -376,6 +559,18 @@ jest-util "^27.2.4" slash "^3.0.0" +"@jest/console@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.4.6.tgz#0742e6787f682b22bdad56f9db2a8a77f6a86107" + integrity sha512-jauXyacQD33n47A44KrlOVeiXHEXDqapSdfb9kTekOchH/Pd18kBIO1+xxJQRLuG+LUuljFCwTG92ra4NW7SpA== + dependencies: + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.4.6" + jest-util "^27.4.2" + slash "^3.0.0" + "@jest/core@^27.2.4": version "27.2.4" resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.2.4.tgz#0b932da787d64848eab720dbb88e5b7a3f86e539" @@ -410,6 +605,40 @@ slash "^3.0.0" strip-ansi "^6.0.0" +"@jest/core@^27.4.7": + version "27.4.7" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.4.7.tgz#84eabdf42a25f1fa138272ed229bcf0a1b5e6913" + integrity sha512-n181PurSJkVMS+kClIFSX/LLvw9ExSb+4IMtD6YnfxZVerw9ANYtW0bPrm0MJu2pfe9SY9FJ9FtQ+MdZkrZwjg== + dependencies: + "@jest/console" "^27.4.6" + "@jest/reporters" "^27.4.6" + "@jest/test-result" "^27.4.6" + "@jest/transform" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-changed-files "^27.4.2" + jest-config "^27.4.7" + jest-haste-map "^27.4.6" + jest-message-util "^27.4.6" + jest-regex-util "^27.4.0" + jest-resolve "^27.4.6" + jest-resolve-dependencies "^27.4.6" + jest-runner "^27.4.6" + jest-runtime "^27.4.6" + jest-snapshot "^27.4.6" + jest-util "^27.4.2" + jest-validate "^27.4.6" + jest-watcher "^27.4.6" + micromatch "^4.0.4" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + "@jest/environment@^27.2.4": version "27.2.4" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.2.4.tgz#db3e60f7dd30ab950f6ce2d6d7293ed9a6b7cbcd" @@ -420,6 +649,16 @@ "@types/node" "*" jest-mock "^27.2.4" +"@jest/environment@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.4.6.tgz#1e92885d64f48c8454df35ed9779fbcf31c56d8b" + integrity sha512-E6t+RXPfATEEGVidr84WngLNWZ8ffCPky8RqqRK6u1Bn0LK92INe0MDttyPl/JOzaq92BmDzOeuqk09TvM22Sg== + dependencies: + "@jest/fake-timers" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + jest-mock "^27.4.6" + "@jest/fake-timers@^27.2.4": version "27.2.4" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.2.4.tgz#00df08bd60332bd59503cb5b6db21e4903785f86" @@ -432,6 +671,18 @@ jest-mock "^27.2.4" jest-util "^27.2.4" +"@jest/fake-timers@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.4.6.tgz#e026ae1671316dbd04a56945be2fa251204324e8" + integrity sha512-mfaethuYF8scV8ntPpiVGIHQgS0XIALbpY2jt2l7wb/bvq4Q5pDLk4EP4D7SAvYT1QrPOPVZAtbdGAOOyIgs7A== + dependencies: + "@jest/types" "^27.4.2" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.4.6" + jest-mock "^27.4.6" + jest-util "^27.4.2" + "@jest/globals@^27.2.4": version "27.2.4" resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.2.4.tgz#0aeb22b011f8c8c4b8ff3b4dbd1ee0392fe0dd8a" @@ -441,6 +692,15 @@ "@jest/types" "^27.2.4" expect "^27.2.4" +"@jest/globals@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.4.6.tgz#3f09bed64b0fd7f5f996920258bd4be8f52f060a" + integrity sha512-kAiwMGZ7UxrgPzu8Yv9uvWmXXxsy0GciNejlHvfPIfWkSxChzv6bgTS3YqBkGuHcis+ouMFI2696n2t+XYIeFw== + dependencies: + "@jest/environment" "^27.4.6" + "@jest/types" "^27.4.2" + expect "^27.4.6" + "@jest/reporters@^27.2.4": version "27.2.4" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.2.4.tgz#1482ff007f2e919d85c54b1563abb8b2ea2d5198" @@ -471,6 +731,37 @@ terminal-link "^2.0.0" v8-to-istanbul "^8.1.0" +"@jest/reporters@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.4.6.tgz#b53dec3a93baf9b00826abf95b932de919d6d8dd" + integrity sha512-+Zo9gV81R14+PSq4wzee4GC2mhAN9i9a7qgJWL90Gpx7fHYkWpTBvwWNZUXvJByYR9tAVBdc8VxDWqfJyIUrIQ== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.4.6" + "@jest/test-result" "^27.4.6" + "@jest/transform" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.4" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-haste-map "^27.4.6" + jest-resolve "^27.4.6" + jest-util "^27.4.2" + jest-worker "^27.4.6" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.1.0" + "@jest/source-map@^27.0.6": version "27.0.6" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.0.6.tgz#be9e9b93565d49b0548b86e232092491fb60551f" @@ -480,6 +771,15 @@ graceful-fs "^4.2.4" source-map "^0.6.0" +"@jest/source-map@^27.4.0": + version "27.4.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.4.0.tgz#2f0385d0d884fb3e2554e8f71f8fa957af9a74b6" + integrity sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.4" + source-map "^0.6.0" + "@jest/test-result@^27.2.4": version "27.2.4" resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.2.4.tgz#d1ca8298d168f1b0be834bfb543b1ac0294c05d7" @@ -490,6 +790,16 @@ "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" +"@jest/test-result@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.4.6.tgz#b3df94c3d899c040f602cea296979844f61bdf69" + integrity sha512-fi9IGj3fkOrlMmhQqa/t9xum8jaJOOAi/lZlm6JXSc55rJMXKHxNDN1oCP39B0/DhNOa2OMupF9BcKZnNtXMOQ== + dependencies: + "@jest/console" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + "@jest/test-sequencer@^27.2.4": version "27.2.4" resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.2.4.tgz#df66422a3e9e7440ce8b7498e255fa6b52c0bc03" @@ -500,6 +810,16 @@ jest-haste-map "^27.2.4" jest-runtime "^27.2.4" +"@jest/test-sequencer@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.4.6.tgz#447339b8a3d7b5436f50934df30854e442a9d904" + integrity sha512-3GL+nsf6E1PsyNsJuvPyIz+DwFuCtBdtvPpm/LMXVkBJbdFvQYCDpccYT56qq5BGniXWlE81n2qk1sdXfZebnw== + dependencies: + "@jest/test-result" "^27.4.6" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.6" + jest-runtime "^27.4.6" + "@jest/transform@^27.2.4": version "27.2.4" resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.2.4.tgz#2fe5b6836895f7a1b8bdec442c51e83943c62733" @@ -521,6 +841,27 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" +"@jest/transform@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.4.6.tgz#153621940b1ed500305eacdb31105d415dc30231" + integrity sha512-9MsufmJC8t5JTpWEQJ0OcOOAXaH5ioaIX6uHVBLBMoCZPfKKQF+EqP8kACAvCZ0Y1h2Zr3uOccg8re+Dr5jxyw== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.4.2" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.6" + jest-regex-util "^27.4.0" + jest-util "^27.4.2" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + "@jest/types@^27.2.4": version "27.2.4" resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.2.4.tgz#2430042a66e00dc5b140c3636f4474d464c21ee8" @@ -532,6 +873,17 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" +"@jest/types@^27.4.2": + version "27.4.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.4.2.tgz#96536ebd34da6392c2b7c7737d693885b5dd44a5" + integrity sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + "@lerna/add@4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@lerna/add/-/add-4.0.0.tgz#c36f57d132502a57b9e7058d1548b7a565ef183f" @@ -1406,6 +1758,31 @@ magic-string "^0.25.2" resolve "^1.11.0" +"@rollup/plugin-commonjs@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-20.0.0.tgz#3246872dcbcb18a54aaa6277a8c7d7f1b155b745" + integrity sha512-5K0g5W2Ol8hAcTHqcTBHiA7M58tfmYi1o9KxeJuuRNpGaTa5iLjcyemBitCBcKXaHamOBBEH2dGom6v6Unmqjg== + dependencies: + "@rollup/pluginutils" "^3.1.0" + commondir "^1.0.1" + estree-walker "^2.0.1" + glob "^7.1.6" + is-reference "^1.2.1" + magic-string "^0.25.7" + resolve "^1.17.0" + +"@rollup/plugin-node-resolve@^13.0.4": + version "13.0.6" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.6.tgz#29629070bb767567be8157f575cfa8f2b8e9ef77" + integrity sha512-sFsPDMPd4gMqnh2gS0uIxELnoRUp5kBl5knxD2EO0778G1oOJv4G1vyT2cpWz75OU2jDVcXhjVUuTAczGyFNKA== + dependencies: + "@rollup/pluginutils" "^3.1.0" + "@types/resolve" "1.17.1" + builtin-modules "^3.1.0" + deepmerge "^4.2.2" + is-module "^1.0.0" + resolve "^1.19.0" + "@rollup/plugin-node-resolve@^7.0.0": version "7.1.3" resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz#80de384edfbd7bfc9101164910f86078151a3eca" @@ -1433,7 +1810,7 @@ "@rollup/pluginutils" "^3.1.0" resolve "^1.17.0" -"@rollup/pluginutils@4": +"@rollup/pluginutils@4", "@rollup/pluginutils@^4.1.0": version "4.1.1" resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.1.1.tgz#1d4da86dd4eded15656a57d933fda2b9a08d47ec" integrity sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ== @@ -1517,6 +1894,11 @@ resolved "https://registry.yarnpkg.com/@types/css-font-loading-module/-/css-font-loading-module-0.0.4.tgz#94a835e27d1af444c65cba88523533c174463d64" integrity sha512-ENdXf7MW4m9HeDojB2Ukbi7lYMIuQNBHVf98dbzaiG4EEJREBd6oleVAjrLRCrp7dm6CK1mmdmU9tcgF61acbw== +"@types/cssom@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cssom/-/cssom-0.4.1.tgz#fb64e145b425bd6c1b0ed78ebd66ba43b6e088ab" + integrity sha512-hHGVfUuGZe5FpgCxpTJccH0gD1bui5gWceW0We0TyAzUr6wBaqDnSLG9Yr3xqS4AkGhnclNOwRSXH/LIfki3fQ== + "@types/eslint-visitor-keys@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" @@ -1566,6 +1948,14 @@ dependencies: "@types/istanbul-lib-report" "*" +"@types/jest@^27.0.1": + version "27.4.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.4.0.tgz#037ab8b872067cae842a320841693080f9cb84ed" + integrity sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ== + dependencies: + jest-diff "^27.0.0" + pretty-format "^27.0.0" + "@types/jest@^27.0.2": version "27.0.2" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.2.tgz#ac383c4d4aaddd29bbf2b916d8d105c304a5fcd7" @@ -1618,6 +2008,11 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== +"@types/nwsapi@^2.2.2": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@types/nwsapi/-/nwsapi-2.2.2.tgz#1b1dccfc38b2b7e1b9ea71d5285796878375e862" + integrity sha512-C4G47l3cAra4729xbhL9y3PjTpO7LJwXd47Fn1mbnZ6WcTkFPo8iDJPyMGCIudxpc7aeM8K1Fmw+lZfOb5ya9g== + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -1669,6 +2064,13 @@ dependencies: "@types/node" "*" +"@types/resolve@1.17.1": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" + integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw== + dependencies: + "@types/node" "*" + "@types/rx-core-binding@*": version "4.0.4" resolved "https://registry.yarnpkg.com/@types/rx-core-binding/-/rx-core-binding-4.0.4.tgz#d969d32f15a62b89e2862c17b3ee78fe329818d3" @@ -2228,6 +2630,20 @@ babel-jest@^27.2.4: graceful-fs "^4.2.4" slash "^3.0.0" +babel-jest@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.4.6.tgz#4d024e69e241cdf4f396e453a07100f44f7ce314" + integrity sha512-qZL0JT0HS1L+lOuH+xC2DVASR3nunZi/ozGhpgauJHgmI7f8rudxf6hUjEHympdQ/J64CdKmPkgfJ+A3U6QCrg== + dependencies: + "@jest/transform" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^27.4.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + slash "^3.0.0" + babel-plugin-istanbul@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" @@ -2239,6 +2655,17 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^4.0.0" test-exclude "^6.0.0" +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + babel-plugin-jest-hoist@^27.2.0: version "27.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz#79f37d43f7e5c4fdc4b2ca3e10cc6cf545626277" @@ -2249,6 +2676,16 @@ babel-plugin-jest-hoist@^27.2.0: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" +babel-plugin-jest-hoist@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz#d7831fc0f93573788d80dee7e682482da4c730d6" + integrity sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + babel-preset-current-node-syntax@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" @@ -2275,6 +2712,14 @@ babel-preset-jest@^27.2.0: babel-plugin-jest-hoist "^27.2.0" babel-preset-current-node-syntax "^1.0.0" +babel-preset-jest@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz#70d0e676a282ccb200fbabd7f415db5fdf393bca" + integrity sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg== + dependencies: + babel-plugin-jest-hoist "^27.4.0" + babel-preset-current-node-syntax "^1.0.0" + babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" @@ -2431,6 +2876,17 @@ browserslist@^4.16.6: node-releases "^1.1.77" picocolors "^0.2.1" +browserslist@^4.17.5: + version "4.19.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" + integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A== + dependencies: + caniuse-lite "^1.0.30001286" + electron-to-chromium "^1.4.17" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + bs-logger@0.x: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" @@ -2587,6 +3043,11 @@ caniuse-lite@^1.0.30001264: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz#0613c9e6c922e422792e6fcefdf9a3afeee4f8c3" integrity sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw== +caniuse-lite@^1.0.30001286: + version "1.0.30001297" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001297.tgz#ea7776ccc4992956582cae5b8fea127fbebde430" + integrity sha512-6bbIbowYG8vFs/Lk4hU9jFt7NknGDleVAciK916tp6ft1j+D//ZwwL6LbF1wXMQ32DMSjeuUV8suhh6dlmFjcA== + capture-stack-trace@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" @@ -2707,6 +3168,11 @@ ci-info@^3.1.1: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.2.0.tgz#2876cb948a498797b5236f0095bc057d0dca38b6" integrity sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A== +ci-info@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + cjs-module-lexer@^1.0.0: version "1.2.2" resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" @@ -3499,6 +3965,11 @@ diff-sequences@^27.0.6: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723" integrity sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ== +diff-sequences@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.4.0.tgz#d783920ad8d06ec718a060d00196dfef25b132a5" + integrity sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww== + diff@^3.0.1, diff@^3.1.0, diff@^3.2.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -3630,6 +4101,11 @@ electron-to-chromium@^1.3.857: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.860.tgz#d612e54ed75fa524c12af8da3ad8121ebfe2802b" integrity sha512-gWwGZ+Wv4Mou2SJRH6JQzhTPjL5f95SX7n6VkLTQ/Q/INsZLZNQ1vH2GlZjozKyvT0kkFuCmWTwIoCj+/hUDPw== +electron-to-chromium@^1.4.17: + version "1.4.37" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.37.tgz#eedd53cad229ae2d1632b958a92a3d7d7b27f553" + integrity sha512-XIvFB1omSAxYgHYX48sC+HR8i/p7lx7R+0cX9faElg1g++h9IilCrJ12+bQuY+d96Wp7zkBiJwMOv+AhLtLrTg== + emittery@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" @@ -3986,6 +4462,16 @@ expect@^27.2.4: jest-message-util "^27.2.4" jest-regex-util "^27.0.6" +expect@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.4.6.tgz#f335e128b0335b6ceb4fcab67ece7cbd14c942e6" + integrity sha512-1M/0kAALIaj5LaG66sFJTbRsWTADnylly82cu4bspI0nl+pgP4E6Bh/aqdHlTUjul06K7xQnnrAoqfxVU0+/ag== + dependencies: + "@jest/types" "^27.4.2" + jest-get-type "^27.4.0" + jest-matcher-utils "^27.4.6" + jest-message-util "^27.4.6" + express@^4.16.4: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" @@ -4218,6 +4704,15 @@ finalhandler@~1.1.2: statuses "~1.5.0" unpipe "~1.0.0" +find-cache-dir@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + find-up@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -4319,6 +4814,15 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== +fs-extra@8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" @@ -5285,7 +5789,7 @@ is-redirect@^1.0.0: resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= -is-reference@^1.1.2: +is-reference@^1.1.2, is-reference@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== @@ -5383,6 +5887,11 @@ istanbul-lib-coverage@^3.0.0: resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.1.tgz#e8900b3ed6069759229cf30f7067388d148aeb5e" integrity sha512-GvCYYTxaCPqwMjobtVcVKvSHtAGe48MNhGjpK8LtVF8K0ISX7hCKl85LgtuaSneWVyQmaGcW3iXVV3GaZSLpmQ== +istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" @@ -5393,6 +5902,17 @@ istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: istanbul-lib-coverage "^3.0.0" semver "^6.3.0" +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" + integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + istanbul-lib-report@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" @@ -5419,6 +5939,14 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +istanbul-reports@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.3.tgz#4bcae3103b94518117930d51283690960b50d3c2" + integrity sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + jest-changed-files@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.2.4.tgz#d7de46e90e5a599c47e260760f5ab53516e835e6" @@ -5428,6 +5956,15 @@ jest-changed-files@^27.2.4: execa "^5.0.0" throat "^6.0.1" +jest-changed-files@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.4.2.tgz#da2547ea47c6e6a5f6ed336151bd2075736eb4a5" + integrity sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A== + dependencies: + "@jest/types" "^27.4.2" + execa "^5.0.0" + throat "^6.0.1" + jest-circus@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.2.4.tgz#3bd898a29dcaf6a506f3f1b780dff5f67ca83c23" @@ -5453,6 +5990,31 @@ jest-circus@^27.2.4: stack-utils "^2.0.3" throat "^6.0.1" +jest-circus@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.4.6.tgz#d3af34c0eb742a967b1919fbb351430727bcea6c" + integrity sha512-UA7AI5HZrW4wRM72Ro80uRR2Fg+7nR0GESbSI/2M+ambbzVuA63mn5T1p3Z/wlhntzGpIG1xx78GP2YIkf6PhQ== + dependencies: + "@jest/environment" "^27.4.6" + "@jest/test-result" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.4.6" + is-generator-fn "^2.0.0" + jest-each "^27.4.6" + jest-matcher-utils "^27.4.6" + jest-message-util "^27.4.6" + jest-runtime "^27.4.6" + jest-snapshot "^27.4.6" + jest-util "^27.4.2" + pretty-format "^27.4.6" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" + jest-cli@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.2.4.tgz#acda7f367aa6e674723fc1a7334e0ae1799448d2" @@ -5471,6 +6033,24 @@ jest-cli@^27.2.4: prompts "^2.0.1" yargs "^16.2.0" +jest-cli@^27.4.7: + version "27.4.7" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.4.7.tgz#d00e759e55d77b3bcfea0715f527c394ca314e5a" + integrity sha512-zREYhvjjqe1KsGV15mdnxjThKNDgza1fhDT+iUsXWLCq3sxe9w5xnvyctcYVT5PcdLSjv7Y5dCwTS3FCF1tiuw== + dependencies: + "@jest/core" "^27.4.7" + "@jest/test-result" "^27.4.6" + "@jest/types" "^27.4.2" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + import-local "^3.0.2" + jest-config "^27.4.7" + jest-util "^27.4.2" + jest-validate "^27.4.6" + prompts "^2.0.1" + yargs "^16.2.0" + jest-config@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.2.4.tgz#0204969f5ae2e5190d47be2c14c04d631b7836e2" @@ -5498,6 +6078,34 @@ jest-config@^27.2.4: micromatch "^4.0.4" pretty-format "^27.2.4" +jest-config@^27.4.7: + version "27.4.7" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.4.7.tgz#4f084b2acbd172c8b43aa4cdffe75d89378d3972" + integrity sha512-xz/o/KJJEedHMrIY9v2ParIoYSrSVY6IVeE4z5Z3i101GoA5XgfbJz+1C8EYPsv7u7f39dS8F9v46BHDhn0vlw== + dependencies: + "@babel/core" "^7.8.0" + "@jest/test-sequencer" "^27.4.6" + "@jest/types" "^27.4.2" + babel-jest "^27.4.6" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.4" + jest-circus "^27.4.6" + jest-environment-jsdom "^27.4.6" + jest-environment-node "^27.4.6" + jest-get-type "^27.4.0" + jest-jasmine2 "^27.4.6" + jest-regex-util "^27.4.0" + jest-resolve "^27.4.6" + jest-runner "^27.4.6" + jest-util "^27.4.2" + jest-validate "^27.4.6" + micromatch "^4.0.4" + pretty-format "^27.4.6" + slash "^3.0.0" + jest-diff@^23.6.0: version "23.6.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-23.6.0.tgz#1500f3f16e850bb3d71233408089be099f610c7d" @@ -5518,6 +6126,16 @@ jest-diff@^27.0.0, jest-diff@^27.2.4: jest-get-type "^27.0.6" pretty-format "^27.2.4" +jest-diff@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.4.6.tgz#93815774d2012a2cbb6cf23f84d48c7a2618f98d" + integrity sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.4.0" + jest-get-type "^27.4.0" + pretty-format "^27.4.6" + jest-docblock@^27.0.6: version "27.0.6" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.0.6.tgz#cc78266acf7fe693ca462cbbda0ea4e639e4e5f3" @@ -5525,6 +6143,13 @@ jest-docblock@^27.0.6: dependencies: detect-newline "^3.0.0" +jest-docblock@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.4.0.tgz#06c78035ca93cbbb84faf8fce64deae79a59f69f" + integrity sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg== + dependencies: + detect-newline "^3.0.0" + jest-each@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.2.4.tgz#b4f280aafd63129ba82e345f0e74c5a10200aeef" @@ -5536,6 +6161,17 @@ jest-each@^27.2.4: jest-util "^27.2.4" pretty-format "^27.2.4" +jest-each@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.4.6.tgz#e7e8561be61d8cc6dbf04296688747ab186c40ff" + integrity sha512-n6QDq8y2Hsmn22tRkgAk+z6MCX7MeVlAzxmZDshfS2jLcaBlyhpF3tZSJLR+kXmh23GEvS0ojMR8i6ZeRvpQcA== + dependencies: + "@jest/types" "^27.4.2" + chalk "^4.0.0" + jest-get-type "^27.4.0" + jest-util "^27.4.2" + pretty-format "^27.4.6" + jest-environment-jsdom@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.2.4.tgz#39ae80bbb8675306bfaf0440be1e5f877554539a" @@ -5549,6 +6185,19 @@ jest-environment-jsdom@^27.2.4: jest-util "^27.2.4" jsdom "^16.6.0" +jest-environment-jsdom@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.4.6.tgz#c23a394eb445b33621dfae9c09e4c8021dea7b36" + integrity sha512-o3dx5p/kHPbUlRvSNjypEcEtgs6LmvESMzgRFQE6c+Prwl2JLA4RZ7qAnxc5VM8kutsGRTB15jXeeSbJsKN9iA== + dependencies: + "@jest/environment" "^27.4.6" + "@jest/fake-timers" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + jest-mock "^27.4.6" + jest-util "^27.4.2" + jsdom "^16.6.0" + jest-environment-node@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.2.4.tgz#b79f98cb36e0c9111aac859c9c99f04eb2f74ff6" @@ -5561,6 +6210,18 @@ jest-environment-node@^27.2.4: jest-mock "^27.2.4" jest-util "^27.2.4" +jest-environment-node@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.4.6.tgz#ee8cd4ef458a0ef09d087c8cd52ca5856df90242" + integrity sha512-yfHlZ9m+kzTKZV0hVfhVu6GuDxKAYeFHrfulmy7Jxwsq4V7+ZK7f+c0XP/tbVDMQW7E4neG2u147hFkuVz0MlQ== + dependencies: + "@jest/environment" "^27.4.6" + "@jest/fake-timers" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + jest-mock "^27.4.6" + jest-util "^27.4.2" + jest-get-type@^22.1.0: version "22.4.3" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4" @@ -5571,6 +6232,11 @@ jest-get-type@^27.0.6: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.0.6.tgz#0eb5c7f755854279ce9b68a9f1a4122f69047cfe" integrity sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg== +jest-get-type@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.4.0.tgz#7503d2663fffa431638337b3998d39c5e928e9b5" + integrity sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ== + jest-haste-map@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.2.4.tgz#f8974807bedf07348ca9fd24e5861ab7c8e61aba" @@ -5591,6 +6257,26 @@ jest-haste-map@^27.2.4: optionalDependencies: fsevents "^2.3.2" +jest-haste-map@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.4.6.tgz#c60b5233a34ca0520f325b7e2cc0a0140ad0862a" + integrity sha512-0tNpgxg7BKurZeFkIOvGCkbmOHbLFf4LUQOxrQSMjvrQaQe3l6E8x6jYC1NuWkGo5WDdbr8FEzUxV2+LWNawKQ== + dependencies: + "@jest/types" "^27.4.2" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^27.4.0" + jest-serializer "^27.4.0" + jest-util "^27.4.2" + jest-worker "^27.4.6" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + jest-jasmine2@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.2.4.tgz#4a1608133dbdb4d68b5929bfd785503ed9c9ba51" @@ -5615,6 +6301,29 @@ jest-jasmine2@^27.2.4: pretty-format "^27.2.4" throat "^6.0.1" +jest-jasmine2@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.4.6.tgz#109e8bc036cb455950ae28a018f983f2abe50127" + integrity sha512-uAGNXF644I/whzhsf7/qf74gqy9OuhvJ0XYp8SDecX2ooGeaPnmJMjXjKt0mqh1Rl5dtRGxJgNrHlBQIBfS5Nw== + dependencies: + "@jest/environment" "^27.4.6" + "@jest/source-map" "^27.4.0" + "@jest/test-result" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^27.4.6" + is-generator-fn "^2.0.0" + jest-each "^27.4.6" + jest-matcher-utils "^27.4.6" + jest-message-util "^27.4.6" + jest-runtime "^27.4.6" + jest-snapshot "^27.4.6" + jest-util "^27.4.2" + pretty-format "^27.4.6" + throat "^6.0.1" + jest-leak-detector@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.2.4.tgz#9bb7eab26a73bb280e9298be8d80f389288ec8f1" @@ -5623,6 +6332,14 @@ jest-leak-detector@^27.2.4: jest-get-type "^27.0.6" pretty-format "^27.2.4" +jest-leak-detector@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.4.6.tgz#ed9bc3ce514b4c582637088d9faf58a33bd59bf4" + integrity sha512-kkaGixDf9R7CjHm2pOzfTxZTQQQ2gHTIWKY/JZSiYTc90bZp8kSZnUMS3uLAfwTZwc0tcMRoEX74e14LG1WapA== + dependencies: + jest-get-type "^27.4.0" + pretty-format "^27.4.6" + jest-matcher-utils@^23.6.0: version "23.6.0" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz#726bcea0c5294261a7417afb6da3186b4b8cac80" @@ -5642,6 +6359,16 @@ jest-matcher-utils@^27.2.4: jest-get-type "^27.0.6" pretty-format "^27.2.4" +jest-matcher-utils@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.4.6.tgz#53ca7f7b58170638590e946f5363b988775509b8" + integrity sha512-XD4PKT3Wn1LQnRAq7ZsTI0VRuEc9OrCPFiO1XL7bftTGmfNF0DcEwMHRgqiu7NGf8ZoZDREpGrCniDkjt79WbA== + dependencies: + chalk "^4.0.0" + jest-diff "^27.4.6" + jest-get-type "^27.4.0" + pretty-format "^27.4.6" + jest-message-util@^23.4.0: version "23.4.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-23.4.0.tgz#17610c50942349508d01a3d1e0bda2c079086a9f" @@ -5668,6 +6395,21 @@ jest-message-util@^27.2.4: slash "^3.0.0" stack-utils "^2.0.3" +jest-message-util@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.4.6.tgz#9fdde41a33820ded3127465e1a5896061524da31" + integrity sha512-0p5szriFU0U74czRSFjH6RyS7UYIAkn/ntwMuOwTGWrQIOh5NzXXrq72LOqIkJKKvFbPq+byZKuBz78fjBERBA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.4.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.4" + pretty-format "^27.4.6" + slash "^3.0.0" + stack-utils "^2.0.3" + jest-mock@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.2.4.tgz#c8f0ef33f73d8ff53e3f60b16d59f1128f4072ae" @@ -5676,6 +6418,14 @@ jest-mock@^27.2.4: "@jest/types" "^27.2.4" "@types/node" "*" +jest-mock@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.4.6.tgz#77d1ba87fbd33ccb8ef1f061697e7341b7635195" + integrity sha512-kvojdYRkst8iVSZ1EJ+vc1RRD9llueBjKzXzeCytH3dMM7zvPV/ULcfI2nr0v0VUgm3Bjt3hBCQvOeaBz+ZTHw== + dependencies: + "@jest/types" "^27.4.2" + "@types/node" "*" + jest-pnp-resolver@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" @@ -5686,6 +6436,11 @@ jest-regex-util@^27.0.6: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.0.6.tgz#02e112082935ae949ce5d13b2675db3d8c87d9c5" integrity sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ== +jest-regex-util@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.4.0.tgz#e4c45b52653128843d07ad94aec34393ea14fbca" + integrity sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg== + jest-resolve-dependencies@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.4.tgz#20c41cc02b66aa45169b282356ec73b133013089" @@ -5695,6 +6450,15 @@ jest-resolve-dependencies@^27.2.4: jest-regex-util "^27.0.6" jest-snapshot "^27.2.4" +jest-resolve-dependencies@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.6.tgz#fc50ee56a67d2c2183063f6a500cc4042b5e2327" + integrity sha512-W85uJZcFXEVZ7+MZqIPCscdjuctruNGXUZ3OHSXOfXR9ITgbUKeHj+uGcies+0SsvI5GtUfTw4dY7u9qjTvQOw== + dependencies: + "@jest/types" "^27.4.2" + jest-regex-util "^27.4.0" + jest-snapshot "^27.4.6" + jest-resolve@^23.6.0: version "23.6.0" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-23.6.0.tgz#cf1d1a24ce7ee7b23d661c33ba2150f3aebfa0ae" @@ -5720,6 +6484,22 @@ jest-resolve@^27.2.4: resolve "^1.20.0" slash "^3.0.0" +jest-resolve@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.4.6.tgz#2ec3110655e86d5bfcfa992e404e22f96b0b5977" + integrity sha512-SFfITVApqtirbITKFAO7jOVN45UgFzcRdQanOFzjnbd+CACDoyeX7206JyU92l4cRr73+Qy/TlW51+4vHGt+zw== + dependencies: + "@jest/types" "^27.4.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.6" + jest-pnp-resolver "^1.2.2" + jest-util "^27.4.2" + jest-validate "^27.4.6" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + jest-runner@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.2.4.tgz#d816f4cb4af04f3cba703afcf5a35a335b77cad4" @@ -5748,6 +6528,34 @@ jest-runner@^27.2.4: source-map-support "^0.5.6" throat "^6.0.1" +jest-runner@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.4.6.tgz#1d390d276ec417e9b4d0d081783584cbc3e24773" + integrity sha512-IDeFt2SG4DzqalYBZRgbbPmpwV3X0DcntjezPBERvnhwKGWTW7C5pbbA5lVkmvgteeNfdd/23gwqv3aiilpYPg== + dependencies: + "@jest/console" "^27.4.6" + "@jest/environment" "^27.4.6" + "@jest/test-result" "^27.4.6" + "@jest/transform" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-docblock "^27.4.0" + jest-environment-jsdom "^27.4.6" + jest-environment-node "^27.4.6" + jest-haste-map "^27.4.6" + jest-leak-detector "^27.4.6" + jest-message-util "^27.4.6" + jest-resolve "^27.4.6" + jest-runtime "^27.4.6" + jest-util "^27.4.2" + jest-worker "^27.4.6" + source-map-support "^0.5.6" + throat "^6.0.1" + jest-runtime@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.2.4.tgz#170044041e5d30625ab8d753516bbe503f213a5c" @@ -5781,6 +6589,34 @@ jest-runtime@^27.2.4: strip-bom "^4.0.0" yargs "^16.2.0" +jest-runtime@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.4.6.tgz#83ae923818e3ea04463b22f3597f017bb5a1cffa" + integrity sha512-eXYeoR/MbIpVDrjqy5d6cGCFOYBFFDeKaNWqTp0h6E74dK0zLHzASQXJpl5a2/40euBmKnprNLJ0Kh0LCndnWQ== + dependencies: + "@jest/environment" "^27.4.6" + "@jest/fake-timers" "^27.4.6" + "@jest/globals" "^27.4.6" + "@jest/source-map" "^27.4.0" + "@jest/test-result" "^27.4.6" + "@jest/transform" "^27.4.6" + "@jest/types" "^27.4.2" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.6" + jest-message-util "^27.4.6" + jest-mock "^27.4.6" + jest-regex-util "^27.4.0" + jest-resolve "^27.4.6" + jest-snapshot "^27.4.6" + jest-util "^27.4.2" + slash "^3.0.0" + strip-bom "^4.0.0" + jest-serializer@^27.0.6: version "27.0.6" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.0.6.tgz#93a6c74e0132b81a2d54623251c46c498bb5bec1" @@ -5789,6 +6625,14 @@ jest-serializer@^27.0.6: "@types/node" "*" graceful-fs "^4.2.4" +jest-serializer@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.4.0.tgz#34866586e1cae2388b7d12ffa2c7819edef5958a" + integrity sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + jest-snapshot@^23.6.0: version "23.6.0" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-23.6.0.tgz#f9c2625d1b18acda01ec2d2b826c0ce58a5aa17a" @@ -5835,6 +6679,34 @@ jest-snapshot@^27.2.4: pretty-format "^27.2.4" semver "^7.3.2" +jest-snapshot@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.4.6.tgz#e2a3b4fff8bdce3033f2373b2e525d8b6871f616" + integrity sha512-fafUCDLQfzuNP9IRcEqaFAMzEe7u5BF7mude51wyWv7VRex60WznZIC7DfKTgSIlJa8aFzYmXclmN328aqSDmQ== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.4.6" + graceful-fs "^4.2.4" + jest-diff "^27.4.6" + jest-get-type "^27.4.0" + jest-haste-map "^27.4.6" + jest-matcher-utils "^27.4.6" + jest-message-util "^27.4.6" + jest-util "^27.4.2" + natural-compare "^1.4.0" + pretty-format "^27.4.6" + semver "^7.3.2" + jest-util@^27.0.0, jest-util@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.2.4.tgz#3d7ce081b2e7f4cfe0156452ac01f3cb456cc656" @@ -5847,6 +6719,18 @@ jest-util@^27.0.0, jest-util@^27.2.4: is-ci "^3.0.0" picomatch "^2.2.3" +jest-util@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.4.2.tgz#ed95b05b1adfd761e2cda47e0144c6a58e05a621" + integrity sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA== + dependencies: + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.4" + picomatch "^2.2.3" + jest-validate@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.2.4.tgz#b66d462b2fb93d7e16a47d1aa8763d5600bf2cfa" @@ -5859,6 +6743,18 @@ jest-validate@^27.2.4: leven "^3.1.0" pretty-format "^27.2.4" +jest-validate@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.4.6.tgz#efc000acc4697b6cf4fa68c7f3f324c92d0c4f1f" + integrity sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ== + dependencies: + "@jest/types" "^27.4.2" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.4.0" + leven "^3.1.0" + pretty-format "^27.4.6" + jest-watcher@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.2.4.tgz#b1d5c39ab94f59f4f35f66cc96f7761a10e0cfc4" @@ -5872,6 +6768,19 @@ jest-watcher@^27.2.4: jest-util "^27.2.4" string-length "^4.0.1" +jest-watcher@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.4.6.tgz#673679ebeffdd3f94338c24f399b85efc932272d" + integrity sha512-yKQ20OMBiCDigbD0quhQKLkBO+ObGN79MO4nT7YaCuQ5SM+dkBNWE8cZX0FjU6czwMvWw6StWbe+Wv4jJPJ+fw== + dependencies: + "@jest/test-result" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.4.2" + string-length "^4.0.1" + jest-worker@^26.2.1: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" @@ -5890,6 +6799,24 @@ jest-worker@^27.2.4: merge-stream "^2.0.0" supports-color "^8.0.0" +jest-worker@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.6.tgz#5d2d93db419566cb680752ca0792780e71b3273e" + integrity sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^27.1.1: + version "27.4.7" + resolved "https://registry.yarnpkg.com/jest/-/jest-27.4.7.tgz#87f74b9026a1592f2da05b4d258e57505f28eca4" + integrity sha512-8heYvsx7nV/m8m24Vk26Y87g73Ba6ueUd0MWed/NXMhSZIm62U/llVbS0PJe1SHunbyXjJ/BqG1z9bFjGUIvTg== + dependencies: + "@jest/core" "^27.4.7" + import-local "^3.0.2" + jest-cli "^27.4.7" + jest@^27.2.4: version "27.2.4" resolved "https://registry.yarnpkg.com/jest/-/jest-27.2.4.tgz#70e27bef873138afc123aa4769f7124c50ad3efb" @@ -6080,6 +7007,13 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -6365,7 +7299,7 @@ make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" -make-dir@^3.0.0: +make-dir@^3.0.0, make-dir@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -6850,6 +7784,11 @@ node-releases@^1.1.77: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e" integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ== +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== + nopt@^4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" @@ -7443,6 +8382,11 @@ picocolors@^0.2.1: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3: version "2.3.0" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" @@ -7487,7 +8431,12 @@ pirates@^4.0.1: dependencies: node-modules-regexp "^1.0.0" -pkg-dir@^4.2.0: +pirates@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.4.tgz#07df81e61028e402735cdd49db701e4885b4e6e6" + integrity sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw== + +pkg-dir@^4.1.0, pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== @@ -7912,6 +8861,15 @@ pretty-format@^27.0.0, pretty-format@^27.2.4: ansi-styles "^5.0.0" react-is "^17.0.1" +pretty-format@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.4.6.tgz#1b784d2f53c68db31797b2348fa39b49e31846b7" + integrity sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -8377,12 +9335,17 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +resolve.exports@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.14.1, resolve@^1.14.2, resolve@^1.16.1, resolve@^1.17.0, resolve@^1.20.0: +resolve@1.20.0, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.14.1, resolve@^1.14.2, resolve@^1.16.1, resolve@^1.17.0, resolve@^1.19.0, resolve@^1.20.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -8500,6 +9463,17 @@ rollup-plugin-terser@^7.0.2: serialize-javascript "^4.0.0" terser "^5.0.0" +rollup-plugin-typescript2@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.30.0.tgz#1cc99ac2309bf4b9d0a3ebdbc2002aecd56083d3" + integrity sha512-NUFszIQyhgDdhRS9ya/VEmsnpTe+GERDMmFo0Y+kf8ds51Xy57nPNGglJY+W6x1vcouA7Au7nsTgsLFj2I0PxQ== + dependencies: + "@rollup/pluginutils" "^4.1.0" + find-cache-dir "^3.3.1" + fs-extra "8.1.0" + resolve "1.20.0" + tslib "2.1.0" + rollup-pluginutils@^2.8.2: version "2.8.2" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" @@ -8514,6 +9488,13 @@ rollup@^2.45.2: optionalDependencies: fsevents "~2.3.2" +rollup@^2.56.3: + version "2.60.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.60.2.tgz#3f45ace36a9b10b4297181831ea0719922513463" + integrity sha512-1Bgjpq61sPjgoZzuiDSGvbI1tD91giZABgjCQBKM5aYLnzjq52GoDuWVwT/cm/MCxCMPU8gqQvkj8doQ5C8Oqw== + optionalDependencies: + fsevents "~2.3.2" + run-async@^2.2.0, run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -9435,6 +10416,11 @@ ts-node@^7.0.1: source-map-support "^0.5.6" yn "^2.0.0" +tslib@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== + tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -9637,7 +10623,7 @@ universal-user-agent@^6.0.0: resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== -universalify@^0.1.2: +universalify@^0.1.0, universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==