From 3c826736a5aed4869224501352ebf1ca371b5f93 Mon Sep 17 00:00:00 2001 From: Yoshihiro OKUMURA Date: Wed, 15 Jun 2022 11:22:57 +0900 Subject: [PATCH] first commit. --- .gitignore | 130 +++++++ README.md | 7 + package.json | 50 +++ src/g3d.ts | 1035 +++++++++++++++++++++++++++++++++++++++++++++++++ src/m3d.ts | 616 +++++++++++++++++++++++++++++ tsconfig.json | 21 + yarn.lock | 859 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 2718 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 package.json create mode 100644 src/g3d.ts create mode 100644 src/m3d.ts create mode 100644 tsconfig.json create mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6bba59 --- /dev/null +++ b/.gitignore @@ -0,0 +1,130 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* diff --git a/README.md b/README.md new file mode 100644 index 0000000..3038b19 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Typescript library for 3D MRI Data Viewer System + +This library is a port of a part of the "3D MRI Data Viewer System on Neuroimaging platform" in typescript. + +## Reference +* Matsuda K, Higo N, Oishi T, Niki K, Suzuki R, Masaki S, Fujimaki N, Ichikawa K and Usui S (2010). 3D MRI Data Viewer System on Neuroimaging-platform. Front. Neurosci. Conference Abstract: Neuroinformatics 2010 . doi: 10.3389/conf.fnins.2010.13.00042 +Typescript diff --git a/package.json b/package.json new file mode 100644 index 0000000..a3bcc26 --- /dev/null +++ b/package.json @@ -0,0 +1,50 @@ +{ + "name": "mridatalib", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "scripts": { + "build": "tsc -p .", + "lint": "eslint 'src/**/*.ts'", + "lint:fix": "eslint --fix 'src/**/*.ts'" + }, + "eslintConfig": { + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + "prettier" + ], + "plugins": [ + "@typescript-eslint" + ], + "env": { + "browser": true, + "es6": true + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "sourceType": "module", + "project": "./tsconfig.json" + }, + "rules": { + } + }, + "prettier": { + "semi": true, + "singleQuote": true, + "printWidth": 1000, + "tabWidth": 4 + }, + "dependencies": {}, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^5.28.0", + "@typescript-eslint/parser": "^5.28.0", + "eslint": "^8.17.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-prettier": "^4.0.0", + "prettier": "^2.7.0", + "typescript": "^4.7.3" + } +} diff --git a/src/g3d.ts b/src/g3d.ts new file mode 100644 index 0000000..82d6083 --- /dev/null +++ b/src/g3d.ts @@ -0,0 +1,1035 @@ +export interface G3DHeader { + magic: number; // MagicNumber GO3D[0x47 0x4f 0x33 0x44], GH3D [0x47 0x48 0x33 0x44] or CO3D[0x43 0x4f 0x33 0x44] + width: number; // surface area silce width in pixels + height: number; // surface area slice height in pixels + depth: number; // surface area slice depth in pixels + org_width: number; // silce width in pixels + org_height: number; // slice height in pixels + org_depth: number; // slice depth in pixels + datatype: number; // 1 (byte per voxel) for gray, 3 (byte for voxel) for color + unit: number; // km:3, m:0, mm:-3, micro m:-6, nano m:-9 + grid: number; // grid width in unit + vs_width: number; // surface voxel width in unit + v_width: number; // voxel width in unit + v_height: number; // voxel height in unit + v_depth: number; // voxel depth in unit + ax: number; // rotation angle x + ay: number; // rotation angle y + az: number; // rotation angle z + ox: number; // origin x in surface voxel coordinates + oy: number; // origin y in surface voxel coordinates + oz: number; // origin z in surface voxel coordinates + s_num: number; // number of surface voxels + s_th: number; // threshold of suface voxel + option: string; // option area for additional parameters + date: string; // free format - sample: 1970/01/01 00:00:00 + coordinate: string; // Talairach, Horsley-Clarke, etc + subject: string; // subject name bm85... etc + memo: string; // memo or something for extend +} + +interface G3DImageRenderingContext { + a1: number; + a2: number; + a3: number; + b1: number; + b2: number; + b3: number; + c1: number; + c2: number; + c3: number; + d1: number; + d2: number; + d3: number; + ra1: number; + ra1_2: number; + ra2: number; + ra2_2: number; + ra3: number; + ra3_2: number; + rb1: number; + rb1_2: number; + rb2: number; + rb2_2: number; + rb3: number; + rb3_2: number; + rc1: number; + rc1_2: number; + rc2: number; + rc2_2: number; + rc3: number; + rc3_2: number; + rd1: number; + rd2: number; + rd3: number; +} + +interface G3DColor { + r: number; + g: number; + b: number; +} + +enum DrawingLineType { + VLine = 0, + VDottedLine = 1, + HLine = 2, + HDottedLine = 3, +} +const LineBrightness = 200; +const DottedLineBrightness = 128; +const EXACTSWITCH: 0 | 1 = 1; +const MaxIntensity = 200; + +class G3D { + private data: ArrayBuffer | null = null; + private header: G3DHeader | null = null; + private isLittleEndianFile = true; + private surfaceView: Int16Array | null = null; + private imgView: Uint8Array | null = null; + private imageSize = 0; + private centerX = 0; + private centerY = 0; + private centerZ = 0; + private ox = 0; + private oy = 0; + private oz = 0; + + constructor(data: ArrayBuffer) { + this._initialize(data); + } + + getHeader(): G3DHeader | null { + return this.header; + } + + drawImage(canvas: HTMLCanvasElement, ax: number, ay: number, az: number, cutdepth: number, th: number, is3d: boolean, mesh: boolean, skincolor: boolean, smoothing: boolean): boolean { + const irc: G3DImageRenderingContext = { + a1: 0, + a2: 0, + a3: 0, + b1: 0, + b2: 0, + b3: 0, + c1: 0, + c2: 0, + c3: 0, + d1: 0, + d2: 0, + d3: 0, + ra1: 0, + ra1_2: 0, + ra2: 0, + ra2_2: 0, + ra3: 0, + ra3_2: 0, + rb1: 0, + rb1_2: 0, + rb2: 0, + rb2_2: 0, + rb3: 0, + rb3_2: 0, + rc1: 0, + rc1_2: 0, + rc2: 0, + rc2_2: 0, + rc3: 0, + rc3_2: 0, + rd1: 0, + rd2: 0, + rd3: 0, + }; + console.log(ax, ay, az, cutdepth, th, is3d, mesh, skincolor, smoothing); + if (this.header === null) { + return false; + } + + canvas.width = this.imageSize; + canvas.height = this.imageSize; + const ctx = canvas.getContext('2d'); + if (ctx === null) { + return false; + } + ctx.fillStyle = 'rgb(0, 0, 0)'; + ctx.fillRect(0, 0, this.imageSize, this.imageSize); + const img = ctx.getImageData(0, 0, this.imageSize, this.imageSize); + + this._setMatrix(ax, ay, az, irc); + switch (this.header.datatype) { + case 1: + if (is3d) { + const flag2d = [...Array(this.imageSize * this.imageSize)].map(() => false); + const ddimg = [...Array(this.imageSize * this.imageSize)].map(() => 0); + this._makeDIMG8(img, cutdepth, th, flag2d, ddimg, irc); + this._makeShadingImage(img, smoothing, false, flag2d, ddimg); + } else { + this._makeSliceImage8(img, cutdepth, irc); + } + break; + case 3: + if (is3d) { + const flag2d = [...Array(this.imageSize * this.imageSize)].map(() => false); + const ddimg = [...Array(this.imageSize * this.imageSize)].map(() => 0); + this._makeDIMG24(img, cutdepth, th, flag2d, ddimg, irc); + this._makeShadingImage(img, smoothing, skincolor, flag2d, ddimg); + } else { + this._makeSliceImage24(img, cutdepth, irc); + } + break; + } + if (mesh) { + this._drawMesh(img, irc); + } + ctx.putImageData(img, 0, 0); + return true; + } + + printHeader(): void { + if (this.header === null) { + console.log('--- invalid g3d data ---'); + return; + } + let message = '--- g3d information ---\n'; + message += 'magic: : ' + this.header.magic.toString(16) + '\n'; + message += 'width [pixel]: ' + this.header.width.toString() + '\n'; + message += 'height [pixel]: ' + this.header.height.toString() + '\n'; + message += 'depth [pixel]: ' + this.header.depth.toString() + '\n'; + message += 'org_width [pixel]: ' + this.header.org_width.toString() + '\n'; + message += 'org_height [pixel]: ' + this.header.org_height.toString() + '\n'; + message += 'org_depth [pixel]: ' + this.header.org_depth.toString() + '\n'; + message += 'datatype [byte] : ' + this.header.datatype.toString() + '\n'; + message += 'unit [m|E] : ' + this.header.unit.toString() + '\n'; + message += 'grid [unit] : ' + this.header.grid.toString() + '\n'; + message += 'surface voxel[unit] : ' + this.header.vs_width.toString() + '\n'; + message += 'voxel width [unit] : ' + this.header.v_width.toString() + '\n'; + message += 'voxel height [unit] : ' + this.header.v_height.toString() + '\n'; + message += 'voxel depth [unit] : ' + this.header.v_depth.toString() + '\n'; + message += 'ax [deg] : ' + this.header.ax.toString() + '\n'; + message += 'ay [deg] : ' + this.header.ay.toString() + '\n'; + message += 'az [deg] : ' + this.header.az.toString() + '\n'; + message += 'ox [pixel]: ' + this.header.ox.toString() + '\n'; + message += 'oy [pixel]: ' + this.header.oy.toString() + '\n'; + message += 'oz [pixel]: ' + this.header.oz.toString() + '\n'; + message += 'ox_real [unit] : ' + (this.header.ox * this.header.vs_width).toString() + '\n'; + message += 'oy_real [unit] : ' + (this.header.oy * this.header.vs_width).toString() + '\n'; + message += 'oz_real [unit] : ' + (this.header.oz * this.header.vs_width).toString() + '\n'; + message += 'surface voxels : ' + this.header.s_num.toString() + '\n'; + message += 'threshold : ' + this.header.s_th.toString() + '\n'; + message += 'date : ' + this.header.date + '\n'; + message += 'coordinate : ' + this.header.coordinate + '\n'; + message += 'subject : ' + this.header.subject + '\n'; + message += 'memo : ' + this.header.memo + '\n'; + message += 'File Type : ' + (this.isLittleEndianFile ? 'Little Endian.' : 'Big Endian'); + console.log(message); + } + + private _makeDIMG8(img: ImageData, cutdepth: number, th: number, flag2d: boolean[], ddimg: number[], irc: G3DImageRenderingContext) { + if (this.header === null) { + return; + } + const pdimg = [...Array(this.imageSize * this.imageSize)].map(() => 0); + const sw = th > this.header.s_th ? 2 : th < this.header.s_th ? 3 : EXACTSWITCH; + switch (sw) { + case 0: { + this._transSurface(cutdepth, pdimg, irc); + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + ddimg[pos] = pdimg[pos]; + let pix = this._getPixel(x, y, cutdepth, irc); + if (pix > th) { + flag2d[pos] = true; + this._drawPixel(img, pos, { r: pix, g: pix, b: pix }); + ddimg[pos] = cutdepth; + continue; + } + pix = this._getPixel(x, y, pdimg[pos], irc); + this._drawPixel(img, pos, { r: pix, g: pix, b: pix }); + } + } + break; + } + case 1: { + this._transSurface(cutdepth, pdimg, irc); + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + let pdPos = pdimg[pos]; + if (pdPos === 0) { + continue; + } + let pix = this._getPixel(x, y, cutdepth, irc); + if (pix > th) { + flag2d[pos] = true; + this._drawPixel(img, pos, { r: pix, g: pix, b: pix }); + ddimg[pos] = cutdepth; + continue; + } + if (pdPos < cutdepth) { + pdPos = cutdepth; + } + ddimg[pos] = 0; + for (let z = pdPos; z < this.imageSize; z++) { + pix = this._getPixel(x, y, z, irc); + if (pix > th) { + ddimg[pos] = z; + this._drawPixel(img, pos, { r: pix, g: pix, b: pix }); + break; + } + } + } + } + break; + } + case 2: { + this._transSurface(cutdepth, pdimg, irc); + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + let pdPos = pdimg[pos]; + if (pdPos === 0) { + continue; + } + let pix = this._getPixel(x, y, cutdepth, irc); + if (pix > th) { + flag2d[pos] = true; + this._drawPixel(img, pos, { r: pix, g: pix, b: pix }); + ddimg[pos] = cutdepth; + continue; + } + if (pix > this.header.s_th || pdPos < cutdepth) { + pdPos = cutdepth; + } + ddimg[pos] = 0; + for (let z = pdPos; z < this.imageSize; z++) { + pix = this._getPixel(x, y, z, irc); + if (pix > th) { + ddimg[pos] = z; + this._drawPixel(img, pos, { r: pix, g: pix, b: pix }); + break; + } + } + } + } + break; + } + case 3: { + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + ddimg[pos] = 0; + for (let z = cutdepth; z < this.imageSize; z++) { + const pix = this._getPixel(x, y, z, irc); + if (pix > th) { + if (z === cutdepth) { + flag2d[pos] = true; + } else { + ddimg[pos] = z; + } + this._drawPixel(img, pos, { r: pix, g: pix, b: pix }); + break; + } + } + } + } + break; + } + } + } + + private _makeDIMG24(img: ImageData, cutdepth: number, th: number, flag2d: boolean[], ddimg: number[], irc: G3DImageRenderingContext) { + if (this.header === null) { + return; + } + const pdimg = [...Array(this.imageSize * this.imageSize)].map(() => 0); + const sw = th > this.header.s_th ? 2 : th < this.header.s_th ? 3 : EXACTSWITCH; + switch (sw) { + case 0: { + this._transSurface(cutdepth, pdimg, irc); + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + ddimg[pos] = pdimg[pos]; + const c = this._getPixelColor(x, y, cutdepth, irc); + if (c.r > th || c.g > th || c.b > th) { + flag2d[pos] = true; + this._drawPixel(img, pos, c); + ddimg[pos] = cutdepth; + continue; + } + this._drawPixel(img, pos, this._getPixelColor(x, y, pdimg[pos], irc)); + } + } + break; + } + case 1: { + this._transSurface(cutdepth, pdimg, irc); + let pos = 0; + for (let j = (pos = 0); j < this.imageSize; j++) { + for (let i = 0; i < this.imageSize; i++, pos++) { + let pdPos = pdimg[pos]; + if (pdPos === 0) { + continue; + } + const c = this._getPixelColor(i, j, cutdepth, irc); + if (c.r > th || c.g > th || c.b > th) { + flag2d[pos] = true; + this._drawPixel(img, pos, c); + ddimg[pos] = cutdepth; + continue; + } + if (pdPos < cutdepth) { + pdPos = cutdepth; + } + ddimg[pos] = 0; + for (let z = pdPos; z < this.imageSize; z++) { + const c = this._getPixelColor(i, j, z, irc); + if (c.r > th || c.g > th || c.b > th) { + ddimg[pos] = z; + this._drawPixel(img, pos, c); + break; + } + } + } + } + break; + } + case 2: { + this._transSurface(cutdepth, pdimg, irc); + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + let pdPos = pdimg[pos]; + if (pdPos === 0) { + continue; + } + const c = this._getPixelColor(x, y, cutdepth, irc); + if (c.r > th || c.g > th || c.b > th) { + flag2d[pos] = true; + this._drawPixel(img, pos, c); + ddimg[pos] = cutdepth; + continue; + } + if (c.r > this.header.s_th || c.g > this.header.s_th || c.b > this.header.s_th || pdPos < cutdepth) { + pdPos = cutdepth; + } + ddimg[pos] = 0; + for (let z = pdPos; z < this.imageSize; z++) { + const c = this._getPixelColor(x, y, z, irc); + if (c.r > th || c.g > th || c.b > th) { + ddimg[pos] = z; + this._drawPixel(img, pos, c); + break; + } + } + } + } + break; + } + case 3: { + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + ddimg[pos] = 0; + for (let z = cutdepth; z < this.imageSize; z++) { + const c = this._getPixelColor(x, y, z, irc); + if (c.r > th || c.g > th || c.b > th) { + if (z === cutdepth) { + flag2d[pos] = true; + } else { + ddimg[pos] = z; + } + this._drawPixel(img, pos, c); + break; + } + } + } + } + break; + } + } + } + + private _makeShadingImage(img: ImageData, smoothing: boolean, skincolor: boolean, flag2d: boolean[], ddimg: number[]) { + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + let timg2d = 0; + if (smoothing) { + if (x < this.imageSize - 2 && y < this.imageSize - 2) { + if (ddimg[pos] !== 0) { + const nx = (ddimg[pos] + ddimg[pos + this.imageSize] - ddimg[pos + 2] - ddimg[pos + 2 + this.imageSize]) / 4.0; + const ny = (ddimg[pos] + ddimg[pos + 1] - ddimg[pos + this.imageSize * 2] - ddimg[pos + 1 + this.imageSize * 2]) / 4.0; + timg2d = Math.round(MaxIntensity / Math.sqrt(nx * nx + ny * ny + 1)); + } + } + } else { + if (x < this.imageSize - 1 && y < this.imageSize - 1) { + if (ddimg[pos] !== 0) { + const nx = ddimg[pos] - ddimg[pos + 1]; + const ny = ddimg[pos] - ddimg[pos + this.imageSize]; + timg2d = Math.round(MaxIntensity / Math.sqrt(nx * nx + ny * ny + 1)); + } + } + } + if (!flag2d[pos]) { + if (skincolor) { + const base = pos * 4; + const c: G3DColor = { r: img.data[base], g: img.data[base + 1], b: img.data[base + 2] }; + const tmp = timg2d / Math.max(c.r, c.g, c.b); + this._drawPixel(img, pos, { r: c.r * tmp, g: c.g * tmp, b: c.b * tmp }); + } else { + const pix = timg2d; + this._drawPixel(img, pos, { r: pix, g: pix, b: pix }); + } + } + } + } + } + + private _makeSliceImage8(img: ImageData, cutdepth: number, irc: G3DImageRenderingContext) { + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + const pix = this._getPixel(x, y, cutdepth, irc); + this._drawPixel(img, pos, { r: pix, g: pix, b: pix }); + } + } + } + + private _makeSliceImage24(img: ImageData, cutdepth: number, irc: G3DImageRenderingContext) { + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + const c = this._getPixelColor(x, y, cutdepth, irc); + this._drawPixel(img, pos, c); + } + } + } + + private _drawMesh(img: ImageData, irc: G3DImageRenderingContext) { + if (this.header === null) { + return; + } + const origx = this._fround(this.header.ox * irc.ra1 + this.header.oy * irc.rb1 + this.header.oz * irc.rc1 + irc.rd1, 5); + const origy = this._fround(this.header.ox * irc.ra2 + this.header.oy * irc.rb2 + this.header.oz * irc.rc2 + irc.rd2, 5); + + const band = this.header.grid / this.header.vs_width; + const c = { r: 0, g: 0, b: LineBrightness }; + const cs = { r: 0, g: 0, b: DottedLineBrightness }; + this._drawLine(img, Math.round(origx), c, DrawingLineType.VLine); + this._drawLine(img, Math.round(origy), c, DrawingLineType.HLine); + for (let pos = Math.round(origx) + band; pos < this.imageSize; pos += band) { + this._drawLine(img, Math.round(pos), cs, DrawingLineType.VDottedLine); + } + for (let pos = Math.round(origx) - band; pos >= 0; pos -= band) { + this._drawLine(img, Math.round(pos), cs, DrawingLineType.VDottedLine); + } + for (let pos = Math.round(origy) + band; pos < this.imageSize; pos += band) { + this._drawLine(img, Math.round(pos), cs, DrawingLineType.HDottedLine); + } + for (let pos = Math.round(origy) - band; pos >= 0; pos -= band) { + this._drawLine(img, Math.round(pos), cs, DrawingLineType.HDottedLine); + } + } + + private _drawLine(img: ImageData, value: number, c: G3DColor, type: DrawingLineType) { + switch (type) { + case DrawingLineType.VLine: { + for (let y = 0; y < this.imageSize; y++) { + this._drawPixel(img, value + y * this.imageSize, c); + } + break; + } + case DrawingLineType.VDottedLine: { + for (let y = 0; y < this.imageSize; y += 2) { + this._drawPixel(img, value + y * this.imageSize, c); + } + break; + } + case DrawingLineType.HLine: { + let pos = value * this.imageSize; + for (let x = 0; x < this.imageSize; x++, pos++) { + this._drawPixel(img, pos, c); + } + break; + } + case DrawingLineType.HDottedLine: { + let pos = value * this.imageSize; + for (let x = 0; x < this.imageSize; x += 2, pos += 2) { + this._drawPixel(img, pos, c); + } + break; + } + } + } + + private _drawPixel(img: ImageData, pos: number, c: G3DColor) { + const base = pos * 4; + img.data[base] = c.r; + img.data[base + 1] = c.g; + img.data[base + 2] = c.b; + img.data[base + 3] = 255; + } + + private _getPixelColor(x: number, y: number, z: number, irc: G3DImageRenderingContext): G3DColor { + const c: G3DColor = { r: 0, g: 0, b: 0 }; + if (this.header === null || this.imgView === null) { + return c; + } + + const tx = x * irc.a1 + y * irc.b1 + z * irc.c1 + irc.d1; + const ty = x * irc.a2 + y * irc.b2 + z * irc.c2 + irc.d2; + const tz = x * irc.a3 + y * irc.b3 + z * irc.c3 + irc.d3; + + if (tx < 0 || ty < 0 || tz < 0) return c; + if (tx > this.header.org_width - 1) return c; + if (ty > this.header.org_height - 1) return c; + if (tz > this.header.org_depth - 1) return c; + + const ix0 = Math.floor(tx); + const iy0 = Math.floor(ty); + const iz0 = Math.floor(tz); + const wix1 = tx - ix0; + const wix0 = 1.0 - wix1; + const wiy1 = ty - iy0; + const wiy0 = 1.0 - wiy1; + const wiz1 = tz - iz0; + const wiz0 = 1.0 - wiz1; + const pixel = this.header.datatype; + const line = this.header.org_width * pixel; + const area = this.header.org_height * line; + + let offset = ix0 * pixel + iy0 * line + iz0 * area; + let tmp1 = offset; + let tmp2 = offset; + const mx0 = [0, 0, 0]; + const mxy0 = [0, 0, 0]; + const mx1 = [0, 0, 0]; + const mxy1 = [0, 0, 0]; + + if (ix0 + 1 === this.header.org_width) { + tmp1 = offset; + mx0[0] = this.imgView[tmp1++]; + mx0[1] = this.imgView[tmp1++]; + mx0[2] = this.imgView[tmp1]; + } else { + tmp1 = offset; + tmp2 = tmp1 + pixel; + mx0[0] = this.imgView[tmp1] * wix0 + this.imgView[tmp2] * wix1; + tmp1++; + tmp2++; + mx0[1] = this.imgView[tmp1] * wix0 + this.imgView[tmp2] * wix1; + tmp1++; + tmp2++; + mx0[2] = this.imgView[tmp1] * wix0 + this.imgView[tmp2] * wix1; + } + if (iy0 + 1 === this.header.org_height) { + mxy0[0] = mx0[0]; + mxy0[1] = mx0[1]; + mxy0[2] = mx0[2]; + } else { + if (ix0 + 1 === this.header.org_width) { + tmp1 = offset + line; + mx1[0] = this.imgView[tmp1++]; + mx1[1] = this.imgView[tmp1++]; + mx1[2] = this.imgView[tmp1]; + } else { + tmp1 = offset + line; + tmp2 = tmp1 + pixel; + mx1[0] = this.imgView[tmp1] * wix0 + this.imgView[tmp2] * wix1; + tmp1++; + tmp2++; + mx1[1] = this.imgView[tmp1] * wix0 + this.imgView[tmp2] * wix1; + tmp1++; + tmp2++; + mx1[2] = this.imgView[tmp1] * wix0 + this.imgView[tmp2] * wix1; + } + mxy0[0] = mx0[0] * wiy0 + mx1[0] * wiy1; + mxy0[1] = mx0[1] * wiy0 + mx1[1] * wiy1; + mxy0[2] = mx0[2] * wiy0 + mx1[2] * wiy1; + } + if (iz0 + 1 === this.header.org_depth) { + c.b = Math.round(mxy0[0]); + c.g = Math.round(mxy0[1]); + c.r = Math.round(mxy0[2]); + return c; + } + offset = offset + area; + if (ix0 + 1 === this.header.org_width) { + tmp1 = offset; + mx0[0] = this.imgView[tmp1++]; + mx0[1] = this.imgView[tmp1++]; + mx0[2] = this.imgView[tmp1]; + } else { + tmp1 = offset; + tmp2 = offset + pixel; + mx0[0] = this.imgView[tmp1] * wix0 + this.imgView[tmp2] * wix1; + tmp1++; + tmp2++; + mx0[1] = this.imgView[tmp1] * wix0 + this.imgView[tmp2] * wix1; + tmp1++; + tmp2++; + mx0[2] = this.imgView[tmp1] * wix0 + this.imgView[tmp2] * wix1; + } + if (iy0 + 1 === this.header.org_height) { + mxy1[0] = mx0[0]; + mxy1[1] = mx0[1]; + mxy1[2] = mx0[2]; + } else { + if (ix0 + 1 === this.header.org_width) { + tmp1 = offset + line; + mx1[0] = this.imgView[tmp1++]; + mx1[1] = this.imgView[tmp1++]; + mx1[2] = this.imgView[tmp1]; + } else { + tmp1 = offset + line; + tmp2 = tmp1 + pixel; + mx1[0] = this.imgView[tmp1] * wix0 + this.imgView[tmp2] * wix1; + tmp1++; + tmp2++; + mx1[1] = this.imgView[tmp1] * wix0 + this.imgView[tmp2] * wix1; + tmp1++; + tmp2++; + mx1[2] = this.imgView[tmp1] * wix0 + this.imgView[tmp2] * wix1; + } + mxy1[0] = mx0[0] * wiy0 + mx1[0] * wiy1; + mxy1[1] = mx0[1] * wiy0 + mx1[1] * wiy1; + mxy1[2] = mx0[2] * wiy0 + mx1[2] * wiy1; + } + c.b = Math.round(mxy0[0] * wiz0 + mxy1[0] * wiz1); + c.g = Math.round(mxy0[1] * wiz0 + mxy1[1] * wiz1); + c.r = Math.round(mxy0[2] * wiz0 + mxy1[2] * wiz1); + return c; + } + + private _getPixel(x: number, y: number, z: number, irc: G3DImageRenderingContext): number { + if (this.header === null || this.imgView === null) { + return 0; + } + + const tx = x * irc.a1 + y * irc.b1 + z * irc.c1 + irc.d1; + const ty = x * irc.a2 + y * irc.b2 + z * irc.c2 + irc.d2; + const tz = x * irc.a3 + y * irc.b3 + z * irc.c3 + irc.d3; + + if (tx < 0 || ty < 0 || tz < 0 || tx > this.header.org_width - 1 || ty > this.header.org_height - 1 || tz > this.header.org_depth - 1) { + return 0; + } + + const ix0 = Math.floor(tx); + const iy0 = Math.floor(ty); + const iz0 = Math.floor(tz); + const wix1 = tx - ix0; + const wix0 = 1.0 - wix1; + const wiy1 = ty - iy0; + const wiy0 = 1.0 - wiy1; + const wiz1 = tz - iz0; + const wiz0 = 1.0 - wiz1; + const pixel = this.header.datatype; + const line = this.header.org_width * pixel; + const area = this.header.org_height * line; + + let mx0: number; + let mx1: number; + let mxy0: number; + let mxy1: number; + + let offset = ix0 * pixel + iy0 * line + iz0 * area; + if (ix0 + 1 === this.header.org_width) { + mx0 = this.imgView[offset]; + } else { + mx0 = this.imgView[offset] * wix0 + this.imgView[offset + pixel] * wix1; + } + if (iy0 + 1 === this.header.org_height) { + mxy0 = mx0; + } else { + if (ix0 + 1 === this.header.org_width) { + mx1 = this.imgView[offset + line]; + } else { + mx1 = this.imgView[offset + line] * wix0 + this.imgView[offset + line + pixel] * wix1; + } + mxy0 = mx0 * wiy0 + mx1 * wiy1; + } + + if (iz0 + 1 === this.header.org_depth) { + return Math.round(mxy0); + } + + offset = offset + area; + if (ix0 + 1 === this.header.org_width) { + mx0 = this.imgView[offset]; + } else { + mx0 = this.imgView[offset] * wix0 + this.imgView[offset + pixel] * wix1; + } + if (iy0 + 1 === this.header.org_height) { + mxy1 = mx0; + } else { + if (ix0 + 1 === this.header.org_width) { + mx1 = this.imgView[offset + line]; + } else { + mx1 = this.imgView[offset + line] * wix0 + this.imgView[offset + line + pixel] * wix1; + } + mxy1 = mx0 * wiy0 + mx1 * wiy1; + } + + return Math.round(mxy0 * wiz0 + mxy1 * wiz1); + } + + private _transSurface(cutdepth: number, pdimg: number[], irc: G3DImageRenderingContext) { + if (this.header === null || this.surfaceView === null) { + return; + } + + const ix = [...Array(7)].map(() => 0); + const iy = [...Array(7)].map(() => 0); + const iz = [...Array(7)].map(() => 0); + + for (let i = 0; i < this.header.s_num * 3; i++) { + const x = this.surfaceView[i++]; + const y = this.surfaceView[i++]; + const z = this.surfaceView[i]; + + ix[0] = x * irc.ra1 + y * irc.rb1 + z * irc.rc1 + irc.rd1; + iy[0] = x * irc.ra2 + y * irc.rb2 + z * irc.rc2 + irc.rd2; + iz[0] = x * irc.ra3 + y * irc.rb3 + z * irc.rc3 + irc.rd3; + ix[1] = ix[0] + irc.ra1_2; + iy[1] = iy[0] + irc.ra2_2; + iz[1] = iz[0] + irc.ra3_2; + ix[2] = ix[0] + irc.rb1_2; + iy[2] = iy[0] + irc.rb2_2; + iz[2] = iz[0] + irc.rb3_2; + ix[3] = ix[0] + irc.rc1_2; + iy[3] = iy[0] + irc.rc2_2; + iz[3] = iz[0] + irc.rc3_2; + ix[4] = ix[1] + irc.rb1_2; + iy[4] = iy[1] + irc.rb2_2; + iz[4] = iz[1] + irc.rb3_2; + ix[5] = ix[1] + irc.rc1_2; + iy[5] = iy[1] + irc.rc2_2; + iz[5] = iz[1] + irc.rc3_2; + ix[6] = ix[2] + irc.rc1_2; + iy[6] = iy[2] + irc.rc2_2; + iz[6] = iz[2] + irc.rc3_2; + + for (let j = 0; j < 7; j++) { + const xi = Math.round(ix[j]); + const yi = Math.round(iy[j]); + if (xi < 0 || xi >= this.imageSize || yi < 0 || yi >= this.imageSize || iz[j] < cutdepth || iz[j] >= this.imageSize) { + continue; + } + const pos = xi + yi * this.imageSize; + if (pdimg[pos] === 0 || pdimg[pos] > iz[j]) { + pdimg[pos] = iz[j]; + } + } + } + } + + private _setMatrix(x: number, y: number, z: number, irc: G3DImageRenderingContext) { + if (this.header === null) { + return; + } + const xtr = [...Array(9)].map(() => 0); + const ytr = [...Array(9)].map(() => 0); + const ztr = [...Array(9)].map(() => 0); + const tmp = [...Array(9)].map(() => 0); + const tr = [...Array(9)].map(() => 0); + this._setXtr(xtr, (x * Math.PI) / 180.0); + this._setYtr(ytr, (y * Math.PI) / 180.0); + this._setZtr(ztr, (z * Math.PI) / 180.0); + this._multi(ytr, xtr, tmp); + this._multi(ztr, tmp, tr); + irc.a1 = tr[0]; + irc.b1 = tr[1]; + irc.c1 = tr[2]; + irc.a2 = tr[3]; + irc.b2 = tr[4]; + irc.c2 = tr[5]; + irc.a3 = tr[6]; + irc.b3 = tr[7]; + irc.c3 = tr[8]; + irc.d1 = -irc.a1 * this.centerX - irc.b1 * this.centerY - irc.c1 * this.centerZ + this.ox; + irc.d2 = -irc.a2 * this.centerX - irc.b2 * this.centerY - irc.c2 * this.centerZ + this.oy; + irc.d3 = -irc.a3 * this.centerX - irc.b3 * this.centerY - irc.c3 * this.centerZ + this.oz; + + const sx = this.header.org_width / this.header.width; + const sy = this.header.org_height / this.header.height; + const sz = this.header.org_depth / this.header.depth; + irc.a1 = sx * irc.a1; + irc.b1 = sx * irc.b1; + irc.c1 = sx * irc.c1; + irc.d1 = sx * irc.d1; + irc.a2 = sy * irc.a2; + irc.b2 = sy * irc.b2; + irc.c2 = sy * irc.c2; + irc.d2 = sy * irc.d2; + irc.a3 = sz * irc.a3; + irc.b3 = sz * irc.b3; + irc.c3 = sz * irc.c3; + irc.d3 = sz * irc.d3; + + this._setXtr(xtr, (-x * Math.PI) / 180.0); + this._setYtr(ytr, (-y * Math.PI) / 180.0); + this._setZtr(ztr, (-z * Math.PI) / 180.0); + this._multi(ytr, ztr, tmp); + this._multi(xtr, tmp, tr); + irc.ra1 = tr[0]; + irc.rb1 = tr[1]; + irc.rc1 = tr[2]; + irc.ra2 = tr[3]; + irc.rb2 = tr[4]; + irc.rc2 = tr[5]; + irc.ra3 = tr[6]; + irc.rb3 = tr[7]; + irc.rc3 = tr[8]; + irc.rd1 = -irc.ra1 * this.ox - irc.rb1 * this.oy - irc.rc1 * this.oz + this.centerX; + irc.rd2 = -irc.ra2 * this.ox - irc.rb2 * this.oy - irc.rc2 * this.oz + this.centerY; + irc.rd3 = -irc.ra3 * this.ox - irc.rb3 * this.oy - irc.rc3 * this.oz + this.centerZ; + irc.ra1_2 = irc.ra1 / 2; + irc.rb1_2 = irc.rb1 / 2; + irc.rc1_2 = irc.rc1 / 2; + irc.ra2_2 = irc.ra2 / 2; + irc.rb2_2 = irc.rb2 / 2; + irc.rc2_2 = irc.rc2 / 2; + irc.ra3_2 = irc.ra3 / 2; + irc.rb3_2 = irc.rb3 / 2; + irc.rc3_2 = irc.rc3 / 2; + } + + private _setXtr(xtr: number[], ang: number) { + xtr[0] = 1; + xtr[1] = 0; + xtr[2] = 0; + xtr[3] = 0; + xtr[4] = Math.cos(ang); + xtr[5] = -Math.sin(ang); + xtr[6] = 0; + xtr[7] = Math.sin(ang); + xtr[8] = Math.cos(ang); + } + + private _setYtr(ytr: number[], ang: number) { + ytr[0] = Math.cos(ang); + ytr[1] = 0; + ytr[2] = Math.sin(ang); + ytr[3] = 0; + ytr[4] = 1; + ytr[5] = 0; + ytr[6] = -Math.sin(ang); + ytr[7] = 0; + ytr[8] = Math.cos(ang); + } + + private _setZtr(ztr: number[], ang: number) { + ztr[0] = Math.cos(ang); + ztr[1] = -Math.sin(ang); + ztr[2] = 0; + ztr[3] = Math.sin(ang); + ztr[4] = Math.cos(ang); + ztr[5] = 0; + ztr[6] = 0; + ztr[7] = 0; + ztr[8] = 1; + } + + private _multi(l: number[], r: number[], a: number[]) { + a[0] = l[0] * r[0] + l[1] * r[3] + l[2] * r[6]; + a[3] = l[3] * r[0] + l[4] * r[3] + l[5] * r[6]; + a[6] = l[6] * r[0] + l[7] * r[3] + l[8] * r[6]; + a[1] = l[0] * r[1] + l[1] * r[4] + l[2] * r[7]; + a[4] = l[3] * r[1] + l[4] * r[4] + l[5] * r[7]; + a[7] = l[6] * r[1] + l[7] * r[4] + l[8] * r[7]; + a[2] = l[0] * r[2] + l[1] * r[5] + l[2] * r[8]; + a[5] = l[3] * r[2] + l[4] * r[5] + l[5] * r[8]; + a[8] = l[6] * r[2] + l[7] * r[5] + l[8] * r[8]; + } + + private _fround(x: number, n: number) { + return Math.round(x * Math.pow(10, n)) / Math.pow(10, n); + } + + private _initialize(data: ArrayBuffer): boolean { + // check browser endianness + const isBigEndian = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x11; + // check magic header and file endianness + const view = new DataView(data); + const magic = view.getInt32(0, true); + let needSwap = false; + switch (magic) { + case 0x474f3344: + case 0x47483344: + case 0x434f3344: + break; + case 0x44334f47: + case 0x44334847: + case 0x44334f43: + needSwap = true; + break; + default: + console.log('invalid magic header found, data is not g3d format.'); + return false; + } + this.isLittleEndianFile = isBigEndian ? needSwap : !needSwap; + // read header + const decoder = new TextDecoder('utf-8'); + let headerOffset = 0; + this.header = { + magic: view.getInt32(headerOffset, this.isLittleEndianFile), + width: view.getInt32((headerOffset += 4), this.isLittleEndianFile), + height: view.getInt32((headerOffset += 4), this.isLittleEndianFile), + depth: view.getInt32((headerOffset += 4), this.isLittleEndianFile), + org_width: view.getInt32((headerOffset += 4), this.isLittleEndianFile), + org_height: view.getInt32((headerOffset += 4), this.isLittleEndianFile), + org_depth: view.getInt32((headerOffset += 4), this.isLittleEndianFile), + datatype: view.getInt32((headerOffset += 4), this.isLittleEndianFile), + unit: view.getInt32((headerOffset += 4), this.isLittleEndianFile), + grid: view.getFloat64((headerOffset += 4), this.isLittleEndianFile), + vs_width: view.getFloat64((headerOffset += 8), this.isLittleEndianFile), + v_width: view.getFloat64((headerOffset += 8), this.isLittleEndianFile), + v_height: view.getFloat64((headerOffset += 8), this.isLittleEndianFile), + v_depth: view.getFloat64((headerOffset += 8), this.isLittleEndianFile), + ax: view.getFloat64((headerOffset += 8), this.isLittleEndianFile), + ay: view.getFloat64((headerOffset += 8), this.isLittleEndianFile), + az: view.getFloat64((headerOffset += 8), this.isLittleEndianFile), + ox: view.getFloat64((headerOffset += 8), this.isLittleEndianFile), + oy: view.getFloat64((headerOffset += 8), this.isLittleEndianFile), + oz: view.getFloat64((headerOffset += 8), this.isLittleEndianFile), + s_num: view.getInt32((headerOffset += 8), this.isLittleEndianFile), + s_th: view.getInt32((headerOffset += 4), this.isLittleEndianFile), + option: decoder.decode(new Uint8Array(data, (headerOffset += 4), 256)).replace(/\0+$/, ''), + date: decoder.decode(new Uint8Array(data, (headerOffset += 256), 32)).replace(/\0+$/, ''), + coordinate: decoder.decode(new Uint8Array(data, (headerOffset += 32), 32)).replace(/\0+$/, ''), + subject: decoder.decode(new Uint8Array(data, (headerOffset += 32), 256)).replace(/\0+$/, ''), + memo: decoder.decode(new Uint8Array(data, (headerOffset += 256), 256)).replace(/\0+$/, ''), + }; + // set surface and image views + const surfaceOffset = 964; + const surfaceLength = this.header.s_num * 3; + this.surfaceView = new Int16Array(data, surfaceOffset, surfaceLength); + if (needSwap) { + // fix endianness + let offset = surfaceOffset; + for (let i = 0; i < surfaceLength; i++) { + const ui8 = new Uint8Array(data, offset, 2); + ui8.reverse(); + offset += 2; + } + } + const imgOffset = surfaceOffset + surfaceLength * 2; + const imgLength = this.header.org_width * this.header.org_height * this.header.org_depth * this.header.datatype; + this.imgView = new Uint8Array(data, imgOffset, imgLength); + // set offset for image rendering + this.imageSize = Math.ceil(Math.sqrt(this.header.width * this.header.width + this.header.height * this.header.height + this.header.depth * this.header.depth)) + 1; + this.centerX = (this.imageSize - 1) / 2.0; + this.centerY = (this.imageSize - 1) / 2.0; + this.centerZ = (this.imageSize - 1) / 2.0; + this.ox = (this.header.width - 1) / 2.0; + this.oy = (this.header.height - 1) / 2.0; + this.oz = (this.header.depth - 1) / 2.0; + // set data + this.data = data; + return true; + } +} + +export default G3D; diff --git a/src/m3d.ts b/src/m3d.ts new file mode 100644 index 0000000..550aad5 --- /dev/null +++ b/src/m3d.ts @@ -0,0 +1,616 @@ +export interface M3DHeader { + magic: number; + x: number; + y: number; + z: number; + filename: string; + subject: string; + direction: string; + date: number; + fov: number; + weight: number; + ax: number; + ay: number; + az: number; + ox: number; + oy: number; + oz: number; + dlen: number; + dth: number; + memo: string; +} + +interface M3DImageRenderingContext { + a1: number; + a2: number; + a3: number; + b1: number; + b2: number; + b3: number; + c1: number; + c2: number; + c3: number; + d1: number; + d2: number; + d3: number; + ra1: number; + ra1_2: number; + ra2: number; + ra2_2: number; + ra3: number; + ra3_2: number; + rb1: number; + rb1_2: number; + rb2: number; + rb2_2: number; + rb3: number; + rb3_2: number; + rc1: number; + rc1_2: number; + rc2: number; + rc2_2: number; + rc3: number; + rc3_2: number; + rd1: number; + rd2: number; + rd3: number; +} + +/* MeshLength unit is same as fov unit */ +const MeshLength = 10; +enum DrawingLineType { + VLine = 0, + VDottedLine = 1, + HLine = 2, + HDottedLine = 3, +} +const LineBrightness = 200; +const DottedLineBrightness = 128; +const EXACTSWITCH: 0 | 1 = 1; +const MaxIntensity = 200; + +class M3D { + private data: ArrayBuffer; + private header: M3DHeader | null = null; + private xposView: Int32Array | null = null; + private zposView: Int32Array | null = null; + private yposView: Int32Array | null = null; + private img3dView: Uint8ClampedArray | null = null; + private imageSize = 0; // imagesize size : max (size_x, size_y, size_z) + private centerX = 0; // camera coordinates origin : x + private centerY = 0; // camera coordinates origin : y + private centerZ = 0; // camera coordinates origin : z + private ox = 0; // object coordinates origin : x + private oy = 0; // object coordinates origin : y + private oz = 0; // object coordinates origin : z + + constructor(data: ArrayBuffer) { + this.data = data; + this._initialize(); + } + + isBigEndian(): boolean { + return new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x11; + } + + getHeader(): M3DHeader | null { + return this.header; + } + + drawImage(canvas: HTMLCanvasElement, ax: number, ay: number, az: number, cutdepth: number, th: number, is3d: boolean, mesh: boolean): boolean { + const irc: M3DImageRenderingContext = { + a1: 0, + a2: 0, + a3: 0, + b1: 0, + b2: 0, + b3: 0, + c1: 0, + c2: 0, + c3: 0, + d1: 0, + d2: 0, + d3: 0, + ra1: 0, + ra1_2: 0, + ra2: 0, + ra2_2: 0, + ra3: 0, + ra3_2: 0, + rb1: 0, + rb1_2: 0, + rb2: 0, + rb2_2: 0, + rb3: 0, + rb3_2: 0, + rc1: 0, + rc1_2: 0, + rc2: 0, + rc2_2: 0, + rc3: 0, + rc3_2: 0, + rd1: 0, + rd2: 0, + rd3: 0, + }; + // console.log(ax, ay, az, cutdepth, th, dim, mesh) + if (this.header === null) { + return false; + } + + canvas.width = this.imageSize; + canvas.height = this.imageSize; + const ctx = canvas.getContext('2d'); + if (ctx === null) { + return false; + } + ctx.fillStyle = 'rgb(0, 0, 0)'; + ctx.fillRect(0, 0, this.imageSize, this.imageSize); + const img = ctx.getImageData(0, 0, this.imageSize, this.imageSize); + + this._setMatrix(ax, ay, az, irc); + if (is3d) { + const ddimg = [...Array(this.imageSize * this.imageSize)].map(() => 0); + this._makeDIMG(img, cutdepth, th, ddimg, irc); + this._makeShadingImage(img, ddimg); + } else { + this._makeSliceImage(img, cutdepth, irc); + } + if (mesh) { + this._drawMesh(img, irc); + } + ctx.putImageData(img, 0, 0); + return true; + } + + private _makeDIMG(img: ImageData, cutdepth: number, th: number, ddimg: number[], irc: M3DImageRenderingContext) { + if (this.header === null) { + return; + } + const pdimg = [...Array(this.imageSize * this.imageSize)].map(() => 0); + const sw = th > this.header.dth ? 1 : th < this.header.dth ? 2 : EXACTSWITCH; + switch (sw) { + case 0: { + this._transSurface(cutdepth, pdimg, irc); + let pos = 0; + for (let j = 0; j < this.imageSize; j++) { + for (let i = 0; i < this.imageSize; i++, pos++) { + ddimg[pos] = pdimg[pos]; + const pix = this._getPixel(i, j, cutdepth, irc); + if (pix > th) { + this._drawPixel(img, pos, pix, pix, pix); + ddimg[pos] = cutdepth; + continue; + } + } + } + break; + } + case 1: { + this._transSurface(cutdepth, pdimg, irc); + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + let pdPos = (ddimg[pos] = pdimg[pos]); + if (pdPos === 0) { + continue; + } + const pix = this._getPixel(x, y, cutdepth, irc); + if (pix > th) { + this._drawPixel(img, pos, pix, pix, pix); + ddimg[pos] = cutdepth; + continue; + } + if (pdPos < cutdepth) { + pdPos = cutdepth; + } + ddimg[pos] = 0; + for (let z = pdPos; z < this.imageSize; z++) { + const pix = this._getPixel(x, y, z, irc); + if (pix > th) { + ddimg[pos] = z; + break; + } + } + } + } + break; + } + case 2: { + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + ddimg[pos] = 0; + for (let z = cutdepth; z < this.imageSize; z++) { + const pix = this._getPixel(x, y, z, irc); + if (pix > th) { + if (z === cutdepth) { + this._drawPixel(img, pos, pix, pix, pix); + } else { + ddimg[pos] = z; + } + break; + } + } + } + } + break; + } + } + } + + private _makeShadingImage(img: ImageData, ddimg: number[]) { + let pos = 0; + for (let x = 0; x < this.imageSize; x++) { + for (let y = 0; y < this.imageSize; y++, pos++) { + const base = pos * 4; + if (img.data[base] === 0) { + let timg2d = 0; + if (x < this.imageSize - 2 && y < this.imageSize - 2) { + if (ddimg[pos] !== 0) { + const nx = (ddimg[pos] + ddimg[pos + this.imageSize] - ddimg[pos + 2] - ddimg[pos + 2 + this.imageSize]) / 4.0; + const ny = (ddimg[pos] + ddimg[pos + 1] - ddimg[pos + this.imageSize * 2] - ddimg[pos + 1 + this.imageSize * 2]) / 4.0; + const n = Math.sqrt(nx * nx + ny * ny + 1); + timg2d = Math.round(MaxIntensity / n); + } + } + this._drawPixel(img, pos, timg2d, timg2d, timg2d); + } + } + } + } + + private _makeSliceImage(img: ImageData, cutdepth: number, irc: M3DImageRenderingContext) { + let pos = 0; + for (let y = 0; y < this.imageSize; y++) { + for (let x = 0; x < this.imageSize; x++, pos++) { + const pix = this._getPixel(x, y, cutdepth, irc); + this._drawPixel(img, pos, pix, pix, pix); + } + } + } + + private _drawMesh(img: ImageData, irc: M3DImageRenderingContext) { + let origx: number; + let origy: number; + if (this.header === null) { + return; + } + if (this.header.ox !== 0 && this.header.oy !== 0) { + origx = this.header.ox * irc.ra1 + this.header.oy * irc.rb1 + this.header.oz * irc.rc1 + irc.rd1; + origy = this.header.ox * irc.ra2 + this.header.oy * irc.rb2 + this.header.oz * irc.rc2 + irc.rd2; + } else { + origx = this.centerX; + origy = this.centerY; + } + origx = this._fround(origx, 5); + origy = this._fround(origy, 5); + + const band = (this.header.x * MeshLength) / this.header.fov; + const r = 0; + const g = 0; + const b = LineBrightness; + const sr = 0; + const sg = 0; + const sb = DottedLineBrightness; + this._drawLine(img, Math.round(origx), r, g, b, DrawingLineType.VLine); + this._drawLine(img, Math.round(origy), r, g, b, DrawingLineType.HLine); + for (let pos = Math.round(origx) + band; pos < this.imageSize; pos += band) { + this._drawLine(img, Math.round(pos), sr, sg, sb, DrawingLineType.VDottedLine); + } + for (let pos = Math.round(origx) - band; pos >= 0; pos -= band) { + this._drawLine(img, Math.round(pos), sr, sg, sb, DrawingLineType.VDottedLine); + } + for (let pos = Math.round(origy) + band; pos < this.imageSize; pos += band) { + this._drawLine(img, Math.round(pos), sr, sg, sb, DrawingLineType.HDottedLine); + } + for (let pos = Math.round(origy) - band; pos >= 0; pos -= band) { + this._drawLine(img, Math.round(pos), sr, sg, sb, DrawingLineType.HDottedLine); + } + } + + private _drawLine(img: ImageData, value: number, r: number, g: number, b: number, type: DrawingLineType) { + switch (type) { + case DrawingLineType.VLine: { + let pos = value; + for (let y = 0; y < this.imageSize; y++, pos += this.imageSize) { + this._drawPixel(img, pos, r, g, b); + } + break; + } + case DrawingLineType.VDottedLine: { + let pos = value; + for (let y = 0; y < this.imageSize; y += 2, pos += this.imageSize * 2) { + this._drawPixel(img, pos, r, g, b); + } + break; + } + case DrawingLineType.HLine: { + let pos = value * this.imageSize; + for (let x = 0; x < this.imageSize; x++, pos++) { + this._drawPixel(img, pos, r, g, b); + } + break; + } + case DrawingLineType.HDottedLine: { + let pos = value * this.imageSize; + for (let x = 0; x < this.imageSize; x += 2, pos += 2) { + this._drawPixel(img, pos, r, g, b); + } + break; + } + default: + break; + } + } + + private _drawPixel(img: ImageData, pos: number, r: number, g: number, b: number) { + let base = pos * 4; + img.data[base++] = r; + img.data[base++] = g; + img.data[base++] = b; + img.data[base] = 255; + } + + private _getPixel(x: number, y: number, z: number, irc: M3DImageRenderingContext): number { + const len = [...Array(8)].map(() => 0); + const ratio = [...Array(8)].map(() => 0); + + const tx = x * irc.a1 + y * irc.b1 + z * irc.c1 + irc.d1; + const ty = x * irc.a2 + y * irc.b2 + z * irc.c2 + irc.d2; + const tz = x * irc.a3 + y * irc.b3 + z * irc.c3 + irc.d3; + + let ix = Math.floor(tx); + let iy = Math.floor(ty); + let iz = Math.floor(tz); + + if (this.header === null || this.img3dView === null) { + return 0; + } + if (ix < 0 || ix + 1 >= this.header.x || iy < 0 || iy + 1 >= this.header.y || iz < 0 || iz + 1 >= this.header.z) { + return 0; + } + + const ax1 = Math.abs(tx - ix); + const ax2 = Math.abs(1 - ax1); + const ay1 = Math.abs(ty - iy); + const ay2 = Math.abs(1 - ay1); + const az1 = Math.abs(tz - iz); + const az2 = Math.abs(1 - az1); + + let sumlen1 = 0; + for (let i = 0; i < 8; i++) { + len[i] = i & 1 ? ax2 : ax1; + len[i] += i & 2 ? ay2 : ay1; + len[i] += i & 4 ? az2 : az1; + if (len[i] < 0.001) { + ix += i & 1 ? 1 : 0; + iy += i & 2 ? 1 : 0; + iz += i & 4 ? 1 : 0; + return this.img3dView[ix + iy * this.header.x + iz * this.header.x * this.header.y]; + } + sumlen1 += ratio[i] = 1 / len[i]; + } + let pos = ix + iy * this.header.x + iz * this.header.x * this.header.y; + let sumlen2 = this.img3dView[pos] * ratio[0]; + sumlen2 += this.img3dView[pos + 1] * ratio[1]; + sumlen2 += this.img3dView[pos + this.header.x] * ratio[2]; + sumlen2 += this.img3dView[pos + 1 + this.header.x] * ratio[3]; + pos += this.header.x * this.header.y; + sumlen2 += this.img3dView[pos] * ratio[4]; + sumlen2 += this.img3dView[pos + 1] * ratio[5]; + sumlen2 += this.img3dView[pos + this.header.x] * ratio[6]; + sumlen2 += this.img3dView[pos + 1 + this.header.x] * ratio[7]; + + return Math.round(sumlen2 / sumlen1); + } + + private _transSurface(cutdepth: number, pdimg: number[], irc: M3DImageRenderingContext) { + if (this.header === null || this.xposView === null || this.yposView === null || this.zposView === null) { + return; + } + const ix = [...Array(8)].map(() => 0); + const iy = [...Array(8)].map(() => 0); + const iz = [...Array(8)].map(() => 0); + for (let i = 0; i < this.header.dlen; i++) { + const x = this.xposView[i]; + const y = this.yposView[i]; + const z = this.zposView[i]; + ix[0] = x * irc.ra1 + y * irc.rb1 + z * irc.rc1 + irc.rd1; + iy[0] = x * irc.ra2 + y * irc.rb2 + z * irc.rc2 + irc.rd2; + iz[0] = x * irc.ra3 + y * irc.rb3 + z * irc.rc3 + irc.rd3; + ix[1] = ix[0] + irc.ra1_2; + iy[1] = iy[0] + irc.ra2_2; + iz[1] = iz[0] + irc.ra3_2; + ix[2] = ix[0] + irc.rb1_2; + iy[2] = iy[0] + irc.rb2_2; + iz[2] = iz[0] + irc.rb3_2; + ix[3] = ix[0] + irc.rc1_2; + iy[3] = iy[0] + irc.rc2_2; + iz[3] = iz[0] + irc.rc3_2; + ix[4] = ix[1] + irc.rb1_2; + iy[4] = iy[1] + irc.rb2_2; + iz[4] = iz[1] + irc.rb3_2; + ix[5] = ix[1] + irc.rc1_2; + iy[5] = iy[1] + irc.rc2_2; + iz[5] = iz[1] + irc.rc3_2; + ix[6] = ix[2] + irc.rc1_2; + iy[6] = iy[2] + irc.rc2_2; + iz[6] = iz[2] + irc.rc3_2; + ix[7] = ix[4] + irc.rc1_2; + iy[7] = iy[4] + irc.rc2_2; + iz[7] = iz[4] + irc.rc3_2; + for (let j = 0; j < 8; j++) { + const xi = Math.round(ix[j]); + const yi = Math.round(iy[j]); + if (xi < 0 || xi >= this.imageSize || yi < 0 || yi >= this.imageSize || iz[j] < cutdepth || iz[j] >= this.imageSize) { + continue; + } + const pos = xi + yi * this.imageSize; + if (pdimg[pos] === 0 || pdimg[pos] > iz[j]) { + pdimg[pos] = iz[j]; + } + } + } + } + + private _setMatrix(x: number, y: number, z: number, irc: M3DImageRenderingContext) { + const xtr = [...Array(9)].map(() => 0); + const ytr = [...Array(9)].map(() => 0); + const ztr = [...Array(9)].map(() => 0); + const tmp = [...Array(9)].map(() => 0); + const tr = [...Array(9)].map(() => 0); + this._setXtr(xtr, (x * Math.PI) / 180.0); + this._setYtr(ytr, (y * Math.PI) / 180.0); + this._setZtr(ztr, (z * Math.PI) / 180.0); + this._multi(ytr, xtr, tmp); + this._multi(ztr, tmp, tr); + irc.a1 = tr[0]; + irc.b1 = tr[1]; + irc.c1 = tr[2]; + irc.a2 = tr[3]; + irc.b2 = tr[4]; + irc.c2 = tr[5]; + irc.a3 = tr[6]; + irc.b3 = tr[7]; + irc.c3 = tr[8]; + irc.d1 = -irc.a1 * this.centerX - irc.b1 * this.centerY - irc.c1 * this.centerZ + this.ox; + irc.d2 = -irc.a2 * this.centerX - irc.b2 * this.centerY - irc.c2 * this.centerZ + this.oy; + irc.d3 = -irc.a3 * this.centerX - irc.b3 * this.centerY - irc.c3 * this.centerZ + this.oz; + + this._setXtr(xtr, (-x * Math.PI) / 180.0); + this._setYtr(ytr, (-y * Math.PI) / 180.0); + this._setZtr(ztr, (-z * Math.PI) / 180.0); + this._multi(ytr, ztr, tmp); + this._multi(xtr, tmp, tr); + irc.ra1 = tr[0]; + irc.rb1 = tr[1]; + irc.rc1 = tr[2]; + irc.ra2 = tr[3]; + irc.rb2 = tr[4]; + irc.rc2 = tr[5]; + irc.ra3 = tr[6]; + irc.rb3 = tr[7]; + irc.rc3 = tr[8]; + irc.rd1 = -irc.ra1 * this.ox - irc.rb1 * this.oy - irc.rc1 * this.oz + this.centerX; + irc.rd2 = -irc.ra2 * this.ox - irc.rb2 * this.oy - irc.rc2 * this.oz + this.centerY; + irc.rd3 = -irc.ra3 * this.ox - irc.rb3 * this.oy - irc.rc3 * this.oz + this.centerZ; + irc.ra1_2 = irc.ra1 / 2; + irc.rb1_2 = irc.rb1 / 2; + irc.rc1_2 = irc.rc1 / 2; + irc.ra2_2 = irc.ra2 / 2; + irc.rb2_2 = irc.rb2 / 2; + irc.rc2_2 = irc.rc2 / 2; + irc.ra3_2 = irc.ra3 / 2; + irc.rb3_2 = irc.rb3 / 2; + irc.rc3_2 = irc.rc3 / 2; + } + + private _setXtr(xtr: number[], ang: number) { + xtr[0] = 1; + xtr[1] = 0; + xtr[2] = 0; + xtr[3] = 0; + xtr[4] = Math.cos(ang); + xtr[5] = -Math.sin(ang); + xtr[6] = 0; + xtr[7] = Math.sin(ang); + xtr[8] = Math.cos(ang); + } + + private _setYtr(ytr: number[], ang: number) { + ytr[0] = Math.cos(ang); + ytr[1] = 0; + ytr[2] = Math.sin(ang); + ytr[3] = 0; + ytr[4] = 1; + ytr[5] = 0; + ytr[6] = -Math.sin(ang); + ytr[7] = 0; + ytr[8] = Math.cos(ang); + } + + private _setZtr(ztr: number[], ang: number) { + ztr[0] = Math.cos(ang); + ztr[1] = -Math.sin(ang); + ztr[2] = 0; + ztr[3] = Math.sin(ang); + ztr[4] = Math.cos(ang); + ztr[5] = 0; + ztr[6] = 0; + ztr[7] = 0; + ztr[8] = 1; + } + + private _multi(l: number[], r: number[], a: number[]) { + a[0] = l[0] * r[0] + l[1] * r[3] + l[2] * r[6]; + a[3] = l[3] * r[0] + l[4] * r[3] + l[5] * r[6]; + a[6] = l[6] * r[0] + l[7] * r[3] + l[8] * r[6]; + a[1] = l[0] * r[1] + l[1] * r[4] + l[2] * r[7]; + a[4] = l[3] * r[1] + l[4] * r[4] + l[5] * r[7]; + a[7] = l[6] * r[1] + l[7] * r[4] + l[8] * r[7]; + a[2] = l[0] * r[2] + l[1] * r[5] + l[2] * r[8]; + a[5] = l[3] * r[2] + l[4] * r[5] + l[5] * r[8]; + a[8] = l[6] * r[2] + l[7] * r[5] + l[8] * r[8]; + } + + private _fround(x: number, n: number) { + return Math.round(x * Math.pow(10, n)) / Math.pow(10, n); + } + + private _initialize(): void { + const view = new DataView(this.data); + const magic = view.getInt32(0, true); + const isLittleEndianFile = magic === 0x4d523344; + if (!isLittleEndianFile && magic !== 0x4433524d) { + console.log('invalid data format, this data is not m3d format'); + return; + } + let offset = 0; + const decoder = new TextDecoder('utf-8'); + this.header = { + magic: view.getInt32(offset, isLittleEndianFile), + x: view.getInt32((offset += 4), isLittleEndianFile), + y: view.getInt32((offset += 4), isLittleEndianFile), + z: view.getInt32((offset += 4), isLittleEndianFile), + filename: decoder.decode(new Uint8Array(this.data, (offset += 4), 256)).replace(/\0+$/, ''), + subject: decoder.decode(new Uint8Array(this.data, (offset += 256), 256)).replace(/\0+$/, ''), + direction: decoder.decode(new Uint8Array(this.data, (offset += 256), 4)).replace(/\0+$/, ''), + date: view.getUint32((offset += 4), isLittleEndianFile), + fov: view.getFloat64((offset += 4), isLittleEndianFile), + weight: view.getFloat64((offset += 8), isLittleEndianFile), + ax: view.getFloat64((offset += 8), isLittleEndianFile), + ay: view.getFloat64((offset += 8), isLittleEndianFile), + az: view.getFloat64((offset += 8), isLittleEndianFile), + ox: view.getFloat64((offset += 8), isLittleEndianFile), + oy: view.getFloat64((offset += 8), isLittleEndianFile), + oz: view.getFloat64((offset += 8), isLittleEndianFile), + dlen: view.getInt32((offset += 8), isLittleEndianFile), + dth: view.getInt32((offset += 4), isLittleEndianFile), + memo: decoder.decode(new Uint8Array(this.data, (offset += 4), 256)).replace(/\0+$/, ''), + }; + // swap byte order if endian is not matched + if ((this.isBigEndian() && isLittleEndianFile) || (!this.isBigEndian() && !isLittleEndianFile)) { + const start = 864; + const end = start + this.header.dlen * 4 * 3; + for (let i = start; i < end; i += 4) { + const data = new Uint8Array(this.data, i, 4); + data.reverse(); + } + } + this.xposView = new Int32Array(this.data, 864, this.header.dlen); + this.yposView = new Int32Array(this.data, 864 + this.header.dlen * 4, this.header.dlen); + this.zposView = new Int32Array(this.data, 864 + this.header.dlen * 8, this.header.dlen); + this.img3dView = new Uint8ClampedArray(this.data, 864 + this.header.dlen * 12, this.header.x * this.header.y * this.header.z); + // set image generation offset + this.imageSize = Math.ceil(Math.max(this.header.x, this.header.y, this.header.z) * Math.sqrt(3.0)) + 1; + this.centerX = (this.imageSize - 1) / 2.0; + this.centerY = (this.imageSize - 1) / 2.0; + this.centerZ = (this.imageSize - 1) / 2.0; + this.ox = (this.header.x - 1) / 2.0; + this.oy = (this.header.y - 1) / 2.0; + this.oz = (this.header.z - 1) / 2.0; + } +} + +export default M3D; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..a09c32f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "umd", + "lib": ["es6", "es2016", "es2017", "dom"], + "sourceMap": true, + "outDir": "dist/lib", + "declarationDir": "dist/types", + "strict": true, + "moduleResolution": "node", + "baseUrl": "src", + "declaration": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "forceConsistentCasingInFileNames": true, + "typeRoots": ["node_modules/@types"] + }, + "include": ["src/**/*"], + "exclude": ["dist", "node_modules"], + "compileOnSave": false +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..2a1a17f --- /dev/null +++ b/yarn.lock @@ -0,0 +1,859 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@eslint/eslintrc@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" + integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.2" + globals "^13.15.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@typescript-eslint/eslint-plugin@^5.28.0": + version "5.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.28.0.tgz#6204ac33bdd05ab27c7f77960f1023951115d403" + integrity sha512-DXVU6Cg29H2M6EybqSg2A+x8DgO9TCUBRp4QEXQHJceLS7ogVDP0g3Lkg/SZCqcvkAP/RruuQqK0gdlkgmhSUA== + dependencies: + "@typescript-eslint/scope-manager" "5.28.0" + "@typescript-eslint/type-utils" "5.28.0" + "@typescript-eslint/utils" "5.28.0" + debug "^4.3.4" + functional-red-black-tree "^1.0.1" + ignore "^5.2.0" + regexpp "^3.2.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.28.0": + version "5.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.28.0.tgz#639b101cad2bfb7ae16e69710ac95c42bd4eae33" + integrity sha512-ekqoNRNK1lAcKhZESN/PdpVsWbP9jtiNqzFWkp/yAUdZvJalw2heCYuqRmM5eUJSIYEkgq5sGOjq+ZqsLMjtRA== + dependencies: + "@typescript-eslint/scope-manager" "5.28.0" + "@typescript-eslint/types" "5.28.0" + "@typescript-eslint/typescript-estree" "5.28.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.28.0": + version "5.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.28.0.tgz#ef9a5c68fecde72fd2ff8a84b9c120324826c1b9" + integrity sha512-LeBLTqF/he1Z+boRhSqnso6YrzcKMTQ8bO/YKEe+6+O/JGof9M0g3IJlIsqfrK/6K03MlFIlycbf1uQR1IjE+w== + dependencies: + "@typescript-eslint/types" "5.28.0" + "@typescript-eslint/visitor-keys" "5.28.0" + +"@typescript-eslint/type-utils@5.28.0": + version "5.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.28.0.tgz#53ccc78fdcf0205ef544d843b84104c0e9c7ca8e" + integrity sha512-SyKjKh4CXPglueyC6ceAFytjYWMoPHMswPQae236zqe1YbhvCVQyIawesYywGiu98L9DwrxsBN69vGIVxJ4mQQ== + dependencies: + "@typescript-eslint/utils" "5.28.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.28.0": + version "5.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.28.0.tgz#cffd9bcdce28db6daaa146e48a0be4387a6f4e9d" + integrity sha512-2OOm8ZTOQxqkPbf+DAo8oc16sDlVR5owgJfKheBkxBKg1vAfw2JsSofH9+16VPlN9PWtv8Wzhklkqw3k/zCVxA== + +"@typescript-eslint/typescript-estree@5.28.0": + version "5.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.28.0.tgz#3487d158d091ca2772b285e67412ff6d9797d863" + integrity sha512-9GX+GfpV+F4hdTtYc6OV9ZkyYilGXPmQpm6AThInpBmKJEyRSIjORJd1G9+bknb7OTFYL+Vd4FBJAO6T78OVqA== + dependencies: + "@typescript-eslint/types" "5.28.0" + "@typescript-eslint/visitor-keys" "5.28.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.28.0": + version "5.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.28.0.tgz#b27a136eac300a48160b36d2aad0da44a1341b99" + integrity sha512-E60N5L0fjv7iPJV3UGc4EC+A3Lcj4jle9zzR0gW7vXhflO7/J29kwiTGITA2RlrmPokKiZbBy2DgaclCaEUs6g== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.28.0" + "@typescript-eslint/types" "5.28.0" + "@typescript-eslint/typescript-estree" "5.28.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.28.0": + version "5.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.28.0.tgz#982bb226b763c48fc1859a60de33fbf939d40a0f" + integrity sha512-BtfP1vCor8cWacovzzPFOoeW4kBQxzmhxGoOpt0v1SFvG+nJ0cWaVdJk7cky1ArTcFHHKNIxyo2LLr3oNkSuXA== + dependencies: + "@typescript-eslint/types" "5.28.0" + eslint-visitor-keys "^3.3.0" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.7.1: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@^8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" + integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== + +eslint-plugin-prettier@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" + integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== + dependencies: + prettier-linter-helpers "^1.0.0" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.17.0: + version "8.17.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.17.0.tgz#1cfc4b6b6912f77d24b874ca1506b0fe09328c21" + integrity sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw== + dependencies: + "@eslint/eslintrc" "^1.3.0" + "@humanwhocodes/config-array" "^0.9.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.2" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^6.0.1" + globals "^13.15.0" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.1" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^9.3.2: + version "9.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" + integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== + dependencies: + acorn "^8.7.1" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.5" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" + integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^13.15.0: + version "13.15.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.15.0.tgz#38113218c907d2f7e98658af246cef8b77e90bac" + integrity sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.0.tgz#a4fdae07e5596c51c9857ea676cd41a0163879d6" + integrity sha512-nwoX4GMFgxoPC6diHvSwmK/4yU8FFH3V8XWtLQrbj4IBsK2pkYhG4kf/ljF/haaZ/aii+wNJqISrCDPgxGWDVQ== + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +semver@^7.3.7: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +typescript@^4.7.3: + version "4.7.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" + integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==