diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8d2f0fdd..c6d8de2f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,11 +9,10 @@
## Changelog
-### **HEAD -> main** 2021/09/21 mandic00@live.com
-
-
-### **origin/main** 2021/09/20 mandic00@live.com
+### **HEAD -> main** 2021/09/22 mandic00@live.com
+- prototype handtracking
+- automated browser tests
- support for dynamic backend switching
- initial automated browser tests
- enhanced automated test coverage
diff --git a/TODO.md b/TODO.md
index b03b656e..057ff3ae 100644
--- a/TODO.md
+++ b/TODO.md
@@ -2,14 +2,31 @@
## Work in Progress
-WebGL shader optimizations for faster load and initial detection
+
-- Fix shader packing:
-- Add and benchmark WGSL for WebGPU
+### Handtrack
+
+- Finish implementation
+- Set defaults and image sizes
+- Optimize model
+- Add tests
-## Exploring
+### Segmentation
+
+- Implement `NodeJS` support
+- Test for leaks
+
+### Backends
+
+- Optimize shader packing for WebGL backend:
+
+- Add and benchmark WGSL for WebGPU
+
+
+
+### Exploring
- Optical Flow:
- TFLite Models:
diff --git a/dist/human.esm-nobundle.js b/dist/human.esm-nobundle.js
index 9ce2c276..71dd43a9 100644
--- a/dist/human.esm-nobundle.js
+++ b/dist/human.esm-nobundle.js
@@ -10,9 +10,6 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
-var __require = typeof require !== "undefined" ? require : (x) => {
- throw new Error('Dynamic require of "' + x + '" is not supported');
-};
var __export = (target, all2) => {
__markAsModule(target);
for (var name in all2)
@@ -112,7 +109,6 @@ var config = {
async: true,
warmup: "full",
cacheSensitivity: 0.75,
- yield: false,
skipFrame: false,
filter: {
enabled: true,
diff --git a/dist/human.esm-nobundle.js.map b/dist/human.esm-nobundle.js.map
index 6410e00b..dac0ed00 100644
--- a/dist/human.esm-nobundle.js.map
+++ b/dist/human.esm-nobundle.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../src/helpers.ts", "../src/config.ts", "tfjs.esm.js", "../src/blazeface/box.ts", "../src/blazeface/util.ts", "../src/blazeface/blazeface.ts", "../src/blazeface/coords.ts", "../src/image/imagefx.ts", "../src/image/image.ts", "../src/env.ts", "../src/blazeface/facepipeline.ts", "../src/blazeface/facemesh.ts", "../src/faceres/faceres.ts", "../src/emotion/emotion.ts", "../src/posenet/keypoints.ts", "../src/posenet/utils.ts", "../src/posenet/poses.ts", "../src/posenet/posenet.ts", "../src/handpose/box.ts", "../src/handpose/anchors.ts", "../src/handpose/handdetector.ts", "../src/handpose/util.ts", "../src/handpose/handpipeline.ts", "../src/fingerpose/description.ts", "../src/fingerpose/estimator.ts", "../src/fingerpose/gesture.ts", "../src/fingerpose/gestures.ts", "../src/fingerpose/fingerpose.ts", "../src/handpose/handpose.ts", "../src/handtrack/handtrack.ts", "../src/blazepose/annotations.ts", "../src/blazepose/blazepose.ts", "../src/efficientpose/efficientpose.ts", "../src/movenet/movenet.ts", "../src/object/labels.ts", "../src/object/nanodet.ts", "../src/object/centernet.ts", "../src/segmentation/segmentation.ts", "../src/models.ts", "../src/face.ts", "../src/gesture/gesture.ts", "../src/draw.ts", "../src/persons.ts", "../src/interpolate.ts", "../src/tfjs/humangl.ts", "../src/tfjs/backend.ts", "../src/sample.ts", "../src/warmup.ts", "../src/human.ts"],
- "sourcesContent": ["/**\n * Simple helper functions used accross codebase\n */\n\n// helper function: join two paths\nexport function join(folder: string, file: string): string {\n const separator = folder.endsWith('/') ? '' : '/';\n const skipJoin = file.startsWith('.') || file.startsWith('/') || file.startsWith('http:') || file.startsWith('https:') || file.startsWith('file:');\n const path = skipJoin ? `${file}` : `${folder}${separator}${file}`;\n if (!path.toLocaleLowerCase().includes('.json')) throw new Error(`modelpath error: ${path} expecting json file`);\n return path;\n}\n\n// helper function: wrapper around console output\nexport function log(...msg): void {\n const dt = new Date();\n const ts = `${dt.getHours().toString().padStart(2, '0')}:${dt.getMinutes().toString().padStart(2, '0')}:${dt.getSeconds().toString().padStart(2, '0')}.${dt.getMilliseconds().toString().padStart(3, '0')}`;\n // eslint-disable-next-line no-console\n if (msg) console.log(ts, 'Human:', ...msg);\n}\n\n// helper function: gets elapsed time on both browser and nodejs\nexport const now = () => {\n if (typeof performance !== 'undefined') return performance.now();\n return parseInt((Number(process.hrtime.bigint()) / 1000 / 1000).toString());\n};\n\n// helper function: checks current config validity\nexport function validate(defaults, config, parent = 'config', msgs: Array<{ reason: string, where: string, expected?: string }> = []) {\n for (const key of Object.keys(config)) {\n if (typeof config[key] === 'object') {\n validate(defaults[key], config[key], key, msgs);\n } else {\n const defined = defaults && (typeof defaults[key] !== 'undefined');\n if (!defined) msgs.push({ reason: 'unknown property', where: `${parent}.${key} = ${config[key]}` });\n const same = defaults && typeof defaults[key] === typeof config[key];\n if (defined && !same) msgs.push({ reason: 'property type mismatch', where: `${parent}.${key} = ${config[key]}`, expected: typeof defaults[key] });\n }\n // ok = ok && defined && same;\n }\n if (config.debug && parent === 'config' && msgs.length > 0) log('invalid configuration', msgs);\n return msgs;\n}\n\n// helper function: perform deep merge of multiple objects so it allows full inheriance with overrides\nexport function mergeDeep(...objects) {\n const isObject = (obj) => obj && typeof obj === 'object';\n return objects.reduce((prev, obj) => {\n Object.keys(obj || {}).forEach((key) => {\n const pVal = prev[key];\n const oVal = obj[key];\n if (Array.isArray(pVal) && Array.isArray(oVal)) prev[key] = pVal.concat(...oVal);\n else if (isObject(pVal) && isObject(oVal)) prev[key] = mergeDeep(pVal, oVal);\n else prev[key] = oVal;\n });\n return prev;\n }, {});\n}\n\n// helper function: return min and max from input array\nexport const minmax = (data: Array) => data.reduce((acc: Array, val) => {\n acc[0] = (acc[0] === undefined || val < acc[0]) ? val : acc[0];\n acc[1] = (acc[1] === undefined || val > acc[1]) ? val : acc[1];\n return acc;\n}, []);\n\n// helper function: async wait\nexport async function wait(time) {\n const waiting = new Promise((resolve) => setTimeout(() => resolve(true), time));\n await waiting;\n}\n", "/* eslint-disable indent */\n/* eslint-disable no-multi-spaces */\n\nexport interface FaceDetectorConfig {\n modelPath: string,\n rotation: boolean,\n maxDetected: number,\n skipFrames: number,\n minConfidence: number,\n iouThreshold: number,\n return: boolean,\n}\n\nexport interface FaceMeshConfig {\n enabled: boolean,\n modelPath: string,\n}\n\nexport interface FaceIrisConfig {\n enabled: boolean,\n modelPath: string,\n}\n\nexport interface FaceDescriptionConfig {\n enabled: boolean,\n modelPath: string,\n skipFrames: number,\n minConfidence: number,\n}\n\nexport interface FaceEmotionConfig {\n enabled: boolean,\n minConfidence: number,\n skipFrames: number,\n modelPath: string,\n}\n\n/** Controlls and configures all face-specific options:\n * - face detection, face mesh detection, age, gender, emotion detection and face description\n * Parameters:\n * - enabled: true/false\n * - modelPath: path for each of face models\n * - minConfidence: threshold for discarding a prediction\n * - iouThreshold: ammount of overlap between two detected objects before one object is removed\n * - maxDetected: maximum number of faces detected in the input, should be set to the minimum number for performance\n * - rotation: use calculated rotated face image or just box with rotation as-is, false means higher performance, but incorrect mesh mapping on higher face angles\n * - return: return extracted face as tensor for futher user processing, in which case user is reponsible for manually disposing the tensor\n*/\nexport interface FaceConfig {\n enabled: boolean,\n detector: Partial,\n mesh: Partial,\n iris: Partial,\n description: Partial,\n emotion: Partial,\n}\n\n/** Controlls and configures all body detection specific options\n * - enabled: true/false\n * - modelPath: body pose model, can be absolute path or relative to modelBasePath\n * - minConfidence: threshold for discarding a prediction\n * - maxDetected: maximum number of people detected in the input, should be set to the minimum number for performance\n*/\nexport interface BodyConfig {\n enabled: boolean,\n modelPath: string,\n maxDetected: number,\n minConfidence: number,\n skipFrames: number,\n}\n\n/** Controlls and configures all hand detection specific options\n * - enabled: true/false\n * - landmarks: detect hand landmarks or just hand boundary box\n * - modelPath: paths for hand detector and hand skeleton models, can be absolute path or relative to modelBasePath\n * - minConfidence: threshold for discarding a prediction\n * - iouThreshold: ammount of overlap between two detected objects before one object is removed\n * - maxDetected: maximum number of hands detected in the input, should be set to the minimum number for performance\n * - rotation: use best-guess rotated hand image or just box with rotation as-is, false means higher performance, but incorrect finger mapping if hand is inverted\n*/\nexport interface HandConfig {\n enabled: boolean,\n rotation: boolean,\n skipFrames: number,\n minConfidence: number,\n iouThreshold: number,\n maxDetected: number,\n landmarks: boolean,\n detector: {\n modelPath?: string,\n },\n skeleton: {\n modelPath?: string,\n },\n}\n\n/** Controlls and configures all object detection specific options\n * - enabled: true/false\n * - modelPath: object detection model, can be absolute path or relative to modelBasePath\n * - minConfidence: minimum score that detection must have to return as valid object\n * - iouThreshold: ammount of overlap between two detected objects before one object is removed\n * - maxDetected: maximum number of detections to return\n*/\nexport interface ObjectConfig {\n enabled: boolean,\n modelPath: string,\n minConfidence: number,\n iouThreshold: number,\n maxDetected: number,\n skipFrames: number,\n}\n\n/** Controlls and configures all body segmentation module\n * removes background from input containing person\n * if segmentation is enabled it will run as preprocessing task before any other model\n * alternatively leave it disabled and use it on-demand using human.segmentation method which can\n * remove background or replace it with user-provided background\n *\n * - enabled: true/false\n * - modelPath: object detection model, can be absolute path or relative to modelBasePath\n * - blur: blur segmentation output by pixels for more realistic image\n*/\nexport interface SegmentationConfig {\n enabled: boolean,\n modelPath: string,\n blur: number,\n}\n\n/** Run input through image filters before inference\n * - image filters run with near-zero latency as they are executed on the GPU\n*/\nexport interface FilterConfig {\n enabled: boolean,\n /** Resize input width\n * - if both width and height are set to 0, there is no resizing\n * - if just one is set, second one is scaled automatically\n * - if both are set, values are used as-is\n */\n width: number,\n /** Resize input height\n * - if both width and height are set to 0, there is no resizing\n * - if just one is set, second one is scaled automatically\n * - if both are set, values are used as-is\n */\n height: number,\n /** Return processed canvas imagedata in result */\n return: boolean,\n /** Flip input as mirror image */\n flip: boolean,\n /** Range: -1 (darken) to 1 (lighten) */\n brightness: number,\n /** Range: -1 (reduce contrast) to 1 (increase contrast) */\n contrast: number,\n /** Range: 0 (no sharpening) to 1 (maximum sharpening) */\n sharpness: number,\n /** Range: 0 (no blur) to N (blur radius in pixels) */\n blur: number\n /** Range: -1 (reduce saturation) to 1 (increase saturation) */\n saturation: number,\n /** Range: 0 (no change) to 360 (hue rotation in degrees) */\n hue: number,\n /** Image negative */\n negative: boolean,\n /** Image sepia colors */\n sepia: boolean,\n /** Image vintage colors */\n vintage: boolean,\n /** Image kodachrome colors */\n kodachrome: boolean,\n /** Image technicolor colors */\n technicolor: boolean,\n /** Image polaroid camera effect */\n polaroid: boolean,\n /** Range: 0 (no pixelate) to N (number of pixels to pixelate) */\n pixelate: number,\n}\n\n/** Controlls gesture detection */\nexport interface GestureConfig {\n enabled: boolean,\n}\n\n/**\n * Configuration interface definition for **Human** library\n *\n * Contains all configurable parameters\n * @typedef Config\n */\nexport interface Config {\n /** Backend used for TFJS operations */\n backend: '' | 'cpu' | 'wasm' | 'webgl' | 'humangl' | 'tensorflow' | 'webgpu',\n // backend: string;\n\n /** Path to *.wasm files if backend is set to `wasm` */\n wasmPath: string,\n\n /** Print debug statements to console */\n debug: boolean,\n\n /** Perform model loading and inference concurrently or sequentially */\n async: boolean,\n\n /** What to use for `human.warmup()`\n * - warmup pre-initializes all models for faster inference but can take significant time on startup\n * - only used for `webgl` and `humangl` backends\n */\n warmup: 'none' | 'face' | 'full' | 'body',\n // warmup: string;\n\n /** Base model path (typically starting with file://, http:// or https://) for all models\n * - individual modelPath values are relative to this path\n */\n modelBasePath: string,\n\n /** Cache sensitivity\n * - values 0..1 where 0.01 means reset cache if input changed more than 1%\n * - set to 0 to disable caching\n */\n cacheSensitivity: number;\n\n /** Yield to main thread periodically */\n yield: boolean;\n\n /** Internal Variable */\n skipFrame: boolean;\n\n /** Run input through image filters before inference\n * - image filters run with near-zero latency as they are executed on the GPU\n */\n filter: Partial,\n // type definition end\n\n gesture: Partial;\n\n face: Partial,\n\n body: Partial,\n\n hand: Partial,\n\n object: Partial,\n\n segmentation: Partial,\n}\n\n/**\n * [See all default Config values...](https://github.com/vladmandic/human/blob/main/src/config.ts#L244)\n *\n */\nconst config: Config = {\n backend: '', // select tfjs backend to use, leave empty to use default backend\n // can be 'webgl', 'wasm', 'cpu', or 'humangl' which is a custom version of webgl\n // default set to `humangl` for browsers and `tensorflow` for nodejs\n modelBasePath: '', // base path for all models\n // default set to `../models/` for browsers and `file://models/` for nodejs\n wasmPath: '', // path for wasm binaries, only used for backend: wasm\n // default set to download from jsdeliv during Human class instantiation\n debug: true, // print additional status messages to console\n async: true, // execute enabled models in parallel\n warmup: 'full', // what to use for human.warmup(), can be 'none', 'face', 'full'\n // warmup pre-initializes all models for faster inference but can take\n // significant time on startup\n // only used for `webgl` and `humangl` backends\n cacheSensitivity: 0.75, // cache sensitivity\n // values 0..1 where 0.01 means reset cache if input changed more than 1%\n // set to 0 to disable caching\n yield: false, // yield to main thread periodically\n skipFrame: false, // internal & dynamic\n filter: { // run input through image filters before inference\n // image filters run with near-zero latency as they are executed on the GPU\n enabled: true, // enable image pre-processing filters\n width: 0, // resize input width\n height: 0, // resize input height\n // if both width and height are set to 0, there is no resizing\n // if just one is set, second one is scaled automatically\n // if both are set, values are used as-is\n flip: false, // flip input as mirror image\n return: true, // return processed canvas imagedata in result\n brightness: 0, // range: -1 (darken) to 1 (lighten)\n contrast: 0, // range: -1 (reduce contrast) to 1 (increase contrast)\n sharpness: 0, // range: 0 (no sharpening) to 1 (maximum sharpening)\n blur: 0, // range: 0 (no blur) to N (blur radius in pixels)\n saturation: 0, // range: -1 (reduce saturation) to 1 (increase saturation)\n hue: 0, // range: 0 (no change) to 360 (hue rotation in degrees)\n negative: false, // image negative\n sepia: false, // image sepia colors\n vintage: false, // image vintage colors\n kodachrome: false, // image kodachrome colors\n technicolor: false, // image technicolor colors\n polaroid: false, // image polaroid camera effect\n pixelate: 0, // range: 0 (no pixelate) to N (number of pixels to pixelate)\n },\n\n gesture: {\n enabled: true, // enable gesture recognition based on model results\n },\n\n face: {\n enabled: true, // controls if specified modul is enabled\n // face.enabled is required for all face models:\n // detector, mesh, iris, age, gender, emotion\n // (note: module is not loaded until it is required)\n detector: {\n modelPath: 'blazeface.json', // detector model, can be absolute path or relative to modelBasePath\n rotation: true, // use best-guess rotated face image or just box with rotation as-is\n // false means higher performance, but incorrect mesh mapping if face angle is above 20 degrees\n // this parameter is not valid in nodejs\n maxDetected: 15, // maximum number of faces detected in the input\n // should be set to the minimum number for performance\n skipFrames: 15, // how many max frames to go without re-running the face bounding box detector\n // only used when cacheSensitivity is not zero\n // e.g., if model is running st 25 FPS, we can re-use existing bounding\n // box for updated face analysis as the head probably hasn't moved much\n // in short time (10 * 1/25 = 0.25 sec)\n minConfidence: 0.2, // threshold for discarding a prediction\n iouThreshold: 0.1, // ammount of overlap between two detected objects before one object is removed\n return: false, // return extracted face as tensor\n // in which case user is reponsible for disposing the tensor\n },\n\n mesh: {\n enabled: true,\n modelPath: 'facemesh.json', // facemesh model, can be absolute path or relative to modelBasePath\n },\n\n iris: {\n enabled: true,\n modelPath: 'iris.json', // face iris model\n // can be either absolute path or relative to modelBasePath\n },\n\n description: {\n enabled: true, // to improve accuracy of face description extraction it is\n // recommended to enable detector.rotation and mesh.enabled\n modelPath: 'faceres.json', // face description model\n // can be either absolute path or relative to modelBasePath\n skipFrames: 11, // how many max frames to go without re-running the detector\n // only used when cacheSensitivity is not zero\n minConfidence: 0.1, // threshold for discarding a prediction\n },\n\n emotion: {\n enabled: true,\n minConfidence: 0.1, // threshold for discarding a prediction\n skipFrames: 17, // how max many frames to go without re-running the detector\n // only used when cacheSensitivity is not zero\n modelPath: 'emotion.json', // face emotion model, can be absolute path or relative to modelBasePath\n },\n },\n\n body: {\n enabled: true,\n modelPath: 'movenet-lightning.json', // body model, can be absolute path or relative to modelBasePath\n // can be 'posenet', 'blazepose', 'efficientpose', 'movenet-lightning', 'movenet-thunder'\n maxDetected: 1, // maximum number of people detected in the input\n // should be set to the minimum number for performance\n // only valid for posenet as other models detects single pose\n minConfidence: 0.2, // threshold for discarding a prediction\n skipFrames: 1, // how many max frames to go without re-running the detector\n // only used when cacheSensitivity is not zero\n},\n\n hand: {\n enabled: true,\n rotation: true, // use best-guess rotated hand image or just box with rotation as-is\n // false means higher performance, but incorrect finger mapping if hand is inverted\n skipFrames: 18, // how many max frames to go without re-running the hand bounding box detector\n // only used when cacheSensitivity is not zero\n // e.g., if model is running st 25 FPS, we can re-use existing bounding\n // box for updated hand skeleton analysis as the hand probably\n // hasn't moved much in short time (10 * 1/25 = 0.25 sec)\n minConfidence: 0.8, // threshold for discarding a prediction\n iouThreshold: 0.2, // ammount of overlap between two detected objects before one object is removed\n maxDetected: 1, // maximum number of hands detected in the input\n // should be set to the minimum number for performance\n landmarks: true, // detect hand landmarks or just hand boundary box\n detector: {\n modelPath: 'handdetect.json', // hand detector model, can be absolute path or relative to modelBasePath\n },\n skeleton: {\n modelPath: 'handskeleton.json', // hand skeleton model, can be absolute path or relative to modelBasePath\n },\n },\n\n object: {\n enabled: false,\n modelPath: 'mb3-centernet.json', // experimental: object detection model, can be absolute path or relative to modelBasePath\n // can be 'mb3-centernet' or 'nanodet'\n minConfidence: 0.2, // threshold for discarding a prediction\n iouThreshold: 0.4, // ammount of overlap between two detected objects before one object is removed\n maxDetected: 10, // maximum number of objects detected in the input\n skipFrames: 19, // how many max frames to go without re-running the detector\n // only used when cacheSensitivity is not zero\n },\n\n segmentation: {\n enabled: false, // controlls and configures all body segmentation module\n // removes background from input containing person\n // if segmentation is enabled it will run as preprocessing task before any other model\n // alternatively leave it disabled and use it on-demand using human.segmentation method which can\n // remove background or replace it with user-provided background\n modelPath: 'selfie.json', // experimental: object detection model, can be absolute path or relative to modelBasePath\n // can be 'selfie' or 'meet'\n blur: 8, // blur segmentation output by n pixels for more realistic image\n },\n};\nexport { config as defaults };\n", "/*\n Human\n homepage: \n author: '\n*/\n\n// tfjs/tf-browser.ts\nexport * from \"@tensorflow/tfjs/dist/index.js\";\nexport * from \"@tensorflow/tfjs-backend-webgl/dist/index.js\";\nexport * from \"@tensorflow/tfjs-backend-wasm/dist/index.js\";\n\n// dist/tfjs.version.js\nvar version = \"3.9.0\";\nvar version2 = \"3.9.0\";\nvar version3 = \"3.9.0\";\nvar version4 = \"3.9.0\";\nvar version5 = \"3.9.0\";\nvar version6 = \"3.9.0\";\nvar version7 = \"3.9.0\";\nvar version8 = \"3.9.0\";\nvar version9 = {\n tfjs: version,\n \"tfjs-core\": version2,\n \"tfjs-data\": version3,\n \"tfjs-layers\": version4,\n \"tfjs-converter\": version5,\n \"tfjs-backend-cpu\": version6,\n \"tfjs-backend-webgl\": version7,\n \"tfjs-backend-wasm\": version8\n};\nexport {\n version9 as version\n};\n", "import * as tf from '../../dist/tfjs.esm.js';\n\nexport function scaleBoxCoordinates(box, factor) {\n const startPoint = [box.startPoint[0] * factor[0], box.startPoint[1] * factor[1]];\n const endPoint = [box.endPoint[0] * factor[0], box.endPoint[1] * factor[1]];\n return { startPoint, endPoint };\n}\n\nexport function getBoxSize(box): [number, number] {\n return [\n Math.abs(box.endPoint[0] - box.startPoint[0]),\n Math.abs(box.endPoint[1] - box.startPoint[1]),\n ];\n}\n\nexport function getBoxCenter(box): [number, number] {\n return [\n box.startPoint[0] + (box.endPoint[0] - box.startPoint[0]) / 2,\n box.startPoint[1] + (box.endPoint[1] - box.startPoint[1]) / 2,\n ];\n}\n\nexport function cutBoxFromImageAndResize(box, image, cropSize) {\n const h = image.shape[1];\n const w = image.shape[2];\n const boxes = [[\n box.startPoint[1] / h,\n box.startPoint[0] / w,\n box.endPoint[1] / h,\n box.endPoint[0] / w,\n ]];\n return tf.image.cropAndResize(image, boxes, [0], cropSize);\n}\n\nexport function enlargeBox(box, factor = 1.5) {\n const center = getBoxCenter(box);\n const size = getBoxSize(box);\n const newHalfSize: [number, number] = [factor * size[0] / 2, factor * size[1] / 2];\n const startPoint = [center[0] - newHalfSize[0], center[1] - newHalfSize[1]];\n const endPoint = [center[0] + newHalfSize[0], center[1] + newHalfSize[1]];\n return { startPoint, endPoint, landmarks: box.landmarks };\n}\n\nexport function squarifyBox(box) {\n const centers = getBoxCenter(box);\n const size = getBoxSize(box);\n const maxEdge = Math.max(...size);\n const halfSize = maxEdge / 2;\n const startPoint = [Math.round(centers[0] - halfSize), Math.round(centers[1] - halfSize)];\n const endPoint = [Math.round(centers[0] + halfSize), Math.round(centers[1] + halfSize)];\n return { startPoint, endPoint, landmarks: box.landmarks };\n}\n\nexport function calculateLandmarksBoundingBox(landmarks) {\n const xs = landmarks.map((d) => d[0]);\n const ys = landmarks.map((d) => d[1]);\n const startPoint = [Math.min(...xs), Math.min(...ys)];\n const endPoint = [Math.max(...xs), Math.max(...ys)];\n return { startPoint, endPoint, landmarks };\n}\n\nexport const disposeBox = (t) => {\n tf.dispose(t.startPoint);\n tf.dispose(t.endPoint);\n};\n\nexport const createBox = (startEndTensor) => ({\n startPoint: tf.slice(startEndTensor, [0, 0], [-1, 2]),\n endPoint: tf.slice(startEndTensor, [0, 2], [-1, 2]),\n});\n", "export const IDENTITY_MATRIX = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];\n/**\n * Normalizes the provided angle to the range -pi to pi.\n * @param angle The angle in radians to be normalized.\n */\nexport function normalizeRadians(angle) {\n return angle - 2 * Math.PI * Math.floor((angle + Math.PI) / (2 * Math.PI));\n}\n\n/**\n * Computes the angle of rotation between two anchor points.\n * @param point1 First anchor point\n * @param point2 Second anchor point\n */\nexport function computeRotation(point1, point2) {\n const radians = Math.PI / 2 - Math.atan2(-(point2[1] - point1[1]), point2[0] - point1[0]);\n return normalizeRadians(radians);\n}\n\nexport function radToDegrees(rad) {\n return rad * 180 / Math.PI;\n}\n\nexport function buildTranslationMatrix(x, y) {\n return [[1, 0, x], [0, 1, y], [0, 0, 1]];\n}\n\nexport function dot(v1, v2) {\n let product = 0;\n for (let i = 0; i < v1.length; i++) {\n product += v1[i] * v2[i];\n }\n return product;\n}\n\nexport function getColumnFrom2DArr(arr, columnIndex) {\n const column: Array = [];\n for (let i = 0; i < arr.length; i++) {\n column.push(arr[i][columnIndex]);\n }\n return column;\n}\n\nexport function multiplyTransformMatrices(mat1, mat2) {\n const product: Array = [];\n const size = mat1.length;\n for (let row = 0; row < size; row++) {\n product.push([]);\n for (let col = 0; col < size; col++) {\n product[row].push(dot(mat1[row], getColumnFrom2DArr(mat2, col)));\n }\n }\n return product;\n}\n\nexport function buildRotationMatrix(rotation, center) {\n const cosA = Math.cos(rotation);\n const sinA = Math.sin(rotation);\n const rotationMatrix = [[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]];\n const translationMatrix = buildTranslationMatrix(center[0], center[1]);\n const translationTimesRotation = multiplyTransformMatrices(translationMatrix, rotationMatrix);\n const negativeTranslationMatrix = buildTranslationMatrix(-center[0], -center[1]);\n return multiplyTransformMatrices(translationTimesRotation, negativeTranslationMatrix);\n}\n\nexport function invertTransformMatrix(matrix) {\n const rotationComponent = [[matrix[0][0], matrix[1][0]], [matrix[0][1], matrix[1][1]]];\n const translationComponent = [matrix[0][2], matrix[1][2]];\n const invertedTranslation = [\n -dot(rotationComponent[0], translationComponent),\n -dot(rotationComponent[1], translationComponent),\n ];\n return [\n rotationComponent[0].concat(invertedTranslation[0]),\n rotationComponent[1].concat(invertedTranslation[1]),\n [0, 0, 1],\n ];\n}\n\nexport function rotatePoint(homogeneousCoordinate, rotationMatrix) {\n return [\n dot(homogeneousCoordinate, rotationMatrix[0]),\n dot(homogeneousCoordinate, rotationMatrix[1]),\n ];\n}\n\nexport function xyDistanceBetweenPoints(a, b) {\n return Math.sqrt(((a[0] - b[0]) ** 2) + ((a[1] - b[1]) ** 2));\n}\n\nexport function generateAnchors(inputSize) {\n const spec = { strides: [inputSize / 16, inputSize / 8], anchors: [2, 6] };\n const anchors: Array<[number, number]> = [];\n for (let i = 0; i < spec.strides.length; i++) {\n const stride = spec.strides[i];\n const gridRows = Math.floor((inputSize + stride - 1) / stride);\n const gridCols = Math.floor((inputSize + stride - 1) / stride);\n const anchorsNum = spec.anchors[i];\n for (let gridY = 0; gridY < gridRows; gridY++) {\n const anchorY = stride * (gridY + 0.5);\n for (let gridX = 0; gridX < gridCols; gridX++) {\n const anchorX = stride * (gridX + 0.5);\n for (let n = 0; n < anchorsNum; n++) {\n anchors.push([anchorX, anchorY]);\n }\n }\n }\n }\n return anchors;\n}\n", "import { log, join, mergeDeep } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as box from './box';\nimport * as util from './util';\nimport type { Config } from '../config';\nimport type { Tensor, GraphModel } from '../tfjs/types';\n\nconst keypointsCount = 6;\n\nfunction decodeBounds(boxOutputs, anchors, inputSize) {\n const boxStarts = tf.slice(boxOutputs, [0, 1], [-1, 2]);\n const centers = tf.add(boxStarts, anchors);\n const boxSizes = tf.slice(boxOutputs, [0, 3], [-1, 2]);\n const boxSizesNormalized = tf.div(boxSizes, inputSize);\n const centersNormalized = tf.div(centers, inputSize);\n const halfBoxSize = tf.div(boxSizesNormalized, 2);\n const starts = tf.sub(centersNormalized, halfBoxSize);\n const ends = tf.add(centersNormalized, halfBoxSize);\n const startNormalized = tf.mul(starts, inputSize);\n const endNormalized = tf.mul(ends, inputSize);\n const concatAxis = 1;\n return tf.concat2d([startNormalized, endNormalized], concatAxis);\n}\n\nexport class BlazeFaceModel {\n model: GraphModel;\n anchorsData: [number, number][];\n anchors: Tensor;\n inputSize: number;\n config: Config;\n\n constructor(model, config: Config) {\n this.model = model;\n this.anchorsData = util.generateAnchors(model.inputs[0].shape[1]);\n this.anchors = tf.tensor2d(this.anchorsData);\n this.inputSize = model.inputs[0].shape[2];\n this.config = config;\n }\n\n async getBoundingBoxes(inputImage: Tensor, userConfig: Config) {\n // sanity check on input\n if ((!inputImage) || (inputImage['isDisposedInternal']) || (inputImage.shape.length !== 4) || (inputImage.shape[1] < 1) || (inputImage.shape[2] < 1)) return { boxes: [] };\n const [batch, boxes, scores] = tf.tidy(() => {\n const resizedImage = tf.image.resizeBilinear(inputImage, [this.inputSize, this.inputSize]);\n const normalizedImage = tf.sub(tf.div(resizedImage, 127.5), 0.5);\n const res = this.model.execute(normalizedImage);\n let batchOut;\n if (Array.isArray(res)) { // are we using tfhub or pinto converted model?\n const sorted = res.sort((a, b) => a.size - b.size);\n const concat384 = tf.concat([sorted[0], sorted[2]], 2); // dim: 384, 1 + 16\n const concat512 = tf.concat([sorted[1], sorted[3]], 2); // dim: 512, 1 + 16\n const concat = tf.concat([concat512, concat384], 1);\n batchOut = tf.squeeze(concat, 0);\n } else {\n batchOut = tf.squeeze(res); // when using tfhub model\n }\n const boxesOut = decodeBounds(batchOut, this.anchors, [this.inputSize, this.inputSize]);\n const logits = tf.slice(batchOut, [0, 0], [-1, 1]);\n const scoresOut = tf.squeeze(tf.sigmoid(logits)); // inside tf.tidy\n return [batchOut, boxesOut, scoresOut];\n });\n\n this.config = mergeDeep(this.config, userConfig) as Config;\n\n const nmsTensor = await tf.image.nonMaxSuppressionAsync(boxes, scores, (this.config.face.detector?.maxDetected || 0), (this.config.face.detector?.iouThreshold || 0), (this.config.face.detector?.minConfidence || 0));\n const nms = await nmsTensor.array();\n tf.dispose(nmsTensor);\n const annotatedBoxes: Array<{ box: { startPoint: Tensor, endPoint: Tensor }, landmarks: Tensor, anchor: [number, number] | undefined, confidence: number }> = [];\n const scoresData = await scores.data();\n for (let i = 0; i < nms.length; i++) {\n const confidence = scoresData[nms[i]];\n if (confidence > (this.config.face.detector?.minConfidence || 0)) {\n const boundingBox = tf.slice(boxes, [nms[i], 0], [1, -1]);\n const landmarks = tf.tidy(() => tf.reshape(tf.squeeze(tf.slice(batch, [nms[i], keypointsCount - 1], [1, -1])), [keypointsCount, -1]));\n annotatedBoxes.push({ box: box.createBox(boundingBox), landmarks, anchor: this.anchorsData[nms[i]], confidence });\n tf.dispose(boundingBox);\n }\n }\n tf.dispose(batch);\n tf.dispose(boxes);\n tf.dispose(scores);\n\n return {\n boxes: annotatedBoxes,\n scaleFactor: [inputImage.shape[2] / this.inputSize, inputImage.shape[1] / this.inputSize],\n };\n }\n}\n\nexport async function load(config: Config) {\n const model = await tf.loadGraphModel(join(config.modelBasePath, config.face.detector?.modelPath || ''), { fromTFHub: (config.face.detector?.modelPath || '').includes('tfhub.dev') });\n const blazeFace = new BlazeFaceModel(model, config);\n if (!model || !model.modelUrl) log('load model failed:', config.face.detector?.modelPath || '');\n else if (config.debug) log('load model:', model.modelUrl);\n return blazeFace;\n}\n", "export const MESH_ANNOTATIONS = {\n silhouette: [\n 10, 338, 297, 332, 284, 251, 389, 356, 454, 323, 361, 288,\n 397, 365, 379, 378, 400, 377, 152, 148, 176, 149, 150, 136,\n 172, 58, 132, 93, 234, 127, 162, 21, 54, 103, 67, 109,\n ],\n lipsUpperOuter: [61, 185, 40, 39, 37, 0, 267, 269, 270, 409, 291],\n lipsLowerOuter: [146, 91, 181, 84, 17, 314, 405, 321, 375, 291],\n lipsUpperInner: [78, 191, 80, 81, 82, 13, 312, 311, 310, 415, 308],\n lipsLowerInner: [78, 95, 88, 178, 87, 14, 317, 402, 318, 324, 308],\n rightEyeUpper0: [246, 161, 160, 159, 158, 157, 173],\n rightEyeLower0: [33, 7, 163, 144, 145, 153, 154, 155, 133],\n rightEyeUpper1: [247, 30, 29, 27, 28, 56, 190],\n rightEyeLower1: [130, 25, 110, 24, 23, 22, 26, 112, 243],\n rightEyeUpper2: [113, 225, 224, 223, 222, 221, 189],\n rightEyeLower2: [226, 31, 228, 229, 230, 231, 232, 233, 244],\n rightEyeLower3: [143, 111, 117, 118, 119, 120, 121, 128, 245],\n rightEyebrowUpper: [156, 70, 63, 105, 66, 107, 55, 193],\n rightEyebrowLower: [35, 124, 46, 53, 52, 65],\n rightEyeIris: [473, 474, 475, 476, 477],\n leftEyeUpper0: [466, 388, 387, 386, 385, 384, 398],\n leftEyeLower0: [263, 249, 390, 373, 374, 380, 381, 382, 362],\n leftEyeUpper1: [467, 260, 259, 257, 258, 286, 414],\n leftEyeLower1: [359, 255, 339, 254, 253, 252, 256, 341, 463],\n leftEyeUpper2: [342, 445, 444, 443, 442, 441, 413],\n leftEyeLower2: [446, 261, 448, 449, 450, 451, 452, 453, 464],\n leftEyeLower3: [372, 340, 346, 347, 348, 349, 350, 357, 465],\n leftEyebrowUpper: [383, 300, 293, 334, 296, 336, 285, 417],\n leftEyebrowLower: [265, 353, 276, 283, 282, 295],\n leftEyeIris: [468, 469, 470, 471, 472],\n midwayBetweenEyes: [168],\n noseTip: [1],\n noseBottom: [2],\n noseRightCorner: [98],\n noseLeftCorner: [327],\n rightCheek: [205],\n leftCheek: [425],\n};\n\nexport const MESH_TO_IRIS_INDICES_MAP = [ // A mapping from facemesh model keypoints to iris model keypoints.\n { key: 'EyeUpper0', indices: [9, 10, 11, 12, 13, 14, 15] },\n { key: 'EyeUpper1', indices: [25, 26, 27, 28, 29, 30, 31] },\n { key: 'EyeUpper2', indices: [41, 42, 43, 44, 45, 46, 47] },\n { key: 'EyeLower0', indices: [0, 1, 2, 3, 4, 5, 6, 7, 8] },\n { key: 'EyeLower1', indices: [16, 17, 18, 19, 20, 21, 22, 23, 24] },\n { key: 'EyeLower2', indices: [32, 33, 34, 35, 36, 37, 38, 39, 40] },\n { key: 'EyeLower3', indices: [54, 55, 56, 57, 58, 59, 60, 61, 62] },\n // { key: 'EyebrowUpper', indices: [63, 64, 65, 66, 67, 68, 69, 70] },\n // { key: 'EyebrowLower', indices: [48, 49, 50, 51, 52, 53] },\n];\n\nexport const UV468 = [\n [0.499976992607117, 0.652534008026123],\n [0.500025987625122, 0.547487020492554],\n [0.499974012374878, 0.602371990680695],\n [0.482113003730774, 0.471979022026062],\n [0.500150978565216, 0.527155995368958],\n [0.499909996986389, 0.498252987861633],\n [0.499523013830185, 0.40106201171875],\n [0.289712011814117, 0.380764007568359],\n [0.499954998493195, 0.312398016452789],\n [0.499987006187439, 0.269918978214264],\n [0.500023007392883, 0.107050001621246],\n [0.500023007392883, 0.666234016418457],\n [0.5000159740448, 0.679224014282227],\n [0.500023007392883, 0.692348003387451],\n [0.499976992607117, 0.695277988910675],\n [0.499976992607117, 0.70593398809433],\n [0.499976992607117, 0.719385027885437],\n [0.499976992607117, 0.737019002437592],\n [0.499967992305756, 0.781370997428894],\n [0.499816000461578, 0.562981009483337],\n [0.473773002624512, 0.573909997940063],\n [0.104906998574734, 0.254140973091125],\n [0.365929991006851, 0.409575998783112],\n [0.338757991790771, 0.41302502155304],\n [0.311120003461838, 0.409460008144379],\n [0.274657994508743, 0.389131009578705],\n [0.393361985683441, 0.403706014156342],\n [0.345234006643295, 0.344011008739471],\n [0.370094001293182, 0.346076011657715],\n [0.319321990013123, 0.347265005111694],\n [0.297903001308441, 0.353591024875641],\n [0.24779200553894, 0.410809993743896],\n [0.396889001131058, 0.842755019664764],\n [0.280097991228104, 0.375599980354309],\n [0.106310002505779, 0.399955987930298],\n [0.2099249958992, 0.391353011131287],\n [0.355807989835739, 0.534406006336212],\n [0.471751004457474, 0.65040397644043],\n [0.474155008792877, 0.680191993713379],\n [0.439785003662109, 0.657229006290436],\n [0.414617002010345, 0.66654098033905],\n [0.450374007225037, 0.680860996246338],\n [0.428770989179611, 0.682690978050232],\n [0.374971002340317, 0.727805018424988],\n [0.486716985702515, 0.547628998756409],\n [0.485300987958908, 0.527395009994507],\n [0.257764995098114, 0.314490020275116],\n [0.401223003864288, 0.455172002315521],\n [0.429818987846375, 0.548614978790283],\n [0.421351999044418, 0.533740997314453],\n [0.276895999908447, 0.532056987285614],\n [0.483370006084442, 0.499586999416351],\n [0.33721199631691, 0.282882988452911],\n [0.296391993761063, 0.293242990970612],\n [0.169294998049736, 0.193813979625702],\n [0.447580009698868, 0.302609980106354],\n [0.392390012741089, 0.353887975215912],\n [0.354490011930466, 0.696784019470215],\n [0.067304998636246, 0.730105042457581],\n [0.442739009857178, 0.572826027870178],\n [0.457098007202148, 0.584792017936707],\n [0.381974011659622, 0.694710969924927],\n [0.392388999462128, 0.694203019142151],\n [0.277076005935669, 0.271932005882263],\n [0.422551989555359, 0.563233017921448],\n [0.385919004678726, 0.281364023685455],\n [0.383103013038635, 0.255840003490448],\n [0.331431001424789, 0.119714021682739],\n [0.229923993349075, 0.232002973556519],\n [0.364500999450684, 0.189113974571228],\n [0.229622006416321, 0.299540996551514],\n [0.173287004232407, 0.278747975826263],\n [0.472878992557526, 0.666198015213013],\n [0.446828007698059, 0.668527007102966],\n [0.422762006521225, 0.673889994621277],\n [0.445307999849319, 0.580065965652466],\n [0.388103008270264, 0.693961024284363],\n [0.403039008378983, 0.706539988517761],\n [0.403629004955292, 0.693953037261963],\n [0.460041999816895, 0.557139039039612],\n [0.431158006191254, 0.692366003990173],\n [0.452181994915009, 0.692366003990173],\n [0.475387006998062, 0.692366003990173],\n [0.465828001499176, 0.779190003871918],\n [0.472328990697861, 0.736225962638855],\n [0.473087012767792, 0.717857003211975],\n [0.473122000694275, 0.704625964164734],\n [0.473033010959625, 0.695277988910675],\n [0.427942007780075, 0.695277988910675],\n [0.426479011774063, 0.703539967536926],\n [0.423162013292313, 0.711845993995667],\n [0.4183090031147, 0.720062971115112],\n [0.390094995498657, 0.639572978019714],\n [0.013953999616206, 0.560034036636353],\n [0.499913990497589, 0.58014702796936],\n [0.413199990987778, 0.69539999961853],\n [0.409626007080078, 0.701822996139526],\n [0.468080013990402, 0.601534962654114],\n [0.422728985548019, 0.585985004901886],\n [0.463079988956451, 0.593783974647522],\n [0.37211999297142, 0.47341400384903],\n [0.334562003612518, 0.496073007583618],\n [0.411671012639999, 0.546965003013611],\n [0.242175996303558, 0.14767599105835],\n [0.290776997804642, 0.201445996761322],\n [0.327338010072708, 0.256527006626129],\n [0.399509996175766, 0.748921036720276],\n [0.441727995872498, 0.261676013469696],\n [0.429764986038208, 0.187834024429321],\n [0.412198007106781, 0.108901023864746],\n [0.288955003023148, 0.398952007293701],\n [0.218936994671822, 0.435410976409912],\n [0.41278201341629, 0.398970007896423],\n [0.257135003805161, 0.355440020561218],\n [0.427684992551804, 0.437960982322693],\n [0.448339998722076, 0.536936044692993],\n [0.178560003638268, 0.45755398273468],\n [0.247308000922203, 0.457193970680237],\n [0.286267012357712, 0.467674970626831],\n [0.332827985286713, 0.460712015628815],\n [0.368755996227264, 0.447206974029541],\n [0.398963987827301, 0.432654976844788],\n [0.476410001516342, 0.405806005001068],\n [0.189241006970406, 0.523923993110657],\n [0.228962004184723, 0.348950982093811],\n [0.490725994110107, 0.562400996685028],\n [0.404670000076294, 0.485132992267609],\n [0.019469000399113, 0.401564002037048],\n [0.426243007183075, 0.420431017875671],\n [0.396993011236191, 0.548797011375427],\n [0.266469985246658, 0.376977026462555],\n [0.439121007919312, 0.51895797252655],\n [0.032313998788595, 0.644356966018677],\n [0.419054001569748, 0.387154996395111],\n [0.462783008813858, 0.505746960639954],\n [0.238978996872902, 0.779744982719421],\n [0.198220998048782, 0.831938028335571],\n [0.107550002634525, 0.540755033493042],\n [0.183610007166862, 0.740257024765015],\n [0.134409993886948, 0.333683013916016],\n [0.385764002799988, 0.883153975009918],\n [0.490967005491257, 0.579378008842468],\n [0.382384985685349, 0.508572995662689],\n [0.174399003386497, 0.397670984268188],\n [0.318785011768341, 0.39623498916626],\n [0.343364000320435, 0.400596976280212],\n [0.396100014448166, 0.710216999053955],\n [0.187885001301765, 0.588537991046906],\n [0.430987000465393, 0.944064974784851],\n [0.318993002176285, 0.898285031318665],\n [0.266247987747192, 0.869701027870178],\n [0.500023007392883, 0.190576016902924],\n [0.499976992607117, 0.954452991485596],\n [0.366169989109039, 0.398822009563446],\n [0.393207013607025, 0.39553701877594],\n [0.410373002290726, 0.391080021858215],\n [0.194993004202843, 0.342101991176605],\n [0.388664990663528, 0.362284004688263],\n [0.365961998701096, 0.355970978736877],\n [0.343364000320435, 0.355356991291046],\n [0.318785011768341, 0.35834002494812],\n [0.301414996385574, 0.363156020641327],\n [0.058132998645306, 0.319076001644135],\n [0.301414996385574, 0.387449026107788],\n [0.499987989664078, 0.618434011936188],\n [0.415838003158569, 0.624195992946625],\n [0.445681989192963, 0.566076993942261],\n [0.465844005346298, 0.620640993118286],\n [0.49992299079895, 0.351523995399475],\n [0.288718998432159, 0.819945991039276],\n [0.335278987884521, 0.852819979190826],\n [0.440512001514435, 0.902418971061707],\n [0.128294005990028, 0.791940987110138],\n [0.408771991729736, 0.373893976211548],\n [0.455606997013092, 0.451801002025604],\n [0.499877005815506, 0.908990025520325],\n [0.375436991453171, 0.924192011356354],\n [0.11421000212431, 0.615022003650665],\n [0.448662012815475, 0.695277988910675],\n [0.4480200111866, 0.704632043838501],\n [0.447111994028091, 0.715808033943176],\n [0.444831997156143, 0.730794012546539],\n [0.430011987686157, 0.766808986663818],\n [0.406787008047104, 0.685672998428345],\n [0.400738000869751, 0.681069016456604],\n [0.392399996519089, 0.677703022956848],\n [0.367855995893478, 0.663918972015381],\n [0.247923001646996, 0.601333022117615],\n [0.452769994735718, 0.420849978923798],\n [0.43639200925827, 0.359887003898621],\n [0.416164010763168, 0.368713974952698],\n [0.413385987281799, 0.692366003990173],\n [0.228018000721931, 0.683571994304657],\n [0.468268007040024, 0.352671027183533],\n [0.411361992359161, 0.804327011108398],\n [0.499989002943039, 0.469825029373169],\n [0.479153990745544, 0.442654013633728],\n [0.499974012374878, 0.439637005329132],\n [0.432112008333206, 0.493588984012604],\n [0.499886006116867, 0.866917014122009],\n [0.49991300702095, 0.821729004383087],\n [0.456548988819122, 0.819200992584229],\n [0.344549000263214, 0.745438992977142],\n [0.37890899181366, 0.574010014533997],\n [0.374292999505997, 0.780184984207153],\n [0.319687992334366, 0.570737957954407],\n [0.357154995203018, 0.604269981384277],\n [0.295284003019333, 0.621580958366394],\n [0.447750002145767, 0.862477004528046],\n [0.410986006259918, 0.508723020553589],\n [0.31395098567009, 0.775308012962341],\n [0.354128003120422, 0.812552988529205],\n [0.324548006057739, 0.703992962837219],\n [0.189096003770828, 0.646299958229065],\n [0.279776990413666, 0.71465802192688],\n [0.1338230073452, 0.682700991630554],\n [0.336768001317978, 0.644733011722565],\n [0.429883986711502, 0.466521978378296],\n [0.455527991056442, 0.548622965812683],\n [0.437114000320435, 0.558896005153656],\n [0.467287987470627, 0.529924988746643],\n [0.414712011814117, 0.335219979286194],\n [0.37704598903656, 0.322777986526489],\n [0.344107985496521, 0.320150971412659],\n [0.312875986099243, 0.32233202457428],\n [0.283526003360748, 0.333190023899078],\n [0.241245999932289, 0.382785975933075],\n [0.102986000478268, 0.468762993812561],\n [0.267612010240555, 0.424560010433197],\n [0.297879010438919, 0.433175981044769],\n [0.333433985710144, 0.433878004550934],\n [0.366427004337311, 0.426115989685059],\n [0.396012008190155, 0.416696012020111],\n [0.420121014118195, 0.41022801399231],\n [0.007561000064015, 0.480777025222778],\n [0.432949006557465, 0.569517970085144],\n [0.458638995885849, 0.479089021682739],\n [0.473466008901596, 0.545744001865387],\n [0.476087987422943, 0.563830018043518],\n [0.468472003936768, 0.555056989192963],\n [0.433990985155106, 0.582361996173859],\n [0.483518004417419, 0.562983989715576],\n [0.482482999563217, 0.57784903049469],\n [0.42645001411438, 0.389798998832703],\n [0.438998997211456, 0.39649498462677],\n [0.450067013502121, 0.400434017181396],\n [0.289712011814117, 0.368252992630005],\n [0.276670008897781, 0.363372981548309],\n [0.517862021923065, 0.471948027610779],\n [0.710287988185883, 0.380764007568359],\n [0.526226997375488, 0.573909997940063],\n [0.895093023777008, 0.254140973091125],\n [0.634069979190826, 0.409575998783112],\n [0.661242008209229, 0.41302502155304],\n [0.688880026340485, 0.409460008144379],\n [0.725341975688934, 0.389131009578705],\n [0.606630027294159, 0.40370500087738],\n [0.654766023159027, 0.344011008739471],\n [0.629905998706818, 0.346076011657715],\n [0.680678009986877, 0.347265005111694],\n [0.702096998691559, 0.353591024875641],\n [0.75221198797226, 0.410804986953735],\n [0.602918028831482, 0.842862963676453],\n [0.719901978969574, 0.375599980354309],\n [0.893692970275879, 0.399959981441498],\n [0.790081977844238, 0.391354024410248],\n [0.643998026847839, 0.534487962722778],\n [0.528249025344849, 0.65040397644043],\n [0.525849997997284, 0.680191040039062],\n [0.560214996337891, 0.657229006290436],\n [0.585384011268616, 0.66654098033905],\n [0.549625992774963, 0.680860996246338],\n [0.57122802734375, 0.682691991329193],\n [0.624852001667023, 0.72809898853302],\n [0.513050019741058, 0.547281980514526],\n [0.51509702205658, 0.527251958847046],\n [0.742246985435486, 0.314507007598877],\n [0.598631024360657, 0.454979002475739],\n [0.570338010787964, 0.548575043678284],\n [0.578631997108459, 0.533622980117798],\n [0.723087012767792, 0.532054007053375],\n [0.516445994377136, 0.499638974666595],\n [0.662801027297974, 0.282917976379395],\n [0.70362401008606, 0.293271005153656],\n [0.830704987049103, 0.193813979625702],\n [0.552385985851288, 0.302568018436432],\n [0.607609987258911, 0.353887975215912],\n [0.645429015159607, 0.696707010269165],\n [0.932694971561432, 0.730105042457581],\n [0.557260990142822, 0.572826027870178],\n [0.542901992797852, 0.584792017936707],\n [0.6180260181427, 0.694710969924927],\n [0.607590973377228, 0.694203019142151],\n [0.722943007946014, 0.271963000297546],\n [0.577413976192474, 0.563166975975037],\n [0.614082992076874, 0.281386971473694],\n [0.616907000541687, 0.255886018276215],\n [0.668509006500244, 0.119913995265961],\n [0.770092010498047, 0.232020974159241],\n [0.635536015033722, 0.189248979091644],\n [0.77039098739624, 0.299556016921997],\n [0.826722025871277, 0.278755009174347],\n [0.527121007442474, 0.666198015213013],\n [0.553171992301941, 0.668527007102966],\n [0.577238023281097, 0.673889994621277],\n [0.554691970348358, 0.580065965652466],\n [0.611896991729736, 0.693961024284363],\n [0.59696102142334, 0.706539988517761],\n [0.596370995044708, 0.693953037261963],\n [0.539958000183105, 0.557139039039612],\n [0.568841993808746, 0.692366003990173],\n [0.547818005084991, 0.692366003990173],\n [0.52461302280426, 0.692366003990173],\n [0.534089982509613, 0.779141008853912],\n [0.527670979499817, 0.736225962638855],\n [0.526912987232208, 0.717857003211975],\n [0.526877999305725, 0.704625964164734],\n [0.526966989040375, 0.695277988910675],\n [0.572058022022247, 0.695277988910675],\n [0.573521018028259, 0.703539967536926],\n [0.57683801651001, 0.711845993995667],\n [0.581691026687622, 0.720062971115112],\n [0.609944999217987, 0.639909982681274],\n [0.986046016216278, 0.560034036636353],\n [0.5867999792099, 0.69539999961853],\n [0.590372025966644, 0.701822996139526],\n [0.531915009021759, 0.601536989212036],\n [0.577268004417419, 0.585934996604919],\n [0.536915004253387, 0.593786001205444],\n [0.627542972564697, 0.473352015018463],\n [0.665585994720459, 0.495950996875763],\n [0.588353991508484, 0.546862006187439],\n [0.757824003696442, 0.14767599105835],\n [0.709249973297119, 0.201507985591888],\n [0.672684013843536, 0.256581008434296],\n [0.600408971309662, 0.74900496006012],\n [0.55826598405838, 0.261672019958496],\n [0.570303976535797, 0.187870979309082],\n [0.588165998458862, 0.109044015407562],\n [0.711045026779175, 0.398952007293701],\n [0.781069993972778, 0.435405015945435],\n [0.587247014045715, 0.398931980133057],\n [0.742869973182678, 0.355445981025696],\n [0.572156012058258, 0.437651991844177],\n [0.55186802148819, 0.536570012569427],\n [0.821442008018494, 0.457556009292603],\n [0.752701997756958, 0.457181990146637],\n [0.71375697851181, 0.467626988887787],\n [0.66711300611496, 0.460672974586487],\n [0.631101012229919, 0.447153985500336],\n [0.6008620262146, 0.432473003864288],\n [0.523481011390686, 0.405627012252808],\n [0.810747981071472, 0.523926019668579],\n [0.771045982837677, 0.348959028720856],\n [0.509127020835876, 0.562718033790588],\n [0.595292985439301, 0.485023975372314],\n [0.980530977249146, 0.401564002037048],\n [0.573499977588654, 0.420000016689301],\n [0.602994978427887, 0.548687994480133],\n [0.733529984951019, 0.376977026462555],\n [0.560611009597778, 0.519016981124878],\n [0.967685997486115, 0.644356966018677],\n [0.580985009670258, 0.387160003185272],\n [0.537728011608124, 0.505385041236877],\n [0.760966002941132, 0.779752969741821],\n [0.801778972148895, 0.831938028335571],\n [0.892440974712372, 0.54076099395752],\n [0.816350996494293, 0.740260004997253],\n [0.865594983100891, 0.333687007427216],\n [0.614073991775513, 0.883246004581451],\n [0.508952975273132, 0.579437971115112],\n [0.617941975593567, 0.508316040039062],\n [0.825608015060425, 0.397674977779388],\n [0.681214988231659, 0.39623498916626],\n [0.656635999679565, 0.400596976280212],\n [0.603900015354156, 0.710216999053955],\n [0.81208598613739, 0.588539004325867],\n [0.56801301240921, 0.944564998149872],\n [0.681007981300354, 0.898285031318665],\n [0.733752012252808, 0.869701027870178],\n [0.633830010890961, 0.398822009563446],\n [0.606792986392975, 0.39553701877594],\n [0.589659988880157, 0.391062021255493],\n [0.805015981197357, 0.342108011245728],\n [0.611334979534149, 0.362284004688263],\n [0.634037971496582, 0.355970978736877],\n [0.656635999679565, 0.355356991291046],\n [0.681214988231659, 0.35834002494812],\n [0.698584973812103, 0.363156020641327],\n [0.941866993904114, 0.319076001644135],\n [0.698584973812103, 0.387449026107788],\n [0.584177017211914, 0.624107003211975],\n [0.554318010807037, 0.566076993942261],\n [0.534153997898102, 0.62064003944397],\n [0.711217999458313, 0.819975018501282],\n [0.664629995822906, 0.852871000766754],\n [0.559099972248077, 0.902631998062134],\n [0.871706008911133, 0.791940987110138],\n [0.591234028339386, 0.373893976211548],\n [0.544341027736664, 0.451583981513977],\n [0.624562978744507, 0.924192011356354],\n [0.88577002286911, 0.615028977394104],\n [0.551338016986847, 0.695277988910675],\n [0.551980018615723, 0.704632043838501],\n [0.552887976169586, 0.715808033943176],\n [0.555167973041534, 0.730794012546539],\n [0.569944024085999, 0.767035007476807],\n [0.593203008174896, 0.685675978660583],\n [0.599261999130249, 0.681069016456604],\n [0.607599973678589, 0.677703022956848],\n [0.631937980651855, 0.663500010967255],\n [0.752032995223999, 0.601315021514893],\n [0.547226011753082, 0.420395016670227],\n [0.563543975353241, 0.359827995300293],\n [0.583841025829315, 0.368713974952698],\n [0.586614012718201, 0.692366003990173],\n [0.771915018558502, 0.683578014373779],\n [0.531597018241882, 0.352482974529266],\n [0.588370978832245, 0.804440975189209],\n [0.52079701423645, 0.442565023899078],\n [0.567984998226166, 0.493479013442993],\n [0.543282985687256, 0.819254994392395],\n [0.655317008495331, 0.745514988899231],\n [0.621008992195129, 0.574018001556396],\n [0.625559985637665, 0.78031200170517],\n [0.680198013782501, 0.570719003677368],\n [0.64276397228241, 0.604337990283966],\n [0.704662978649139, 0.621529996395111],\n [0.552012026309967, 0.862591981887817],\n [0.589071989059448, 0.508637011051178],\n [0.685944974422455, 0.775357007980347],\n [0.645735025405884, 0.812640011310577],\n [0.675342977046967, 0.703978002071381],\n [0.810858011245728, 0.646304965019226],\n [0.72012197971344, 0.714666962623596],\n [0.866151988506317, 0.682704985141754],\n [0.663187026977539, 0.644596993923187],\n [0.570082008838654, 0.466325998306274],\n [0.544561982154846, 0.548375964164734],\n [0.562758982181549, 0.558784961700439],\n [0.531987011432648, 0.530140042304993],\n [0.585271000862122, 0.335177004337311],\n [0.622952997684479, 0.32277899980545],\n [0.655896008014679, 0.320163011550903],\n [0.687132000923157, 0.322345972061157],\n [0.716481983661652, 0.333200991153717],\n [0.758756995201111, 0.382786989212036],\n [0.897013008594513, 0.468769013881683],\n [0.732392013072968, 0.424547016620636],\n [0.70211398601532, 0.433162987232208],\n [0.66652500629425, 0.433866024017334],\n [0.633504986763, 0.426087975502014],\n [0.603875994682312, 0.416586995124817],\n [0.579657971858978, 0.409945011138916],\n [0.992439985275269, 0.480777025222778],\n [0.567192018032074, 0.569419980049133],\n [0.54136598110199, 0.478899002075195],\n [0.526564002037048, 0.546118021011353],\n [0.523913025856018, 0.563830018043518],\n [0.531529009342194, 0.555056989192963],\n [0.566035985946655, 0.582329034805298],\n [0.51631098985672, 0.563053965568542],\n [0.5174720287323, 0.577877044677734],\n [0.573594987392426, 0.389806985855103],\n [0.560697972774506, 0.395331978797913],\n [0.549755990505219, 0.399751007556915],\n [0.710287988185883, 0.368252992630005],\n [0.723330020904541, 0.363372981548309],\n];\n\nexport const TRI468 = [\n 127, 34, 139, 11, 0, 37, 232, 231, 120, 72, 37, 39, 128, 121, 47, 232, 121, 128, 104, 69, 67, 175, 171, 148, 157, 154, 155, 118, 50, 101, 73, 39, 40, 9,\n 151, 108, 48, 115, 131, 194, 204, 211, 74, 40, 185, 80, 42, 183, 40, 92, 186, 230, 229, 118, 202, 212, 214, 83, 18, 17, 76, 61, 146, 160, 29, 30, 56,\n 157, 173, 106, 204, 194, 135, 214, 192, 203, 165, 98, 21, 71, 68, 51, 45, 4, 144, 24, 23, 77, 146, 91, 205, 50, 187, 201, 200, 18, 91, 106, 182, 90, 91,\n 181, 85, 84, 17, 206, 203, 36, 148, 171, 140, 92, 40, 39, 193, 189, 244, 159, 158, 28, 247, 246, 161, 236, 3, 196, 54, 68, 104, 193, 168, 8, 117,\n 228, 31, 189, 193, 55, 98, 97, 99, 126, 47, 100, 166, 79, 218, 155, 154, 26, 209, 49, 131, 135, 136, 150, 47, 126, 217, 223, 52, 53, 45, 51, 134, 211,\n 170, 140, 67, 69, 108, 43, 106, 91, 230, 119, 120, 226, 130, 247, 63, 53, 52, 238, 20, 242, 46, 70, 156, 78, 62, 96, 46, 53, 63, 143, 34, 227, 173,\n 155, 133, 123, 117, 111, 44, 125, 19, 236, 134, 51, 216, 206, 205, 154, 153, 22, 39, 37, 167, 200, 201, 208, 36, 142, 100, 57, 212, 202, 20, 60, 99, 28,\n 158, 157, 35, 226, 113, 160, 159, 27, 204, 202, 210, 113, 225, 46, 43, 202, 204, 62, 76, 77, 137, 123, 116, 41, 38, 72, 203, 129, 142, 64, 98, 240, 49,\n 102, 64, 41, 73, 74, 212, 216, 207, 42, 74, 184, 169, 170, 211, 170, 149, 176, 105, 66, 69, 122, 6, 168, 123, 147, 187, 96, 77, 90, 65, 55, 107, 89,\n 90, 180, 101, 100, 120, 63, 105, 104, 93, 137, 227, 15, 86, 85, 129, 102, 49, 14, 87, 86, 55, 8, 9, 100, 47, 121, 145, 23, 22, 88, 89, 179, 6, 122,\n 196, 88, 95, 96, 138, 172, 136, 215, 58, 172, 115, 48, 219, 42, 80, 81, 195, 3, 51, 43, 146, 61, 171, 175, 199, 81, 82, 38, 53, 46, 225, 144, 163, 110,\n 246, 33, 7, 52, 65, 66, 229, 228, 117, 34, 127, 234, 107, 108, 69, 109, 108, 151, 48, 64, 235, 62, 78, 191, 129, 209, 126, 111, 35, 143, 163, 161, 246,\n 117, 123, 50, 222, 65, 52, 19, 125, 141, 221, 55, 65, 3, 195, 197, 25, 7, 33, 220, 237, 44, 70, 71, 139, 122, 193, 245, 247, 130, 33, 71, 21, 162,\n 153, 158, 159, 170, 169, 150, 188, 174, 196, 216, 186, 92, 144, 160, 161, 2, 97, 167, 141, 125, 241, 164, 167, 37, 72, 38, 12, 145, 159, 160, 38, 82, 13,\n 63, 68, 71, 226, 35, 111, 158, 153, 154, 101, 50, 205, 206, 92, 165, 209, 198, 217, 165, 167, 97, 220, 115, 218, 133, 112, 243, 239, 238, 241, 214,\n 135, 169, 190, 173, 133, 171, 208, 32, 125, 44, 237, 86, 87, 178, 85, 86, 179, 84, 85, 180, 83, 84, 181, 201, 83, 182, 137, 93, 132, 76, 62, 183, 61,\n 76, 184, 57, 61, 185, 212, 57, 186, 214, 207, 187, 34, 143, 156, 79, 239, 237, 123, 137, 177, 44, 1, 4, 201, 194, 32, 64, 102, 129, 213, 215, 138, 59,\n 166, 219, 242, 99, 97, 2, 94, 141, 75, 59, 235, 24, 110, 228, 25, 130, 226, 23, 24, 229, 22, 23, 230, 26, 22, 231, 112, 26, 232, 189, 190, 243, 221, 56,\n 190, 28, 56, 221, 27, 28, 222, 29, 27, 223, 30, 29, 224, 247, 30, 225, 238, 79, 20, 166, 59, 75, 60, 75, 240, 147, 177, 215, 20, 79, 166, 187, 147, 213,\n 112, 233, 244, 233, 128, 245, 128, 114, 188, 114, 217, 174, 131, 115, 220, 217, 198, 236, 198, 131, 134, 177, 132, 58, 143, 35, 124, 110, 163, 7, 228,\n 110, 25, 356, 389, 368, 11, 302, 267, 452, 350, 349, 302, 303, 269, 357, 343, 277, 452, 453, 357, 333, 332, 297, 175, 152, 377, 384, 398, 382, 347,\n 348, 330, 303, 304, 270, 9, 336, 337, 278, 279, 360, 418, 262, 431, 304, 408, 409, 310, 415, 407, 270, 409, 410, 450, 348, 347, 422, 430, 434, 313,\n 314, 17, 306, 307, 375, 387, 388, 260, 286, 414, 398, 335, 406, 418, 364, 367, 416, 423, 358, 327, 251, 284, 298, 281, 5, 4, 373, 374, 253, 307, 320,\n 321, 425, 427, 411, 421, 313, 18, 321, 405, 406, 320, 404, 405, 315, 16, 17, 426, 425, 266, 377, 400, 369, 322, 391, 269, 417, 465, 464, 386, 257, 258,\n 466, 260, 388, 456, 399, 419, 284, 332, 333, 417, 285, 8, 346, 340, 261, 413, 441, 285, 327, 460, 328, 355, 371, 329, 392, 439, 438, 382, 341, 256,\n 429, 420, 360, 364, 394, 379, 277, 343, 437, 443, 444, 283, 275, 440, 363, 431, 262, 369, 297, 338, 337, 273, 375, 321, 450, 451, 349, 446, 342, 467,\n 293, 334, 282, 458, 461, 462, 276, 353, 383, 308, 324, 325, 276, 300, 293, 372, 345, 447, 382, 398, 362, 352, 345, 340, 274, 1, 19, 456, 248, 281, 436,\n 427, 425, 381, 256, 252, 269, 391, 393, 200, 199, 428, 266, 330, 329, 287, 273, 422, 250, 462, 328, 258, 286, 384, 265, 353, 342, 387, 259, 257, 424,\n 431, 430, 342, 353, 276, 273, 335, 424, 292, 325, 307, 366, 447, 345, 271, 303, 302, 423, 266, 371, 294, 455, 460, 279, 278, 294, 271, 272, 304, 432,\n 434, 427, 272, 407, 408, 394, 430, 431, 395, 369, 400, 334, 333, 299, 351, 417, 168, 352, 280, 411, 325, 319, 320, 295, 296, 336, 319, 403, 404, 330,\n 348, 349, 293, 298, 333, 323, 454, 447, 15, 16, 315, 358, 429, 279, 14, 15, 316, 285, 336, 9, 329, 349, 350, 374, 380, 252, 318, 402, 403, 6, 197, 419,\n 318, 319, 325, 367, 364, 365, 435, 367, 397, 344, 438, 439, 272, 271, 311, 195, 5, 281, 273, 287, 291, 396, 428, 199, 311, 271, 268, 283, 444, 445,\n 373, 254, 339, 263, 466, 249, 282, 334, 296, 449, 347, 346, 264, 447, 454, 336, 296, 299, 338, 10, 151, 278, 439, 455, 292, 407, 415, 358, 371, 355,\n 340, 345, 372, 390, 249, 466, 346, 347, 280, 442, 443, 282, 19, 94, 370, 441, 442, 295, 248, 419, 197, 263, 255, 359, 440, 275, 274, 300, 383, 368,\n 351, 412, 465, 263, 467, 466, 301, 368, 389, 380, 374, 386, 395, 378, 379, 412, 351, 419, 436, 426, 322, 373, 390, 388, 2, 164, 393, 370, 462, 461,\n 164, 0, 267, 302, 11, 12, 374, 373, 387, 268, 12, 13, 293, 300, 301, 446, 261, 340, 385, 384, 381, 330, 266, 425, 426, 423, 391, 429, 355, 437, 391,\n 327, 326, 440, 457, 438, 341, 382, 362, 459, 457, 461, 434, 430, 394, 414, 463, 362, 396, 369, 262, 354, 461, 457, 316, 403, 402, 315, 404, 403, 314,\n 405, 404, 313, 406, 405, 421, 418, 406, 366, 401, 361, 306, 408, 407, 291, 409, 408, 287, 410, 409, 432, 436, 410, 434, 416, 411, 264, 368, 383, 309,\n 438, 457, 352, 376, 401, 274, 275, 4, 421, 428, 262, 294, 327, 358, 433, 416, 367, 289, 455, 439, 462, 370, 326, 2, 326, 370, 305, 460, 455, 254,\n 449, 448, 255, 261, 446, 253, 450, 449, 252, 451, 450, 256, 452, 451, 341, 453, 452, 413, 464, 463, 441, 413, 414, 258, 442, 441, 257, 443, 442, 259,\n 444, 443, 260, 445, 444, 467, 342, 445, 459, 458, 250, 289, 392, 290, 290, 328, 460, 376, 433, 435, 250, 290, 392, 411, 416, 433, 341, 463, 464, 453,\n 464, 465, 357, 465, 412, 343, 412, 399, 360, 363, 440, 437, 399, 456, 420, 456, 363, 401, 435, 288, 372, 383, 353, 339, 255, 249, 448, 261, 255, 133,\n 243, 190, 133, 155, 112, 33, 246, 247, 33, 130, 25, 398, 384, 286, 362, 398, 414, 362, 463, 341, 263, 359, 467, 263, 249, 255, 466, 467, 260, 75, 60,\n 166, 238, 239, 79, 162, 127, 139, 72, 11, 37, 121, 232, 120, 73, 72, 39, 114, 128, 47, 233, 232, 128, 103, 104, 67, 152, 175, 148, 173, 157, 155,\n 119, 118, 101, 74, 73, 40, 107, 9, 108, 49, 48, 131, 32, 194, 211, 184, 74, 185, 191, 80, 183, 185, 40, 186, 119, 230, 118, 210, 202, 214, 84, 83, 17,\n 77, 76, 146, 161, 160, 30, 190, 56, 173, 182, 106, 194, 138, 135, 192, 129, 203, 98, 54, 21, 68, 5, 51, 4, 145, 144, 23, 90, 77, 91, 207, 205, 187, 83,\n 201, 18, 181, 91, 182, 180, 90, 181, 16, 85, 17, 205, 206, 36, 176, 148, 140, 165, 92, 39, 245, 193, 244, 27, 159, 28, 30, 247, 161, 174, 236, 196,\n 103, 54, 104, 55, 193, 8, 111, 117, 31, 221, 189, 55, 240, 98, 99, 142, 126, 100, 219, 166, 218, 112, 155, 26, 198, 209, 131, 169, 135, 150, 114, 47,\n 217, 224, 223, 53, 220, 45, 134, 32, 211, 140, 109, 67, 108, 146, 43, 91, 231, 230, 120, 113, 226, 247, 105, 63, 52, 241, 238, 242, 124, 46, 156, 95,\n 78, 96, 70, 46, 63, 116, 143, 227, 116, 123, 111, 1, 44, 19, 3, 236, 51, 207, 216, 205, 26, 154, 22, 165, 39, 167, 199, 200, 208, 101, 36, 100, 43,\n 57, 202, 242, 20, 99, 56, 28, 157, 124, 35, 113, 29, 160, 27, 211, 204, 210, 124, 113, 46, 106, 43, 204, 96, 62, 77, 227, 137, 116, 73, 41, 72, 36, 203,\n 142, 235, 64, 240, 48, 49, 64, 42, 41, 74, 214, 212, 207, 183, 42, 184, 210, 169, 211, 140, 170, 176, 104, 105, 69, 193, 122, 168, 50, 123, 187, 89, 96,\n 90, 66, 65, 107, 179, 89, 180, 119, 101, 120, 68, 63, 104, 234, 93, 227, 16, 15, 85, 209, 129, 49, 15, 14, 86, 107, 55, 9, 120, 100, 121, 153, 145, 22,\n 178, 88, 179, 197, 6, 196, 89, 88, 96, 135, 138, 136, 138, 215, 172, 218, 115, 219, 41, 42, 81, 5, 195, 51, 57, 43, 61, 208, 171, 199, 41, 81, 38,\n 224, 53, 225, 24, 144, 110, 105, 52, 66, 118, 229, 117, 227, 34, 234, 66, 107, 69, 10, 109, 151, 219, 48, 235, 183, 62, 191, 142, 129, 126, 116, 111,\n 143, 7, 163, 246, 118, 117, 50, 223, 222, 52, 94, 19, 141, 222, 221, 65, 196, 3, 197, 45, 220, 44, 156, 70, 139, 188, 122, 245, 139, 71, 162, 145,\n 153, 159, 149, 170, 150, 122, 188, 196, 206, 216, 92, 163, 144, 161, 164, 2, 167, 242, 141, 241, 0, 164, 37, 11, 72, 12, 144, 145, 160, 12, 38, 13, 70,\n 63, 71, 31, 226, 111, 157, 158, 154, 36, 101, 205, 203, 206, 165, 126, 209, 217, 98, 165, 97, 237, 220, 218, 237, 239, 241, 210, 214, 169, 140, 171, 32,\n 241, 125, 237, 179, 86, 178, 180, 85, 179, 181, 84, 180, 182, 83, 181, 194, 201, 182, 177, 137, 132, 184, 76, 183, 185, 61, 184, 186, 57, 185, 216, 212,\n 186, 192, 214, 187, 139, 34, 156, 218, 79, 237, 147, 123, 177, 45, 44, 4, 208, 201, 32, 98, 64, 129, 192, 213, 138, 235, 59, 219, 141, 242, 97, 97, 2,\n 141, 240, 75, 235, 229, 24, 228, 31, 25, 226, 230, 23, 229, 231, 22, 230, 232, 26, 231, 233, 112, 232, 244, 189, 243, 189, 221, 190, 222, 28, 221,\n 223, 27, 222, 224, 29, 223, 225, 30, 224, 113, 247, 225, 99, 60, 240, 213, 147, 215, 60, 20, 166, 192, 187, 213, 243, 112, 244, 244, 233, 245, 245,\n 128, 188, 188, 114, 174, 134, 131, 220, 174, 217, 236, 236, 198, 134, 215, 177, 58, 156, 143, 124, 25, 110, 7, 31, 228, 25, 264, 356, 368, 0, 11, 267,\n 451, 452, 349, 267, 302, 269, 350, 357, 277, 350, 452, 357, 299, 333, 297, 396, 175, 377, 381, 384, 382, 280, 347, 330, 269, 303, 270, 151, 9, 337,\n 344, 278, 360, 424, 418, 431, 270, 304, 409, 272, 310, 407, 322, 270, 410, 449, 450, 347, 432, 422, 434, 18, 313, 17, 291, 306, 375, 259, 387, 260,\n 424, 335, 418, 434, 364, 416, 391, 423, 327, 301, 251, 298, 275, 281, 4, 254, 373, 253, 375, 307, 321, 280, 425, 411, 200, 421, 18, 335, 321, 406,\n 321, 320, 405, 314, 315, 17, 423, 426, 266, 396, 377, 369, 270, 322, 269, 413, 417, 464, 385, 386, 258, 248, 456, 419, 298, 284, 333, 168, 417, 8,\n 448, 346, 261, 417, 413, 285, 326, 327, 328, 277, 355, 329, 309, 392, 438, 381, 382, 256, 279, 429, 360, 365, 364, 379, 355, 277, 437, 282, 443, 283,\n 281, 275, 363, 395, 431, 369, 299, 297, 337, 335, 273, 321, 348, 450, 349, 359, 446, 467, 283, 293, 282, 250, 458, 462, 300, 276, 383, 292, 308, 325,\n 283, 276, 293, 264, 372, 447, 346, 352, 340, 354, 274, 19, 363, 456, 281, 426, 436, 425, 380, 381, 252, 267, 269, 393, 421, 200, 428, 371, 266, 329,\n 432, 287, 422, 290, 250, 328, 385, 258, 384, 446, 265, 342, 386, 387, 257, 422, 424, 430, 445, 342, 276, 422, 273, 424, 306, 292, 307, 352, 366, 345,\n 268, 271, 302, 358, 423, 371, 327, 294, 460, 331, 279, 294, 303, 271, 304, 436, 432, 427, 304, 272, 408, 395, 394, 431, 378, 395, 400, 296, 334, 299,\n 6, 351, 168, 376, 352, 411, 307, 325, 320, 285, 295, 336, 320, 319, 404, 329, 330, 349, 334, 293, 333, 366, 323, 447, 316, 15, 315, 331, 358, 279,\n 317, 14, 316, 8, 285, 9, 277, 329, 350, 253, 374, 252, 319, 318, 403, 351, 6, 419, 324, 318, 325, 397, 367, 365, 288, 435, 397, 278, 344, 439, 310,\n 272, 311, 248, 195, 281, 375, 273, 291, 175, 396, 199, 312, 311, 268, 276, 283, 445, 390, 373, 339, 295, 282, 296, 448, 449, 346, 356, 264, 454, 337,\n 336, 299, 337, 338, 151, 294, 278, 455, 308, 292, 415, 429, 358, 355, 265, 340, 372, 388, 390, 466, 352, 346, 280, 295, 442, 282, 354, 19, 370, 285,\n 441, 295, 195, 248, 197, 457, 440, 274, 301, 300, 368, 417, 351, 465, 251, 301, 389, 385, 380, 386, 394, 395, 379, 399, 412, 419, 410, 436, 322, 387,\n 373, 388, 326, 2, 393, 354, 370, 461, 393, 164, 267, 268, 302, 12, 386, 374, 387, 312, 268, 13, 298, 293, 301, 265, 446, 340, 380, 385, 381, 280, 330,\n 425, 322, 426, 391, 420, 429, 437, 393, 391, 326, 344, 440, 438, 458, 459, 461, 364, 434, 394, 428, 396, 262, 274, 354, 457, 317, 316, 402, 316, 315,\n 403, 315, 314, 404, 314, 313, 405, 313, 421, 406, 323, 366, 361, 292, 306, 407, 306, 291, 408, 291, 287, 409, 287, 432, 410, 427, 434, 411, 372, 264,\n 383, 459, 309, 457, 366, 352, 401, 1, 274, 4, 418, 421, 262, 331, 294, 358, 435, 433, 367, 392, 289, 439, 328, 462, 326, 94, 2, 370, 289, 305, 455, 339,\n 254, 448, 359, 255, 446, 254, 253, 449, 253, 252, 450, 252, 256, 451, 256, 341, 452, 414, 413, 463, 286, 441, 414, 286, 258, 441, 258, 257, 442, 257,\n 259, 443, 259, 260, 444, 260, 467, 445, 309, 459, 250, 305, 289, 290, 305, 290, 460, 401, 376, 435, 309, 250, 392, 376, 411, 433, 453, 341, 464, 357,\n 453, 465, 343, 357, 412, 437, 343, 399, 344, 360, 440, 420, 437, 456, 360, 420, 363, 361, 401, 288, 265, 372, 353, 390, 339, 249, 339, 448, 255];\n\nexport const TRI68 = [0, 1, 36, 0, 36, 17, 1, 2, 41, 1, 41, 36, 2, 3, 31, 2, 31, 41, 3, 4, 48, 3, 48, 31, 4, 5, 48, 5, 6, 48, 6, 7, 59, 6, 59, 48, 7, 8, 58, 7, 58, 59,\n 8, 9, 56, 8, 56, 57, 8, 57, 58, 9, 10, 55, 9, 55, 56, 10, 11, 54, 10, 54, 55, 11, 12, 54, 12, 13, 54, 13, 14, 35, 13, 35, 54, 14, 15, 46, 14, 46, 35, 15, 16,\n 45, 15, 45, 46, 16, 26, 45, 17, 36, 18, 18, 37, 19, 18, 36, 37, 19, 38, 20, 19, 37, 38, 20, 39, 21, 20, 38, 39, 21, 39, 27, 22, 42, 23, 22, 27, 42, 23, 43, 24,\n 23, 42, 43, 24, 44, 25, 24, 43, 44, 25, 45, 26, 25, 44, 45, 27, 39, 28, 27, 28, 42, 28, 39, 29, 28, 29, 42, 29, 31, 30, 29, 30, 35, 29, 40, 31, 29, 35, 47, 29,\n 39, 40, 29, 47, 42, 30, 31, 32, 30, 32, 33, 30, 33, 34, 30, 34, 35, 31, 50, 32, 31, 40, 41, 31, 48, 49, 31, 49, 50, 32, 51, 33, 32, 50, 51, 33, 51, 34, 34, 52,\n 35, 34, 51, 52, 35, 46, 47, 35, 52, 53, 35, 53, 54, 36, 41, 37, 37, 40, 38, 37, 41, 40, 38, 40, 39, 42, 47, 43, 43, 47, 44, 44, 46, 45, 44, 47, 46, 48, 60, 49,\n 48, 59, 60, 49, 61, 50, 49, 60, 61, 50, 62, 51, 50, 61, 62, 51, 62, 52, 52, 63, 53, 52, 62, 63, 53, 64, 54, 53, 63, 64, 54, 64, 55, 55, 65, 56, 55, 64, 65, 56,\n 66, 57, 56, 65, 66, 57, 66, 58, 58, 67, 59, 58, 66, 67, 59, 67, 60, 60, 67, 61, 61, 66, 62, 61, 67, 66, 62, 66, 63, 63, 65, 64, 63, 66, 65, 21, 27, 22];\n\nexport const TRI33 = [\n /* eyes */ 0, 8, 7, 7, 8, 1, 2, 10, 9, 9, 10, 3,\n /* brows */ 17, 0, 18, 18, 0, 7, 18, 7, 19, 19, 7, 1, 19, 1, 11, 19, 11, 20, 21, 3, 22, 21, 9, 3, 20, 9, 21, 20, 2, 9, 20, 11, 2,\n /* 4head */ 23, 17, 18, 25, 21, 22, 24, 19, 20, 24, 18, 19, 24, 20, 21, 24, 23, 18, 24, 21, 25,\n /* nose */ 11, 12, 4, 11, 4, 13, 1, 12, 11, 11, 13, 2, 12, 14, 4, 4, 14, 13,\n /* up-lip */ 14, 5, 15, 14, 15, 6, 12, 5, 14, 14, 6, 13,\n /* cheeks */ 8, 12, 1, 2, 13, 10, 8, 26, 12, 10, 13, 27, 26, 5, 12, 13, 6, 27, 0, 26, 8, 10, 27, 3,\n /* chin */ 5, 32, 16, 16, 32, 6, 5, 30, 32, 6, 32, 31,\n /* cont */ 26, 30, 5, 27, 6, 31, 0, 28, 26, 3, 27, 29, 17, 28, 0, 3, 29, 22, 23, 28, 17, 22, 29, 25, 28, 30, 26, 27, 31, 29,\n];\n\nexport const TRI7 = [0, 4, 1, 2, 4, 3, 4, 5, 6];\n\nexport const VTX68 = [\n /* cont */ 127, 234, 132, 58, 172, 150, 149, 148, 152, 377, 378, 379, 397, 288, 361, 454, 356,\n /* brows */ 70, 63, 105, 66, 107, 336, 296, 334, 293, 300,\n /* nose */ 168, 6, 195, 4, 98, 97, 2, 326, 327,\n /* eyes */ 33, 160, 158, 133, 153, 144, 362, 385, 387, 263, 373, 380,\n /* lip */ 57, 40, 37, 0, 267, 270, 287, 321, 314, 17, 84, 91,\n /* mouth */ 78, 81, 13, 311, 308, 402, 14, 178,\n];\n\nexport const VTX33 = [33, 133, 362, 263, 1, 62, 308, 159, 145, 386, 374, 6, 102, 331, 2, 13, 14, 70, 105, 107, 336, 334, 300, 54, 10, 284, 50, 280, 234, 454, 58, 288, 152];\n\nexport const VTX7 = [33, 133, 362, 263, 1, 78, 308];\n\nexport const UV68 = VTX68.map((x) => UV468[x]);\n\nexport const UV33 = VTX33.map((x) => UV468[x]);\n\nexport const UV7 = VTX7.map((x) => UV468[x]);\n", "/*\nWebGLImageFilter by Dominic Szablewski: \n*/\n\n// @ts-nocheck\n\nfunction GLProgram(gl, vertexSource, fragmentSource) {\n const _collect = function (source, prefix, collection) {\n const r = new RegExp('\\\\b' + prefix + ' \\\\w+ (\\\\w+)', 'ig');\n source.replace(r, (match, name) => {\n collection[name] = 0;\n return match;\n });\n };\n\n const _compile = function (source, type) {\n const shader = gl.createShader(type);\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw new Error('filter: gl compile failed', gl.getShaderInfoLog(shader));\n return shader;\n };\n\n this.uniform = {};\n this.attribute = {};\n const _vsh = _compile(vertexSource, gl.VERTEX_SHADER);\n const _fsh = _compile(fragmentSource, gl.FRAGMENT_SHADER);\n this.id = gl.createProgram();\n gl.attachShader(this.id, _vsh);\n gl.attachShader(this.id, _fsh);\n gl.linkProgram(this.id);\n\n if (!gl.getProgramParameter(this.id, gl.LINK_STATUS)) throw new Error('filter: gl link failed', gl.getProgramInfoLog(this.id));\n\n gl.useProgram(this.id);\n // Collect attributes\n _collect(vertexSource, 'attribute', this.attribute);\n for (const a in this.attribute) this.attribute[a] = gl.getAttribLocation(this.id, a);\n // Collect uniforms\n _collect(vertexSource, 'uniform', this.uniform);\n _collect(fragmentSource, 'uniform', this.uniform);\n for (const u in this.uniform) this.uniform[u] = gl.getUniformLocation(this.id, u);\n}\n\n// export const GLImageFilter = function (params) {\nexport function GLImageFilter(params) {\n if (!params) params = { };\n let _drawCount = 0;\n let _sourceTexture = null;\n let _lastInChain = false;\n let _currentFramebufferIndex = -1;\n let _tempFramebuffers = [null, null];\n let _filterChain = [];\n let _width = -1;\n let _height = -1;\n let _vertexBuffer = null;\n let _currentProgram = null;\n const _filter = {};\n const _canvas = params.canvas || document.createElement('canvas');\n // key is the shader program source, value is the compiled program\n const _shaderProgramCache = { };\n const DRAW = { INTERMEDIATE: 1 };\n const gl = _canvas.getContext('webgl');\n if (!gl) throw new Error('filter: context failed');\n\n this.addFilter = function (name) {\n // eslint-disable-next-line prefer-rest-params\n const args = Array.prototype.slice.call(arguments, 1);\n const filter = _filter[name];\n _filterChain.push({ func: filter, args });\n };\n\n this.reset = function () {\n _filterChain = [];\n };\n\n const _resize = function (width, height) {\n // Same width/height? Nothing to do here\n if (width === _width && height === _height) { return; }\n _canvas.width = width;\n _width = width;\n _canvas.height = height;\n _height = height;\n // Create the context if we don't have it yet\n if (!_vertexBuffer) {\n // Create the vertex buffer for the two triangles [x, y, u, v] * 6\n const vertices = new Float32Array([\n -1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0,\n -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0,\n ]);\n // eslint-disable-next-line no-unused-expressions\n (_vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer));\n gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);\n gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);\n }\n gl.viewport(0, 0, _width, _height);\n // Delete old temp framebuffers\n _tempFramebuffers = [null, null];\n };\n\n const _createFramebufferTexture = function (width, height) {\n const fbo = gl.createFramebuffer();\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n const renderbuffer = gl.createRenderbuffer();\n gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);\n const texture = gl.createTexture();\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);\n gl.bindTexture(gl.TEXTURE_2D, null);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n return { fbo, texture };\n };\n\n const _getTempFramebuffer = function (index) {\n _tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);\n return _tempFramebuffers[index];\n };\n\n const _draw = function (flags = null) {\n let source = null;\n let target = null;\n let flipY = false;\n // Set up the source\n if (_drawCount === 0) {\n // First draw call - use the source texture\n source = _sourceTexture;\n } else {\n // All following draw calls use the temp buffer last drawn to\n source = _getTempFramebuffer(_currentFramebufferIndex)?.texture;\n }\n _drawCount++;\n // Set up the target\n if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {\n // Last filter in our chain - draw directly to the WebGL Canvas. We may\n // also have to flip the image vertically now\n target = null;\n flipY = _drawCount % 2 === 0;\n } else {\n // Intermediate draw call - get a temp buffer to draw to\n _currentFramebufferIndex = (_currentFramebufferIndex + 1) % 2;\n target = _getTempFramebuffer(_currentFramebufferIndex)?.fbo;\n }\n // Bind the source and target and draw the two triangles\n gl.bindTexture(gl.TEXTURE_2D, source);\n gl.bindFramebuffer(gl.FRAMEBUFFER, target);\n gl.uniform1f(_currentProgram.uniform.flipY, (flipY ? -1 : 1));\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n };\n\n this.apply = function (image) {\n _resize(image.width, image.height);\n _drawCount = 0;\n // Create the texture for the input image if we haven't yet\n if (!_sourceTexture) _sourceTexture = gl.createTexture();\n gl.bindTexture(gl.TEXTURE_2D, _sourceTexture);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);\n // No filters? Just draw\n if (_filterChain.length === 0) {\n // const program = _compileShader(SHADER.FRAGMENT_IDENTITY);\n _draw();\n return _canvas;\n }\n for (let i = 0; i < _filterChain.length; i++) {\n _lastInChain = (i === _filterChain.length - 1);\n const f = _filterChain[i];\n f.func.apply(this, f.args || []);\n }\n return _canvas;\n };\n\n const _compileShader = function (fragmentSource) {\n if (_shaderProgramCache[fragmentSource]) {\n _currentProgram = _shaderProgramCache[fragmentSource];\n gl.useProgram(_currentProgram.id);\n return _currentProgram;\n }\n // Compile shaders\n const SHADER = {};\n SHADER.VERTEX_IDENTITY = [\n 'precision highp float;',\n 'attribute vec2 pos;',\n 'attribute vec2 uv;',\n 'varying vec2 vUv;',\n 'uniform float flipY;',\n 'void main(void) {',\n 'vUv = uv;',\n 'gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);',\n '}',\n ].join('\\n');\n SHADER.FRAGMENT_IDENTITY = [\n 'precision highp float;',\n 'varying vec2 vUv;',\n 'uniform sampler2D texture;',\n 'void main(void) {',\n 'gl_FragColor = texture2D(texture, vUv);',\n '}',\n ].join('\\n');\n _currentProgram = new GLProgram(gl, SHADER.VERTEX_IDENTITY, fragmentSource);\n const floatSize = Float32Array.BYTES_PER_ELEMENT;\n const vertSize = 4 * floatSize;\n gl.enableVertexAttribArray(_currentProgram.attribute.pos);\n gl.vertexAttribPointer(_currentProgram.attribute.pos, 2, gl.FLOAT, false, vertSize, 0 * floatSize);\n gl.enableVertexAttribArray(_currentProgram.attribute.uv);\n gl.vertexAttribPointer(_currentProgram.attribute.uv, 2, gl.FLOAT, false, vertSize, 2 * floatSize);\n _shaderProgramCache[fragmentSource] = _currentProgram;\n return _currentProgram;\n };\n\n // -------------------------------------------------------------------------\n // Color Matrix Filter\n _filter.colorMatrix = function (matrix) {\n // Create a Float32 Array and normalize the offset component to 0-1\n const m = new Float32Array(matrix);\n m[4] /= 255;\n m[9] /= 255;\n m[14] /= 255;\n m[19] /= 255;\n // Can we ignore the alpha value? Makes things a bit faster.\n const shader = (m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0)\n ? _filter.colorMatrix.SHADER.WITHOUT_ALPHA\n : _filter.colorMatrix.SHADER.WITH_ALPHA;\n const program = _compileShader(shader);\n gl.uniform1fv(program.uniform.m, m);\n _draw();\n };\n _filter.colorMatrix.SHADER = {};\n _filter.colorMatrix.SHADER.WITH_ALPHA = [\n 'precision highp float;',\n 'varying vec2 vUv;',\n 'uniform sampler2D texture;',\n 'uniform float m[20];',\n 'void main(void) {',\n 'vec4 c = texture2D(texture, vUv);',\n 'gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];',\n 'gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];',\n 'gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];',\n 'gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];',\n '}',\n ].join('\\n');\n _filter.colorMatrix.SHADER.WITHOUT_ALPHA = [\n 'precision highp float;',\n 'varying vec2 vUv;',\n 'uniform sampler2D texture;',\n 'uniform float m[20];',\n 'void main(void) {',\n 'vec4 c = texture2D(texture, vUv);',\n 'gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];',\n 'gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];',\n 'gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];',\n 'gl_FragColor.a = c.a;',\n '}',\n ].join('\\n');\n\n _filter.brightness = function (brightness) {\n const b = (brightness || 0) + 1;\n _filter.colorMatrix([\n b, 0, 0, 0, 0,\n 0, b, 0, 0, 0,\n 0, 0, b, 0, 0,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.saturation = function (amount) {\n const x = (amount || 0) * 2 / 3 + 1;\n const y = ((x - 1) * -0.5);\n _filter.colorMatrix([\n x, y, y, 0, 0,\n y, x, y, 0, 0,\n y, y, x, 0, 0,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.desaturate = function () {\n _filter.saturation(-1);\n };\n\n _filter.contrast = function (amount) {\n const v = (amount || 0) + 1;\n const o = -128 * (v - 1);\n\n _filter.colorMatrix([\n v, 0, 0, 0, o,\n 0, v, 0, 0, o,\n 0, 0, v, 0, o,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.negative = function () {\n _filter.contrast(-2);\n };\n\n _filter.hue = function (rotation) {\n rotation = (rotation || 0) / 180 * Math.PI;\n const cos = Math.cos(rotation);\n const sin = Math.sin(rotation);\n const lumR = 0.213;\n const lumG = 0.715;\n const lumB = 0.072;\n\n _filter.colorMatrix([\n lumR + cos * (1 - lumR) + sin * (-lumR), lumG + cos * (-lumG) + sin * (-lumG), lumB + cos * (-lumB) + sin * (1 - lumB), 0, 0,\n lumR + cos * (-lumR) + sin * (0.143), lumG + cos * (1 - lumG) + sin * (0.140), lumB + cos * (-lumB) + sin * (-0.283), 0, 0,\n lumR + cos * (-lumR) + sin * (-(1 - lumR)), lumG + cos * (-lumG) + sin * (lumG), lumB + cos * (1 - lumB) + sin * (lumB), 0, 0,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.desaturateLuminance = function () {\n _filter.colorMatrix([\n 0.2764723, 0.9297080, 0.0938197, 0, -37.1,\n 0.2764723, 0.9297080, 0.0938197, 0, -37.1,\n 0.2764723, 0.9297080, 0.0938197, 0, -37.1,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.sepia = function () {\n _filter.colorMatrix([\n 0.393, 0.7689999, 0.18899999, 0, 0,\n 0.349, 0.6859999, 0.16799999, 0, 0,\n 0.272, 0.5339999, 0.13099999, 0, 0,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.brownie = function () {\n _filter.colorMatrix([\n 0.5997023498159715, 0.34553243048391263, -0.2708298674538042, 0, 47.43192855600873,\n -0.037703249837783157, 0.8609577587992641, 0.15059552388459913, 0, -36.96841498319127,\n 0.24113635128153335, -0.07441037908422492, 0.44972182064877153, 0, -7.562075277591283,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.vintagePinhole = function () {\n _filter.colorMatrix([\n 0.6279345635605994, 0.3202183420819367, -0.03965408211312453, 0, 9.651285835294123,\n 0.02578397704808868, 0.6441188644374771, 0.03259127616149294, 0, 7.462829176470591,\n 0.0466055556782719, -0.0851232987247891, 0.5241648018700465, 0, 5.159190588235296,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.kodachrome = function () {\n _filter.colorMatrix([\n 1.1285582396593525, -0.3967382283601348, -0.03992559172921793, 0, 63.72958762196502,\n -0.16404339962244616, 1.0835251566291304, -0.05498805115633132, 0, 24.732407896706203,\n -0.16786010706155763, -0.5603416277695248, 1.6014850761964943, 0, 35.62982807460946,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.technicolor = function () {\n _filter.colorMatrix([\n 1.9125277891456083, -0.8545344976951645, -0.09155508482755585, 0, 11.793603434377337,\n -0.3087833385928097, 1.7658908555458428, -0.10601743074722245, 0, -70.35205161461398,\n -0.231103377548616, -0.7501899197440212, 1.847597816108189, 0, 30.950940869491138,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.polaroid = function () {\n _filter.colorMatrix([\n 1.438, -0.062, -0.062, 0, 0,\n -0.122, 1.378, -0.122, 0, 0,\n -0.016, -0.016, 1.483, 0, 0,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.shiftToBGR = function () {\n _filter.colorMatrix([\n 0, 0, 1, 0, 0,\n 0, 1, 0, 0, 0,\n 1, 0, 0, 0, 0,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n // -------------------------------------------------------------------------\n // Convolution Filter\n _filter.convolution = function (matrix) {\n const m = new Float32Array(matrix);\n const pixelSizeX = 1 / _width;\n const pixelSizeY = 1 / _height;\n const program = _compileShader(_filter.convolution.SHADER);\n gl.uniform1fv(program.uniform.m, m);\n gl.uniform2f(program.uniform.px, pixelSizeX, pixelSizeY);\n _draw();\n };\n\n _filter.convolution.SHADER = [\n 'precision highp float;',\n 'varying vec2 vUv;',\n 'uniform sampler2D texture;',\n 'uniform vec2 px;',\n 'uniform float m[9];',\n 'void main(void) {',\n 'vec4 c11 = texture2D(texture, vUv - px);', // top left\n 'vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y));', // top center\n 'vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y));', // top right\n 'vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) );', // mid left\n 'vec4 c22 = texture2D(texture, vUv);', // mid center\n 'vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) );', // mid right\n 'vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) );', // bottom left\n 'vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) );', // bottom center\n 'vec4 c33 = texture2D(texture, vUv + px );', // bottom right\n 'gl_FragColor = ',\n 'c11 * m[0] + c12 * m[1] + c22 * m[2] +',\n 'c21 * m[3] + c22 * m[4] + c23 * m[5] +',\n 'c31 * m[6] + c32 * m[7] + c33 * m[8];',\n 'gl_FragColor.a = c22.a;',\n '}',\n ].join('\\n');\n\n _filter.detectEdges = function () {\n _filter.convolution.call(this, [\n 0, 1, 0,\n 1, -4, 1,\n 0, 1, 0,\n ]);\n };\n\n _filter.sobelX = function () {\n _filter.convolution.call(this, [\n -1, 0, 1,\n -2, 0, 2,\n -1, 0, 1,\n ]);\n };\n\n _filter.sobelY = function () {\n _filter.convolution.call(this, [\n -1, -2, -1,\n 0, 0, 0,\n 1, 2, 1,\n ]);\n };\n\n _filter.sharpen = function (amount) {\n const a = amount || 1;\n _filter.convolution.call(this, [\n 0, -1 * a, 0,\n -1 * a, 1 + 4 * a, -1 * a,\n 0, -1 * a, 0,\n ]);\n };\n\n _filter.emboss = function (size) {\n const s = size || 1;\n _filter.convolution.call(this, [\n -2 * s, -1 * s, 0,\n -1 * s, 1, 1 * s,\n 0, 1 * s, 2 * s,\n ]);\n };\n\n // -------------------------------------------------------------------------\n // Blur Filter\n _filter.blur = function (size) {\n const blurSizeX = (size / 7) / _width;\n const blurSizeY = (size / 7) / _height;\n const program = _compileShader(_filter.blur.SHADER);\n // Vertical\n gl.uniform2f(program.uniform.px, 0, blurSizeY);\n _draw(DRAW.INTERMEDIATE);\n // Horizontal\n gl.uniform2f(program.uniform.px, blurSizeX, 0);\n _draw();\n };\n\n _filter.blur.SHADER = [\n 'precision highp float;',\n 'varying vec2 vUv;',\n 'uniform sampler2D texture;',\n 'uniform vec2 px;',\n 'void main(void) {',\n 'gl_FragColor = vec4(0.0);',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;',\n 'gl_FragColor += texture2D(texture, vUv )*0.159576912161;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;',\n '}',\n ].join('\\n');\n\n // -------------------------------------------------------------------------\n // Pixelate Filter\n _filter.pixelate = function (size) {\n const blurSizeX = (size) / _width;\n const blurSizeY = (size) / _height;\n const program = _compileShader(_filter.pixelate.SHADER);\n // Horizontal\n gl.uniform2f(program.uniform.size, blurSizeX, blurSizeY);\n _draw();\n };\n\n _filter.pixelate.SHADER = [\n 'precision highp float;',\n 'varying vec2 vUv;',\n 'uniform vec2 size;',\n 'uniform sampler2D texture;',\n 'vec2 pixelate(vec2 coord, vec2 size) {',\n 'return floor( coord / size ) * size;',\n '}',\n 'void main(void) {',\n 'gl_FragColor = vec4(0.0);',\n 'vec2 coord = pixelate(vUv, size);',\n 'gl_FragColor += texture2D(texture, coord);',\n '}',\n ].join('\\n');\n}\n", "/**\n * Image Processing module used by Human\n */\n\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as fxImage from './imagefx';\nimport type { Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\nimport { log } from '../helpers';\n\ntype Input = Tensor | ImageData | ImageBitmap | HTMLImageElement | HTMLMediaElement | HTMLVideoElement | HTMLCanvasElement | OffscreenCanvas | typeof Image | typeof env.Canvas;\n\nconst maxSize = 2048;\n// internal temp canvases\nlet inCanvas;\nlet outCanvas;\n// @ts-ignore // imagefx is js module that should be converted to a class\nlet fx: fxImage.GLImageFilter | null; // instance of imagefx\n\nexport function canvas(width, height): HTMLCanvasElement | OffscreenCanvas {\n let c;\n if (env.browser) {\n if (env.offscreen) {\n c = new OffscreenCanvas(width, height);\n } else {\n c = document.createElement('canvas');\n c.width = width;\n c.height = height;\n }\n } else {\n // @ts-ignore // env.canvas is an external monkey-patch\n c = (typeof env.Canvas !== 'undefined') ? new env.Canvas(width, height) : null;\n }\n // if (!c) throw new Error('cannot create canvas');\n return c;\n}\n\n// process input image and return tensor\n// input can be tensor, imagedata, htmlimageelement, htmlvideoelement\n// input is resized and run through imagefx filter\nexport function process(input: Input, config: Config): { tensor: Tensor | null, canvas: OffscreenCanvas | HTMLCanvasElement | null } {\n let tensor;\n if (!input) {\n // throw new Error('input is missing');\n if (config.debug) log('input is missing');\n return { tensor: null, canvas: null }; // video may become temporarily unavailable due to onresize\n }\n // sanity checks since different browsers do not implement all dom elements\n if (\n !(input instanceof tf.Tensor)\n && !(typeof Image !== 'undefined' && input instanceof Image)\n && !(typeof env.Canvas !== 'undefined' && input instanceof env.Canvas)\n && !(typeof ImageData !== 'undefined' && input instanceof ImageData)\n && !(typeof ImageBitmap !== 'undefined' && input instanceof ImageBitmap)\n && !(typeof HTMLImageElement !== 'undefined' && input instanceof HTMLImageElement)\n && !(typeof HTMLMediaElement !== 'undefined' && input instanceof HTMLMediaElement)\n && !(typeof HTMLVideoElement !== 'undefined' && input instanceof HTMLVideoElement)\n && !(typeof HTMLCanvasElement !== 'undefined' && input instanceof HTMLCanvasElement)\n && !(typeof OffscreenCanvas !== 'undefined' && input instanceof OffscreenCanvas)\n ) {\n throw new Error('input type is not recognized');\n }\n if (input instanceof tf.Tensor) {\n // if input is tensor, use as-is\n if ((input as Tensor)['isDisposedInternal']) throw new Error('input tensor is disposed');\n if ((input as Tensor).shape && (input as Tensor).shape.length === 4 && (input as unknown as Tensor).shape[0] === 1 && (input as unknown as Tensor).shape[3] === 3) tensor = tf.clone(input);\n else throw new Error(`input tensor shape must be [1, height, width, 3] and instead was ${(input as Tensor).shape}`);\n } else {\n // check if resizing will be needed\n if (typeof input['readyState'] !== 'undefined' && input['readyState'] <= 2) {\n if (config.debug) log('input stream is not ready');\n return { tensor: null, canvas: inCanvas }; // video may become temporarily unavailable due to onresize\n }\n const originalWidth = input['naturalWidth'] || input['videoWidth'] || input['width'] || (input['shape'] && (input['shape'][1] > 0));\n const originalHeight = input['naturalHeight'] || input['videoHeight'] || input['height'] || (input['shape'] && (input['shape'][2] > 0));\n if (!originalWidth || !originalHeight) {\n if (config.debug) log('cannot determine input dimensions');\n return { tensor: null, canvas: inCanvas }; // video may become temporarily unavailable due to onresize\n }\n let targetWidth = originalWidth;\n let targetHeight = originalHeight;\n if (targetWidth > maxSize) {\n targetWidth = maxSize;\n targetHeight = targetWidth * originalHeight / originalWidth;\n }\n if (targetHeight > maxSize) {\n targetHeight = maxSize;\n targetWidth = targetHeight * originalWidth / originalHeight;\n }\n\n // create our canvas and resize it if needed\n if ((config.filter.width || 0) > 0) targetWidth = config.filter.width;\n else if ((config.filter.height || 0) > 0) targetWidth = originalWidth * ((config.filter.height || 0) / originalHeight);\n if ((config.filter.height || 0) > 0) targetHeight = config.filter.height;\n else if ((config.filter.width || 0) > 0) targetHeight = originalHeight * ((config.filter.width || 0) / originalWidth);\n if (!targetWidth || !targetHeight) throw new Error('input cannot determine dimension');\n if (!inCanvas || (inCanvas?.width !== targetWidth) || (inCanvas?.height !== targetHeight)) inCanvas = canvas(targetWidth, targetHeight);\n\n // draw input to our canvas\n const ctx = inCanvas.getContext('2d');\n if ((typeof ImageData !== 'undefined') && (input instanceof ImageData)) {\n ctx.putImageData(input, 0, 0);\n } else {\n if (config.filter.flip && typeof ctx.translate !== 'undefined') {\n ctx.translate(originalWidth, 0);\n ctx.scale(-1, 1);\n ctx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, inCanvas?.width, inCanvas?.height);\n ctx.setTransform(1, 0, 0, 1, 0, 0); // resets transforms to defaults\n } else {\n ctx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, inCanvas?.width, inCanvas?.height);\n }\n }\n // imagefx transforms using gl\n if (config.filter.enabled && env.webgl.supported) {\n if (!fx || !outCanvas || (inCanvas.width !== outCanvas.width) || (inCanvas?.height !== outCanvas?.height)) {\n outCanvas = canvas(inCanvas?.width, inCanvas?.height);\n if (outCanvas?.width !== inCanvas?.width) outCanvas.width = inCanvas?.width;\n if (outCanvas?.height !== inCanvas?.height) outCanvas.height = inCanvas?.height;\n // log('created FX filter');\n fx = env.browser ? new fxImage.GLImageFilter({ canvas: outCanvas }) : null; // && (typeof document !== 'undefined')\n }\n if (!fx) return { tensor: null, canvas: inCanvas };\n fx.reset();\n fx.addFilter('brightness', config.filter.brightness); // must have at least one filter enabled\n if (config.filter.contrast !== 0) fx.addFilter('contrast', config.filter.contrast);\n if (config.filter.sharpness !== 0) fx.addFilter('sharpen', config.filter.sharpness);\n if (config.filter.blur !== 0) fx.addFilter('blur', config.filter.blur);\n if (config.filter.saturation !== 0) fx.addFilter('saturation', config.filter.saturation);\n if (config.filter.hue !== 0) fx.addFilter('hue', config.filter.hue);\n if (config.filter.negative) fx.addFilter('negative');\n if (config.filter.sepia) fx.addFilter('sepia');\n if (config.filter.vintage) fx.addFilter('brownie');\n if (config.filter.sepia) fx.addFilter('sepia');\n if (config.filter.kodachrome) fx.addFilter('kodachrome');\n if (config.filter.technicolor) fx.addFilter('technicolor');\n if (config.filter.polaroid) fx.addFilter('polaroid');\n if (config.filter.pixelate !== 0) fx.addFilter('pixelate', config.filter.pixelate);\n fx.apply(inCanvas);\n // read pixel data\n /*\n const gl = outCanvas.getContext('webgl');\n if (gl) {\n const glBuffer = new Uint8Array(outCanvas.width * outCanvas.height * 4);\n const pixBuffer = new Uint8Array(outCanvas.width * outCanvas.height * 3);\n gl.readPixels(0, 0, outCanvas.width, outCanvas.height, gl.RGBA, gl.UNSIGNED_BYTE, glBuffer);\n // gl returns rbga while we only need rgb, so discarding alpha channel\n // gl returns starting point as lower left, so need to invert vertical\n let i = 0;\n for (let y = outCanvas.height - 1; y >= 0; y--) {\n for (let x = 0; x < outCanvas.width; x++) {\n const index = (x + y * outCanvas.width) * 4;\n pixBuffer[i++] = glBuffer[index + 0];\n pixBuffer[i++] = glBuffer[index + 1];\n pixBuffer[i++] = glBuffer[index + 2];\n }\n }\n outCanvas.data = pixBuffer;\n const shape = [outCanvas.height, outCanvas.width, 3];\n const pixels = tf.tensor3d(outCanvas.data, shape, 'float32');\n tensor = tf.expandDims(pixels, 0);\n tf.dispose(pixels);\n }\n */\n } else {\n outCanvas = inCanvas;\n if (fx) fx = null;\n }\n // create tensor from image if tensor is not already defined\n if (!tensor) {\n let pixels;\n if (outCanvas.data) { // if we have data, just convert to tensor\n const shape = [outCanvas.height, outCanvas.width, 3];\n pixels = tf.tensor3d(outCanvas.data, shape, 'float32');\n } else if ((typeof ImageData !== 'undefined') && (outCanvas instanceof ImageData)) { // if input is imagedata, just use it\n pixels = tf.browser ? tf.browser.fromPixels(outCanvas) : null;\n } else if (config.backend === 'webgl' || config.backend === 'humangl') { // tf kernel-optimized method to get imagedata\n // we cant use canvas as-is as it already has a context, so we do a silly one more canvas\n const tempCanvas = canvas(targetWidth, targetHeight);\n tempCanvas.width = targetWidth;\n tempCanvas.height = targetHeight;\n const tempCtx = tempCanvas.getContext('2d');\n tempCtx?.drawImage(outCanvas, 0, 0);\n try {\n pixels = (tf.browser && env.browser) ? tf.browser.fromPixels(tempCanvas) : null;\n } catch (err) {\n throw new Error('browser webgl error');\n }\n } else { // cpu and wasm kernel does not implement efficient fromPixels method\n // we cant use canvas as-is as it already has a context, so we do a silly one more canvas and do fromPixels on ImageData instead\n const tempCanvas = canvas(targetWidth, targetHeight);\n if (!tempCanvas) return { tensor: null, canvas: inCanvas };\n tempCanvas.width = targetWidth;\n tempCanvas.height = targetHeight;\n const tempCtx = tempCanvas.getContext('2d');\n if (!tempCtx) return { tensor: null, canvas: inCanvas };\n tempCtx.drawImage(outCanvas, 0, 0);\n const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);\n if (tf.browser && env.browser) {\n pixels = tf.browser.fromPixels(data);\n } else {\n pixels = tf.tidy(() => {\n const imageData = tf.tensor(Array.from(data.data), [targetWidth, targetHeight, 4]);\n const channels = tf.split(imageData, 4, 2); // split rgba to channels\n const rgb = tf.stack([channels[0], channels[1], channels[2]], 2); // stack channels back to rgb and ignore alpha\n const expand = tf.reshape(rgb, [imageData.shape[0], imageData.shape[1], 3]); // move extra dim from the end of tensor and use it as batch number instead\n return expand;\n });\n }\n }\n if (pixels) {\n const casted = tf.cast(pixels, 'float32');\n tensor = tf.expandDims(casted, 0);\n tf.dispose(pixels);\n tf.dispose(casted);\n } else {\n tensor = tf.zeros([1, targetWidth, targetHeight, 3]);\n throw new Error('cannot create tensor from input');\n }\n }\n }\n return { tensor, canvas: (config.filter.return ? outCanvas : null) };\n}\n\nlet lastInputSum = 0;\nlet lastCacheDiff = 1;\nexport async function skip(config, input: Tensor) {\n if (config.cacheSensitivity === 0) return false;\n const resizeFact = 32;\n if (!input.shape[1] || !input.shape[2]) return false;\n const reduced: Tensor = tf.image.resizeBilinear(input, [Math.trunc(input.shape[1] / resizeFact), Math.trunc(input.shape[2] / resizeFact)]);\n\n // use tensor sum\n /*\n const sumT = this.tf.sum(reduced);\n const sum = await sumT.data()[0] as number;\n sumT.dispose();\n */\n // use js loop sum, faster than uploading tensor to gpu calculating and downloading back\n const reducedData = await reduced.data(); // raw image rgb array\n tf.dispose(reduced);\n let sum = 0;\n for (let i = 0; i < reducedData.length / 3; i++) sum += reducedData[3 * i + 2]; // look only at green value of each pixel\n\n const diff = 100 * (Math.max(sum, lastInputSum) / Math.min(sum, lastInputSum) - 1);\n lastInputSum = sum;\n // if previous frame was skipped, skip this frame if changed more than cacheSensitivity\n // if previous frame was not skipped, then look for cacheSensitivity or difference larger than one in previous frame to avoid resetting cache in subsequent frames unnecessarily\n const skipFrame = diff < Math.max(config.cacheSensitivity, lastCacheDiff);\n // if difference is above 10x threshold, don't use last value to force reset cache for significant change of scenes or images\n lastCacheDiff = diff > 10 * config.cacheSensitivity ? 0 : diff;\n // console.log('skipFrame', skipFrame, this.config.cacheSensitivity, diff);\n return skipFrame;\n}\n", "import * as tf from '../dist/tfjs.esm.js';\nimport * as image from './image/image';\nimport { mergeDeep } from './helpers';\n\nexport type Env = {\n browser: undefined | boolean,\n node: undefined | boolean,\n worker: undefined | boolean,\n platform: undefined | string,\n agent: undefined | string,\n backends: string[],\n initial: boolean,\n tfjs: {\n version: undefined | string,\n },\n offscreen: undefined | boolean,\n wasm: {\n supported: undefined | boolean,\n backend: undefined | boolean,\n simd: undefined | boolean,\n multithread: undefined | boolean,\n },\n webgl: {\n supported: undefined | boolean,\n backend: undefined | boolean,\n version: undefined | string,\n renderer: undefined | string,\n },\n webgpu: {\n supported: undefined | boolean,\n backend: undefined | boolean,\n adapter: undefined | string,\n },\n kernels: string[],\n Canvas: undefined,\n Image: undefined,\n}\n\n// eslint-disable-next-line import/no-mutable-exports\nexport let env: Env = {\n browser: undefined,\n node: undefined,\n worker: undefined,\n platform: undefined,\n agent: undefined,\n initial: true,\n backends: [],\n offscreen: undefined,\n tfjs: {\n version: undefined,\n },\n wasm: {\n supported: undefined,\n backend: undefined,\n simd: undefined,\n multithread: undefined,\n },\n webgl: {\n supported: undefined,\n backend: undefined,\n version: undefined,\n renderer: undefined,\n },\n webgpu: {\n supported: undefined,\n backend: undefined,\n adapter: undefined,\n },\n kernels: [],\n Canvas: undefined,\n Image: undefined,\n};\n\nexport async function cpuInfo() {\n const cpu = { model: '', flags: [] };\n if (env.node && env.platform?.startsWith('linux')) {\n // eslint-disable-next-line global-require\n const fs = require('fs');\n try {\n const data = fs.readFileSync('/proc/cpuinfo').toString();\n for (const line of data.split('\\n')) {\n if (line.startsWith('model name')) {\n cpu.model = line.match(/:(.*)/g)[0].replace(':', '').trim();\n }\n if (line.startsWith('flags')) {\n cpu.flags = line.match(/:(.*)/g)[0].replace(':', '').trim().split(' ').sort();\n }\n }\n } catch { /**/ }\n }\n if (!env['cpu']) Object.defineProperty(env, 'cpu', { value: cpu });\n else env['cpu'] = cpu;\n}\n\nexport async function backendInfo() {\n // analyze backends\n env.backends = Object.keys(tf.engine().registryFactory);\n env.wasm.supported = typeof WebAssembly !== 'undefined';\n env.wasm.backend = env.backends.includes('wasm');\n if (env.wasm.supported && env.wasm.backend && tf.getBackend() === 'wasm') {\n env.wasm.simd = await tf.env().getAsync('WASM_HAS_SIMD_SUPPORT');\n env.wasm.multithread = await tf.env().getAsync('WASM_HAS_MULTITHREAD_SUPPORT');\n }\n\n const c = image.canvas(100, 100);\n const ctx = c ? c.getContext('webgl2') : undefined; // causes too many gl contexts\n // const ctx = typeof tf.backend().getGPGPUContext !== undefined ? tf.backend().getGPGPUContext : null;\n env.webgl.supported = typeof ctx !== 'undefined';\n env.webgl.backend = env.backends.includes('webgl');\n if (env.webgl.supported && env.webgl.backend && (tf.getBackend() === 'webgl' || tf.getBackend() === 'humangl')) {\n // @ts-ignore getGPGPUContext only exists on WebGL backend\n const gl = tf.backend().gpgpu !== 'undefined' ? await tf.backend().getGPGPUContext().gl : null;\n if (gl) {\n env.webgl.version = gl.getParameter(gl.VERSION);\n env.webgl.renderer = gl.getParameter(gl.RENDERER);\n }\n }\n\n env.webgpu.supported = env.browser && typeof navigator['gpu'] !== 'undefined';\n env.webgpu.backend = env.backends.includes('webgpu');\n if (env.webgpu.supported) env.webgpu.adapter = (await navigator['gpu'].requestAdapter())?.name;\n\n // enumerate kernels\n env.kernels = tf.getKernelsForBackend(tf.getBackend()).map((kernel) => kernel.kernelName.toLowerCase());\n}\n\nexport async function get() {\n env.browser = typeof navigator !== 'undefined';\n env.node = typeof process !== 'undefined';\n // @ts-ignore WorkerGlobalScope evaluated in browser only\n env.worker = env.browser ? (typeof WorkerGlobalScope !== 'undefined') : undefined;\n env.tfjs.version = tf.version_core;\n\n // offscreencanvas supported?\n env.offscreen = typeof env.offscreen === 'undefined' ? typeof OffscreenCanvas !== 'undefined' : env.offscreen;\n // get platform and agent\n if (typeof navigator !== 'undefined') {\n const raw = navigator.userAgent.match(/\\(([^()]+)\\)/g);\n if (raw && raw[0]) {\n const platformMatch = raw[0].match(/\\(([^()]+)\\)/g);\n env.platform = (platformMatch && platformMatch[0]) ? platformMatch[0].replace(/\\(|\\)/g, '') : '';\n env.agent = navigator.userAgent.replace(raw[0], '');\n if (env.platform[1]) env.agent = env.agent.replace(raw[1], '');\n env.agent = env.agent.replace(/ /g, ' ');\n }\n } else if (typeof process !== 'undefined') {\n env.platform = `${process.platform} ${process.arch}`;\n env.agent = `NodeJS ${process.version}`;\n }\n await backendInfo();\n\n // get cpu info\n // await cpuInfo();\n}\n\nexport async function set(obj) {\n env = mergeDeep(env, obj);\n}\n", "import * as tf from '../../dist/tfjs.esm.js';\nimport * as bounding from './box';\nimport * as util from './util';\nimport * as coords from './coords';\nimport type { Tensor, GraphModel } from '../tfjs/types';\nimport type { BlazeFaceModel } from './blazeface';\nimport { env } from '../env';\n\nconst leftOutline = coords.MESH_ANNOTATIONS['leftEyeLower0'];\nconst rightOutline = coords.MESH_ANNOTATIONS['rightEyeLower0'];\n\nconst eyeLandmarks = {\n leftBounds: [leftOutline[0], leftOutline[leftOutline.length - 1]],\n rightBounds: [rightOutline[0], rightOutline[rightOutline.length - 1]],\n};\n\nconst meshLandmarks = {\n count: 468,\n mouth: 13,\n symmetryLine: [13, coords.MESH_ANNOTATIONS['midwayBetweenEyes'][0]],\n};\n\nconst blazeFaceLandmarks = {\n leftEye: 0,\n rightEye: 1,\n nose: 2,\n mouth: 3,\n leftEar: 4,\n rightEar: 5,\n symmetryLine: [3, 2],\n};\n\nconst irisLandmarks = {\n upperCenter: 3,\n lowerCenter: 4,\n index: 71,\n numCoordinates: 76,\n};\n\n// Replace the raw coordinates returned by facemesh with refined iris model coordinates\n// Update the z coordinate to be an average of the original and the new.\nfunction replaceRawCoordinates(rawCoords, newCoords, prefix, keys) {\n for (let i = 0; i < coords.MESH_TO_IRIS_INDICES_MAP.length; i++) {\n const { key, indices } = coords.MESH_TO_IRIS_INDICES_MAP[i];\n const originalIndices = coords.MESH_ANNOTATIONS[`${prefix}${key}`];\n if (!keys || keys.includes(key)) {\n for (let j = 0; j < indices.length; j++) {\n const index = indices[j];\n rawCoords[originalIndices[j]] = [\n newCoords[index][0], newCoords[index][1],\n (newCoords[index][2] + rawCoords[originalIndices[j]][2]) / 2,\n ];\n }\n }\n }\n}\n// The Pipeline coordinates between the bounding box and skeleton models.\nexport class Pipeline {\n storedBoxes: Array<{ startPoint: number[], endPoint: number[], landmarks: Array, confidence: number, faceConfidence?: number | undefined }>;\n boundingBoxDetector: BlazeFaceModel; // tf.GraphModel\n meshDetector: GraphModel; // tf.GraphModel\n irisModel: GraphModel; // tf.GraphModel\n boxSize: number;\n meshSize: number;\n irisSize: number;\n irisEnlarge: number;\n skipped: number;\n detectedFaces: number;\n\n constructor(boundingBoxDetector, meshDetector, irisModel) {\n // An array of facial bounding boxes.\n this.storedBoxes = [];\n this.boundingBoxDetector = boundingBoxDetector;\n this.meshDetector = meshDetector;\n this.irisModel = irisModel;\n this.boxSize = boundingBoxDetector?.model?.inputs[0].shape[2] || 0;\n this.meshSize = meshDetector?.inputs[0].shape[2] || boundingBoxDetector?.model?.inputs[0].shape[2];\n this.irisSize = irisModel?.inputs[0].shape[1] || 0;\n this.irisEnlarge = 2.3;\n this.skipped = 0;\n this.detectedFaces = 0;\n }\n\n transformRawCoords(rawCoords, box, angle, rotationMatrix) {\n const boxSize = bounding.getBoxSize({ startPoint: box.startPoint, endPoint: box.endPoint });\n const coordsScaled = rawCoords.map((coord) => ([\n boxSize[0] / this.meshSize * (coord[0] - this.meshSize / 2),\n boxSize[1] / this.meshSize * (coord[1] - this.meshSize / 2),\n coord[2],\n ]));\n const coordsRotationMatrix = (angle !== 0) ? util.buildRotationMatrix(angle, [0, 0]) : util.IDENTITY_MATRIX;\n const coordsRotated = (angle !== 0) ? coordsScaled.map((coord) => ([...util.rotatePoint(coord, coordsRotationMatrix), coord[2]])) : coordsScaled;\n const inverseRotationMatrix = (angle !== 0) ? util.invertTransformMatrix(rotationMatrix) : util.IDENTITY_MATRIX;\n const boxCenter = [...bounding.getBoxCenter({ startPoint: box.startPoint, endPoint: box.endPoint }), 1];\n return coordsRotated.map((coord) => ([\n Math.round(coord[0] + util.dot(boxCenter, inverseRotationMatrix[0])),\n Math.round(coord[1] + util.dot(boxCenter, inverseRotationMatrix[1])),\n Math.round(coord[2]),\n ]));\n }\n\n // eslint-disable-next-line class-methods-use-this\n getLeftToRightEyeDepthDifference(rawCoords) {\n const leftEyeZ = rawCoords[eyeLandmarks.leftBounds[0]][2];\n const rightEyeZ = rawCoords[eyeLandmarks.rightBounds[0]][2];\n return leftEyeZ - rightEyeZ;\n }\n\n // Returns a box describing a cropped region around the eye fit for passing to the iris model.\n getEyeBox(rawCoords, face, eyeInnerCornerIndex, eyeOuterCornerIndex, flip = false) {\n const box = bounding.squarifyBox(bounding.enlargeBox(bounding.calculateLandmarksBoundingBox([rawCoords[eyeInnerCornerIndex], rawCoords[eyeOuterCornerIndex]]), this.irisEnlarge));\n const boxSize = bounding.getBoxSize(box);\n let crop = tf.image.cropAndResize(face, [[\n box.startPoint[1] / this.meshSize,\n box.startPoint[0] / this.meshSize, box.endPoint[1] / this.meshSize,\n box.endPoint[0] / this.meshSize,\n ]], [0], [this.irisSize, this.irisSize]);\n if (flip && env.kernels.includes('flipleftright')) {\n const flipped = tf.image.flipLeftRight(crop); // flipLeftRight is not defined for tfjs-node\n tf.dispose(crop);\n crop = flipped;\n }\n return { box, boxSize, crop };\n }\n\n // Given a cropped image of an eye, returns the coordinates of the contours surrounding the eye and the iris.\n getEyeCoords(eyeData, eyeBox, eyeBoxSize, flip = false) {\n const eyeRawCoords: Array<[number, number, number]> = [];\n for (let i = 0; i < irisLandmarks.numCoordinates; i++) {\n const x = eyeData[i * 3];\n const y = eyeData[i * 3 + 1];\n const z = eyeData[i * 3 + 2];\n eyeRawCoords.push([\n (flip ? (1 - (x / this.irisSize)) : (x / this.irisSize)) * eyeBoxSize[0] + eyeBox.startPoint[0],\n (y / this.irisSize) * eyeBoxSize[1] + eyeBox.startPoint[1], z,\n ]);\n }\n return { rawCoords: eyeRawCoords, iris: eyeRawCoords.slice(irisLandmarks.index) };\n }\n\n // The z-coordinates returned for the iris are unreliable, so we take the z values from the surrounding keypoints.\n // eslint-disable-next-line class-methods-use-this\n getAdjustedIrisCoords(rawCoords, irisCoords, direction) {\n const upperCenterZ = rawCoords[coords.MESH_ANNOTATIONS[`${direction}EyeUpper0`][irisLandmarks.upperCenter]][2];\n const lowerCenterZ = rawCoords[coords.MESH_ANNOTATIONS[`${direction}EyeLower0`][irisLandmarks.lowerCenter]][2];\n const averageZ = (upperCenterZ + lowerCenterZ) / 2;\n // Iris indices: 0: center | 1: right | 2: above | 3: left | 4: below\n return irisCoords.map((coord, i) => {\n let z = averageZ;\n if (i === 2) {\n z = upperCenterZ;\n } else if (i === 4) {\n z = lowerCenterZ;\n }\n return [coord[0], coord[1], z];\n });\n }\n\n correctFaceRotation(config, box, input) {\n const [indexOfMouth, indexOfForehead] = (box.landmarks.length >= meshLandmarks.count) ? meshLandmarks.symmetryLine : blazeFaceLandmarks.symmetryLine;\n const angle: number = util.computeRotation(box.landmarks[indexOfMouth], box.landmarks[indexOfForehead]);\n const faceCenter: [number, number] = bounding.getBoxCenter({ startPoint: box.startPoint, endPoint: box.endPoint });\n const faceCenterNormalized: [number, number] = [faceCenter[0] / input.shape[2], faceCenter[1] / input.shape[1]];\n const rotated = tf.image.rotateWithOffset(input, angle, 0, faceCenterNormalized); // rotateWithOffset is not defined for tfjs-node\n const rotationMatrix = util.buildRotationMatrix(-angle, faceCenter);\n const cut = config.face.mesh.enabled\n ? bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, rotated, [this.meshSize, this.meshSize])\n : bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, rotated, [this.boxSize, this.boxSize]);\n const face = tf.div(cut, 255);\n tf.dispose(cut);\n tf.dispose(rotated);\n return [angle, rotationMatrix, face];\n }\n\n async augmentIris(rawCoords, face) {\n const { box: leftEyeBox, boxSize: leftEyeBoxSize, crop: leftEyeCrop } = this.getEyeBox(rawCoords, face, eyeLandmarks.leftBounds[0], eyeLandmarks.leftBounds[1], true);\n const { box: rightEyeBox, boxSize: rightEyeBoxSize, crop: rightEyeCrop } = this.getEyeBox(rawCoords, face, eyeLandmarks.rightBounds[0], eyeLandmarks.rightBounds[1]);\n const combined = tf.concat([leftEyeCrop, rightEyeCrop]);\n tf.dispose(leftEyeCrop);\n tf.dispose(rightEyeCrop);\n const eyePredictions = this.irisModel.predict(combined) as Tensor;\n tf.dispose(combined);\n const eyePredictionsData = await eyePredictions.data(); // inside tf.tidy\n tf.dispose(eyePredictions);\n const leftEyeData = eyePredictionsData.slice(0, irisLandmarks.numCoordinates * 3);\n const { rawCoords: leftEyeRawCoords, iris: leftIrisRawCoords } = this.getEyeCoords(leftEyeData, leftEyeBox, leftEyeBoxSize, true);\n const rightEyeData = eyePredictionsData.slice(irisLandmarks.numCoordinates * 3);\n const { rawCoords: rightEyeRawCoords, iris: rightIrisRawCoords } = this.getEyeCoords(rightEyeData, rightEyeBox, rightEyeBoxSize);\n const leftToRightEyeDepthDifference = this.getLeftToRightEyeDepthDifference(rawCoords);\n if (Math.abs(leftToRightEyeDepthDifference) < 30) { // User is looking straight ahead.\n replaceRawCoordinates(rawCoords, leftEyeRawCoords, 'left', null);\n replaceRawCoordinates(rawCoords, rightEyeRawCoords, 'right', null);\n // If the user is looking to the left or to the right, the iris coordinates tend to diverge too much from the mesh coordinates for them to be merged\n // So we only update a single contour line above and below the eye.\n } else if (leftToRightEyeDepthDifference < 1) { // User is looking towards the right.\n replaceRawCoordinates(rawCoords, leftEyeRawCoords, 'left', ['EyeUpper0', 'EyeLower0']);\n } else { // User is looking towards the left.\n replaceRawCoordinates(rawCoords, rightEyeRawCoords, 'right', ['EyeUpper0', 'EyeLower0']);\n }\n const adjustedLeftIrisCoords = this.getAdjustedIrisCoords(rawCoords, leftIrisRawCoords, 'left');\n const adjustedRightIrisCoords = this.getAdjustedIrisCoords(rawCoords, rightIrisRawCoords, 'right');\n const newCoords = rawCoords.concat(adjustedLeftIrisCoords).concat(adjustedRightIrisCoords);\n return newCoords;\n }\n\n async predict(input, config) {\n let useFreshBox = false;\n // run new detector every skipFrames unless we only want box to start with\n let detector;\n if ((this.skipped === 0) || (this.skipped > config.face.detector.skipFrames) || !config.face.mesh.enabled || !config.skipFrame) {\n detector = await this.boundingBoxDetector.getBoundingBoxes(input, config);\n this.skipped = 0;\n }\n if (config.skipFrame) this.skipped++;\n\n // if detector result count doesn't match current working set, use it to reset current working set\n if (!config.skipFrame || (detector && detector.boxes && (!config.face.mesh.enabled || (detector.boxes.length !== this.detectedFaces) && (this.detectedFaces !== config.face.detector.maxDetected)))) {\n this.storedBoxes = [];\n this.detectedFaces = 0;\n for (const possible of detector.boxes) {\n const startPoint = await possible.box.startPoint.data();\n const endPoint = await possible.box.endPoint.data();\n const landmarks = await possible.landmarks.array();\n this.storedBoxes.push({ startPoint, endPoint, landmarks, confidence: possible.confidence });\n }\n if (this.storedBoxes.length > 0) useFreshBox = true;\n }\n\n if (useFreshBox) {\n if (!detector || !detector.boxes || (detector.boxes.length === 0)) {\n this.storedBoxes = [];\n this.detectedFaces = 0;\n return null;\n }\n for (let i = 0; i < this.storedBoxes.length; i++) {\n const scaledBox = bounding.scaleBoxCoordinates({ startPoint: this.storedBoxes[i].startPoint, endPoint: this.storedBoxes[i].endPoint }, detector.scaleFactor);\n const enlargedBox = bounding.enlargeBox(scaledBox);\n const squarifiedBox = bounding.squarifyBox(enlargedBox);\n const landmarks = this.storedBoxes[i].landmarks;\n const confidence = this.storedBoxes[i].confidence;\n this.storedBoxes[i] = { ...squarifiedBox, confidence, landmarks };\n }\n }\n if (detector && detector.boxes) {\n detector.boxes.forEach((prediction) => {\n tf.dispose(prediction.box.startPoint);\n tf.dispose(prediction.box.endPoint);\n tf.dispose(prediction.landmarks);\n });\n }\n\n const results: Array<{ mesh, box, faceConfidence, boxConfidence, confidence, image }> = [];\n // for (let i = 0; i < this.storedBoxes.length; i++) {\n const newBoxes: Array<{ startPoint: number[]; endPoint: number[]; landmarks: number[]; confidence: number; faceConfidence?: number | undefined; }> = [];\n for (let box of this.storedBoxes) {\n // let box = this.storedBoxes[i]; // The facial bounding box landmarks could come either from blazeface (if we are using a fresh box), or from the mesh model (if we are reusing an old box).\n let face;\n let angle = 0;\n let rotationMatrix;\n\n if (config.face.detector.rotation && config.face.mesh.enabled && env.kernels.includes('rotatewithoffset')) {\n [angle, rotationMatrix, face] = this.correctFaceRotation(config, box, input);\n } else {\n rotationMatrix = util.IDENTITY_MATRIX;\n const cloned = input.clone();\n const cut = config.face.mesh.enabled\n ? bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, cloned, [this.meshSize, this.meshSize])\n : bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, cloned, [this.boxSize, this.boxSize]);\n face = tf.div(cut, 255);\n tf.dispose(cut);\n tf.dispose(cloned);\n }\n // if we're not going to produce mesh, don't spend time with further processing\n if (!config.face.mesh.enabled) {\n results.push({\n mesh: [],\n box,\n faceConfidence: null,\n boxConfidence: box.confidence,\n confidence: box.confidence,\n image: face,\n });\n } else {\n const [contours, confidence, contourCoords] = this.meshDetector.execute(face) as Array; // The first returned tensor represents facial contours which are already included in the coordinates.\n tf.dispose(contours);\n const faceConfidence = (await confidence.data())[0] as number; // inside tf.tidy\n tf.dispose(confidence);\n const coordsReshaped = tf.reshape(contourCoords, [-1, 3]);\n let rawCoords = await coordsReshaped.array();\n tf.dispose(contourCoords);\n tf.dispose(coordsReshaped);\n if (faceConfidence < config.face.detector.minConfidence) {\n // if (!this.storedBoxes[i]) console.log('2', i, this.storedBoxes.length, this.storedBoxes[i], box, this.storedBoxes);\n // this.storedBoxes[i].confidence = faceConfidence; // reset confidence of cached box\n box.confidence = faceConfidence; // reset confidence of cached box\n tf.dispose(face);\n } else {\n if (config.face.iris.enabled) rawCoords = await this.augmentIris(rawCoords, face);\n\n // override box from detection with one calculated from mesh\n const mesh = this.transformRawCoords(rawCoords, box, angle, rotationMatrix);\n box = { ...bounding.enlargeBox(bounding.calculateLandmarksBoundingBox(mesh), 1.5), confidence: box.confidence }; // redefine box with mesh calculated one\n\n // do rotation one more time with mesh keypoints if we want to return perfect image\n if (config.face.detector.rotation && config.face.mesh.enabled && config.face.description.enabled && env.kernels.includes('rotatewithoffset')) {\n tf.dispose(face); // we'll overwrite original face\n [angle, rotationMatrix, face] = this.correctFaceRotation(config, box, input);\n }\n results.push({\n mesh,\n box,\n faceConfidence,\n boxConfidence: box.confidence,\n confidence: faceConfidence,\n image: face,\n });\n\n // updated stored cache values\n // this.storedBoxes[i] = { ...bounding.squarifyBox(box), confidence: box.confidence, faceConfidence };\n box = { ...bounding.squarifyBox(box), confidence: box.confidence, faceConfidence };\n }\n }\n newBoxes.push(box);\n }\n\n // results = results.filter((a) => a !== null);\n // remove cache entries for detected boxes on low confidence\n if (config.face.mesh.enabled) this.storedBoxes = newBoxes.filter((a) => a.confidence > config.face.detector.minConfidence);\n this.detectedFaces = results.length;\n\n return results;\n }\n}\n", "/**\n * FaceMesh & BlazeFace Module entry point\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as blazeface from './blazeface';\nimport * as facepipeline from './facepipeline';\nimport * as coords from './coords';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { FaceResult } from '../result';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet faceModels: [blazeface.BlazeFaceModel | null, GraphModel | null, GraphModel | null] = [null, null, null];\nlet facePipeline;\n\nexport async function predict(input: Tensor, config: Config): Promise {\n const predictions = await facePipeline.predict(input, config);\n const results: Array = [];\n let id = 0;\n for (const prediction of (predictions || [])) {\n if (!prediction || prediction.isDisposedInternal) continue; // guard against disposed tensors on long running operations such as pause in middle of processing\n const meshRaw = prediction.mesh.map((pt) => [\n pt[0] / (input.shape[2] || 0),\n pt[1] / (input.shape[1] || 0),\n pt[2] / facePipeline.meshSize,\n ]);\n const annotations = {};\n if (prediction.mesh && prediction.mesh.length > 0) {\n for (const key of Object.keys(coords.MESH_ANNOTATIONS)) annotations[key] = coords.MESH_ANNOTATIONS[key].map((index) => prediction.mesh[index]);\n }\n const clampedBox: [number, number, number, number] = prediction.box ? [\n Math.trunc(Math.max(0, prediction.box.startPoint[0])),\n Math.trunc(Math.max(0, prediction.box.startPoint[1])),\n Math.trunc(Math.min((input.shape[2] || 0), prediction.box.endPoint[0]) - Math.max(0, prediction.box.startPoint[0])),\n Math.trunc(Math.min((input.shape[1] || 0), prediction.box.endPoint[1]) - Math.max(0, prediction.box.startPoint[1])),\n ] : [0, 0, 0, 0];\n const boxRaw: [number, number, number, number] = prediction.box ? [\n prediction.box.startPoint[0] / (input.shape[2] || 0),\n prediction.box.startPoint[1] / (input.shape[1] || 0),\n (prediction.box.endPoint[0] - prediction.box.startPoint[0]) / (input.shape[2] || 0),\n (prediction.box.endPoint[1] - prediction.box.startPoint[1]) / (input.shape[1] || 0),\n ] : [0, 0, 0, 0];\n results.push({\n id: id++,\n score: Math.round(100 * prediction.faceConfidence || 100 * prediction.boxConfidence || 0) / 100,\n boxScore: Math.round(100 * prediction.boxConfidence) / 100,\n faceScore: Math.round(100 * prediction.faceConfidence) / 100,\n box: clampedBox,\n boxRaw,\n mesh: prediction.mesh,\n meshRaw,\n annotations,\n tensor: prediction.image,\n });\n }\n return results;\n}\n\nexport async function load(config): Promise<[unknown, GraphModel | null, GraphModel | null]> {\n if (env.initial) faceModels = [null, null, null];\n if ((!faceModels[0] && config.face.enabled) || (!faceModels[1] && config.face.mesh.enabled) || (!faceModels[2] && config.face.iris.enabled) || env.initial) {\n faceModels = await Promise.all([\n (!faceModels[0] && config.face.enabled) ? blazeface.load(config) : null,\n (!faceModels[1] && config.face.mesh.enabled) ? tf.loadGraphModel(join(config.modelBasePath, config.face.mesh.modelPath), { fromTFHub: config.face.mesh.modelPath.includes('tfhub.dev') }) as unknown as GraphModel : null,\n (!faceModels[2] && config.face.iris.enabled) ? tf.loadGraphModel(join(config.modelBasePath, config.face.iris.modelPath), { fromTFHub: config.face.iris.modelPath.includes('tfhub.dev') }) as unknown as GraphModel : null,\n ]);\n if (config.face.mesh.enabled) {\n if (!faceModels[1] || !faceModels[1]['modelUrl']) log('load model failed:', config.face.mesh.modelPath);\n else if (config.debug) log('load model:', faceModels[1]['modelUrl']);\n }\n if (config.face.iris.enabled) {\n if (!faceModels[2] || !faceModels[2]['modelUrl']) log('load model failed:', config.face.iris.modelPath);\n else if (config.debug) log('load model:', faceModels[2]['modelUrl']);\n }\n } else if (config.debug) {\n if (faceModels[0]) log('cached model:', faceModels[0].model['modelUrl']);\n if (faceModels[1]) log('cached model:', faceModels[1]['modelUrl']);\n if (faceModels[2]) log('cached model:', faceModels[2]['modelUrl']);\n }\n facePipeline = new facepipeline.Pipeline(faceModels[0], faceModels[1], faceModels[2]);\n return faceModels;\n}\n\nexport const triangulation = coords.TRI468;\nexport const uvmap = coords.UV468;\n", "/**\n * HSE-FaceRes Module\n * Returns Age, Gender, Descriptor\n * Implements Face simmilarity function\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport type { Tensor, GraphModel } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model: GraphModel | null;\nconst last: Array<{\n age: number,\n gender: string,\n genderScore: number,\n descriptor: number[],\n}> = [];\n\nlet lastCount = 0;\nlet skipped = Number.MAX_SAFE_INTEGER;\n\ntype DB = Array<{ name: string, source: string, embedding: number[] }>;\n\nexport async function load(config: Config): Promise {\n const modelUrl = join(config.modelBasePath, config.face.description?.modelPath || '');\n if (env.initial) model = null;\n if (!model) {\n model = await tf.loadGraphModel(modelUrl) as unknown as GraphModel;\n if (!model) log('load model failed:', config.face.description?.modelPath || '');\n else if (config.debug) log('load model:', modelUrl);\n } else if (config.debug) log('cached model:', modelUrl);\n return model;\n}\n\nexport function similarity(embedding1: Array, embedding2: Array, order = 2): number {\n if (!embedding1 || !embedding2) return 0;\n if (embedding1?.length === 0 || embedding2?.length === 0) return 0;\n if (embedding1?.length !== embedding2?.length) return 0;\n // general minkowski distance, euclidean distance is limited case where order is 2\n const distance = 5.0 * embedding1\n .map((_val, i) => (Math.abs(embedding1[i] - embedding2[i]) ** order)) // distance squared\n .reduce((sum, now) => (sum + now), 0) // sum all distances\n ** (1 / order); // get root of\n const res = Math.max(0, 100 - distance) / 100.0;\n return res;\n}\n\nexport function match(embedding: Array, db: DB, threshold = 0) {\n let best = { similarity: 0, name: '', source: '', embedding: [] as number[] };\n if (!embedding || !db || !Array.isArray(embedding) || !Array.isArray(db)) return best;\n for (const f of db) {\n if (f.embedding && f.name) {\n const perc = similarity(embedding, f.embedding);\n if (perc > threshold && perc > best.similarity) best = { ...f, similarity: perc };\n }\n }\n return best;\n}\n\nexport function enhance(input): Tensor {\n const image = tf.tidy(() => {\n // input received from detector is already normalized to 0..1\n // input is also assumed to be straightened\n const tensor = input.image || input.tensor || input;\n if (!(tensor instanceof tf.Tensor)) return null;\n // do a tight crop of image and resize it to fit the model\n const box = [[0.05, 0.15, 0.85, 0.85]]; // empyrical values for top, left, bottom, right\n // const box = [[0.0, 0.0, 1.0, 1.0]]; // basically no crop for test\n if (!model?.inputs[0].shape) return null; // model has no shape so no point continuing\n const crop = (tensor.shape.length === 3)\n ? tf.image.cropAndResize(tf.expandDims(tensor, 0), box, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]) // add batch dimension if missing\n : tf.image.cropAndResize(tensor, box, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]);\n\n /*\n // just resize to fit the embedding model instead of cropping\n const crop = tf.image.resizeBilinear(tensor, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false);\n */\n\n /*\n // convert to black&white to avoid colorization impact\n const rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when converting to grayscale: https://www.mathworks.com/help/matlab/ref/rgb2gray.html\n const [red, green, blue] = tf.split(crop, 3, 3);\n const redNorm = tf.mul(red, rgb[0]);\n const greenNorm = tf.mul(green, rgb[1]);\n const blueNorm = tf.mul(blue, rgb[2]);\n const grayscale = tf.addN([redNorm, greenNorm, blueNorm]);\n const merge = tf.stack([grayscale, grayscale, grayscale], 3).squeeze(4);\n */\n\n /*\n // increase image pseudo-contrast 100%\n // (or do it per-channel so mean is done on each channel)\n // (or calculate histogram and do it based on histogram)\n const mean = merge.mean();\n const factor = 2;\n const contrast = merge.sub(mean).mul(factor).add(mean);\n */\n\n /*\n // normalize brightness from 0..1\n // silly way of creating pseudo-hdr of image\n const darken = crop.sub(crop.min());\n const lighten = darken.div(darken.max());\n */\n\n const norm = tf.mul(crop, 255);\n\n return norm;\n });\n return image;\n}\n\nexport async function predict(image: Tensor, config: Config, idx, count) {\n if (!model) return null;\n if ((skipped < (config.face.description?.skipFrames || 0)) && config.skipFrame && (lastCount === count) && last[idx]?.age && (last[idx]?.age > 0)) {\n skipped++;\n return last[idx];\n }\n skipped = 0;\n return new Promise(async (resolve) => {\n const enhanced = enhance(image);\n\n let resT;\n const obj = {\n age: 0,\n gender: 'unknown',\n genderScore: 0,\n descriptor: [],\n };\n\n if (config.face.description?.enabled) resT = await model?.predict(enhanced);\n tf.dispose(enhanced);\n\n if (resT) {\n const gender = await resT.find((t) => t.shape[1] === 1).data();\n const confidence = Math.trunc(200 * Math.abs((gender[0] - 0.5))) / 100;\n if (confidence > (config.face.description?.minConfidence || 0)) {\n obj.gender = gender[0] <= 0.5 ? 'female' : 'male';\n obj.genderScore = Math.min(0.99, confidence);\n }\n const argmax = tf.argMax(resT.find((t) => t.shape[1] === 100), 1);\n const age = (await argmax.data())[0];\n tf.dispose(argmax);\n const all = await resT.find((t) => t.shape[1] === 100).data();\n obj.age = Math.round(all[age - 1] > all[age + 1] ? 10 * age - 100 * all[age - 1] : 10 * age + 100 * all[age + 1]) / 10;\n\n const desc = resT.find((t) => t.shape[1] === 1024);\n // const reshape = desc.reshape([128, 8]); // reshape large 1024-element descriptor to 128 x 8\n // const reduce = reshape.logSumExp(1); // reduce 2nd dimension by calculating logSumExp on it which leaves us with 128-element descriptor\n\n const descriptor = await desc.data();\n obj.descriptor = [...descriptor];\n resT.forEach((t) => tf.dispose(t));\n }\n last[idx] = obj;\n lastCount = count;\n resolve(obj);\n });\n}\n", "/**\n * Emotion Module\n */\n\nimport { log, join } from '../helpers';\nimport type { Config } from '../config';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport { env } from '../env';\n\nconst annotations = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral'];\nlet model: GraphModel | null;\n// let last: Array<{ score: number, emotion: string }> = [];\nconst last: Array> = [];\nlet lastCount = 0;\nlet skipped = Number.MAX_SAFE_INTEGER;\n\n// tuning values\nconst rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when converting to grayscale\n\nexport async function load(config: Config): Promise {\n if (env.initial) model = null;\n if (!model) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.face.emotion?.modelPath || '')) as unknown as GraphModel;\n if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n\nexport async function predict(image: Tensor, config: Config, idx, count) {\n if (!model) return null;\n if ((skipped < (config.face.emotion?.skipFrames || 0)) && config.skipFrame && (lastCount === count) && last[idx] && (last[idx].length > 0)) {\n skipped++;\n return last[idx];\n }\n skipped = 0;\n return new Promise(async (resolve) => {\n const resize = tf.image.resizeBilinear(image, [model?.inputs[0].shape ? model.inputs[0].shape[2] : 0, model?.inputs[0].shape ? model.inputs[0].shape[1] : 0], false);\n const [red, green, blue] = tf.split(resize, 3, 3);\n tf.dispose(resize);\n // weighted rgb to grayscale: https://www.mathworks.com/help/matlab/ref/rgb2gray.html\n const redNorm = tf.mul(red, rgb[0]);\n const greenNorm = tf.mul(green, rgb[1]);\n const blueNorm = tf.mul(blue, rgb[2]);\n tf.dispose(red);\n tf.dispose(green);\n tf.dispose(blue);\n const grayscale = tf.addN([redNorm, greenNorm, blueNorm]);\n tf.dispose(redNorm);\n tf.dispose(greenNorm);\n tf.dispose(blueNorm);\n const normalize = tf.tidy(() => tf.mul(tf.sub(grayscale, 0.5), 2));\n tf.dispose(grayscale);\n const obj: Array<{ score: number, emotion: string }> = [];\n if (config.face.emotion?.enabled) {\n const emotionT = await model?.predict(normalize) as Tensor; // result is already in range 0..1, no need for additional activation\n const data = await emotionT.data();\n tf.dispose(emotionT);\n for (let i = 0; i < data.length; i++) {\n if (data[i] > (config.face.emotion?.minConfidence || 0)) obj.push({ score: Math.min(0.99, Math.trunc(100 * data[i]) / 100), emotion: annotations[i] });\n }\n obj.sort((a, b) => b.score - a.score);\n }\n tf.dispose(normalize);\n last[idx] = obj;\n lastCount = count;\n resolve(obj);\n });\n}\n", "export const partNames = [\n 'nose', 'leftEye', 'rightEye', 'leftEar', 'rightEar', 'leftShoulder',\n 'rightShoulder', 'leftElbow', 'rightElbow', 'leftWrist', 'rightWrist',\n 'leftHip', 'rightHip', 'leftKnee', 'rightKnee', 'leftAnkle', 'rightAnkle',\n];\n\nexport const count = partNames.length; // 17 keypoints\n\nexport const partIds = partNames.reduce((result, jointName, i) => {\n result[jointName] = i;\n return result;\n}, {});\n\nconst connectedPartNames = [\n ['leftHip', 'leftShoulder'], ['leftElbow', 'leftShoulder'],\n ['leftElbow', 'leftWrist'], ['leftHip', 'leftKnee'],\n ['leftKnee', 'leftAnkle'], ['rightHip', 'rightShoulder'],\n ['rightElbow', 'rightShoulder'], ['rightElbow', 'rightWrist'],\n ['rightHip', 'rightKnee'], ['rightKnee', 'rightAnkle'],\n ['leftShoulder', 'rightShoulder'], ['leftHip', 'rightHip'],\n];\nexport const connectedPartIndices = connectedPartNames.map(([jointNameA, jointNameB]) => ([partIds[jointNameA], partIds[jointNameB]]));\n\nexport const poseChain = [\n ['nose', 'leftEye'], ['leftEye', 'leftEar'], ['nose', 'rightEye'],\n ['rightEye', 'rightEar'], ['nose', 'leftShoulder'],\n ['leftShoulder', 'leftElbow'], ['leftElbow', 'leftWrist'],\n ['leftShoulder', 'leftHip'], ['leftHip', 'leftKnee'],\n ['leftKnee', 'leftAnkle'], ['nose', 'rightShoulder'],\n ['rightShoulder', 'rightElbow'], ['rightElbow', 'rightWrist'],\n ['rightShoulder', 'rightHip'], ['rightHip', 'rightKnee'],\n ['rightKnee', 'rightAnkle'],\n];\n", "import * as kpt from './keypoints';\nimport type { BodyResult } from '../result';\n\nexport function eitherPointDoesntMeetConfidence(a: number, b: number, minConfidence: number) {\n return (a < minConfidence || b < minConfidence);\n}\n\nexport function getAdjacentKeyPoints(keypoints, minConfidence: number) {\n return kpt.connectedPartIndices.reduce((result, [leftJoint, rightJoint]) => {\n if (eitherPointDoesntMeetConfidence(keypoints[leftJoint].score, keypoints[rightJoint].score, minConfidence)) {\n return result;\n }\n result.push([keypoints[leftJoint], keypoints[rightJoint]]);\n return result;\n }, []);\n}\n\nexport function getBoundingBox(keypoints): [number, number, number, number] {\n const coord = keypoints.reduce(({ maxX, maxY, minX, minY }, { position: { x, y } }) => ({\n maxX: Math.max(maxX, x),\n maxY: Math.max(maxY, y),\n minX: Math.min(minX, x),\n minY: Math.min(minY, y),\n }), {\n maxX: Number.NEGATIVE_INFINITY,\n maxY: Number.NEGATIVE_INFINITY,\n minX: Number.POSITIVE_INFINITY,\n minY: Number.POSITIVE_INFINITY,\n });\n return [coord.minX, coord.minY, coord.maxX - coord.minX, coord.maxY - coord.minY];\n}\n\nexport function scalePoses(poses, [height, width], [inputResolutionHeight, inputResolutionWidth]): Array {\n const scaleY = height / inputResolutionHeight;\n const scaleX = width / inputResolutionWidth;\n const scalePose = (pose, i) => ({\n id: i,\n score: pose.score,\n boxRaw: [pose.box[0] / inputResolutionWidth, pose.box[1] / inputResolutionHeight, pose.box[2] / inputResolutionWidth, pose.box[3] / inputResolutionHeight],\n box: [Math.trunc(pose.box[0] * scaleX), Math.trunc(pose.box[1] * scaleY), Math.trunc(pose.box[2] * scaleX), Math.trunc(pose.box[3] * scaleY)],\n keypoints: pose.keypoints.map(({ score, part, position }) => ({\n score,\n part,\n position: [Math.trunc(position.x * scaleX), Math.trunc(position.y * scaleY)],\n positionRaw: [position.x / inputResolutionHeight, position.y / inputResolutionHeight],\n })),\n });\n const scaledPoses = poses.map((pose, i) => scalePose(pose, i));\n return scaledPoses;\n}\n\n// algorithm based on Coursera Lecture from Algorithms, Part 1: https://www.coursera.org/learn/algorithms-part1/lecture/ZjoSM/heapsort\nexport class MaxHeap {\n priorityQueue: Array; // don't touch\n numberOfElements: number;\n getElementValue: unknown; // function call\n\n constructor(maxSize, getElementValue) {\n this.priorityQueue = new Array(maxSize);\n this.numberOfElements = -1;\n this.getElementValue = getElementValue;\n }\n\n enqueue(x) {\n this.priorityQueue[++this.numberOfElements] = x;\n this.swim(this.numberOfElements);\n }\n\n dequeue() {\n const max = this.priorityQueue[0];\n this.exchange(0, this.numberOfElements--);\n this.sink(0);\n this.priorityQueue[this.numberOfElements + 1] = null;\n return max;\n }\n\n empty() { return this.numberOfElements === -1; }\n\n size() { return this.numberOfElements + 1; }\n\n all() { return this.priorityQueue.slice(0, this.numberOfElements + 1); }\n\n max() { return this.priorityQueue[0]; }\n\n swim(k) {\n while (k > 0 && this.less(Math.floor(k / 2), k)) {\n this.exchange(k, Math.floor(k / 2));\n k = Math.floor(k / 2);\n }\n }\n\n sink(k) {\n while (2 * k <= this.numberOfElements) {\n let j = 2 * k;\n if (j < this.numberOfElements && this.less(j, j + 1)) j++;\n if (!this.less(k, j)) break;\n this.exchange(k, j);\n k = j;\n }\n }\n\n getValueAt(i) {\n // @ts-ignore getter is of unknown type\n return this.getElementValue(this.priorityQueue[i]);\n }\n\n less(i, j) {\n return this.getValueAt(i) < this.getValueAt(j);\n }\n\n exchange(i, j) {\n const t = this.priorityQueue[i];\n this.priorityQueue[i] = this.priorityQueue[j];\n this.priorityQueue[j] = t;\n }\n}\n\nexport function getOffsetPoint(y, x, keypoint, offsets) {\n return {\n y: offsets.get(y, x, keypoint),\n x: offsets.get(y, x, keypoint + kpt.count),\n };\n}\n\nexport function getImageCoords(part, outputStride, offsets) {\n const { heatmapY, heatmapX, id: keypoint } = part;\n const { y, x } = getOffsetPoint(heatmapY, heatmapX, keypoint, offsets);\n return {\n x: part.heatmapX * outputStride + x,\n y: part.heatmapY * outputStride + y,\n };\n}\n\nexport function fillArray(element, size) {\n const result = new Array(size);\n for (let i = 0; i < size; i++) {\n result[i] = element;\n }\n return result;\n}\n\nexport function clamp(a, min, max) {\n if (a < min) return min;\n if (a > max) return max;\n return a;\n}\n\nexport function squaredDistance(y1, x1, y2, x2) {\n const dy = y2 - y1;\n const dx = x2 - x1;\n return dy * dy + dx * dx;\n}\n\nexport function addVectors(a, b) {\n return { x: a.x + b.x, y: a.y + b.y };\n}\n\nexport function clampVector(a, min, max) {\n return { y: clamp(a.y, min, max), x: clamp(a.x, min, max) };\n}\n", "import * as utils from './utils';\nimport * as kpt from './keypoints';\n\nconst localMaximumRadius = 1;\nconst outputStride = 16;\nconst squaredNmsRadius = 50 ** 2;\n\nfunction traverse(edgeId, sourceKeypoint, targetId, scores, offsets, displacements, offsetRefineStep = 2) {\n const getDisplacement = (point) => ({\n y: displacements.get(point.y, point.x, edgeId),\n x: displacements.get(point.y, point.x, (displacements.shape[2] / 2) + edgeId),\n });\n const getStridedIndexNearPoint = (point, height, width) => ({\n y: utils.clamp(Math.round(point.y / outputStride), 0, height - 1),\n x: utils.clamp(Math.round(point.x / outputStride), 0, width - 1),\n });\n\n const [height, width] = scores.shape;\n // Nearest neighbor interpolation for the source->target displacements.\n const sourceKeypointIndices = getStridedIndexNearPoint(sourceKeypoint.position, height, width);\n const displacement = getDisplacement(sourceKeypointIndices);\n const displacedPoint = utils.addVectors(sourceKeypoint.position, displacement);\n let targetKeypoint = displacedPoint;\n for (let i = 0; i < offsetRefineStep; i++) {\n const targetKeypointIndices = getStridedIndexNearPoint(targetKeypoint, height, width);\n const offsetPoint = utils.getOffsetPoint(targetKeypointIndices.y, targetKeypointIndices.x, targetId, offsets);\n targetKeypoint = utils.addVectors(\n { x: targetKeypointIndices.x * outputStride, y: targetKeypointIndices.y * outputStride },\n { x: offsetPoint.x, y: offsetPoint.y },\n );\n }\n const targetKeyPointIndices = getStridedIndexNearPoint(targetKeypoint, height, width);\n const score = scores.get(targetKeyPointIndices.y, targetKeyPointIndices.x, targetId);\n return { position: targetKeypoint, part: kpt.partNames[targetId], score };\n}\n\nexport function decodePose(root, scores, offsets, displacementsFwd, displacementsBwd) {\n const tuples = kpt.poseChain.map(([parentJoinName, childJoinName]) => ([kpt.partIds[parentJoinName], kpt.partIds[childJoinName]]));\n const edgesFwd = tuples.map(([, childJointId]) => childJointId);\n const edgesBwd = tuples.map(([parentJointId]) => parentJointId);\n const numParts = scores.shape[2]; // [21,21,17]\n const numEdges = edgesFwd.length;\n const keypoints = new Array(numParts);\n // Start a new detection instance at the position of the root.\n const rootPoint = utils.getImageCoords(root.part, outputStride, offsets);\n keypoints[root.part.id] = {\n score: root.score,\n part: kpt.partNames[root.part.id],\n position: rootPoint,\n };\n // Decode the part positions upwards in the tree, following the backward displacements.\n for (let edge = numEdges - 1; edge >= 0; --edge) {\n const sourceId = edgesFwd[edge];\n const targetId = edgesBwd[edge];\n if (keypoints[sourceId] && !keypoints[targetId]) {\n keypoints[targetId] = traverse(edge, keypoints[sourceId], targetId, scores, offsets, displacementsBwd);\n }\n }\n // Decode the part positions downwards in the tree, following the forward displacements.\n for (let edge = 0; edge < numEdges; ++edge) {\n const sourceId = edgesBwd[edge];\n const targetId = edgesFwd[edge];\n if (keypoints[sourceId] && !keypoints[targetId]) {\n keypoints[targetId] = traverse(edge, keypoints[sourceId], targetId, scores, offsets, displacementsFwd);\n }\n }\n return keypoints;\n}\n\nfunction scoreIsMaximumInLocalWindow(keypointId, score, heatmapY, heatmapX, scores) {\n const [height, width] = scores.shape;\n let localMaximum = true;\n const yStart = Math.max(heatmapY - localMaximumRadius, 0);\n const yEnd = Math.min(heatmapY + localMaximumRadius + 1, height);\n for (let yCurrent = yStart; yCurrent < yEnd; ++yCurrent) {\n const xStart = Math.max(heatmapX - localMaximumRadius, 0);\n const xEnd = Math.min(heatmapX + localMaximumRadius + 1, width);\n for (let xCurrent = xStart; xCurrent < xEnd; ++xCurrent) {\n if (scores.get(yCurrent, xCurrent, keypointId) > score) {\n localMaximum = false;\n break;\n }\n }\n if (!localMaximum) break;\n }\n return localMaximum;\n}\n\nexport function buildPartWithScoreQueue(minConfidence, scores) {\n const [height, width, numKeypoints] = scores.shape;\n const queue = new utils.MaxHeap(height * width * numKeypoints, ({ score }) => score);\n for (let heatmapY = 0; heatmapY < height; ++heatmapY) {\n for (let heatmapX = 0; heatmapX < width; ++heatmapX) {\n for (let keypointId = 0; keypointId < numKeypoints; ++keypointId) {\n const score = scores.get(heatmapY, heatmapX, keypointId);\n // Only consider parts with score greater or equal to threshold as root candidates.\n if (score < minConfidence) continue;\n // Only consider keypoints whose score is maximum in a local window.\n if (scoreIsMaximumInLocalWindow(keypointId, score, heatmapY, heatmapX, scores)) queue.enqueue({ score, part: { heatmapY, heatmapX, id: keypointId } });\n }\n }\n }\n return queue;\n}\n\nfunction withinRadius(poses, { x, y }, keypointId) {\n return poses.some(({ keypoints }) => {\n const correspondingKeypoint = keypoints[keypointId]?.position;\n if (!correspondingKeypoint) return false;\n return utils.squaredDistance(y, x, correspondingKeypoint.y, correspondingKeypoint.x) <= squaredNmsRadius;\n });\n}\n\nfunction getInstanceScore(existingPoses, keypoints) {\n const notOverlappedKeypointScores = keypoints.reduce((result, { position, score }, keypointId) => {\n if (!withinRadius(existingPoses, position, keypointId)) result += score;\n return result;\n }, 0.0);\n return notOverlappedKeypointScores / keypoints.length;\n}\n\nexport function decode(offsets, scores, displacementsFwd, displacementsBwd, maxDetected, minConfidence) {\n const poses: Array<{ keypoints, box: [number, number, number, number], score: number }> = [];\n const queue = buildPartWithScoreQueue(minConfidence, scores);\n // Generate at most maxDetected object instances per image in decreasing root part score order.\n while (poses.length < maxDetected && !queue.empty()) {\n // The top element in the queue is the next root candidate.\n const root = queue.dequeue();\n // Part-based non-maximum suppression: We reject a root candidate if it is within a disk of `nmsRadius` pixels from the corresponding part of a previously detected instance.\n // @ts-ignore this one is tree walk\n const rootImageCoords = utils.getImageCoords(root.part, outputStride, offsets);\n // @ts-ignore this one is tree walk\n if (withinRadius(poses, rootImageCoords, root.part.id)) continue;\n // Else start a new detection instance at the position of the root.\n let keypoints = decodePose(root, scores, offsets, displacementsFwd, displacementsBwd);\n keypoints = keypoints.filter((a) => a.score > minConfidence);\n const score = getInstanceScore(poses, keypoints);\n const box = utils.getBoundingBox(keypoints);\n if (score > minConfidence) poses.push({ keypoints, box, score: Math.round(100 * score) / 100 });\n }\n return poses;\n}\n", "/**\n * PoseNet module entry point\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as poses from './poses';\nimport * as util from './utils';\nimport type { BodyResult } from '../result';\nimport type { Tensor, GraphModel } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model: GraphModel;\nconst poseNetOutputs = ['MobilenetV1/offset_2/BiasAdd'/* offsets */, 'MobilenetV1/heatmap_2/BiasAdd'/* heatmapScores */, 'MobilenetV1/displacement_fwd_2/BiasAdd'/* displacementFwd */, 'MobilenetV1/displacement_bwd_2/BiasAdd'/* displacementBwd */];\n\nexport async function predict(input: Tensor, config: Config): Promise {\n const res = tf.tidy(() => {\n if (!model.inputs[0].shape) return [];\n const resized = tf.image.resizeBilinear(input, [model.inputs[0].shape[2], model.inputs[0].shape[1]]);\n const normalized = tf.sub(tf.div(tf.cast(resized, 'float32'), 127.5), 1.0);\n const results: Array = model.execute(normalized, poseNetOutputs) as Array;\n const results3d = results.map((y) => tf.squeeze(y, [0]));\n results3d[1] = results3d[1].sigmoid(); // apply sigmoid on scores\n return results3d;\n });\n\n const buffers = await Promise.all(res.map((tensor: Tensor) => tensor.buffer()));\n for (const t of res) tf.dispose(t);\n\n const decoded = await poses.decode(buffers[0], buffers[1], buffers[2], buffers[3], config.body.maxDetected, config.body.minConfidence);\n if (!model.inputs[0].shape) return [];\n const scaled = util.scalePoses(decoded, [input.shape[1], input.shape[2]], [model.inputs[0].shape[2], model.inputs[0].shape[1]]) as BodyResult[];\n return scaled;\n}\n\nexport async function load(config: Config): Promise {\n if (!model || env.initial) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath || '')) as unknown as GraphModel;\n if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n", "import * as tf from '../../dist/tfjs.esm.js';\n\nexport function getBoxSize(box) {\n return [\n Math.abs(box.endPoint[0] - box.startPoint[0]),\n Math.abs(box.endPoint[1] - box.startPoint[1]),\n ];\n}\n\nexport function getBoxCenter(box) {\n return [\n box.startPoint[0] + (box.endPoint[0] - box.startPoint[0]) / 2,\n box.startPoint[1] + (box.endPoint[1] - box.startPoint[1]) / 2,\n ];\n}\n\nexport function cutBoxFromImageAndResize(box, image, cropSize) {\n const h = image.shape[1];\n const w = image.shape[2];\n const boxes = [[\n box.startPoint[1] / h,\n box.startPoint[0] / w,\n box.endPoint[1] / h,\n box.endPoint[0] / w,\n ]];\n return tf.image.cropAndResize(image, boxes, [0], cropSize);\n}\n\nexport function scaleBoxCoordinates(box, factor) {\n const startPoint = [box.startPoint[0] * factor[0], box.startPoint[1] * factor[1]];\n const endPoint = [box.endPoint[0] * factor[0], box.endPoint[1] * factor[1]];\n const palmLandmarks = box.palmLandmarks.map((coord) => {\n const scaledCoord = [coord[0] * factor[0], coord[1] * factor[1]];\n return scaledCoord;\n });\n return { startPoint, endPoint, palmLandmarks, confidence: box.confidence };\n}\n\nexport function enlargeBox(box, factor = 1.5) {\n const center = getBoxCenter(box);\n const size = getBoxSize(box);\n const newHalfSize = [factor * size[0] / 2, factor * size[1] / 2];\n const startPoint = [center[0] - newHalfSize[0], center[1] - newHalfSize[1]];\n const endPoint = [center[0] + newHalfSize[0], center[1] + newHalfSize[1]];\n return { startPoint, endPoint, palmLandmarks: box.palmLandmarks };\n}\n\nexport function squarifyBox(box) {\n const centers = getBoxCenter(box);\n const size = getBoxSize(box);\n const maxEdge = Math.max(...size);\n const halfSize = maxEdge / 2;\n const startPoint = [centers[0] - halfSize, centers[1] - halfSize];\n const endPoint = [centers[0] + halfSize, centers[1] + halfSize];\n return { startPoint, endPoint, palmLandmarks: box.palmLandmarks };\n}\n\nexport function shiftBox(box, shiftFactor) {\n const boxSize = [\n box.endPoint[0] - box.startPoint[0],\n box.endPoint[1] - box.startPoint[1],\n ];\n const shiftVector = [boxSize[0] * shiftFactor[0], boxSize[1] * shiftFactor[1]];\n const startPoint = [box.startPoint[0] + shiftVector[0], box.startPoint[1] + shiftVector[1]];\n const endPoint = [box.endPoint[0] + shiftVector[0], box.endPoint[1] + shiftVector[1]];\n return { startPoint, endPoint, palmLandmarks: box.palmLandmarks };\n}\n", "export const anchors = [\n { x: 0.015625, y: 0.015625 },\n { x: 0.015625, y: 0.015625 },\n { x: 0.046875, y: 0.015625 },\n { x: 0.046875, y: 0.015625 },\n { x: 0.078125, y: 0.015625 },\n { x: 0.078125, y: 0.015625 },\n { x: 0.109375, y: 0.015625 },\n { x: 0.109375, y: 0.015625 },\n { x: 0.140625, y: 0.015625 },\n { x: 0.140625, y: 0.015625 },\n { x: 0.171875, y: 0.015625 },\n { x: 0.171875, y: 0.015625 },\n { x: 0.203125, y: 0.015625 },\n { x: 0.203125, y: 0.015625 },\n { x: 0.234375, y: 0.015625 },\n { x: 0.234375, y: 0.015625 },\n { x: 0.265625, y: 0.015625 },\n { x: 0.265625, y: 0.015625 },\n { x: 0.296875, y: 0.015625 },\n { x: 0.296875, y: 0.015625 },\n { x: 0.328125, y: 0.015625 },\n { x: 0.328125, y: 0.015625 },\n { x: 0.359375, y: 0.015625 },\n { x: 0.359375, y: 0.015625 },\n { x: 0.390625, y: 0.015625 },\n { x: 0.390625, y: 0.015625 },\n { x: 0.421875, y: 0.015625 },\n { x: 0.421875, y: 0.015625 },\n { x: 0.453125, y: 0.015625 },\n { x: 0.453125, y: 0.015625 },\n { x: 0.484375, y: 0.015625 },\n { x: 0.484375, y: 0.015625 },\n { x: 0.515625, y: 0.015625 },\n { x: 0.515625, y: 0.015625 },\n { x: 0.546875, y: 0.015625 },\n { x: 0.546875, y: 0.015625 },\n { x: 0.578125, y: 0.015625 },\n { x: 0.578125, y: 0.015625 },\n { x: 0.609375, y: 0.015625 },\n { x: 0.609375, y: 0.015625 },\n { x: 0.640625, y: 0.015625 },\n { x: 0.640625, y: 0.015625 },\n { x: 0.671875, y: 0.015625 },\n { x: 0.671875, y: 0.015625 },\n { x: 0.703125, y: 0.015625 },\n { x: 0.703125, y: 0.015625 },\n { x: 0.734375, y: 0.015625 },\n { x: 0.734375, y: 0.015625 },\n { x: 0.765625, y: 0.015625 },\n { x: 0.765625, y: 0.015625 },\n { x: 0.796875, y: 0.015625 },\n { x: 0.796875, y: 0.015625 },\n { x: 0.828125, y: 0.015625 },\n { x: 0.828125, y: 0.015625 },\n { x: 0.859375, y: 0.015625 },\n { x: 0.859375, y: 0.015625 },\n { x: 0.890625, y: 0.015625 },\n { x: 0.890625, y: 0.015625 },\n { x: 0.921875, y: 0.015625 },\n { x: 0.921875, y: 0.015625 },\n { x: 0.953125, y: 0.015625 },\n { x: 0.953125, y: 0.015625 },\n { x: 0.984375, y: 0.015625 },\n { x: 0.984375, y: 0.015625 },\n { x: 0.015625, y: 0.046875 },\n { x: 0.015625, y: 0.046875 },\n { x: 0.046875, y: 0.046875 },\n { x: 0.046875, y: 0.046875 },\n { x: 0.078125, y: 0.046875 },\n { x: 0.078125, y: 0.046875 },\n { x: 0.109375, y: 0.046875 },\n { x: 0.109375, y: 0.046875 },\n { x: 0.140625, y: 0.046875 },\n { x: 0.140625, y: 0.046875 },\n { x: 0.171875, y: 0.046875 },\n { x: 0.171875, y: 0.046875 },\n { x: 0.203125, y: 0.046875 },\n { x: 0.203125, y: 0.046875 },\n { x: 0.234375, y: 0.046875 },\n { x: 0.234375, y: 0.046875 },\n { x: 0.265625, y: 0.046875 },\n { x: 0.265625, y: 0.046875 },\n { x: 0.296875, y: 0.046875 },\n { x: 0.296875, y: 0.046875 },\n { x: 0.328125, y: 0.046875 },\n { x: 0.328125, y: 0.046875 },\n { x: 0.359375, y: 0.046875 },\n { x: 0.359375, y: 0.046875 },\n { x: 0.390625, y: 0.046875 },\n { x: 0.390625, y: 0.046875 },\n { x: 0.421875, y: 0.046875 },\n { x: 0.421875, y: 0.046875 },\n { x: 0.453125, y: 0.046875 },\n { x: 0.453125, y: 0.046875 },\n { x: 0.484375, y: 0.046875 },\n { x: 0.484375, y: 0.046875 },\n { x: 0.515625, y: 0.046875 },\n { x: 0.515625, y: 0.046875 },\n { x: 0.546875, y: 0.046875 },\n { x: 0.546875, y: 0.046875 },\n { x: 0.578125, y: 0.046875 },\n { x: 0.578125, y: 0.046875 },\n { x: 0.609375, y: 0.046875 },\n { x: 0.609375, y: 0.046875 },\n { x: 0.640625, y: 0.046875 },\n { x: 0.640625, y: 0.046875 },\n { x: 0.671875, y: 0.046875 },\n { x: 0.671875, y: 0.046875 },\n { x: 0.703125, y: 0.046875 },\n { x: 0.703125, y: 0.046875 },\n { x: 0.734375, y: 0.046875 },\n { x: 0.734375, y: 0.046875 },\n { x: 0.765625, y: 0.046875 },\n { x: 0.765625, y: 0.046875 },\n { x: 0.796875, y: 0.046875 },\n { x: 0.796875, y: 0.046875 },\n { x: 0.828125, y: 0.046875 },\n { x: 0.828125, y: 0.046875 },\n { x: 0.859375, y: 0.046875 },\n { x: 0.859375, y: 0.046875 },\n { x: 0.890625, y: 0.046875 },\n { x: 0.890625, y: 0.046875 },\n { x: 0.921875, y: 0.046875 },\n { x: 0.921875, y: 0.046875 },\n { x: 0.953125, y: 0.046875 },\n { x: 0.953125, y: 0.046875 },\n { x: 0.984375, y: 0.046875 },\n { x: 0.984375, y: 0.046875 },\n { x: 0.015625, y: 0.078125 },\n { x: 0.015625, y: 0.078125 },\n { x: 0.046875, y: 0.078125 },\n { x: 0.046875, y: 0.078125 },\n { x: 0.078125, y: 0.078125 },\n { x: 0.078125, y: 0.078125 },\n { x: 0.109375, y: 0.078125 },\n { x: 0.109375, y: 0.078125 },\n { x: 0.140625, y: 0.078125 },\n { x: 0.140625, y: 0.078125 },\n { x: 0.171875, y: 0.078125 },\n { x: 0.171875, y: 0.078125 },\n { x: 0.203125, y: 0.078125 },\n { x: 0.203125, y: 0.078125 },\n { x: 0.234375, y: 0.078125 },\n { x: 0.234375, y: 0.078125 },\n { x: 0.265625, y: 0.078125 },\n { x: 0.265625, y: 0.078125 },\n { x: 0.296875, y: 0.078125 },\n { x: 0.296875, y: 0.078125 },\n { x: 0.328125, y: 0.078125 },\n { x: 0.328125, y: 0.078125 },\n { x: 0.359375, y: 0.078125 },\n { x: 0.359375, y: 0.078125 },\n { x: 0.390625, y: 0.078125 },\n { x: 0.390625, y: 0.078125 },\n { x: 0.421875, y: 0.078125 },\n { x: 0.421875, y: 0.078125 },\n { x: 0.453125, y: 0.078125 },\n { x: 0.453125, y: 0.078125 },\n { x: 0.484375, y: 0.078125 },\n { x: 0.484375, y: 0.078125 },\n { x: 0.515625, y: 0.078125 },\n { x: 0.515625, y: 0.078125 },\n { x: 0.546875, y: 0.078125 },\n { x: 0.546875, y: 0.078125 },\n { x: 0.578125, y: 0.078125 },\n { x: 0.578125, y: 0.078125 },\n { x: 0.609375, y: 0.078125 },\n { x: 0.609375, y: 0.078125 },\n { x: 0.640625, y: 0.078125 },\n { x: 0.640625, y: 0.078125 },\n { x: 0.671875, y: 0.078125 },\n { x: 0.671875, y: 0.078125 },\n { x: 0.703125, y: 0.078125 },\n { x: 0.703125, y: 0.078125 },\n { x: 0.734375, y: 0.078125 },\n { x: 0.734375, y: 0.078125 },\n { x: 0.765625, y: 0.078125 },\n { x: 0.765625, y: 0.078125 },\n { x: 0.796875, y: 0.078125 },\n { x: 0.796875, y: 0.078125 },\n { x: 0.828125, y: 0.078125 },\n { x: 0.828125, y: 0.078125 },\n { x: 0.859375, y: 0.078125 },\n { x: 0.859375, y: 0.078125 },\n { x: 0.890625, y: 0.078125 },\n { x: 0.890625, y: 0.078125 },\n { x: 0.921875, y: 0.078125 },\n { x: 0.921875, y: 0.078125 },\n { x: 0.953125, y: 0.078125 },\n { x: 0.953125, y: 0.078125 },\n { x: 0.984375, y: 0.078125 },\n { x: 0.984375, y: 0.078125 },\n { x: 0.015625, y: 0.109375 },\n { x: 0.015625, y: 0.109375 },\n { x: 0.046875, y: 0.109375 },\n { x: 0.046875, y: 0.109375 },\n { x: 0.078125, y: 0.109375 },\n { x: 0.078125, y: 0.109375 },\n { x: 0.109375, y: 0.109375 },\n { x: 0.109375, y: 0.109375 },\n { x: 0.140625, y: 0.109375 },\n { x: 0.140625, y: 0.109375 },\n { x: 0.171875, y: 0.109375 },\n { x: 0.171875, y: 0.109375 },\n { x: 0.203125, y: 0.109375 },\n { x: 0.203125, y: 0.109375 },\n { x: 0.234375, y: 0.109375 },\n { x: 0.234375, y: 0.109375 },\n { x: 0.265625, y: 0.109375 },\n { x: 0.265625, y: 0.109375 },\n { x: 0.296875, y: 0.109375 },\n { x: 0.296875, y: 0.109375 },\n { x: 0.328125, y: 0.109375 },\n { x: 0.328125, y: 0.109375 },\n { x: 0.359375, y: 0.109375 },\n { x: 0.359375, y: 0.109375 },\n { x: 0.390625, y: 0.109375 },\n { x: 0.390625, y: 0.109375 },\n { x: 0.421875, y: 0.109375 },\n { x: 0.421875, y: 0.109375 },\n { x: 0.453125, y: 0.109375 },\n { x: 0.453125, y: 0.109375 },\n { x: 0.484375, y: 0.109375 },\n { x: 0.484375, y: 0.109375 },\n { x: 0.515625, y: 0.109375 },\n { x: 0.515625, y: 0.109375 },\n { x: 0.546875, y: 0.109375 },\n { x: 0.546875, y: 0.109375 },\n { x: 0.578125, y: 0.109375 },\n { x: 0.578125, y: 0.109375 },\n { x: 0.609375, y: 0.109375 },\n { x: 0.609375, y: 0.109375 },\n { x: 0.640625, y: 0.109375 },\n { x: 0.640625, y: 0.109375 },\n { x: 0.671875, y: 0.109375 },\n { x: 0.671875, y: 0.109375 },\n { x: 0.703125, y: 0.109375 },\n { x: 0.703125, y: 0.109375 },\n { x: 0.734375, y: 0.109375 },\n { x: 0.734375, y: 0.109375 },\n { x: 0.765625, y: 0.109375 },\n { x: 0.765625, y: 0.109375 },\n { x: 0.796875, y: 0.109375 },\n { x: 0.796875, y: 0.109375 },\n { x: 0.828125, y: 0.109375 },\n { x: 0.828125, y: 0.109375 },\n { x: 0.859375, y: 0.109375 },\n { x: 0.859375, y: 0.109375 },\n { x: 0.890625, y: 0.109375 },\n { x: 0.890625, y: 0.109375 },\n { x: 0.921875, y: 0.109375 },\n { x: 0.921875, y: 0.109375 },\n { x: 0.953125, y: 0.109375 },\n { x: 0.953125, y: 0.109375 },\n { x: 0.984375, y: 0.109375 },\n { x: 0.984375, y: 0.109375 },\n { x: 0.015625, y: 0.140625 },\n { x: 0.015625, y: 0.140625 },\n { x: 0.046875, y: 0.140625 },\n { x: 0.046875, y: 0.140625 },\n { x: 0.078125, y: 0.140625 },\n { x: 0.078125, y: 0.140625 },\n { x: 0.109375, y: 0.140625 },\n { x: 0.109375, y: 0.140625 },\n { x: 0.140625, y: 0.140625 },\n { x: 0.140625, y: 0.140625 },\n { x: 0.171875, y: 0.140625 },\n { x: 0.171875, y: 0.140625 },\n { x: 0.203125, y: 0.140625 },\n { x: 0.203125, y: 0.140625 },\n { x: 0.234375, y: 0.140625 },\n { x: 0.234375, y: 0.140625 },\n { x: 0.265625, y: 0.140625 },\n { x: 0.265625, y: 0.140625 },\n { x: 0.296875, y: 0.140625 },\n { x: 0.296875, y: 0.140625 },\n { x: 0.328125, y: 0.140625 },\n { x: 0.328125, y: 0.140625 },\n { x: 0.359375, y: 0.140625 },\n { x: 0.359375, y: 0.140625 },\n { x: 0.390625, y: 0.140625 },\n { x: 0.390625, y: 0.140625 },\n { x: 0.421875, y: 0.140625 },\n { x: 0.421875, y: 0.140625 },\n { x: 0.453125, y: 0.140625 },\n { x: 0.453125, y: 0.140625 },\n { x: 0.484375, y: 0.140625 },\n { x: 0.484375, y: 0.140625 },\n { x: 0.515625, y: 0.140625 },\n { x: 0.515625, y: 0.140625 },\n { x: 0.546875, y: 0.140625 },\n { x: 0.546875, y: 0.140625 },\n { x: 0.578125, y: 0.140625 },\n { x: 0.578125, y: 0.140625 },\n { x: 0.609375, y: 0.140625 },\n { x: 0.609375, y: 0.140625 },\n { x: 0.640625, y: 0.140625 },\n { x: 0.640625, y: 0.140625 },\n { x: 0.671875, y: 0.140625 },\n { x: 0.671875, y: 0.140625 },\n { x: 0.703125, y: 0.140625 },\n { x: 0.703125, y: 0.140625 },\n { x: 0.734375, y: 0.140625 },\n { x: 0.734375, y: 0.140625 },\n { x: 0.765625, y: 0.140625 },\n { x: 0.765625, y: 0.140625 },\n { x: 0.796875, y: 0.140625 },\n { x: 0.796875, y: 0.140625 },\n { x: 0.828125, y: 0.140625 },\n { x: 0.828125, y: 0.140625 },\n { x: 0.859375, y: 0.140625 },\n { x: 0.859375, y: 0.140625 },\n { x: 0.890625, y: 0.140625 },\n { x: 0.890625, y: 0.140625 },\n { x: 0.921875, y: 0.140625 },\n { x: 0.921875, y: 0.140625 },\n { x: 0.953125, y: 0.140625 },\n { x: 0.953125, y: 0.140625 },\n { x: 0.984375, y: 0.140625 },\n { x: 0.984375, y: 0.140625 },\n { x: 0.015625, y: 0.171875 },\n { x: 0.015625, y: 0.171875 },\n { x: 0.046875, y: 0.171875 },\n { x: 0.046875, y: 0.171875 },\n { x: 0.078125, y: 0.171875 },\n { x: 0.078125, y: 0.171875 },\n { x: 0.109375, y: 0.171875 },\n { x: 0.109375, y: 0.171875 },\n { x: 0.140625, y: 0.171875 },\n { x: 0.140625, y: 0.171875 },\n { x: 0.171875, y: 0.171875 },\n { x: 0.171875, y: 0.171875 },\n { x: 0.203125, y: 0.171875 },\n { x: 0.203125, y: 0.171875 },\n { x: 0.234375, y: 0.171875 },\n { x: 0.234375, y: 0.171875 },\n { x: 0.265625, y: 0.171875 },\n { x: 0.265625, y: 0.171875 },\n { x: 0.296875, y: 0.171875 },\n { x: 0.296875, y: 0.171875 },\n { x: 0.328125, y: 0.171875 },\n { x: 0.328125, y: 0.171875 },\n { x: 0.359375, y: 0.171875 },\n { x: 0.359375, y: 0.171875 },\n { x: 0.390625, y: 0.171875 },\n { x: 0.390625, y: 0.171875 },\n { x: 0.421875, y: 0.171875 },\n { x: 0.421875, y: 0.171875 },\n { x: 0.453125, y: 0.171875 },\n { x: 0.453125, y: 0.171875 },\n { x: 0.484375, y: 0.171875 },\n { x: 0.484375, y: 0.171875 },\n { x: 0.515625, y: 0.171875 },\n { x: 0.515625, y: 0.171875 },\n { x: 0.546875, y: 0.171875 },\n { x: 0.546875, y: 0.171875 },\n { x: 0.578125, y: 0.171875 },\n { x: 0.578125, y: 0.171875 },\n { x: 0.609375, y: 0.171875 },\n { x: 0.609375, y: 0.171875 },\n { x: 0.640625, y: 0.171875 },\n { x: 0.640625, y: 0.171875 },\n { x: 0.671875, y: 0.171875 },\n { x: 0.671875, y: 0.171875 },\n { x: 0.703125, y: 0.171875 },\n { x: 0.703125, y: 0.171875 },\n { x: 0.734375, y: 0.171875 },\n { x: 0.734375, y: 0.171875 },\n { x: 0.765625, y: 0.171875 },\n { x: 0.765625, y: 0.171875 },\n { x: 0.796875, y: 0.171875 },\n { x: 0.796875, y: 0.171875 },\n { x: 0.828125, y: 0.171875 },\n { x: 0.828125, y: 0.171875 },\n { x: 0.859375, y: 0.171875 },\n { x: 0.859375, y: 0.171875 },\n { x: 0.890625, y: 0.171875 },\n { x: 0.890625, y: 0.171875 },\n { x: 0.921875, y: 0.171875 },\n { x: 0.921875, y: 0.171875 },\n { x: 0.953125, y: 0.171875 },\n { x: 0.953125, y: 0.171875 },\n { x: 0.984375, y: 0.171875 },\n { x: 0.984375, y: 0.171875 },\n { x: 0.015625, y: 0.203125 },\n { x: 0.015625, y: 0.203125 },\n { x: 0.046875, y: 0.203125 },\n { x: 0.046875, y: 0.203125 },\n { x: 0.078125, y: 0.203125 },\n { x: 0.078125, y: 0.203125 },\n { x: 0.109375, y: 0.203125 },\n { x: 0.109375, y: 0.203125 },\n { x: 0.140625, y: 0.203125 },\n { x: 0.140625, y: 0.203125 },\n { x: 0.171875, y: 0.203125 },\n { x: 0.171875, y: 0.203125 },\n { x: 0.203125, y: 0.203125 },\n { x: 0.203125, y: 0.203125 },\n { x: 0.234375, y: 0.203125 },\n { x: 0.234375, y: 0.203125 },\n { x: 0.265625, y: 0.203125 },\n { x: 0.265625, y: 0.203125 },\n { x: 0.296875, y: 0.203125 },\n { x: 0.296875, y: 0.203125 },\n { x: 0.328125, y: 0.203125 },\n { x: 0.328125, y: 0.203125 },\n { x: 0.359375, y: 0.203125 },\n { x: 0.359375, y: 0.203125 },\n { x: 0.390625, y: 0.203125 },\n { x: 0.390625, y: 0.203125 },\n { x: 0.421875, y: 0.203125 },\n { x: 0.421875, y: 0.203125 },\n { x: 0.453125, y: 0.203125 },\n { x: 0.453125, y: 0.203125 },\n { x: 0.484375, y: 0.203125 },\n { x: 0.484375, y: 0.203125 },\n { x: 0.515625, y: 0.203125 },\n { x: 0.515625, y: 0.203125 },\n { x: 0.546875, y: 0.203125 },\n { x: 0.546875, y: 0.203125 },\n { x: 0.578125, y: 0.203125 },\n { x: 0.578125, y: 0.203125 },\n { x: 0.609375, y: 0.203125 },\n { x: 0.609375, y: 0.203125 },\n { x: 0.640625, y: 0.203125 },\n { x: 0.640625, y: 0.203125 },\n { x: 0.671875, y: 0.203125 },\n { x: 0.671875, y: 0.203125 },\n { x: 0.703125, y: 0.203125 },\n { x: 0.703125, y: 0.203125 },\n { x: 0.734375, y: 0.203125 },\n { x: 0.734375, y: 0.203125 },\n { x: 0.765625, y: 0.203125 },\n { x: 0.765625, y: 0.203125 },\n { x: 0.796875, y: 0.203125 },\n { x: 0.796875, y: 0.203125 },\n { x: 0.828125, y: 0.203125 },\n { x: 0.828125, y: 0.203125 },\n { x: 0.859375, y: 0.203125 },\n { x: 0.859375, y: 0.203125 },\n { x: 0.890625, y: 0.203125 },\n { x: 0.890625, y: 0.203125 },\n { x: 0.921875, y: 0.203125 },\n { x: 0.921875, y: 0.203125 },\n { x: 0.953125, y: 0.203125 },\n { x: 0.953125, y: 0.203125 },\n { x: 0.984375, y: 0.203125 },\n { x: 0.984375, y: 0.203125 },\n { x: 0.015625, y: 0.234375 },\n { x: 0.015625, y: 0.234375 },\n { x: 0.046875, y: 0.234375 },\n { x: 0.046875, y: 0.234375 },\n { x: 0.078125, y: 0.234375 },\n { x: 0.078125, y: 0.234375 },\n { x: 0.109375, y: 0.234375 },\n { x: 0.109375, y: 0.234375 },\n { x: 0.140625, y: 0.234375 },\n { x: 0.140625, y: 0.234375 },\n { x: 0.171875, y: 0.234375 },\n { x: 0.171875, y: 0.234375 },\n { x: 0.203125, y: 0.234375 },\n { x: 0.203125, y: 0.234375 },\n { x: 0.234375, y: 0.234375 },\n { x: 0.234375, y: 0.234375 },\n { x: 0.265625, y: 0.234375 },\n { x: 0.265625, y: 0.234375 },\n { x: 0.296875, y: 0.234375 },\n { x: 0.296875, y: 0.234375 },\n { x: 0.328125, y: 0.234375 },\n { x: 0.328125, y: 0.234375 },\n { x: 0.359375, y: 0.234375 },\n { x: 0.359375, y: 0.234375 },\n { x: 0.390625, y: 0.234375 },\n { x: 0.390625, y: 0.234375 },\n { x: 0.421875, y: 0.234375 },\n { x: 0.421875, y: 0.234375 },\n { x: 0.453125, y: 0.234375 },\n { x: 0.453125, y: 0.234375 },\n { x: 0.484375, y: 0.234375 },\n { x: 0.484375, y: 0.234375 },\n { x: 0.515625, y: 0.234375 },\n { x: 0.515625, y: 0.234375 },\n { x: 0.546875, y: 0.234375 },\n { x: 0.546875, y: 0.234375 },\n { x: 0.578125, y: 0.234375 },\n { x: 0.578125, y: 0.234375 },\n { x: 0.609375, y: 0.234375 },\n { x: 0.609375, y: 0.234375 },\n { x: 0.640625, y: 0.234375 },\n { x: 0.640625, y: 0.234375 },\n { x: 0.671875, y: 0.234375 },\n { x: 0.671875, y: 0.234375 },\n { x: 0.703125, y: 0.234375 },\n { x: 0.703125, y: 0.234375 },\n { x: 0.734375, y: 0.234375 },\n { x: 0.734375, y: 0.234375 },\n { x: 0.765625, y: 0.234375 },\n { x: 0.765625, y: 0.234375 },\n { x: 0.796875, y: 0.234375 },\n { x: 0.796875, y: 0.234375 },\n { x: 0.828125, y: 0.234375 },\n { x: 0.828125, y: 0.234375 },\n { x: 0.859375, y: 0.234375 },\n { x: 0.859375, y: 0.234375 },\n { x: 0.890625, y: 0.234375 },\n { x: 0.890625, y: 0.234375 },\n { x: 0.921875, y: 0.234375 },\n { x: 0.921875, y: 0.234375 },\n { x: 0.953125, y: 0.234375 },\n { x: 0.953125, y: 0.234375 },\n { x: 0.984375, y: 0.234375 },\n { x: 0.984375, y: 0.234375 },\n { x: 0.015625, y: 0.265625 },\n { x: 0.015625, y: 0.265625 },\n { x: 0.046875, y: 0.265625 },\n { x: 0.046875, y: 0.265625 },\n { x: 0.078125, y: 0.265625 },\n { x: 0.078125, y: 0.265625 },\n { x: 0.109375, y: 0.265625 },\n { x: 0.109375, y: 0.265625 },\n { x: 0.140625, y: 0.265625 },\n { x: 0.140625, y: 0.265625 },\n { x: 0.171875, y: 0.265625 },\n { x: 0.171875, y: 0.265625 },\n { x: 0.203125, y: 0.265625 },\n { x: 0.203125, y: 0.265625 },\n { x: 0.234375, y: 0.265625 },\n { x: 0.234375, y: 0.265625 },\n { x: 0.265625, y: 0.265625 },\n { x: 0.265625, y: 0.265625 },\n { x: 0.296875, y: 0.265625 },\n { x: 0.296875, y: 0.265625 },\n { x: 0.328125, y: 0.265625 },\n { x: 0.328125, y: 0.265625 },\n { x: 0.359375, y: 0.265625 },\n { x: 0.359375, y: 0.265625 },\n { x: 0.390625, y: 0.265625 },\n { x: 0.390625, y: 0.265625 },\n { x: 0.421875, y: 0.265625 },\n { x: 0.421875, y: 0.265625 },\n { x: 0.453125, y: 0.265625 },\n { x: 0.453125, y: 0.265625 },\n { x: 0.484375, y: 0.265625 },\n { x: 0.484375, y: 0.265625 },\n { x: 0.515625, y: 0.265625 },\n { x: 0.515625, y: 0.265625 },\n { x: 0.546875, y: 0.265625 },\n { x: 0.546875, y: 0.265625 },\n { x: 0.578125, y: 0.265625 },\n { x: 0.578125, y: 0.265625 },\n { x: 0.609375, y: 0.265625 },\n { x: 0.609375, y: 0.265625 },\n { x: 0.640625, y: 0.265625 },\n { x: 0.640625, y: 0.265625 },\n { x: 0.671875, y: 0.265625 },\n { x: 0.671875, y: 0.265625 },\n { x: 0.703125, y: 0.265625 },\n { x: 0.703125, y: 0.265625 },\n { x: 0.734375, y: 0.265625 },\n { x: 0.734375, y: 0.265625 },\n { x: 0.765625, y: 0.265625 },\n { x: 0.765625, y: 0.265625 },\n { x: 0.796875, y: 0.265625 },\n { x: 0.796875, y: 0.265625 },\n { x: 0.828125, y: 0.265625 },\n { x: 0.828125, y: 0.265625 },\n { x: 0.859375, y: 0.265625 },\n { x: 0.859375, y: 0.265625 },\n { x: 0.890625, y: 0.265625 },\n { x: 0.890625, y: 0.265625 },\n { x: 0.921875, y: 0.265625 },\n { x: 0.921875, y: 0.265625 },\n { x: 0.953125, y: 0.265625 },\n { x: 0.953125, y: 0.265625 },\n { x: 0.984375, y: 0.265625 },\n { x: 0.984375, y: 0.265625 },\n { x: 0.015625, y: 0.296875 },\n { x: 0.015625, y: 0.296875 },\n { x: 0.046875, y: 0.296875 },\n { x: 0.046875, y: 0.296875 },\n { x: 0.078125, y: 0.296875 },\n { x: 0.078125, y: 0.296875 },\n { x: 0.109375, y: 0.296875 },\n { x: 0.109375, y: 0.296875 },\n { x: 0.140625, y: 0.296875 },\n { x: 0.140625, y: 0.296875 },\n { x: 0.171875, y: 0.296875 },\n { x: 0.171875, y: 0.296875 },\n { x: 0.203125, y: 0.296875 },\n { x: 0.203125, y: 0.296875 },\n { x: 0.234375, y: 0.296875 },\n { x: 0.234375, y: 0.296875 },\n { x: 0.265625, y: 0.296875 },\n { x: 0.265625, y: 0.296875 },\n { x: 0.296875, y: 0.296875 },\n { x: 0.296875, y: 0.296875 },\n { x: 0.328125, y: 0.296875 },\n { x: 0.328125, y: 0.296875 },\n { x: 0.359375, y: 0.296875 },\n { x: 0.359375, y: 0.296875 },\n { x: 0.390625, y: 0.296875 },\n { x: 0.390625, y: 0.296875 },\n { x: 0.421875, y: 0.296875 },\n { x: 0.421875, y: 0.296875 },\n { x: 0.453125, y: 0.296875 },\n { x: 0.453125, y: 0.296875 },\n { x: 0.484375, y: 0.296875 },\n { x: 0.484375, y: 0.296875 },\n { x: 0.515625, y: 0.296875 },\n { x: 0.515625, y: 0.296875 },\n { x: 0.546875, y: 0.296875 },\n { x: 0.546875, y: 0.296875 },\n { x: 0.578125, y: 0.296875 },\n { x: 0.578125, y: 0.296875 },\n { x: 0.609375, y: 0.296875 },\n { x: 0.609375, y: 0.296875 },\n { x: 0.640625, y: 0.296875 },\n { x: 0.640625, y: 0.296875 },\n { x: 0.671875, y: 0.296875 },\n { x: 0.671875, y: 0.296875 },\n { x: 0.703125, y: 0.296875 },\n { x: 0.703125, y: 0.296875 },\n { x: 0.734375, y: 0.296875 },\n { x: 0.734375, y: 0.296875 },\n { x: 0.765625, y: 0.296875 },\n { x: 0.765625, y: 0.296875 },\n { x: 0.796875, y: 0.296875 },\n { x: 0.796875, y: 0.296875 },\n { x: 0.828125, y: 0.296875 },\n { x: 0.828125, y: 0.296875 },\n { x: 0.859375, y: 0.296875 },\n { x: 0.859375, y: 0.296875 },\n { x: 0.890625, y: 0.296875 },\n { x: 0.890625, y: 0.296875 },\n { x: 0.921875, y: 0.296875 },\n { x: 0.921875, y: 0.296875 },\n { x: 0.953125, y: 0.296875 },\n { x: 0.953125, y: 0.296875 },\n { x: 0.984375, y: 0.296875 },\n { x: 0.984375, y: 0.296875 },\n { x: 0.015625, y: 0.328125 },\n { x: 0.015625, y: 0.328125 },\n { x: 0.046875, y: 0.328125 },\n { x: 0.046875, y: 0.328125 },\n { x: 0.078125, y: 0.328125 },\n { x: 0.078125, y: 0.328125 },\n { x: 0.109375, y: 0.328125 },\n { x: 0.109375, y: 0.328125 },\n { x: 0.140625, y: 0.328125 },\n { x: 0.140625, y: 0.328125 },\n { x: 0.171875, y: 0.328125 },\n { x: 0.171875, y: 0.328125 },\n { x: 0.203125, y: 0.328125 },\n { x: 0.203125, y: 0.328125 },\n { x: 0.234375, y: 0.328125 },\n { x: 0.234375, y: 0.328125 },\n { x: 0.265625, y: 0.328125 },\n { x: 0.265625, y: 0.328125 },\n { x: 0.296875, y: 0.328125 },\n { x: 0.296875, y: 0.328125 },\n { x: 0.328125, y: 0.328125 },\n { x: 0.328125, y: 0.328125 },\n { x: 0.359375, y: 0.328125 },\n { x: 0.359375, y: 0.328125 },\n { x: 0.390625, y: 0.328125 },\n { x: 0.390625, y: 0.328125 },\n { x: 0.421875, y: 0.328125 },\n { x: 0.421875, y: 0.328125 },\n { x: 0.453125, y: 0.328125 },\n { x: 0.453125, y: 0.328125 },\n { x: 0.484375, y: 0.328125 },\n { x: 0.484375, y: 0.328125 },\n { x: 0.515625, y: 0.328125 },\n { x: 0.515625, y: 0.328125 },\n { x: 0.546875, y: 0.328125 },\n { x: 0.546875, y: 0.328125 },\n { x: 0.578125, y: 0.328125 },\n { x: 0.578125, y: 0.328125 },\n { x: 0.609375, y: 0.328125 },\n { x: 0.609375, y: 0.328125 },\n { x: 0.640625, y: 0.328125 },\n { x: 0.640625, y: 0.328125 },\n { x: 0.671875, y: 0.328125 },\n { x: 0.671875, y: 0.328125 },\n { x: 0.703125, y: 0.328125 },\n { x: 0.703125, y: 0.328125 },\n { x: 0.734375, y: 0.328125 },\n { x: 0.734375, y: 0.328125 },\n { x: 0.765625, y: 0.328125 },\n { x: 0.765625, y: 0.328125 },\n { x: 0.796875, y: 0.328125 },\n { x: 0.796875, y: 0.328125 },\n { x: 0.828125, y: 0.328125 },\n { x: 0.828125, y: 0.328125 },\n { x: 0.859375, y: 0.328125 },\n { x: 0.859375, y: 0.328125 },\n { x: 0.890625, y: 0.328125 },\n { x: 0.890625, y: 0.328125 },\n { x: 0.921875, y: 0.328125 },\n { x: 0.921875, y: 0.328125 },\n { x: 0.953125, y: 0.328125 },\n { x: 0.953125, y: 0.328125 },\n { x: 0.984375, y: 0.328125 },\n { x: 0.984375, y: 0.328125 },\n { x: 0.015625, y: 0.359375 },\n { x: 0.015625, y: 0.359375 },\n { x: 0.046875, y: 0.359375 },\n { x: 0.046875, y: 0.359375 },\n { x: 0.078125, y: 0.359375 },\n { x: 0.078125, y: 0.359375 },\n { x: 0.109375, y: 0.359375 },\n { x: 0.109375, y: 0.359375 },\n { x: 0.140625, y: 0.359375 },\n { x: 0.140625, y: 0.359375 },\n { x: 0.171875, y: 0.359375 },\n { x: 0.171875, y: 0.359375 },\n { x: 0.203125, y: 0.359375 },\n { x: 0.203125, y: 0.359375 },\n { x: 0.234375, y: 0.359375 },\n { x: 0.234375, y: 0.359375 },\n { x: 0.265625, y: 0.359375 },\n { x: 0.265625, y: 0.359375 },\n { x: 0.296875, y: 0.359375 },\n { x: 0.296875, y: 0.359375 },\n { x: 0.328125, y: 0.359375 },\n { x: 0.328125, y: 0.359375 },\n { x: 0.359375, y: 0.359375 },\n { x: 0.359375, y: 0.359375 },\n { x: 0.390625, y: 0.359375 },\n { x: 0.390625, y: 0.359375 },\n { x: 0.421875, y: 0.359375 },\n { x: 0.421875, y: 0.359375 },\n { x: 0.453125, y: 0.359375 },\n { x: 0.453125, y: 0.359375 },\n { x: 0.484375, y: 0.359375 },\n { x: 0.484375, y: 0.359375 },\n { x: 0.515625, y: 0.359375 },\n { x: 0.515625, y: 0.359375 },\n { x: 0.546875, y: 0.359375 },\n { x: 0.546875, y: 0.359375 },\n { x: 0.578125, y: 0.359375 },\n { x: 0.578125, y: 0.359375 },\n { x: 0.609375, y: 0.359375 },\n { x: 0.609375, y: 0.359375 },\n { x: 0.640625, y: 0.359375 },\n { x: 0.640625, y: 0.359375 },\n { x: 0.671875, y: 0.359375 },\n { x: 0.671875, y: 0.359375 },\n { x: 0.703125, y: 0.359375 },\n { x: 0.703125, y: 0.359375 },\n { x: 0.734375, y: 0.359375 },\n { x: 0.734375, y: 0.359375 },\n { x: 0.765625, y: 0.359375 },\n { x: 0.765625, y: 0.359375 },\n { x: 0.796875, y: 0.359375 },\n { x: 0.796875, y: 0.359375 },\n { x: 0.828125, y: 0.359375 },\n { x: 0.828125, y: 0.359375 },\n { x: 0.859375, y: 0.359375 },\n { x: 0.859375, y: 0.359375 },\n { x: 0.890625, y: 0.359375 },\n { x: 0.890625, y: 0.359375 },\n { x: 0.921875, y: 0.359375 },\n { x: 0.921875, y: 0.359375 },\n { x: 0.953125, y: 0.359375 },\n { x: 0.953125, y: 0.359375 },\n { x: 0.984375, y: 0.359375 },\n { x: 0.984375, y: 0.359375 },\n { x: 0.015625, y: 0.390625 },\n { x: 0.015625, y: 0.390625 },\n { x: 0.046875, y: 0.390625 },\n { x: 0.046875, y: 0.390625 },\n { x: 0.078125, y: 0.390625 },\n { x: 0.078125, y: 0.390625 },\n { x: 0.109375, y: 0.390625 },\n { x: 0.109375, y: 0.390625 },\n { x: 0.140625, y: 0.390625 },\n { x: 0.140625, y: 0.390625 },\n { x: 0.171875, y: 0.390625 },\n { x: 0.171875, y: 0.390625 },\n { x: 0.203125, y: 0.390625 },\n { x: 0.203125, y: 0.390625 },\n { x: 0.234375, y: 0.390625 },\n { x: 0.234375, y: 0.390625 },\n { x: 0.265625, y: 0.390625 },\n { x: 0.265625, y: 0.390625 },\n { x: 0.296875, y: 0.390625 },\n { x: 0.296875, y: 0.390625 },\n { x: 0.328125, y: 0.390625 },\n { x: 0.328125, y: 0.390625 },\n { x: 0.359375, y: 0.390625 },\n { x: 0.359375, y: 0.390625 },\n { x: 0.390625, y: 0.390625 },\n { x: 0.390625, y: 0.390625 },\n { x: 0.421875, y: 0.390625 },\n { x: 0.421875, y: 0.390625 },\n { x: 0.453125, y: 0.390625 },\n { x: 0.453125, y: 0.390625 },\n { x: 0.484375, y: 0.390625 },\n { x: 0.484375, y: 0.390625 },\n { x: 0.515625, y: 0.390625 },\n { x: 0.515625, y: 0.390625 },\n { x: 0.546875, y: 0.390625 },\n { x: 0.546875, y: 0.390625 },\n { x: 0.578125, y: 0.390625 },\n { x: 0.578125, y: 0.390625 },\n { x: 0.609375, y: 0.390625 },\n { x: 0.609375, y: 0.390625 },\n { x: 0.640625, y: 0.390625 },\n { x: 0.640625, y: 0.390625 },\n { x: 0.671875, y: 0.390625 },\n { x: 0.671875, y: 0.390625 },\n { x: 0.703125, y: 0.390625 },\n { x: 0.703125, y: 0.390625 },\n { x: 0.734375, y: 0.390625 },\n { x: 0.734375, y: 0.390625 },\n { x: 0.765625, y: 0.390625 },\n { x: 0.765625, y: 0.390625 },\n { x: 0.796875, y: 0.390625 },\n { x: 0.796875, y: 0.390625 },\n { x: 0.828125, y: 0.390625 },\n { x: 0.828125, y: 0.390625 },\n { x: 0.859375, y: 0.390625 },\n { x: 0.859375, y: 0.390625 },\n { x: 0.890625, y: 0.390625 },\n { x: 0.890625, y: 0.390625 },\n { x: 0.921875, y: 0.390625 },\n { x: 0.921875, y: 0.390625 },\n { x: 0.953125, y: 0.390625 },\n { x: 0.953125, y: 0.390625 },\n { x: 0.984375, y: 0.390625 },\n { x: 0.984375, y: 0.390625 },\n { x: 0.015625, y: 0.421875 },\n { x: 0.015625, y: 0.421875 },\n { x: 0.046875, y: 0.421875 },\n { x: 0.046875, y: 0.421875 },\n { x: 0.078125, y: 0.421875 },\n { x: 0.078125, y: 0.421875 },\n { x: 0.109375, y: 0.421875 },\n { x: 0.109375, y: 0.421875 },\n { x: 0.140625, y: 0.421875 },\n { x: 0.140625, y: 0.421875 },\n { x: 0.171875, y: 0.421875 },\n { x: 0.171875, y: 0.421875 },\n { x: 0.203125, y: 0.421875 },\n { x: 0.203125, y: 0.421875 },\n { x: 0.234375, y: 0.421875 },\n { x: 0.234375, y: 0.421875 },\n { x: 0.265625, y: 0.421875 },\n { x: 0.265625, y: 0.421875 },\n { x: 0.296875, y: 0.421875 },\n { x: 0.296875, y: 0.421875 },\n { x: 0.328125, y: 0.421875 },\n { x: 0.328125, y: 0.421875 },\n { x: 0.359375, y: 0.421875 },\n { x: 0.359375, y: 0.421875 },\n { x: 0.390625, y: 0.421875 },\n { x: 0.390625, y: 0.421875 },\n { x: 0.421875, y: 0.421875 },\n { x: 0.421875, y: 0.421875 },\n { x: 0.453125, y: 0.421875 },\n { x: 0.453125, y: 0.421875 },\n { x: 0.484375, y: 0.421875 },\n { x: 0.484375, y: 0.421875 },\n { x: 0.515625, y: 0.421875 },\n { x: 0.515625, y: 0.421875 },\n { x: 0.546875, y: 0.421875 },\n { x: 0.546875, y: 0.421875 },\n { x: 0.578125, y: 0.421875 },\n { x: 0.578125, y: 0.421875 },\n { x: 0.609375, y: 0.421875 },\n { x: 0.609375, y: 0.421875 },\n { x: 0.640625, y: 0.421875 },\n { x: 0.640625, y: 0.421875 },\n { x: 0.671875, y: 0.421875 },\n { x: 0.671875, y: 0.421875 },\n { x: 0.703125, y: 0.421875 },\n { x: 0.703125, y: 0.421875 },\n { x: 0.734375, y: 0.421875 },\n { x: 0.734375, y: 0.421875 },\n { x: 0.765625, y: 0.421875 },\n { x: 0.765625, y: 0.421875 },\n { x: 0.796875, y: 0.421875 },\n { x: 0.796875, y: 0.421875 },\n { x: 0.828125, y: 0.421875 },\n { x: 0.828125, y: 0.421875 },\n { x: 0.859375, y: 0.421875 },\n { x: 0.859375, y: 0.421875 },\n { x: 0.890625, y: 0.421875 },\n { x: 0.890625, y: 0.421875 },\n { x: 0.921875, y: 0.421875 },\n { x: 0.921875, y: 0.421875 },\n { x: 0.953125, y: 0.421875 },\n { x: 0.953125, y: 0.421875 },\n { x: 0.984375, y: 0.421875 },\n { x: 0.984375, y: 0.421875 },\n { x: 0.015625, y: 0.453125 },\n { x: 0.015625, y: 0.453125 },\n { x: 0.046875, y: 0.453125 },\n { x: 0.046875, y: 0.453125 },\n { x: 0.078125, y: 0.453125 },\n { x: 0.078125, y: 0.453125 },\n { x: 0.109375, y: 0.453125 },\n { x: 0.109375, y: 0.453125 },\n { x: 0.140625, y: 0.453125 },\n { x: 0.140625, y: 0.453125 },\n { x: 0.171875, y: 0.453125 },\n { x: 0.171875, y: 0.453125 },\n { x: 0.203125, y: 0.453125 },\n { x: 0.203125, y: 0.453125 },\n { x: 0.234375, y: 0.453125 },\n { x: 0.234375, y: 0.453125 },\n { x: 0.265625, y: 0.453125 },\n { x: 0.265625, y: 0.453125 },\n { x: 0.296875, y: 0.453125 },\n { x: 0.296875, y: 0.453125 },\n { x: 0.328125, y: 0.453125 },\n { x: 0.328125, y: 0.453125 },\n { x: 0.359375, y: 0.453125 },\n { x: 0.359375, y: 0.453125 },\n { x: 0.390625, y: 0.453125 },\n { x: 0.390625, y: 0.453125 },\n { x: 0.421875, y: 0.453125 },\n { x: 0.421875, y: 0.453125 },\n { x: 0.453125, y: 0.453125 },\n { x: 0.453125, y: 0.453125 },\n { x: 0.484375, y: 0.453125 },\n { x: 0.484375, y: 0.453125 },\n { x: 0.515625, y: 0.453125 },\n { x: 0.515625, y: 0.453125 },\n { x: 0.546875, y: 0.453125 },\n { x: 0.546875, y: 0.453125 },\n { x: 0.578125, y: 0.453125 },\n { x: 0.578125, y: 0.453125 },\n { x: 0.609375, y: 0.453125 },\n { x: 0.609375, y: 0.453125 },\n { x: 0.640625, y: 0.453125 },\n { x: 0.640625, y: 0.453125 },\n { x: 0.671875, y: 0.453125 },\n { x: 0.671875, y: 0.453125 },\n { x: 0.703125, y: 0.453125 },\n { x: 0.703125, y: 0.453125 },\n { x: 0.734375, y: 0.453125 },\n { x: 0.734375, y: 0.453125 },\n { x: 0.765625, y: 0.453125 },\n { x: 0.765625, y: 0.453125 },\n { x: 0.796875, y: 0.453125 },\n { x: 0.796875, y: 0.453125 },\n { x: 0.828125, y: 0.453125 },\n { x: 0.828125, y: 0.453125 },\n { x: 0.859375, y: 0.453125 },\n { x: 0.859375, y: 0.453125 },\n { x: 0.890625, y: 0.453125 },\n { x: 0.890625, y: 0.453125 },\n { x: 0.921875, y: 0.453125 },\n { x: 0.921875, y: 0.453125 },\n { x: 0.953125, y: 0.453125 },\n { x: 0.953125, y: 0.453125 },\n { x: 0.984375, y: 0.453125 },\n { x: 0.984375, y: 0.453125 },\n { x: 0.015625, y: 0.484375 },\n { x: 0.015625, y: 0.484375 },\n { x: 0.046875, y: 0.484375 },\n { x: 0.046875, y: 0.484375 },\n { x: 0.078125, y: 0.484375 },\n { x: 0.078125, y: 0.484375 },\n { x: 0.109375, y: 0.484375 },\n { x: 0.109375, y: 0.484375 },\n { x: 0.140625, y: 0.484375 },\n { x: 0.140625, y: 0.484375 },\n { x: 0.171875, y: 0.484375 },\n { x: 0.171875, y: 0.484375 },\n { x: 0.203125, y: 0.484375 },\n { x: 0.203125, y: 0.484375 },\n { x: 0.234375, y: 0.484375 },\n { x: 0.234375, y: 0.484375 },\n { x: 0.265625, y: 0.484375 },\n { x: 0.265625, y: 0.484375 },\n { x: 0.296875, y: 0.484375 },\n { x: 0.296875, y: 0.484375 },\n { x: 0.328125, y: 0.484375 },\n { x: 0.328125, y: 0.484375 },\n { x: 0.359375, y: 0.484375 },\n { x: 0.359375, y: 0.484375 },\n { x: 0.390625, y: 0.484375 },\n { x: 0.390625, y: 0.484375 },\n { x: 0.421875, y: 0.484375 },\n { x: 0.421875, y: 0.484375 },\n { x: 0.453125, y: 0.484375 },\n { x: 0.453125, y: 0.484375 },\n { x: 0.484375, y: 0.484375 },\n { x: 0.484375, y: 0.484375 },\n { x: 0.515625, y: 0.484375 },\n { x: 0.515625, y: 0.484375 },\n { x: 0.546875, y: 0.484375 },\n { x: 0.546875, y: 0.484375 },\n { x: 0.578125, y: 0.484375 },\n { x: 0.578125, y: 0.484375 },\n { x: 0.609375, y: 0.484375 },\n { x: 0.609375, y: 0.484375 },\n { x: 0.640625, y: 0.484375 },\n { x: 0.640625, y: 0.484375 },\n { x: 0.671875, y: 0.484375 },\n { x: 0.671875, y: 0.484375 },\n { x: 0.703125, y: 0.484375 },\n { x: 0.703125, y: 0.484375 },\n { x: 0.734375, y: 0.484375 },\n { x: 0.734375, y: 0.484375 },\n { x: 0.765625, y: 0.484375 },\n { x: 0.765625, y: 0.484375 },\n { x: 0.796875, y: 0.484375 },\n { x: 0.796875, y: 0.484375 },\n { x: 0.828125, y: 0.484375 },\n { x: 0.828125, y: 0.484375 },\n { x: 0.859375, y: 0.484375 },\n { x: 0.859375, y: 0.484375 },\n { x: 0.890625, y: 0.484375 },\n { x: 0.890625, y: 0.484375 },\n { x: 0.921875, y: 0.484375 },\n { x: 0.921875, y: 0.484375 },\n { x: 0.953125, y: 0.484375 },\n { x: 0.953125, y: 0.484375 },\n { x: 0.984375, y: 0.484375 },\n { x: 0.984375, y: 0.484375 },\n { x: 0.015625, y: 0.515625 },\n { x: 0.015625, y: 0.515625 },\n { x: 0.046875, y: 0.515625 },\n { x: 0.046875, y: 0.515625 },\n { x: 0.078125, y: 0.515625 },\n { x: 0.078125, y: 0.515625 },\n { x: 0.109375, y: 0.515625 },\n { x: 0.109375, y: 0.515625 },\n { x: 0.140625, y: 0.515625 },\n { x: 0.140625, y: 0.515625 },\n { x: 0.171875, y: 0.515625 },\n { x: 0.171875, y: 0.515625 },\n { x: 0.203125, y: 0.515625 },\n { x: 0.203125, y: 0.515625 },\n { x: 0.234375, y: 0.515625 },\n { x: 0.234375, y: 0.515625 },\n { x: 0.265625, y: 0.515625 },\n { x: 0.265625, y: 0.515625 },\n { x: 0.296875, y: 0.515625 },\n { x: 0.296875, y: 0.515625 },\n { x: 0.328125, y: 0.515625 },\n { x: 0.328125, y: 0.515625 },\n { x: 0.359375, y: 0.515625 },\n { x: 0.359375, y: 0.515625 },\n { x: 0.390625, y: 0.515625 },\n { x: 0.390625, y: 0.515625 },\n { x: 0.421875, y: 0.515625 },\n { x: 0.421875, y: 0.515625 },\n { x: 0.453125, y: 0.515625 },\n { x: 0.453125, y: 0.515625 },\n { x: 0.484375, y: 0.515625 },\n { x: 0.484375, y: 0.515625 },\n { x: 0.515625, y: 0.515625 },\n { x: 0.515625, y: 0.515625 },\n { x: 0.546875, y: 0.515625 },\n { x: 0.546875, y: 0.515625 },\n { x: 0.578125, y: 0.515625 },\n { x: 0.578125, y: 0.515625 },\n { x: 0.609375, y: 0.515625 },\n { x: 0.609375, y: 0.515625 },\n { x: 0.640625, y: 0.515625 },\n { x: 0.640625, y: 0.515625 },\n { x: 0.671875, y: 0.515625 },\n { x: 0.671875, y: 0.515625 },\n { x: 0.703125, y: 0.515625 },\n { x: 0.703125, y: 0.515625 },\n { x: 0.734375, y: 0.515625 },\n { x: 0.734375, y: 0.515625 },\n { x: 0.765625, y: 0.515625 },\n { x: 0.765625, y: 0.515625 },\n { x: 0.796875, y: 0.515625 },\n { x: 0.796875, y: 0.515625 },\n { x: 0.828125, y: 0.515625 },\n { x: 0.828125, y: 0.515625 },\n { x: 0.859375, y: 0.515625 },\n { x: 0.859375, y: 0.515625 },\n { x: 0.890625, y: 0.515625 },\n { x: 0.890625, y: 0.515625 },\n { x: 0.921875, y: 0.515625 },\n { x: 0.921875, y: 0.515625 },\n { x: 0.953125, y: 0.515625 },\n { x: 0.953125, y: 0.515625 },\n { x: 0.984375, y: 0.515625 },\n { x: 0.984375, y: 0.515625 },\n { x: 0.015625, y: 0.546875 },\n { x: 0.015625, y: 0.546875 },\n { x: 0.046875, y: 0.546875 },\n { x: 0.046875, y: 0.546875 },\n { x: 0.078125, y: 0.546875 },\n { x: 0.078125, y: 0.546875 },\n { x: 0.109375, y: 0.546875 },\n { x: 0.109375, y: 0.546875 },\n { x: 0.140625, y: 0.546875 },\n { x: 0.140625, y: 0.546875 },\n { x: 0.171875, y: 0.546875 },\n { x: 0.171875, y: 0.546875 },\n { x: 0.203125, y: 0.546875 },\n { x: 0.203125, y: 0.546875 },\n { x: 0.234375, y: 0.546875 },\n { x: 0.234375, y: 0.546875 },\n { x: 0.265625, y: 0.546875 },\n { x: 0.265625, y: 0.546875 },\n { x: 0.296875, y: 0.546875 },\n { x: 0.296875, y: 0.546875 },\n { x: 0.328125, y: 0.546875 },\n { x: 0.328125, y: 0.546875 },\n { x: 0.359375, y: 0.546875 },\n { x: 0.359375, y: 0.546875 },\n { x: 0.390625, y: 0.546875 },\n { x: 0.390625, y: 0.546875 },\n { x: 0.421875, y: 0.546875 },\n { x: 0.421875, y: 0.546875 },\n { x: 0.453125, y: 0.546875 },\n { x: 0.453125, y: 0.546875 },\n { x: 0.484375, y: 0.546875 },\n { x: 0.484375, y: 0.546875 },\n { x: 0.515625, y: 0.546875 },\n { x: 0.515625, y: 0.546875 },\n { x: 0.546875, y: 0.546875 },\n { x: 0.546875, y: 0.546875 },\n { x: 0.578125, y: 0.546875 },\n { x: 0.578125, y: 0.546875 },\n { x: 0.609375, y: 0.546875 },\n { x: 0.609375, y: 0.546875 },\n { x: 0.640625, y: 0.546875 },\n { x: 0.640625, y: 0.546875 },\n { x: 0.671875, y: 0.546875 },\n { x: 0.671875, y: 0.546875 },\n { x: 0.703125, y: 0.546875 },\n { x: 0.703125, y: 0.546875 },\n { x: 0.734375, y: 0.546875 },\n { x: 0.734375, y: 0.546875 },\n { x: 0.765625, y: 0.546875 },\n { x: 0.765625, y: 0.546875 },\n { x: 0.796875, y: 0.546875 },\n { x: 0.796875, y: 0.546875 },\n { x: 0.828125, y: 0.546875 },\n { x: 0.828125, y: 0.546875 },\n { x: 0.859375, y: 0.546875 },\n { x: 0.859375, y: 0.546875 },\n { x: 0.890625, y: 0.546875 },\n { x: 0.890625, y: 0.546875 },\n { x: 0.921875, y: 0.546875 },\n { x: 0.921875, y: 0.546875 },\n { x: 0.953125, y: 0.546875 },\n { x: 0.953125, y: 0.546875 },\n { x: 0.984375, y: 0.546875 },\n { x: 0.984375, y: 0.546875 },\n { x: 0.015625, y: 0.578125 },\n { x: 0.015625, y: 0.578125 },\n { x: 0.046875, y: 0.578125 },\n { x: 0.046875, y: 0.578125 },\n { x: 0.078125, y: 0.578125 },\n { x: 0.078125, y: 0.578125 },\n { x: 0.109375, y: 0.578125 },\n { x: 0.109375, y: 0.578125 },\n { x: 0.140625, y: 0.578125 },\n { x: 0.140625, y: 0.578125 },\n { x: 0.171875, y: 0.578125 },\n { x: 0.171875, y: 0.578125 },\n { x: 0.203125, y: 0.578125 },\n { x: 0.203125, y: 0.578125 },\n { x: 0.234375, y: 0.578125 },\n { x: 0.234375, y: 0.578125 },\n { x: 0.265625, y: 0.578125 },\n { x: 0.265625, y: 0.578125 },\n { x: 0.296875, y: 0.578125 },\n { x: 0.296875, y: 0.578125 },\n { x: 0.328125, y: 0.578125 },\n { x: 0.328125, y: 0.578125 },\n { x: 0.359375, y: 0.578125 },\n { x: 0.359375, y: 0.578125 },\n { x: 0.390625, y: 0.578125 },\n { x: 0.390625, y: 0.578125 },\n { x: 0.421875, y: 0.578125 },\n { x: 0.421875, y: 0.578125 },\n { x: 0.453125, y: 0.578125 },\n { x: 0.453125, y: 0.578125 },\n { x: 0.484375, y: 0.578125 },\n { x: 0.484375, y: 0.578125 },\n { x: 0.515625, y: 0.578125 },\n { x: 0.515625, y: 0.578125 },\n { x: 0.546875, y: 0.578125 },\n { x: 0.546875, y: 0.578125 },\n { x: 0.578125, y: 0.578125 },\n { x: 0.578125, y: 0.578125 },\n { x: 0.609375, y: 0.578125 },\n { x: 0.609375, y: 0.578125 },\n { x: 0.640625, y: 0.578125 },\n { x: 0.640625, y: 0.578125 },\n { x: 0.671875, y: 0.578125 },\n { x: 0.671875, y: 0.578125 },\n { x: 0.703125, y: 0.578125 },\n { x: 0.703125, y: 0.578125 },\n { x: 0.734375, y: 0.578125 },\n { x: 0.734375, y: 0.578125 },\n { x: 0.765625, y: 0.578125 },\n { x: 0.765625, y: 0.578125 },\n { x: 0.796875, y: 0.578125 },\n { x: 0.796875, y: 0.578125 },\n { x: 0.828125, y: 0.578125 },\n { x: 0.828125, y: 0.578125 },\n { x: 0.859375, y: 0.578125 },\n { x: 0.859375, y: 0.578125 },\n { x: 0.890625, y: 0.578125 },\n { x: 0.890625, y: 0.578125 },\n { x: 0.921875, y: 0.578125 },\n { x: 0.921875, y: 0.578125 },\n { x: 0.953125, y: 0.578125 },\n { x: 0.953125, y: 0.578125 },\n { x: 0.984375, y: 0.578125 },\n { x: 0.984375, y: 0.578125 },\n { x: 0.015625, y: 0.609375 },\n { x: 0.015625, y: 0.609375 },\n { x: 0.046875, y: 0.609375 },\n { x: 0.046875, y: 0.609375 },\n { x: 0.078125, y: 0.609375 },\n { x: 0.078125, y: 0.609375 },\n { x: 0.109375, y: 0.609375 },\n { x: 0.109375, y: 0.609375 },\n { x: 0.140625, y: 0.609375 },\n { x: 0.140625, y: 0.609375 },\n { x: 0.171875, y: 0.609375 },\n { x: 0.171875, y: 0.609375 },\n { x: 0.203125, y: 0.609375 },\n { x: 0.203125, y: 0.609375 },\n { x: 0.234375, y: 0.609375 },\n { x: 0.234375, y: 0.609375 },\n { x: 0.265625, y: 0.609375 },\n { x: 0.265625, y: 0.609375 },\n { x: 0.296875, y: 0.609375 },\n { x: 0.296875, y: 0.609375 },\n { x: 0.328125, y: 0.609375 },\n { x: 0.328125, y: 0.609375 },\n { x: 0.359375, y: 0.609375 },\n { x: 0.359375, y: 0.609375 },\n { x: 0.390625, y: 0.609375 },\n { x: 0.390625, y: 0.609375 },\n { x: 0.421875, y: 0.609375 },\n { x: 0.421875, y: 0.609375 },\n { x: 0.453125, y: 0.609375 },\n { x: 0.453125, y: 0.609375 },\n { x: 0.484375, y: 0.609375 },\n { x: 0.484375, y: 0.609375 },\n { x: 0.515625, y: 0.609375 },\n { x: 0.515625, y: 0.609375 },\n { x: 0.546875, y: 0.609375 },\n { x: 0.546875, y: 0.609375 },\n { x: 0.578125, y: 0.609375 },\n { x: 0.578125, y: 0.609375 },\n { x: 0.609375, y: 0.609375 },\n { x: 0.609375, y: 0.609375 },\n { x: 0.640625, y: 0.609375 },\n { x: 0.640625, y: 0.609375 },\n { x: 0.671875, y: 0.609375 },\n { x: 0.671875, y: 0.609375 },\n { x: 0.703125, y: 0.609375 },\n { x: 0.703125, y: 0.609375 },\n { x: 0.734375, y: 0.609375 },\n { x: 0.734375, y: 0.609375 },\n { x: 0.765625, y: 0.609375 },\n { x: 0.765625, y: 0.609375 },\n { x: 0.796875, y: 0.609375 },\n { x: 0.796875, y: 0.609375 },\n { x: 0.828125, y: 0.609375 },\n { x: 0.828125, y: 0.609375 },\n { x: 0.859375, y: 0.609375 },\n { x: 0.859375, y: 0.609375 },\n { x: 0.890625, y: 0.609375 },\n { x: 0.890625, y: 0.609375 },\n { x: 0.921875, y: 0.609375 },\n { x: 0.921875, y: 0.609375 },\n { x: 0.953125, y: 0.609375 },\n { x: 0.953125, y: 0.609375 },\n { x: 0.984375, y: 0.609375 },\n { x: 0.984375, y: 0.609375 },\n { x: 0.015625, y: 0.640625 },\n { x: 0.015625, y: 0.640625 },\n { x: 0.046875, y: 0.640625 },\n { x: 0.046875, y: 0.640625 },\n { x: 0.078125, y: 0.640625 },\n { x: 0.078125, y: 0.640625 },\n { x: 0.109375, y: 0.640625 },\n { x: 0.109375, y: 0.640625 },\n { x: 0.140625, y: 0.640625 },\n { x: 0.140625, y: 0.640625 },\n { x: 0.171875, y: 0.640625 },\n { x: 0.171875, y: 0.640625 },\n { x: 0.203125, y: 0.640625 },\n { x: 0.203125, y: 0.640625 },\n { x: 0.234375, y: 0.640625 },\n { x: 0.234375, y: 0.640625 },\n { x: 0.265625, y: 0.640625 },\n { x: 0.265625, y: 0.640625 },\n { x: 0.296875, y: 0.640625 },\n { x: 0.296875, y: 0.640625 },\n { x: 0.328125, y: 0.640625 },\n { x: 0.328125, y: 0.640625 },\n { x: 0.359375, y: 0.640625 },\n { x: 0.359375, y: 0.640625 },\n { x: 0.390625, y: 0.640625 },\n { x: 0.390625, y: 0.640625 },\n { x: 0.421875, y: 0.640625 },\n { x: 0.421875, y: 0.640625 },\n { x: 0.453125, y: 0.640625 },\n { x: 0.453125, y: 0.640625 },\n { x: 0.484375, y: 0.640625 },\n { x: 0.484375, y: 0.640625 },\n { x: 0.515625, y: 0.640625 },\n { x: 0.515625, y: 0.640625 },\n { x: 0.546875, y: 0.640625 },\n { x: 0.546875, y: 0.640625 },\n { x: 0.578125, y: 0.640625 },\n { x: 0.578125, y: 0.640625 },\n { x: 0.609375, y: 0.640625 },\n { x: 0.609375, y: 0.640625 },\n { x: 0.640625, y: 0.640625 },\n { x: 0.640625, y: 0.640625 },\n { x: 0.671875, y: 0.640625 },\n { x: 0.671875, y: 0.640625 },\n { x: 0.703125, y: 0.640625 },\n { x: 0.703125, y: 0.640625 },\n { x: 0.734375, y: 0.640625 },\n { x: 0.734375, y: 0.640625 },\n { x: 0.765625, y: 0.640625 },\n { x: 0.765625, y: 0.640625 },\n { x: 0.796875, y: 0.640625 },\n { x: 0.796875, y: 0.640625 },\n { x: 0.828125, y: 0.640625 },\n { x: 0.828125, y: 0.640625 },\n { x: 0.859375, y: 0.640625 },\n { x: 0.859375, y: 0.640625 },\n { x: 0.890625, y: 0.640625 },\n { x: 0.890625, y: 0.640625 },\n { x: 0.921875, y: 0.640625 },\n { x: 0.921875, y: 0.640625 },\n { x: 0.953125, y: 0.640625 },\n { x: 0.953125, y: 0.640625 },\n { x: 0.984375, y: 0.640625 },\n { x: 0.984375, y: 0.640625 },\n { x: 0.015625, y: 0.671875 },\n { x: 0.015625, y: 0.671875 },\n { x: 0.046875, y: 0.671875 },\n { x: 0.046875, y: 0.671875 },\n { x: 0.078125, y: 0.671875 },\n { x: 0.078125, y: 0.671875 },\n { x: 0.109375, y: 0.671875 },\n { x: 0.109375, y: 0.671875 },\n { x: 0.140625, y: 0.671875 },\n { x: 0.140625, y: 0.671875 },\n { x: 0.171875, y: 0.671875 },\n { x: 0.171875, y: 0.671875 },\n { x: 0.203125, y: 0.671875 },\n { x: 0.203125, y: 0.671875 },\n { x: 0.234375, y: 0.671875 },\n { x: 0.234375, y: 0.671875 },\n { x: 0.265625, y: 0.671875 },\n { x: 0.265625, y: 0.671875 },\n { x: 0.296875, y: 0.671875 },\n { x: 0.296875, y: 0.671875 },\n { x: 0.328125, y: 0.671875 },\n { x: 0.328125, y: 0.671875 },\n { x: 0.359375, y: 0.671875 },\n { x: 0.359375, y: 0.671875 },\n { x: 0.390625, y: 0.671875 },\n { x: 0.390625, y: 0.671875 },\n { x: 0.421875, y: 0.671875 },\n { x: 0.421875, y: 0.671875 },\n { x: 0.453125, y: 0.671875 },\n { x: 0.453125, y: 0.671875 },\n { x: 0.484375, y: 0.671875 },\n { x: 0.484375, y: 0.671875 },\n { x: 0.515625, y: 0.671875 },\n { x: 0.515625, y: 0.671875 },\n { x: 0.546875, y: 0.671875 },\n { x: 0.546875, y: 0.671875 },\n { x: 0.578125, y: 0.671875 },\n { x: 0.578125, y: 0.671875 },\n { x: 0.609375, y: 0.671875 },\n { x: 0.609375, y: 0.671875 },\n { x: 0.640625, y: 0.671875 },\n { x: 0.640625, y: 0.671875 },\n { x: 0.671875, y: 0.671875 },\n { x: 0.671875, y: 0.671875 },\n { x: 0.703125, y: 0.671875 },\n { x: 0.703125, y: 0.671875 },\n { x: 0.734375, y: 0.671875 },\n { x: 0.734375, y: 0.671875 },\n { x: 0.765625, y: 0.671875 },\n { x: 0.765625, y: 0.671875 },\n { x: 0.796875, y: 0.671875 },\n { x: 0.796875, y: 0.671875 },\n { x: 0.828125, y: 0.671875 },\n { x: 0.828125, y: 0.671875 },\n { x: 0.859375, y: 0.671875 },\n { x: 0.859375, y: 0.671875 },\n { x: 0.890625, y: 0.671875 },\n { x: 0.890625, y: 0.671875 },\n { x: 0.921875, y: 0.671875 },\n { x: 0.921875, y: 0.671875 },\n { x: 0.953125, y: 0.671875 },\n { x: 0.953125, y: 0.671875 },\n { x: 0.984375, y: 0.671875 },\n { x: 0.984375, y: 0.671875 },\n { x: 0.015625, y: 0.703125 },\n { x: 0.015625, y: 0.703125 },\n { x: 0.046875, y: 0.703125 },\n { x: 0.046875, y: 0.703125 },\n { x: 0.078125, y: 0.703125 },\n { x: 0.078125, y: 0.703125 },\n { x: 0.109375, y: 0.703125 },\n { x: 0.109375, y: 0.703125 },\n { x: 0.140625, y: 0.703125 },\n { x: 0.140625, y: 0.703125 },\n { x: 0.171875, y: 0.703125 },\n { x: 0.171875, y: 0.703125 },\n { x: 0.203125, y: 0.703125 },\n { x: 0.203125, y: 0.703125 },\n { x: 0.234375, y: 0.703125 },\n { x: 0.234375, y: 0.703125 },\n { x: 0.265625, y: 0.703125 },\n { x: 0.265625, y: 0.703125 },\n { x: 0.296875, y: 0.703125 },\n { x: 0.296875, y: 0.703125 },\n { x: 0.328125, y: 0.703125 },\n { x: 0.328125, y: 0.703125 },\n { x: 0.359375, y: 0.703125 },\n { x: 0.359375, y: 0.703125 },\n { x: 0.390625, y: 0.703125 },\n { x: 0.390625, y: 0.703125 },\n { x: 0.421875, y: 0.703125 },\n { x: 0.421875, y: 0.703125 },\n { x: 0.453125, y: 0.703125 },\n { x: 0.453125, y: 0.703125 },\n { x: 0.484375, y: 0.703125 },\n { x: 0.484375, y: 0.703125 },\n { x: 0.515625, y: 0.703125 },\n { x: 0.515625, y: 0.703125 },\n { x: 0.546875, y: 0.703125 },\n { x: 0.546875, y: 0.703125 },\n { x: 0.578125, y: 0.703125 },\n { x: 0.578125, y: 0.703125 },\n { x: 0.609375, y: 0.703125 },\n { x: 0.609375, y: 0.703125 },\n { x: 0.640625, y: 0.703125 },\n { x: 0.640625, y: 0.703125 },\n { x: 0.671875, y: 0.703125 },\n { x: 0.671875, y: 0.703125 },\n { x: 0.703125, y: 0.703125 },\n { x: 0.703125, y: 0.703125 },\n { x: 0.734375, y: 0.703125 },\n { x: 0.734375, y: 0.703125 },\n { x: 0.765625, y: 0.703125 },\n { x: 0.765625, y: 0.703125 },\n { x: 0.796875, y: 0.703125 },\n { x: 0.796875, y: 0.703125 },\n { x: 0.828125, y: 0.703125 },\n { x: 0.828125, y: 0.703125 },\n { x: 0.859375, y: 0.703125 },\n { x: 0.859375, y: 0.703125 },\n { x: 0.890625, y: 0.703125 },\n { x: 0.890625, y: 0.703125 },\n { x: 0.921875, y: 0.703125 },\n { x: 0.921875, y: 0.703125 },\n { x: 0.953125, y: 0.703125 },\n { x: 0.953125, y: 0.703125 },\n { x: 0.984375, y: 0.703125 },\n { x: 0.984375, y: 0.703125 },\n { x: 0.015625, y: 0.734375 },\n { x: 0.015625, y: 0.734375 },\n { x: 0.046875, y: 0.734375 },\n { x: 0.046875, y: 0.734375 },\n { x: 0.078125, y: 0.734375 },\n { x: 0.078125, y: 0.734375 },\n { x: 0.109375, y: 0.734375 },\n { x: 0.109375, y: 0.734375 },\n { x: 0.140625, y: 0.734375 },\n { x: 0.140625, y: 0.734375 },\n { x: 0.171875, y: 0.734375 },\n { x: 0.171875, y: 0.734375 },\n { x: 0.203125, y: 0.734375 },\n { x: 0.203125, y: 0.734375 },\n { x: 0.234375, y: 0.734375 },\n { x: 0.234375, y: 0.734375 },\n { x: 0.265625, y: 0.734375 },\n { x: 0.265625, y: 0.734375 },\n { x: 0.296875, y: 0.734375 },\n { x: 0.296875, y: 0.734375 },\n { x: 0.328125, y: 0.734375 },\n { x: 0.328125, y: 0.734375 },\n { x: 0.359375, y: 0.734375 },\n { x: 0.359375, y: 0.734375 },\n { x: 0.390625, y: 0.734375 },\n { x: 0.390625, y: 0.734375 },\n { x: 0.421875, y: 0.734375 },\n { x: 0.421875, y: 0.734375 },\n { x: 0.453125, y: 0.734375 },\n { x: 0.453125, y: 0.734375 },\n { x: 0.484375, y: 0.734375 },\n { x: 0.484375, y: 0.734375 },\n { x: 0.515625, y: 0.734375 },\n { x: 0.515625, y: 0.734375 },\n { x: 0.546875, y: 0.734375 },\n { x: 0.546875, y: 0.734375 },\n { x: 0.578125, y: 0.734375 },\n { x: 0.578125, y: 0.734375 },\n { x: 0.609375, y: 0.734375 },\n { x: 0.609375, y: 0.734375 },\n { x: 0.640625, y: 0.734375 },\n { x: 0.640625, y: 0.734375 },\n { x: 0.671875, y: 0.734375 },\n { x: 0.671875, y: 0.734375 },\n { x: 0.703125, y: 0.734375 },\n { x: 0.703125, y: 0.734375 },\n { x: 0.734375, y: 0.734375 },\n { x: 0.734375, y: 0.734375 },\n { x: 0.765625, y: 0.734375 },\n { x: 0.765625, y: 0.734375 },\n { x: 0.796875, y: 0.734375 },\n { x: 0.796875, y: 0.734375 },\n { x: 0.828125, y: 0.734375 },\n { x: 0.828125, y: 0.734375 },\n { x: 0.859375, y: 0.734375 },\n { x: 0.859375, y: 0.734375 },\n { x: 0.890625, y: 0.734375 },\n { x: 0.890625, y: 0.734375 },\n { x: 0.921875, y: 0.734375 },\n { x: 0.921875, y: 0.734375 },\n { x: 0.953125, y: 0.734375 },\n { x: 0.953125, y: 0.734375 },\n { x: 0.984375, y: 0.734375 },\n { x: 0.984375, y: 0.734375 },\n { x: 0.015625, y: 0.765625 },\n { x: 0.015625, y: 0.765625 },\n { x: 0.046875, y: 0.765625 },\n { x: 0.046875, y: 0.765625 },\n { x: 0.078125, y: 0.765625 },\n { x: 0.078125, y: 0.765625 },\n { x: 0.109375, y: 0.765625 },\n { x: 0.109375, y: 0.765625 },\n { x: 0.140625, y: 0.765625 },\n { x: 0.140625, y: 0.765625 },\n { x: 0.171875, y: 0.765625 },\n { x: 0.171875, y: 0.765625 },\n { x: 0.203125, y: 0.765625 },\n { x: 0.203125, y: 0.765625 },\n { x: 0.234375, y: 0.765625 },\n { x: 0.234375, y: 0.765625 },\n { x: 0.265625, y: 0.765625 },\n { x: 0.265625, y: 0.765625 },\n { x: 0.296875, y: 0.765625 },\n { x: 0.296875, y: 0.765625 },\n { x: 0.328125, y: 0.765625 },\n { x: 0.328125, y: 0.765625 },\n { x: 0.359375, y: 0.765625 },\n { x: 0.359375, y: 0.765625 },\n { x: 0.390625, y: 0.765625 },\n { x: 0.390625, y: 0.765625 },\n { x: 0.421875, y: 0.765625 },\n { x: 0.421875, y: 0.765625 },\n { x: 0.453125, y: 0.765625 },\n { x: 0.453125, y: 0.765625 },\n { x: 0.484375, y: 0.765625 },\n { x: 0.484375, y: 0.765625 },\n { x: 0.515625, y: 0.765625 },\n { x: 0.515625, y: 0.765625 },\n { x: 0.546875, y: 0.765625 },\n { x: 0.546875, y: 0.765625 },\n { x: 0.578125, y: 0.765625 },\n { x: 0.578125, y: 0.765625 },\n { x: 0.609375, y: 0.765625 },\n { x: 0.609375, y: 0.765625 },\n { x: 0.640625, y: 0.765625 },\n { x: 0.640625, y: 0.765625 },\n { x: 0.671875, y: 0.765625 },\n { x: 0.671875, y: 0.765625 },\n { x: 0.703125, y: 0.765625 },\n { x: 0.703125, y: 0.765625 },\n { x: 0.734375, y: 0.765625 },\n { x: 0.734375, y: 0.765625 },\n { x: 0.765625, y: 0.765625 },\n { x: 0.765625, y: 0.765625 },\n { x: 0.796875, y: 0.765625 },\n { x: 0.796875, y: 0.765625 },\n { x: 0.828125, y: 0.765625 },\n { x: 0.828125, y: 0.765625 },\n { x: 0.859375, y: 0.765625 },\n { x: 0.859375, y: 0.765625 },\n { x: 0.890625, y: 0.765625 },\n { x: 0.890625, y: 0.765625 },\n { x: 0.921875, y: 0.765625 },\n { x: 0.921875, y: 0.765625 },\n { x: 0.953125, y: 0.765625 },\n { x: 0.953125, y: 0.765625 },\n { x: 0.984375, y: 0.765625 },\n { x: 0.984375, y: 0.765625 },\n { x: 0.015625, y: 0.796875 },\n { x: 0.015625, y: 0.796875 },\n { x: 0.046875, y: 0.796875 },\n { x: 0.046875, y: 0.796875 },\n { x: 0.078125, y: 0.796875 },\n { x: 0.078125, y: 0.796875 },\n { x: 0.109375, y: 0.796875 },\n { x: 0.109375, y: 0.796875 },\n { x: 0.140625, y: 0.796875 },\n { x: 0.140625, y: 0.796875 },\n { x: 0.171875, y: 0.796875 },\n { x: 0.171875, y: 0.796875 },\n { x: 0.203125, y: 0.796875 },\n { x: 0.203125, y: 0.796875 },\n { x: 0.234375, y: 0.796875 },\n { x: 0.234375, y: 0.796875 },\n { x: 0.265625, y: 0.796875 },\n { x: 0.265625, y: 0.796875 },\n { x: 0.296875, y: 0.796875 },\n { x: 0.296875, y: 0.796875 },\n { x: 0.328125, y: 0.796875 },\n { x: 0.328125, y: 0.796875 },\n { x: 0.359375, y: 0.796875 },\n { x: 0.359375, y: 0.796875 },\n { x: 0.390625, y: 0.796875 },\n { x: 0.390625, y: 0.796875 },\n { x: 0.421875, y: 0.796875 },\n { x: 0.421875, y: 0.796875 },\n { x: 0.453125, y: 0.796875 },\n { x: 0.453125, y: 0.796875 },\n { x: 0.484375, y: 0.796875 },\n { x: 0.484375, y: 0.796875 },\n { x: 0.515625, y: 0.796875 },\n { x: 0.515625, y: 0.796875 },\n { x: 0.546875, y: 0.796875 },\n { x: 0.546875, y: 0.796875 },\n { x: 0.578125, y: 0.796875 },\n { x: 0.578125, y: 0.796875 },\n { x: 0.609375, y: 0.796875 },\n { x: 0.609375, y: 0.796875 },\n { x: 0.640625, y: 0.796875 },\n { x: 0.640625, y: 0.796875 },\n { x: 0.671875, y: 0.796875 },\n { x: 0.671875, y: 0.796875 },\n { x: 0.703125, y: 0.796875 },\n { x: 0.703125, y: 0.796875 },\n { x: 0.734375, y: 0.796875 },\n { x: 0.734375, y: 0.796875 },\n { x: 0.765625, y: 0.796875 },\n { x: 0.765625, y: 0.796875 },\n { x: 0.796875, y: 0.796875 },\n { x: 0.796875, y: 0.796875 },\n { x: 0.828125, y: 0.796875 },\n { x: 0.828125, y: 0.796875 },\n { x: 0.859375, y: 0.796875 },\n { x: 0.859375, y: 0.796875 },\n { x: 0.890625, y: 0.796875 },\n { x: 0.890625, y: 0.796875 },\n { x: 0.921875, y: 0.796875 },\n { x: 0.921875, y: 0.796875 },\n { x: 0.953125, y: 0.796875 },\n { x: 0.953125, y: 0.796875 },\n { x: 0.984375, y: 0.796875 },\n { x: 0.984375, y: 0.796875 },\n { x: 0.015625, y: 0.828125 },\n { x: 0.015625, y: 0.828125 },\n { x: 0.046875, y: 0.828125 },\n { x: 0.046875, y: 0.828125 },\n { x: 0.078125, y: 0.828125 },\n { x: 0.078125, y: 0.828125 },\n { x: 0.109375, y: 0.828125 },\n { x: 0.109375, y: 0.828125 },\n { x: 0.140625, y: 0.828125 },\n { x: 0.140625, y: 0.828125 },\n { x: 0.171875, y: 0.828125 },\n { x: 0.171875, y: 0.828125 },\n { x: 0.203125, y: 0.828125 },\n { x: 0.203125, y: 0.828125 },\n { x: 0.234375, y: 0.828125 },\n { x: 0.234375, y: 0.828125 },\n { x: 0.265625, y: 0.828125 },\n { x: 0.265625, y: 0.828125 },\n { x: 0.296875, y: 0.828125 },\n { x: 0.296875, y: 0.828125 },\n { x: 0.328125, y: 0.828125 },\n { x: 0.328125, y: 0.828125 },\n { x: 0.359375, y: 0.828125 },\n { x: 0.359375, y: 0.828125 },\n { x: 0.390625, y: 0.828125 },\n { x: 0.390625, y: 0.828125 },\n { x: 0.421875, y: 0.828125 },\n { x: 0.421875, y: 0.828125 },\n { x: 0.453125, y: 0.828125 },\n { x: 0.453125, y: 0.828125 },\n { x: 0.484375, y: 0.828125 },\n { x: 0.484375, y: 0.828125 },\n { x: 0.515625, y: 0.828125 },\n { x: 0.515625, y: 0.828125 },\n { x: 0.546875, y: 0.828125 },\n { x: 0.546875, y: 0.828125 },\n { x: 0.578125, y: 0.828125 },\n { x: 0.578125, y: 0.828125 },\n { x: 0.609375, y: 0.828125 },\n { x: 0.609375, y: 0.828125 },\n { x: 0.640625, y: 0.828125 },\n { x: 0.640625, y: 0.828125 },\n { x: 0.671875, y: 0.828125 },\n { x: 0.671875, y: 0.828125 },\n { x: 0.703125, y: 0.828125 },\n { x: 0.703125, y: 0.828125 },\n { x: 0.734375, y: 0.828125 },\n { x: 0.734375, y: 0.828125 },\n { x: 0.765625, y: 0.828125 },\n { x: 0.765625, y: 0.828125 },\n { x: 0.796875, y: 0.828125 },\n { x: 0.796875, y: 0.828125 },\n { x: 0.828125, y: 0.828125 },\n { x: 0.828125, y: 0.828125 },\n { x: 0.859375, y: 0.828125 },\n { x: 0.859375, y: 0.828125 },\n { x: 0.890625, y: 0.828125 },\n { x: 0.890625, y: 0.828125 },\n { x: 0.921875, y: 0.828125 },\n { x: 0.921875, y: 0.828125 },\n { x: 0.953125, y: 0.828125 },\n { x: 0.953125, y: 0.828125 },\n { x: 0.984375, y: 0.828125 },\n { x: 0.984375, y: 0.828125 },\n { x: 0.015625, y: 0.859375 },\n { x: 0.015625, y: 0.859375 },\n { x: 0.046875, y: 0.859375 },\n { x: 0.046875, y: 0.859375 },\n { x: 0.078125, y: 0.859375 },\n { x: 0.078125, y: 0.859375 },\n { x: 0.109375, y: 0.859375 },\n { x: 0.109375, y: 0.859375 },\n { x: 0.140625, y: 0.859375 },\n { x: 0.140625, y: 0.859375 },\n { x: 0.171875, y: 0.859375 },\n { x: 0.171875, y: 0.859375 },\n { x: 0.203125, y: 0.859375 },\n { x: 0.203125, y: 0.859375 },\n { x: 0.234375, y: 0.859375 },\n { x: 0.234375, y: 0.859375 },\n { x: 0.265625, y: 0.859375 },\n { x: 0.265625, y: 0.859375 },\n { x: 0.296875, y: 0.859375 },\n { x: 0.296875, y: 0.859375 },\n { x: 0.328125, y: 0.859375 },\n { x: 0.328125, y: 0.859375 },\n { x: 0.359375, y: 0.859375 },\n { x: 0.359375, y: 0.859375 },\n { x: 0.390625, y: 0.859375 },\n { x: 0.390625, y: 0.859375 },\n { x: 0.421875, y: 0.859375 },\n { x: 0.421875, y: 0.859375 },\n { x: 0.453125, y: 0.859375 },\n { x: 0.453125, y: 0.859375 },\n { x: 0.484375, y: 0.859375 },\n { x: 0.484375, y: 0.859375 },\n { x: 0.515625, y: 0.859375 },\n { x: 0.515625, y: 0.859375 },\n { x: 0.546875, y: 0.859375 },\n { x: 0.546875, y: 0.859375 },\n { x: 0.578125, y: 0.859375 },\n { x: 0.578125, y: 0.859375 },\n { x: 0.609375, y: 0.859375 },\n { x: 0.609375, y: 0.859375 },\n { x: 0.640625, y: 0.859375 },\n { x: 0.640625, y: 0.859375 },\n { x: 0.671875, y: 0.859375 },\n { x: 0.671875, y: 0.859375 },\n { x: 0.703125, y: 0.859375 },\n { x: 0.703125, y: 0.859375 },\n { x: 0.734375, y: 0.859375 },\n { x: 0.734375, y: 0.859375 },\n { x: 0.765625, y: 0.859375 },\n { x: 0.765625, y: 0.859375 },\n { x: 0.796875, y: 0.859375 },\n { x: 0.796875, y: 0.859375 },\n { x: 0.828125, y: 0.859375 },\n { x: 0.828125, y: 0.859375 },\n { x: 0.859375, y: 0.859375 },\n { x: 0.859375, y: 0.859375 },\n { x: 0.890625, y: 0.859375 },\n { x: 0.890625, y: 0.859375 },\n { x: 0.921875, y: 0.859375 },\n { x: 0.921875, y: 0.859375 },\n { x: 0.953125, y: 0.859375 },\n { x: 0.953125, y: 0.859375 },\n { x: 0.984375, y: 0.859375 },\n { x: 0.984375, y: 0.859375 },\n { x: 0.015625, y: 0.890625 },\n { x: 0.015625, y: 0.890625 },\n { x: 0.046875, y: 0.890625 },\n { x: 0.046875, y: 0.890625 },\n { x: 0.078125, y: 0.890625 },\n { x: 0.078125, y: 0.890625 },\n { x: 0.109375, y: 0.890625 },\n { x: 0.109375, y: 0.890625 },\n { x: 0.140625, y: 0.890625 },\n { x: 0.140625, y: 0.890625 },\n { x: 0.171875, y: 0.890625 },\n { x: 0.171875, y: 0.890625 },\n { x: 0.203125, y: 0.890625 },\n { x: 0.203125, y: 0.890625 },\n { x: 0.234375, y: 0.890625 },\n { x: 0.234375, y: 0.890625 },\n { x: 0.265625, y: 0.890625 },\n { x: 0.265625, y: 0.890625 },\n { x: 0.296875, y: 0.890625 },\n { x: 0.296875, y: 0.890625 },\n { x: 0.328125, y: 0.890625 },\n { x: 0.328125, y: 0.890625 },\n { x: 0.359375, y: 0.890625 },\n { x: 0.359375, y: 0.890625 },\n { x: 0.390625, y: 0.890625 },\n { x: 0.390625, y: 0.890625 },\n { x: 0.421875, y: 0.890625 },\n { x: 0.421875, y: 0.890625 },\n { x: 0.453125, y: 0.890625 },\n { x: 0.453125, y: 0.890625 },\n { x: 0.484375, y: 0.890625 },\n { x: 0.484375, y: 0.890625 },\n { x: 0.515625, y: 0.890625 },\n { x: 0.515625, y: 0.890625 },\n { x: 0.546875, y: 0.890625 },\n { x: 0.546875, y: 0.890625 },\n { x: 0.578125, y: 0.890625 },\n { x: 0.578125, y: 0.890625 },\n { x: 0.609375, y: 0.890625 },\n { x: 0.609375, y: 0.890625 },\n { x: 0.640625, y: 0.890625 },\n { x: 0.640625, y: 0.890625 },\n { x: 0.671875, y: 0.890625 },\n { x: 0.671875, y: 0.890625 },\n { x: 0.703125, y: 0.890625 },\n { x: 0.703125, y: 0.890625 },\n { x: 0.734375, y: 0.890625 },\n { x: 0.734375, y: 0.890625 },\n { x: 0.765625, y: 0.890625 },\n { x: 0.765625, y: 0.890625 },\n { x: 0.796875, y: 0.890625 },\n { x: 0.796875, y: 0.890625 },\n { x: 0.828125, y: 0.890625 },\n { x: 0.828125, y: 0.890625 },\n { x: 0.859375, y: 0.890625 },\n { x: 0.859375, y: 0.890625 },\n { x: 0.890625, y: 0.890625 },\n { x: 0.890625, y: 0.890625 },\n { x: 0.921875, y: 0.890625 },\n { x: 0.921875, y: 0.890625 },\n { x: 0.953125, y: 0.890625 },\n { x: 0.953125, y: 0.890625 },\n { x: 0.984375, y: 0.890625 },\n { x: 0.984375, y: 0.890625 },\n { x: 0.015625, y: 0.921875 },\n { x: 0.015625, y: 0.921875 },\n { x: 0.046875, y: 0.921875 },\n { x: 0.046875, y: 0.921875 },\n { x: 0.078125, y: 0.921875 },\n { x: 0.078125, y: 0.921875 },\n { x: 0.109375, y: 0.921875 },\n { x: 0.109375, y: 0.921875 },\n { x: 0.140625, y: 0.921875 },\n { x: 0.140625, y: 0.921875 },\n { x: 0.171875, y: 0.921875 },\n { x: 0.171875, y: 0.921875 },\n { x: 0.203125, y: 0.921875 },\n { x: 0.203125, y: 0.921875 },\n { x: 0.234375, y: 0.921875 },\n { x: 0.234375, y: 0.921875 },\n { x: 0.265625, y: 0.921875 },\n { x: 0.265625, y: 0.921875 },\n { x: 0.296875, y: 0.921875 },\n { x: 0.296875, y: 0.921875 },\n { x: 0.328125, y: 0.921875 },\n { x: 0.328125, y: 0.921875 },\n { x: 0.359375, y: 0.921875 },\n { x: 0.359375, y: 0.921875 },\n { x: 0.390625, y: 0.921875 },\n { x: 0.390625, y: 0.921875 },\n { x: 0.421875, y: 0.921875 },\n { x: 0.421875, y: 0.921875 },\n { x: 0.453125, y: 0.921875 },\n { x: 0.453125, y: 0.921875 },\n { x: 0.484375, y: 0.921875 },\n { x: 0.484375, y: 0.921875 },\n { x: 0.515625, y: 0.921875 },\n { x: 0.515625, y: 0.921875 },\n { x: 0.546875, y: 0.921875 },\n { x: 0.546875, y: 0.921875 },\n { x: 0.578125, y: 0.921875 },\n { x: 0.578125, y: 0.921875 },\n { x: 0.609375, y: 0.921875 },\n { x: 0.609375, y: 0.921875 },\n { x: 0.640625, y: 0.921875 },\n { x: 0.640625, y: 0.921875 },\n { x: 0.671875, y: 0.921875 },\n { x: 0.671875, y: 0.921875 },\n { x: 0.703125, y: 0.921875 },\n { x: 0.703125, y: 0.921875 },\n { x: 0.734375, y: 0.921875 },\n { x: 0.734375, y: 0.921875 },\n { x: 0.765625, y: 0.921875 },\n { x: 0.765625, y: 0.921875 },\n { x: 0.796875, y: 0.921875 },\n { x: 0.796875, y: 0.921875 },\n { x: 0.828125, y: 0.921875 },\n { x: 0.828125, y: 0.921875 },\n { x: 0.859375, y: 0.921875 },\n { x: 0.859375, y: 0.921875 },\n { x: 0.890625, y: 0.921875 },\n { x: 0.890625, y: 0.921875 },\n { x: 0.921875, y: 0.921875 },\n { x: 0.921875, y: 0.921875 },\n { x: 0.953125, y: 0.921875 },\n { x: 0.953125, y: 0.921875 },\n { x: 0.984375, y: 0.921875 },\n { x: 0.984375, y: 0.921875 },\n { x: 0.015625, y: 0.953125 },\n { x: 0.015625, y: 0.953125 },\n { x: 0.046875, y: 0.953125 },\n { x: 0.046875, y: 0.953125 },\n { x: 0.078125, y: 0.953125 },\n { x: 0.078125, y: 0.953125 },\n { x: 0.109375, y: 0.953125 },\n { x: 0.109375, y: 0.953125 },\n { x: 0.140625, y: 0.953125 },\n { x: 0.140625, y: 0.953125 },\n { x: 0.171875, y: 0.953125 },\n { x: 0.171875, y: 0.953125 },\n { x: 0.203125, y: 0.953125 },\n { x: 0.203125, y: 0.953125 },\n { x: 0.234375, y: 0.953125 },\n { x: 0.234375, y: 0.953125 },\n { x: 0.265625, y: 0.953125 },\n { x: 0.265625, y: 0.953125 },\n { x: 0.296875, y: 0.953125 },\n { x: 0.296875, y: 0.953125 },\n { x: 0.328125, y: 0.953125 },\n { x: 0.328125, y: 0.953125 },\n { x: 0.359375, y: 0.953125 },\n { x: 0.359375, y: 0.953125 },\n { x: 0.390625, y: 0.953125 },\n { x: 0.390625, y: 0.953125 },\n { x: 0.421875, y: 0.953125 },\n { x: 0.421875, y: 0.953125 },\n { x: 0.453125, y: 0.953125 },\n { x: 0.453125, y: 0.953125 },\n { x: 0.484375, y: 0.953125 },\n { x: 0.484375, y: 0.953125 },\n { x: 0.515625, y: 0.953125 },\n { x: 0.515625, y: 0.953125 },\n { x: 0.546875, y: 0.953125 },\n { x: 0.546875, y: 0.953125 },\n { x: 0.578125, y: 0.953125 },\n { x: 0.578125, y: 0.953125 },\n { x: 0.609375, y: 0.953125 },\n { x: 0.609375, y: 0.953125 },\n { x: 0.640625, y: 0.953125 },\n { x: 0.640625, y: 0.953125 },\n { x: 0.671875, y: 0.953125 },\n { x: 0.671875, y: 0.953125 },\n { x: 0.703125, y: 0.953125 },\n { x: 0.703125, y: 0.953125 },\n { x: 0.734375, y: 0.953125 },\n { x: 0.734375, y: 0.953125 },\n { x: 0.765625, y: 0.953125 },\n { x: 0.765625, y: 0.953125 },\n { x: 0.796875, y: 0.953125 },\n { x: 0.796875, y: 0.953125 },\n { x: 0.828125, y: 0.953125 },\n { x: 0.828125, y: 0.953125 },\n { x: 0.859375, y: 0.953125 },\n { x: 0.859375, y: 0.953125 },\n { x: 0.890625, y: 0.953125 },\n { x: 0.890625, y: 0.953125 },\n { x: 0.921875, y: 0.953125 },\n { x: 0.921875, y: 0.953125 },\n { x: 0.953125, y: 0.953125 },\n { x: 0.953125, y: 0.953125 },\n { x: 0.984375, y: 0.953125 },\n { x: 0.984375, y: 0.953125 },\n { x: 0.015625, y: 0.984375 },\n { x: 0.015625, y: 0.984375 },\n { x: 0.046875, y: 0.984375 },\n { x: 0.046875, y: 0.984375 },\n { x: 0.078125, y: 0.984375 },\n { x: 0.078125, y: 0.984375 },\n { x: 0.109375, y: 0.984375 },\n { x: 0.109375, y: 0.984375 },\n { x: 0.140625, y: 0.984375 },\n { x: 0.140625, y: 0.984375 },\n { x: 0.171875, y: 0.984375 },\n { x: 0.171875, y: 0.984375 },\n { x: 0.203125, y: 0.984375 },\n { x: 0.203125, y: 0.984375 },\n { x: 0.234375, y: 0.984375 },\n { x: 0.234375, y: 0.984375 },\n { x: 0.265625, y: 0.984375 },\n { x: 0.265625, y: 0.984375 },\n { x: 0.296875, y: 0.984375 },\n { x: 0.296875, y: 0.984375 },\n { x: 0.328125, y: 0.984375 },\n { x: 0.328125, y: 0.984375 },\n { x: 0.359375, y: 0.984375 },\n { x: 0.359375, y: 0.984375 },\n { x: 0.390625, y: 0.984375 },\n { x: 0.390625, y: 0.984375 },\n { x: 0.421875, y: 0.984375 },\n { x: 0.421875, y: 0.984375 },\n { x: 0.453125, y: 0.984375 },\n { x: 0.453125, y: 0.984375 },\n { x: 0.484375, y: 0.984375 },\n { x: 0.484375, y: 0.984375 },\n { x: 0.515625, y: 0.984375 },\n { x: 0.515625, y: 0.984375 },\n { x: 0.546875, y: 0.984375 },\n { x: 0.546875, y: 0.984375 },\n { x: 0.578125, y: 0.984375 },\n { x: 0.578125, y: 0.984375 },\n { x: 0.609375, y: 0.984375 },\n { x: 0.609375, y: 0.984375 },\n { x: 0.640625, y: 0.984375 },\n { x: 0.640625, y: 0.984375 },\n { x: 0.671875, y: 0.984375 },\n { x: 0.671875, y: 0.984375 },\n { x: 0.703125, y: 0.984375 },\n { x: 0.703125, y: 0.984375 },\n { x: 0.734375, y: 0.984375 },\n { x: 0.734375, y: 0.984375 },\n { x: 0.765625, y: 0.984375 },\n { x: 0.765625, y: 0.984375 },\n { x: 0.796875, y: 0.984375 },\n { x: 0.796875, y: 0.984375 },\n { x: 0.828125, y: 0.984375 },\n { x: 0.828125, y: 0.984375 },\n { x: 0.859375, y: 0.984375 },\n { x: 0.859375, y: 0.984375 },\n { x: 0.890625, y: 0.984375 },\n { x: 0.890625, y: 0.984375 },\n { x: 0.921875, y: 0.984375 },\n { x: 0.921875, y: 0.984375 },\n { x: 0.953125, y: 0.984375 },\n { x: 0.953125, y: 0.984375 },\n { x: 0.984375, y: 0.984375 },\n { x: 0.984375, y: 0.984375 },\n { x: 0.03125, y: 0.03125 },\n { x: 0.03125, y: 0.03125 },\n { x: 0.09375, y: 0.03125 },\n { x: 0.09375, y: 0.03125 },\n { x: 0.15625, y: 0.03125 },\n { x: 0.15625, y: 0.03125 },\n { x: 0.21875, y: 0.03125 },\n { x: 0.21875, y: 0.03125 },\n { x: 0.28125, y: 0.03125 },\n { x: 0.28125, y: 0.03125 },\n { x: 0.34375, y: 0.03125 },\n { x: 0.34375, y: 0.03125 },\n { x: 0.40625, y: 0.03125 },\n { x: 0.40625, y: 0.03125 },\n { x: 0.46875, y: 0.03125 },\n { x: 0.46875, y: 0.03125 },\n { x: 0.53125, y: 0.03125 },\n { x: 0.53125, y: 0.03125 },\n { x: 0.59375, y: 0.03125 },\n { x: 0.59375, y: 0.03125 },\n { x: 0.65625, y: 0.03125 },\n { x: 0.65625, y: 0.03125 },\n { x: 0.71875, y: 0.03125 },\n { x: 0.71875, y: 0.03125 },\n { x: 0.78125, y: 0.03125 },\n { x: 0.78125, y: 0.03125 },\n { x: 0.84375, y: 0.03125 },\n { x: 0.84375, y: 0.03125 },\n { x: 0.90625, y: 0.03125 },\n { x: 0.90625, y: 0.03125 },\n { x: 0.96875, y: 0.03125 },\n { x: 0.96875, y: 0.03125 },\n { x: 0.03125, y: 0.09375 },\n { x: 0.03125, y: 0.09375 },\n { x: 0.09375, y: 0.09375 },\n { x: 0.09375, y: 0.09375 },\n { x: 0.15625, y: 0.09375 },\n { x: 0.15625, y: 0.09375 },\n { x: 0.21875, y: 0.09375 },\n { x: 0.21875, y: 0.09375 },\n { x: 0.28125, y: 0.09375 },\n { x: 0.28125, y: 0.09375 },\n { x: 0.34375, y: 0.09375 },\n { x: 0.34375, y: 0.09375 },\n { x: 0.40625, y: 0.09375 },\n { x: 0.40625, y: 0.09375 },\n { x: 0.46875, y: 0.09375 },\n { x: 0.46875, y: 0.09375 },\n { x: 0.53125, y: 0.09375 },\n { x: 0.53125, y: 0.09375 },\n { x: 0.59375, y: 0.09375 },\n { x: 0.59375, y: 0.09375 },\n { x: 0.65625, y: 0.09375 },\n { x: 0.65625, y: 0.09375 },\n { x: 0.71875, y: 0.09375 },\n { x: 0.71875, y: 0.09375 },\n { x: 0.78125, y: 0.09375 },\n { x: 0.78125, y: 0.09375 },\n { x: 0.84375, y: 0.09375 },\n { x: 0.84375, y: 0.09375 },\n { x: 0.90625, y: 0.09375 },\n { x: 0.90625, y: 0.09375 },\n { x: 0.96875, y: 0.09375 },\n { x: 0.96875, y: 0.09375 },\n { x: 0.03125, y: 0.15625 },\n { x: 0.03125, y: 0.15625 },\n { x: 0.09375, y: 0.15625 },\n { x: 0.09375, y: 0.15625 },\n { x: 0.15625, y: 0.15625 },\n { x: 0.15625, y: 0.15625 },\n { x: 0.21875, y: 0.15625 },\n { x: 0.21875, y: 0.15625 },\n { x: 0.28125, y: 0.15625 },\n { x: 0.28125, y: 0.15625 },\n { x: 0.34375, y: 0.15625 },\n { x: 0.34375, y: 0.15625 },\n { x: 0.40625, y: 0.15625 },\n { x: 0.40625, y: 0.15625 },\n { x: 0.46875, y: 0.15625 },\n { x: 0.46875, y: 0.15625 },\n { x: 0.53125, y: 0.15625 },\n { x: 0.53125, y: 0.15625 },\n { x: 0.59375, y: 0.15625 },\n { x: 0.59375, y: 0.15625 },\n { x: 0.65625, y: 0.15625 },\n { x: 0.65625, y: 0.15625 },\n { x: 0.71875, y: 0.15625 },\n { x: 0.71875, y: 0.15625 },\n { x: 0.78125, y: 0.15625 },\n { x: 0.78125, y: 0.15625 },\n { x: 0.84375, y: 0.15625 },\n { x: 0.84375, y: 0.15625 },\n { x: 0.90625, y: 0.15625 },\n { x: 0.90625, y: 0.15625 },\n { x: 0.96875, y: 0.15625 },\n { x: 0.96875, y: 0.15625 },\n { x: 0.03125, y: 0.21875 },\n { x: 0.03125, y: 0.21875 },\n { x: 0.09375, y: 0.21875 },\n { x: 0.09375, y: 0.21875 },\n { x: 0.15625, y: 0.21875 },\n { x: 0.15625, y: 0.21875 },\n { x: 0.21875, y: 0.21875 },\n { x: 0.21875, y: 0.21875 },\n { x: 0.28125, y: 0.21875 },\n { x: 0.28125, y: 0.21875 },\n { x: 0.34375, y: 0.21875 },\n { x: 0.34375, y: 0.21875 },\n { x: 0.40625, y: 0.21875 },\n { x: 0.40625, y: 0.21875 },\n { x: 0.46875, y: 0.21875 },\n { x: 0.46875, y: 0.21875 },\n { x: 0.53125, y: 0.21875 },\n { x: 0.53125, y: 0.21875 },\n { x: 0.59375, y: 0.21875 },\n { x: 0.59375, y: 0.21875 },\n { x: 0.65625, y: 0.21875 },\n { x: 0.65625, y: 0.21875 },\n { x: 0.71875, y: 0.21875 },\n { x: 0.71875, y: 0.21875 },\n { x: 0.78125, y: 0.21875 },\n { x: 0.78125, y: 0.21875 },\n { x: 0.84375, y: 0.21875 },\n { x: 0.84375, y: 0.21875 },\n { x: 0.90625, y: 0.21875 },\n { x: 0.90625, y: 0.21875 },\n { x: 0.96875, y: 0.21875 },\n { x: 0.96875, y: 0.21875 },\n { x: 0.03125, y: 0.28125 },\n { x: 0.03125, y: 0.28125 },\n { x: 0.09375, y: 0.28125 },\n { x: 0.09375, y: 0.28125 },\n { x: 0.15625, y: 0.28125 },\n { x: 0.15625, y: 0.28125 },\n { x: 0.21875, y: 0.28125 },\n { x: 0.21875, y: 0.28125 },\n { x: 0.28125, y: 0.28125 },\n { x: 0.28125, y: 0.28125 },\n { x: 0.34375, y: 0.28125 },\n { x: 0.34375, y: 0.28125 },\n { x: 0.40625, y: 0.28125 },\n { x: 0.40625, y: 0.28125 },\n { x: 0.46875, y: 0.28125 },\n { x: 0.46875, y: 0.28125 },\n { x: 0.53125, y: 0.28125 },\n { x: 0.53125, y: 0.28125 },\n { x: 0.59375, y: 0.28125 },\n { x: 0.59375, y: 0.28125 },\n { x: 0.65625, y: 0.28125 },\n { x: 0.65625, y: 0.28125 },\n { x: 0.71875, y: 0.28125 },\n { x: 0.71875, y: 0.28125 },\n { x: 0.78125, y: 0.28125 },\n { x: 0.78125, y: 0.28125 },\n { x: 0.84375, y: 0.28125 },\n { x: 0.84375, y: 0.28125 },\n { x: 0.90625, y: 0.28125 },\n { x: 0.90625, y: 0.28125 },\n { x: 0.96875, y: 0.28125 },\n { x: 0.96875, y: 0.28125 },\n { x: 0.03125, y: 0.34375 },\n { x: 0.03125, y: 0.34375 },\n { x: 0.09375, y: 0.34375 },\n { x: 0.09375, y: 0.34375 },\n { x: 0.15625, y: 0.34375 },\n { x: 0.15625, y: 0.34375 },\n { x: 0.21875, y: 0.34375 },\n { x: 0.21875, y: 0.34375 },\n { x: 0.28125, y: 0.34375 },\n { x: 0.28125, y: 0.34375 },\n { x: 0.34375, y: 0.34375 },\n { x: 0.34375, y: 0.34375 },\n { x: 0.40625, y: 0.34375 },\n { x: 0.40625, y: 0.34375 },\n { x: 0.46875, y: 0.34375 },\n { x: 0.46875, y: 0.34375 },\n { x: 0.53125, y: 0.34375 },\n { x: 0.53125, y: 0.34375 },\n { x: 0.59375, y: 0.34375 },\n { x: 0.59375, y: 0.34375 },\n { x: 0.65625, y: 0.34375 },\n { x: 0.65625, y: 0.34375 },\n { x: 0.71875, y: 0.34375 },\n { x: 0.71875, y: 0.34375 },\n { x: 0.78125, y: 0.34375 },\n { x: 0.78125, y: 0.34375 },\n { x: 0.84375, y: 0.34375 },\n { x: 0.84375, y: 0.34375 },\n { x: 0.90625, y: 0.34375 },\n { x: 0.90625, y: 0.34375 },\n { x: 0.96875, y: 0.34375 },\n { x: 0.96875, y: 0.34375 },\n { x: 0.03125, y: 0.40625 },\n { x: 0.03125, y: 0.40625 },\n { x: 0.09375, y: 0.40625 },\n { x: 0.09375, y: 0.40625 },\n { x: 0.15625, y: 0.40625 },\n { x: 0.15625, y: 0.40625 },\n { x: 0.21875, y: 0.40625 },\n { x: 0.21875, y: 0.40625 },\n { x: 0.28125, y: 0.40625 },\n { x: 0.28125, y: 0.40625 },\n { x: 0.34375, y: 0.40625 },\n { x: 0.34375, y: 0.40625 },\n { x: 0.40625, y: 0.40625 },\n { x: 0.40625, y: 0.40625 },\n { x: 0.46875, y: 0.40625 },\n { x: 0.46875, y: 0.40625 },\n { x: 0.53125, y: 0.40625 },\n { x: 0.53125, y: 0.40625 },\n { x: 0.59375, y: 0.40625 },\n { x: 0.59375, y: 0.40625 },\n { x: 0.65625, y: 0.40625 },\n { x: 0.65625, y: 0.40625 },\n { x: 0.71875, y: 0.40625 },\n { x: 0.71875, y: 0.40625 },\n { x: 0.78125, y: 0.40625 },\n { x: 0.78125, y: 0.40625 },\n { x: 0.84375, y: 0.40625 },\n { x: 0.84375, y: 0.40625 },\n { x: 0.90625, y: 0.40625 },\n { x: 0.90625, y: 0.40625 },\n { x: 0.96875, y: 0.40625 },\n { x: 0.96875, y: 0.40625 },\n { x: 0.03125, y: 0.46875 },\n { x: 0.03125, y: 0.46875 },\n { x: 0.09375, y: 0.46875 },\n { x: 0.09375, y: 0.46875 },\n { x: 0.15625, y: 0.46875 },\n { x: 0.15625, y: 0.46875 },\n { x: 0.21875, y: 0.46875 },\n { x: 0.21875, y: 0.46875 },\n { x: 0.28125, y: 0.46875 },\n { x: 0.28125, y: 0.46875 },\n { x: 0.34375, y: 0.46875 },\n { x: 0.34375, y: 0.46875 },\n { x: 0.40625, y: 0.46875 },\n { x: 0.40625, y: 0.46875 },\n { x: 0.46875, y: 0.46875 },\n { x: 0.46875, y: 0.46875 },\n { x: 0.53125, y: 0.46875 },\n { x: 0.53125, y: 0.46875 },\n { x: 0.59375, y: 0.46875 },\n { x: 0.59375, y: 0.46875 },\n { x: 0.65625, y: 0.46875 },\n { x: 0.65625, y: 0.46875 },\n { x: 0.71875, y: 0.46875 },\n { x: 0.71875, y: 0.46875 },\n { x: 0.78125, y: 0.46875 },\n { x: 0.78125, y: 0.46875 },\n { x: 0.84375, y: 0.46875 },\n { x: 0.84375, y: 0.46875 },\n { x: 0.90625, y: 0.46875 },\n { x: 0.90625, y: 0.46875 },\n { x: 0.96875, y: 0.46875 },\n { x: 0.96875, y: 0.46875 },\n { x: 0.03125, y: 0.53125 },\n { x: 0.03125, y: 0.53125 },\n { x: 0.09375, y: 0.53125 },\n { x: 0.09375, y: 0.53125 },\n { x: 0.15625, y: 0.53125 },\n { x: 0.15625, y: 0.53125 },\n { x: 0.21875, y: 0.53125 },\n { x: 0.21875, y: 0.53125 },\n { x: 0.28125, y: 0.53125 },\n { x: 0.28125, y: 0.53125 },\n { x: 0.34375, y: 0.53125 },\n { x: 0.34375, y: 0.53125 },\n { x: 0.40625, y: 0.53125 },\n { x: 0.40625, y: 0.53125 },\n { x: 0.46875, y: 0.53125 },\n { x: 0.46875, y: 0.53125 },\n { x: 0.53125, y: 0.53125 },\n { x: 0.53125, y: 0.53125 },\n { x: 0.59375, y: 0.53125 },\n { x: 0.59375, y: 0.53125 },\n { x: 0.65625, y: 0.53125 },\n { x: 0.65625, y: 0.53125 },\n { x: 0.71875, y: 0.53125 },\n { x: 0.71875, y: 0.53125 },\n { x: 0.78125, y: 0.53125 },\n { x: 0.78125, y: 0.53125 },\n { x: 0.84375, y: 0.53125 },\n { x: 0.84375, y: 0.53125 },\n { x: 0.90625, y: 0.53125 },\n { x: 0.90625, y: 0.53125 },\n { x: 0.96875, y: 0.53125 },\n { x: 0.96875, y: 0.53125 },\n { x: 0.03125, y: 0.59375 },\n { x: 0.03125, y: 0.59375 },\n { x: 0.09375, y: 0.59375 },\n { x: 0.09375, y: 0.59375 },\n { x: 0.15625, y: 0.59375 },\n { x: 0.15625, y: 0.59375 },\n { x: 0.21875, y: 0.59375 },\n { x: 0.21875, y: 0.59375 },\n { x: 0.28125, y: 0.59375 },\n { x: 0.28125, y: 0.59375 },\n { x: 0.34375, y: 0.59375 },\n { x: 0.34375, y: 0.59375 },\n { x: 0.40625, y: 0.59375 },\n { x: 0.40625, y: 0.59375 },\n { x: 0.46875, y: 0.59375 },\n { x: 0.46875, y: 0.59375 },\n { x: 0.53125, y: 0.59375 },\n { x: 0.53125, y: 0.59375 },\n { x: 0.59375, y: 0.59375 },\n { x: 0.59375, y: 0.59375 },\n { x: 0.65625, y: 0.59375 },\n { x: 0.65625, y: 0.59375 },\n { x: 0.71875, y: 0.59375 },\n { x: 0.71875, y: 0.59375 },\n { x: 0.78125, y: 0.59375 },\n { x: 0.78125, y: 0.59375 },\n { x: 0.84375, y: 0.59375 },\n { x: 0.84375, y: 0.59375 },\n { x: 0.90625, y: 0.59375 },\n { x: 0.90625, y: 0.59375 },\n { x: 0.96875, y: 0.59375 },\n { x: 0.96875, y: 0.59375 },\n { x: 0.03125, y: 0.65625 },\n { x: 0.03125, y: 0.65625 },\n { x: 0.09375, y: 0.65625 },\n { x: 0.09375, y: 0.65625 },\n { x: 0.15625, y: 0.65625 },\n { x: 0.15625, y: 0.65625 },\n { x: 0.21875, y: 0.65625 },\n { x: 0.21875, y: 0.65625 },\n { x: 0.28125, y: 0.65625 },\n { x: 0.28125, y: 0.65625 },\n { x: 0.34375, y: 0.65625 },\n { x: 0.34375, y: 0.65625 },\n { x: 0.40625, y: 0.65625 },\n { x: 0.40625, y: 0.65625 },\n { x: 0.46875, y: 0.65625 },\n { x: 0.46875, y: 0.65625 },\n { x: 0.53125, y: 0.65625 },\n { x: 0.53125, y: 0.65625 },\n { x: 0.59375, y: 0.65625 },\n { x: 0.59375, y: 0.65625 },\n { x: 0.65625, y: 0.65625 },\n { x: 0.65625, y: 0.65625 },\n { x: 0.71875, y: 0.65625 },\n { x: 0.71875, y: 0.65625 },\n { x: 0.78125, y: 0.65625 },\n { x: 0.78125, y: 0.65625 },\n { x: 0.84375, y: 0.65625 },\n { x: 0.84375, y: 0.65625 },\n { x: 0.90625, y: 0.65625 },\n { x: 0.90625, y: 0.65625 },\n { x: 0.96875, y: 0.65625 },\n { x: 0.96875, y: 0.65625 },\n { x: 0.03125, y: 0.71875 },\n { x: 0.03125, y: 0.71875 },\n { x: 0.09375, y: 0.71875 },\n { x: 0.09375, y: 0.71875 },\n { x: 0.15625, y: 0.71875 },\n { x: 0.15625, y: 0.71875 },\n { x: 0.21875, y: 0.71875 },\n { x: 0.21875, y: 0.71875 },\n { x: 0.28125, y: 0.71875 },\n { x: 0.28125, y: 0.71875 },\n { x: 0.34375, y: 0.71875 },\n { x: 0.34375, y: 0.71875 },\n { x: 0.40625, y: 0.71875 },\n { x: 0.40625, y: 0.71875 },\n { x: 0.46875, y: 0.71875 },\n { x: 0.46875, y: 0.71875 },\n { x: 0.53125, y: 0.71875 },\n { x: 0.53125, y: 0.71875 },\n { x: 0.59375, y: 0.71875 },\n { x: 0.59375, y: 0.71875 },\n { x: 0.65625, y: 0.71875 },\n { x: 0.65625, y: 0.71875 },\n { x: 0.71875, y: 0.71875 },\n { x: 0.71875, y: 0.71875 },\n { x: 0.78125, y: 0.71875 },\n { x: 0.78125, y: 0.71875 },\n { x: 0.84375, y: 0.71875 },\n { x: 0.84375, y: 0.71875 },\n { x: 0.90625, y: 0.71875 },\n { x: 0.90625, y: 0.71875 },\n { x: 0.96875, y: 0.71875 },\n { x: 0.96875, y: 0.71875 },\n { x: 0.03125, y: 0.78125 },\n { x: 0.03125, y: 0.78125 },\n { x: 0.09375, y: 0.78125 },\n { x: 0.09375, y: 0.78125 },\n { x: 0.15625, y: 0.78125 },\n { x: 0.15625, y: 0.78125 },\n { x: 0.21875, y: 0.78125 },\n { x: 0.21875, y: 0.78125 },\n { x: 0.28125, y: 0.78125 },\n { x: 0.28125, y: 0.78125 },\n { x: 0.34375, y: 0.78125 },\n { x: 0.34375, y: 0.78125 },\n { x: 0.40625, y: 0.78125 },\n { x: 0.40625, y: 0.78125 },\n { x: 0.46875, y: 0.78125 },\n { x: 0.46875, y: 0.78125 },\n { x: 0.53125, y: 0.78125 },\n { x: 0.53125, y: 0.78125 },\n { x: 0.59375, y: 0.78125 },\n { x: 0.59375, y: 0.78125 },\n { x: 0.65625, y: 0.78125 },\n { x: 0.65625, y: 0.78125 },\n { x: 0.71875, y: 0.78125 },\n { x: 0.71875, y: 0.78125 },\n { x: 0.78125, y: 0.78125 },\n { x: 0.78125, y: 0.78125 },\n { x: 0.84375, y: 0.78125 },\n { x: 0.84375, y: 0.78125 },\n { x: 0.90625, y: 0.78125 },\n { x: 0.90625, y: 0.78125 },\n { x: 0.96875, y: 0.78125 },\n { x: 0.96875, y: 0.78125 },\n { x: 0.03125, y: 0.84375 },\n { x: 0.03125, y: 0.84375 },\n { x: 0.09375, y: 0.84375 },\n { x: 0.09375, y: 0.84375 },\n { x: 0.15625, y: 0.84375 },\n { x: 0.15625, y: 0.84375 },\n { x: 0.21875, y: 0.84375 },\n { x: 0.21875, y: 0.84375 },\n { x: 0.28125, y: 0.84375 },\n { x: 0.28125, y: 0.84375 },\n { x: 0.34375, y: 0.84375 },\n { x: 0.34375, y: 0.84375 },\n { x: 0.40625, y: 0.84375 },\n { x: 0.40625, y: 0.84375 },\n { x: 0.46875, y: 0.84375 },\n { x: 0.46875, y: 0.84375 },\n { x: 0.53125, y: 0.84375 },\n { x: 0.53125, y: 0.84375 },\n { x: 0.59375, y: 0.84375 },\n { x: 0.59375, y: 0.84375 },\n { x: 0.65625, y: 0.84375 },\n { x: 0.65625, y: 0.84375 },\n { x: 0.71875, y: 0.84375 },\n { x: 0.71875, y: 0.84375 },\n { x: 0.78125, y: 0.84375 },\n { x: 0.78125, y: 0.84375 },\n { x: 0.84375, y: 0.84375 },\n { x: 0.84375, y: 0.84375 },\n { x: 0.90625, y: 0.84375 },\n { x: 0.90625, y: 0.84375 },\n { x: 0.96875, y: 0.84375 },\n { x: 0.96875, y: 0.84375 },\n { x: 0.03125, y: 0.90625 },\n { x: 0.03125, y: 0.90625 },\n { x: 0.09375, y: 0.90625 },\n { x: 0.09375, y: 0.90625 },\n { x: 0.15625, y: 0.90625 },\n { x: 0.15625, y: 0.90625 },\n { x: 0.21875, y: 0.90625 },\n { x: 0.21875, y: 0.90625 },\n { x: 0.28125, y: 0.90625 },\n { x: 0.28125, y: 0.90625 },\n { x: 0.34375, y: 0.90625 },\n { x: 0.34375, y: 0.90625 },\n { x: 0.40625, y: 0.90625 },\n { x: 0.40625, y: 0.90625 },\n { x: 0.46875, y: 0.90625 },\n { x: 0.46875, y: 0.90625 },\n { x: 0.53125, y: 0.90625 },\n { x: 0.53125, y: 0.90625 },\n { x: 0.59375, y: 0.90625 },\n { x: 0.59375, y: 0.90625 },\n { x: 0.65625, y: 0.90625 },\n { x: 0.65625, y: 0.90625 },\n { x: 0.71875, y: 0.90625 },\n { x: 0.71875, y: 0.90625 },\n { x: 0.78125, y: 0.90625 },\n { x: 0.78125, y: 0.90625 },\n { x: 0.84375, y: 0.90625 },\n { x: 0.84375, y: 0.90625 },\n { x: 0.90625, y: 0.90625 },\n { x: 0.90625, y: 0.90625 },\n { x: 0.96875, y: 0.90625 },\n { x: 0.96875, y: 0.90625 },\n { x: 0.03125, y: 0.96875 },\n { x: 0.03125, y: 0.96875 },\n { x: 0.09375, y: 0.96875 },\n { x: 0.09375, y: 0.96875 },\n { x: 0.15625, y: 0.96875 },\n { x: 0.15625, y: 0.96875 },\n { x: 0.21875, y: 0.96875 },\n { x: 0.21875, y: 0.96875 },\n { x: 0.28125, y: 0.96875 },\n { x: 0.28125, y: 0.96875 },\n { x: 0.34375, y: 0.96875 },\n { x: 0.34375, y: 0.96875 },\n { x: 0.40625, y: 0.96875 },\n { x: 0.40625, y: 0.96875 },\n { x: 0.46875, y: 0.96875 },\n { x: 0.46875, y: 0.96875 },\n { x: 0.53125, y: 0.96875 },\n { x: 0.53125, y: 0.96875 },\n { x: 0.59375, y: 0.96875 },\n { x: 0.59375, y: 0.96875 },\n { x: 0.65625, y: 0.96875 },\n { x: 0.65625, y: 0.96875 },\n { x: 0.71875, y: 0.96875 },\n { x: 0.71875, y: 0.96875 },\n { x: 0.78125, y: 0.96875 },\n { x: 0.78125, y: 0.96875 },\n { x: 0.84375, y: 0.96875 },\n { x: 0.84375, y: 0.96875 },\n { x: 0.90625, y: 0.96875 },\n { x: 0.90625, y: 0.96875 },\n { x: 0.96875, y: 0.96875 },\n { x: 0.96875, y: 0.96875 },\n { x: 0.0625, y: 0.0625 },\n { x: 0.0625, y: 0.0625 },\n { x: 0.0625, y: 0.0625 },\n { x: 0.0625, y: 0.0625 },\n { x: 0.0625, y: 0.0625 },\n { x: 0.0625, y: 0.0625 },\n { x: 0.1875, y: 0.0625 },\n { x: 0.1875, y: 0.0625 },\n { x: 0.1875, y: 0.0625 },\n { x: 0.1875, y: 0.0625 },\n { x: 0.1875, y: 0.0625 },\n { x: 0.1875, y: 0.0625 },\n { x: 0.3125, y: 0.0625 },\n { x: 0.3125, y: 0.0625 },\n { x: 0.3125, y: 0.0625 },\n { x: 0.3125, y: 0.0625 },\n { x: 0.3125, y: 0.0625 },\n { x: 0.3125, y: 0.0625 },\n { x: 0.4375, y: 0.0625 },\n { x: 0.4375, y: 0.0625 },\n { x: 0.4375, y: 0.0625 },\n { x: 0.4375, y: 0.0625 },\n { x: 0.4375, y: 0.0625 },\n { x: 0.4375, y: 0.0625 },\n { x: 0.5625, y: 0.0625 },\n { x: 0.5625, y: 0.0625 },\n { x: 0.5625, y: 0.0625 },\n { x: 0.5625, y: 0.0625 },\n { x: 0.5625, y: 0.0625 },\n { x: 0.5625, y: 0.0625 },\n { x: 0.6875, y: 0.0625 },\n { x: 0.6875, y: 0.0625 },\n { x: 0.6875, y: 0.0625 },\n { x: 0.6875, y: 0.0625 },\n { x: 0.6875, y: 0.0625 },\n { x: 0.6875, y: 0.0625 },\n { x: 0.8125, y: 0.0625 },\n { x: 0.8125, y: 0.0625 },\n { x: 0.8125, y: 0.0625 },\n { x: 0.8125, y: 0.0625 },\n { x: 0.8125, y: 0.0625 },\n { x: 0.8125, y: 0.0625 },\n { x: 0.9375, y: 0.0625 },\n { x: 0.9375, y: 0.0625 },\n { x: 0.9375, y: 0.0625 },\n { x: 0.9375, y: 0.0625 },\n { x: 0.9375, y: 0.0625 },\n { x: 0.9375, y: 0.0625 },\n { x: 0.0625, y: 0.1875 },\n { x: 0.0625, y: 0.1875 },\n { x: 0.0625, y: 0.1875 },\n { x: 0.0625, y: 0.1875 },\n { x: 0.0625, y: 0.1875 },\n { x: 0.0625, y: 0.1875 },\n { x: 0.1875, y: 0.1875 },\n { x: 0.1875, y: 0.1875 },\n { x: 0.1875, y: 0.1875 },\n { x: 0.1875, y: 0.1875 },\n { x: 0.1875, y: 0.1875 },\n { x: 0.1875, y: 0.1875 },\n { x: 0.3125, y: 0.1875 },\n { x: 0.3125, y: 0.1875 },\n { x: 0.3125, y: 0.1875 },\n { x: 0.3125, y: 0.1875 },\n { x: 0.3125, y: 0.1875 },\n { x: 0.3125, y: 0.1875 },\n { x: 0.4375, y: 0.1875 },\n { x: 0.4375, y: 0.1875 },\n { x: 0.4375, y: 0.1875 },\n { x: 0.4375, y: 0.1875 },\n { x: 0.4375, y: 0.1875 },\n { x: 0.4375, y: 0.1875 },\n { x: 0.5625, y: 0.1875 },\n { x: 0.5625, y: 0.1875 },\n { x: 0.5625, y: 0.1875 },\n { x: 0.5625, y: 0.1875 },\n { x: 0.5625, y: 0.1875 },\n { x: 0.5625, y: 0.1875 },\n { x: 0.6875, y: 0.1875 },\n { x: 0.6875, y: 0.1875 },\n { x: 0.6875, y: 0.1875 },\n { x: 0.6875, y: 0.1875 },\n { x: 0.6875, y: 0.1875 },\n { x: 0.6875, y: 0.1875 },\n { x: 0.8125, y: 0.1875 },\n { x: 0.8125, y: 0.1875 },\n { x: 0.8125, y: 0.1875 },\n { x: 0.8125, y: 0.1875 },\n { x: 0.8125, y: 0.1875 },\n { x: 0.8125, y: 0.1875 },\n { x: 0.9375, y: 0.1875 },\n { x: 0.9375, y: 0.1875 },\n { x: 0.9375, y: 0.1875 },\n { x: 0.9375, y: 0.1875 },\n { x: 0.9375, y: 0.1875 },\n { x: 0.9375, y: 0.1875 },\n { x: 0.0625, y: 0.3125 },\n { x: 0.0625, y: 0.3125 },\n { x: 0.0625, y: 0.3125 },\n { x: 0.0625, y: 0.3125 },\n { x: 0.0625, y: 0.3125 },\n { x: 0.0625, y: 0.3125 },\n { x: 0.1875, y: 0.3125 },\n { x: 0.1875, y: 0.3125 },\n { x: 0.1875, y: 0.3125 },\n { x: 0.1875, y: 0.3125 },\n { x: 0.1875, y: 0.3125 },\n { x: 0.1875, y: 0.3125 },\n { x: 0.3125, y: 0.3125 },\n { x: 0.3125, y: 0.3125 },\n { x: 0.3125, y: 0.3125 },\n { x: 0.3125, y: 0.3125 },\n { x: 0.3125, y: 0.3125 },\n { x: 0.3125, y: 0.3125 },\n { x: 0.4375, y: 0.3125 },\n { x: 0.4375, y: 0.3125 },\n { x: 0.4375, y: 0.3125 },\n { x: 0.4375, y: 0.3125 },\n { x: 0.4375, y: 0.3125 },\n { x: 0.4375, y: 0.3125 },\n { x: 0.5625, y: 0.3125 },\n { x: 0.5625, y: 0.3125 },\n { x: 0.5625, y: 0.3125 },\n { x: 0.5625, y: 0.3125 },\n { x: 0.5625, y: 0.3125 },\n { x: 0.5625, y: 0.3125 },\n { x: 0.6875, y: 0.3125 },\n { x: 0.6875, y: 0.3125 },\n { x: 0.6875, y: 0.3125 },\n { x: 0.6875, y: 0.3125 },\n { x: 0.6875, y: 0.3125 },\n { x: 0.6875, y: 0.3125 },\n { x: 0.8125, y: 0.3125 },\n { x: 0.8125, y: 0.3125 },\n { x: 0.8125, y: 0.3125 },\n { x: 0.8125, y: 0.3125 },\n { x: 0.8125, y: 0.3125 },\n { x: 0.8125, y: 0.3125 },\n { x: 0.9375, y: 0.3125 },\n { x: 0.9375, y: 0.3125 },\n { x: 0.9375, y: 0.3125 },\n { x: 0.9375, y: 0.3125 },\n { x: 0.9375, y: 0.3125 },\n { x: 0.9375, y: 0.3125 },\n { x: 0.0625, y: 0.4375 },\n { x: 0.0625, y: 0.4375 },\n { x: 0.0625, y: 0.4375 },\n { x: 0.0625, y: 0.4375 },\n { x: 0.0625, y: 0.4375 },\n { x: 0.0625, y: 0.4375 },\n { x: 0.1875, y: 0.4375 },\n { x: 0.1875, y: 0.4375 },\n { x: 0.1875, y: 0.4375 },\n { x: 0.1875, y: 0.4375 },\n { x: 0.1875, y: 0.4375 },\n { x: 0.1875, y: 0.4375 },\n { x: 0.3125, y: 0.4375 },\n { x: 0.3125, y: 0.4375 },\n { x: 0.3125, y: 0.4375 },\n { x: 0.3125, y: 0.4375 },\n { x: 0.3125, y: 0.4375 },\n { x: 0.3125, y: 0.4375 },\n { x: 0.4375, y: 0.4375 },\n { x: 0.4375, y: 0.4375 },\n { x: 0.4375, y: 0.4375 },\n { x: 0.4375, y: 0.4375 },\n { x: 0.4375, y: 0.4375 },\n { x: 0.4375, y: 0.4375 },\n { x: 0.5625, y: 0.4375 },\n { x: 0.5625, y: 0.4375 },\n { x: 0.5625, y: 0.4375 },\n { x: 0.5625, y: 0.4375 },\n { x: 0.5625, y: 0.4375 },\n { x: 0.5625, y: 0.4375 },\n { x: 0.6875, y: 0.4375 },\n { x: 0.6875, y: 0.4375 },\n { x: 0.6875, y: 0.4375 },\n { x: 0.6875, y: 0.4375 },\n { x: 0.6875, y: 0.4375 },\n { x: 0.6875, y: 0.4375 },\n { x: 0.8125, y: 0.4375 },\n { x: 0.8125, y: 0.4375 },\n { x: 0.8125, y: 0.4375 },\n { x: 0.8125, y: 0.4375 },\n { x: 0.8125, y: 0.4375 },\n { x: 0.8125, y: 0.4375 },\n { x: 0.9375, y: 0.4375 },\n { x: 0.9375, y: 0.4375 },\n { x: 0.9375, y: 0.4375 },\n { x: 0.9375, y: 0.4375 },\n { x: 0.9375, y: 0.4375 },\n { x: 0.9375, y: 0.4375 },\n { x: 0.0625, y: 0.5625 },\n { x: 0.0625, y: 0.5625 },\n { x: 0.0625, y: 0.5625 },\n { x: 0.0625, y: 0.5625 },\n { x: 0.0625, y: 0.5625 },\n { x: 0.0625, y: 0.5625 },\n { x: 0.1875, y: 0.5625 },\n { x: 0.1875, y: 0.5625 },\n { x: 0.1875, y: 0.5625 },\n { x: 0.1875, y: 0.5625 },\n { x: 0.1875, y: 0.5625 },\n { x: 0.1875, y: 0.5625 },\n { x: 0.3125, y: 0.5625 },\n { x: 0.3125, y: 0.5625 },\n { x: 0.3125, y: 0.5625 },\n { x: 0.3125, y: 0.5625 },\n { x: 0.3125, y: 0.5625 },\n { x: 0.3125, y: 0.5625 },\n { x: 0.4375, y: 0.5625 },\n { x: 0.4375, y: 0.5625 },\n { x: 0.4375, y: 0.5625 },\n { x: 0.4375, y: 0.5625 },\n { x: 0.4375, y: 0.5625 },\n { x: 0.4375, y: 0.5625 },\n { x: 0.5625, y: 0.5625 },\n { x: 0.5625, y: 0.5625 },\n { x: 0.5625, y: 0.5625 },\n { x: 0.5625, y: 0.5625 },\n { x: 0.5625, y: 0.5625 },\n { x: 0.5625, y: 0.5625 },\n { x: 0.6875, y: 0.5625 },\n { x: 0.6875, y: 0.5625 },\n { x: 0.6875, y: 0.5625 },\n { x: 0.6875, y: 0.5625 },\n { x: 0.6875, y: 0.5625 },\n { x: 0.6875, y: 0.5625 },\n { x: 0.8125, y: 0.5625 },\n { x: 0.8125, y: 0.5625 },\n { x: 0.8125, y: 0.5625 },\n { x: 0.8125, y: 0.5625 },\n { x: 0.8125, y: 0.5625 },\n { x: 0.8125, y: 0.5625 },\n { x: 0.9375, y: 0.5625 },\n { x: 0.9375, y: 0.5625 },\n { x: 0.9375, y: 0.5625 },\n { x: 0.9375, y: 0.5625 },\n { x: 0.9375, y: 0.5625 },\n { x: 0.9375, y: 0.5625 },\n { x: 0.0625, y: 0.6875 },\n { x: 0.0625, y: 0.6875 },\n { x: 0.0625, y: 0.6875 },\n { x: 0.0625, y: 0.6875 },\n { x: 0.0625, y: 0.6875 },\n { x: 0.0625, y: 0.6875 },\n { x: 0.1875, y: 0.6875 },\n { x: 0.1875, y: 0.6875 },\n { x: 0.1875, y: 0.6875 },\n { x: 0.1875, y: 0.6875 },\n { x: 0.1875, y: 0.6875 },\n { x: 0.1875, y: 0.6875 },\n { x: 0.3125, y: 0.6875 },\n { x: 0.3125, y: 0.6875 },\n { x: 0.3125, y: 0.6875 },\n { x: 0.3125, y: 0.6875 },\n { x: 0.3125, y: 0.6875 },\n { x: 0.3125, y: 0.6875 },\n { x: 0.4375, y: 0.6875 },\n { x: 0.4375, y: 0.6875 },\n { x: 0.4375, y: 0.6875 },\n { x: 0.4375, y: 0.6875 },\n { x: 0.4375, y: 0.6875 },\n { x: 0.4375, y: 0.6875 },\n { x: 0.5625, y: 0.6875 },\n { x: 0.5625, y: 0.6875 },\n { x: 0.5625, y: 0.6875 },\n { x: 0.5625, y: 0.6875 },\n { x: 0.5625, y: 0.6875 },\n { x: 0.5625, y: 0.6875 },\n { x: 0.6875, y: 0.6875 },\n { x: 0.6875, y: 0.6875 },\n { x: 0.6875, y: 0.6875 },\n { x: 0.6875, y: 0.6875 },\n { x: 0.6875, y: 0.6875 },\n { x: 0.6875, y: 0.6875 },\n { x: 0.8125, y: 0.6875 },\n { x: 0.8125, y: 0.6875 },\n { x: 0.8125, y: 0.6875 },\n { x: 0.8125, y: 0.6875 },\n { x: 0.8125, y: 0.6875 },\n { x: 0.8125, y: 0.6875 },\n { x: 0.9375, y: 0.6875 },\n { x: 0.9375, y: 0.6875 },\n { x: 0.9375, y: 0.6875 },\n { x: 0.9375, y: 0.6875 },\n { x: 0.9375, y: 0.6875 },\n { x: 0.9375, y: 0.6875 },\n { x: 0.0625, y: 0.8125 },\n { x: 0.0625, y: 0.8125 },\n { x: 0.0625, y: 0.8125 },\n { x: 0.0625, y: 0.8125 },\n { x: 0.0625, y: 0.8125 },\n { x: 0.0625, y: 0.8125 },\n { x: 0.1875, y: 0.8125 },\n { x: 0.1875, y: 0.8125 },\n { x: 0.1875, y: 0.8125 },\n { x: 0.1875, y: 0.8125 },\n { x: 0.1875, y: 0.8125 },\n { x: 0.1875, y: 0.8125 },\n { x: 0.3125, y: 0.8125 },\n { x: 0.3125, y: 0.8125 },\n { x: 0.3125, y: 0.8125 },\n { x: 0.3125, y: 0.8125 },\n { x: 0.3125, y: 0.8125 },\n { x: 0.3125, y: 0.8125 },\n { x: 0.4375, y: 0.8125 },\n { x: 0.4375, y: 0.8125 },\n { x: 0.4375, y: 0.8125 },\n { x: 0.4375, y: 0.8125 },\n { x: 0.4375, y: 0.8125 },\n { x: 0.4375, y: 0.8125 },\n { x: 0.5625, y: 0.8125 },\n { x: 0.5625, y: 0.8125 },\n { x: 0.5625, y: 0.8125 },\n { x: 0.5625, y: 0.8125 },\n { x: 0.5625, y: 0.8125 },\n { x: 0.5625, y: 0.8125 },\n { x: 0.6875, y: 0.8125 },\n { x: 0.6875, y: 0.8125 },\n { x: 0.6875, y: 0.8125 },\n { x: 0.6875, y: 0.8125 },\n { x: 0.6875, y: 0.8125 },\n { x: 0.6875, y: 0.8125 },\n { x: 0.8125, y: 0.8125 },\n { x: 0.8125, y: 0.8125 },\n { x: 0.8125, y: 0.8125 },\n { x: 0.8125, y: 0.8125 },\n { x: 0.8125, y: 0.8125 },\n { x: 0.8125, y: 0.8125 },\n { x: 0.9375, y: 0.8125 },\n { x: 0.9375, y: 0.8125 },\n { x: 0.9375, y: 0.8125 },\n { x: 0.9375, y: 0.8125 },\n { x: 0.9375, y: 0.8125 },\n { x: 0.9375, y: 0.8125 },\n { x: 0.0625, y: 0.9375 },\n { x: 0.0625, y: 0.9375 },\n { x: 0.0625, y: 0.9375 },\n { x: 0.0625, y: 0.9375 },\n { x: 0.0625, y: 0.9375 },\n { x: 0.0625, y: 0.9375 },\n { x: 0.1875, y: 0.9375 },\n { x: 0.1875, y: 0.9375 },\n { x: 0.1875, y: 0.9375 },\n { x: 0.1875, y: 0.9375 },\n { x: 0.1875, y: 0.9375 },\n { x: 0.1875, y: 0.9375 },\n { x: 0.3125, y: 0.9375 },\n { x: 0.3125, y: 0.9375 },\n { x: 0.3125, y: 0.9375 },\n { x: 0.3125, y: 0.9375 },\n { x: 0.3125, y: 0.9375 },\n { x: 0.3125, y: 0.9375 },\n { x: 0.4375, y: 0.9375 },\n { x: 0.4375, y: 0.9375 },\n { x: 0.4375, y: 0.9375 },\n { x: 0.4375, y: 0.9375 },\n { x: 0.4375, y: 0.9375 },\n { x: 0.4375, y: 0.9375 },\n { x: 0.5625, y: 0.9375 },\n { x: 0.5625, y: 0.9375 },\n { x: 0.5625, y: 0.9375 },\n { x: 0.5625, y: 0.9375 },\n { x: 0.5625, y: 0.9375 },\n { x: 0.5625, y: 0.9375 },\n { x: 0.6875, y: 0.9375 },\n { x: 0.6875, y: 0.9375 },\n { x: 0.6875, y: 0.9375 },\n { x: 0.6875, y: 0.9375 },\n { x: 0.6875, y: 0.9375 },\n { x: 0.6875, y: 0.9375 },\n { x: 0.8125, y: 0.9375 },\n { x: 0.8125, y: 0.9375 },\n { x: 0.8125, y: 0.9375 },\n { x: 0.8125, y: 0.9375 },\n { x: 0.8125, y: 0.9375 },\n { x: 0.8125, y: 0.9375 },\n { x: 0.9375, y: 0.9375 },\n { x: 0.9375, y: 0.9375 },\n { x: 0.9375, y: 0.9375 },\n { x: 0.9375, y: 0.9375 },\n { x: 0.9375, y: 0.9375 },\n { x: 0.9375, y: 0.9375 },\n];\n", "import * as tf from '../../dist/tfjs.esm.js';\nimport * as box from './box';\nimport * as anchors from './anchors';\nimport type { Tensor, GraphModel } from '../tfjs/types';\n\nexport class HandDetector {\n model: GraphModel;\n anchors: number[][];\n anchorsTensor: Tensor;\n inputSize: number;\n inputSizeTensor: Tensor;\n doubleInputSizeTensor: Tensor;\n\n constructor(model) {\n this.model = model;\n this.anchors = anchors.anchors.map((anchor) => [anchor.x, anchor.y]);\n this.anchorsTensor = tf.tensor2d(this.anchors);\n this.inputSize = (this.model && this.model.inputs && this.model.inputs[0].shape) ? this.model.inputs[0].shape[2] : 0;\n this.inputSizeTensor = tf.tensor1d([this.inputSize, this.inputSize]);\n this.doubleInputSizeTensor = tf.tensor1d([this.inputSize * 2, this.inputSize * 2]);\n }\n\n normalizeBoxes(boxes) {\n return tf.tidy(() => {\n const boxOffsets = tf.slice(boxes, [0, 0], [-1, 2]);\n const boxSizes = tf.slice(boxes, [0, 2], [-1, 2]);\n const boxCenterPoints = tf.add(tf.div(boxOffsets, this.inputSizeTensor), this.anchorsTensor);\n const halfBoxSizes = tf.div(boxSizes, this.doubleInputSizeTensor);\n const startPoints = tf.mul(tf.sub(boxCenterPoints, halfBoxSizes), this.inputSizeTensor);\n const endPoints = tf.mul(tf.add(boxCenterPoints, halfBoxSizes), this.inputSizeTensor);\n return tf.concat2d([startPoints, endPoints], 1);\n });\n }\n\n normalizeLandmarks(rawPalmLandmarks, index) {\n return tf.tidy(() => {\n const landmarks = tf.add(tf.div(tf.reshape(rawPalmLandmarks, [-1, 7, 2]), this.inputSizeTensor), this.anchors[index]);\n return tf.mul(landmarks, this.inputSizeTensor);\n });\n }\n\n async getBoxes(input, config) {\n const t: Record = {};\n t.batched = this.model.predict(input) as Tensor;\n t.predictions = tf.squeeze(t.batched);\n t.scores = tf.tidy(() => tf.squeeze(tf.sigmoid(tf.slice(t.predictions, [0, 0], [-1, 1]))));\n const scores = await t.scores.data();\n t.boxes = tf.slice(t.predictions, [0, 1], [-1, 4]);\n t.norm = this.normalizeBoxes(t.boxes);\n // box detection is flaky so we look for 3x boxes than we need results\n t.nms = await tf.image.nonMaxSuppressionAsync(t.norm, t.scores, 3 * config.hand.maxDetected, config.hand.iouThreshold, config.hand.minConfidence);\n const nms = await t.nms.array() as Array;\n const hands: Array<{ box: Tensor, palmLandmarks: Tensor, confidence: number }> = [];\n for (const index of nms) {\n const palmBox = tf.slice(t.norm, [index, 0], [1, -1]);\n const palmLandmarks = tf.tidy(() => tf.reshape(this.normalizeLandmarks(tf.slice(t.predictions, [index, 5], [1, 14]), index), [-1, 2]));\n hands.push({ box: palmBox, palmLandmarks, confidence: scores[index] });\n // console.log('handdetector:getBoxes', nms.length, index, scores[index], config.hand.maxDetected, config.hand.iouThreshold, config.hand.minConfidence, palmBox.dataSync());\n }\n for (const tensor of Object.keys(t)) tf.dispose(t[tensor]); // dispose all\n return hands;\n }\n\n async estimateHandBounds(input, config): Promise<{ startPoint: number[]; endPoint: number[]; palmLandmarks: number[]; confidence: number }[]> {\n const inputHeight = input.shape[1];\n const inputWidth = input.shape[2];\n const image = tf.tidy(() => tf.sub(tf.div(tf.image.resizeBilinear(input, [this.inputSize, this.inputSize]), 127.5), 1));\n const predictions = await this.getBoxes(image, config);\n tf.dispose(image);\n const hands: Array<{ startPoint: number[]; endPoint: number[]; palmLandmarks: number[]; confidence: number }> = [];\n if (!predictions || predictions.length === 0) return hands;\n for (const prediction of predictions) {\n const boxes = await prediction.box.data();\n const startPoint = boxes.slice(0, 2);\n const endPoint = boxes.slice(2, 4);\n const palmLandmarks = await prediction.palmLandmarks.array();\n tf.dispose(prediction.box);\n tf.dispose(prediction.palmLandmarks);\n hands.push(box.scaleBoxCoordinates({ startPoint, endPoint, palmLandmarks, confidence: prediction.confidence }, [inputWidth / this.inputSize, inputHeight / this.inputSize]));\n }\n return hands;\n }\n}\n", "export function normalizeRadians(angle) {\n return angle - 2 * Math.PI * Math.floor((angle + Math.PI) / (2 * Math.PI));\n}\n\nexport function computeRotation(point1, point2) {\n const radians = Math.PI / 2 - Math.atan2(-(point2[1] - point1[1]), point2[0] - point1[0]);\n return normalizeRadians(radians);\n}\n\nexport const buildTranslationMatrix = (x, y) => [[1, 0, x], [0, 1, y], [0, 0, 1]];\n\nexport function dot(v1, v2) {\n let product = 0;\n for (let i = 0; i < v1.length; i++) {\n product += v1[i] * v2[i];\n }\n return product;\n}\n\nexport function getColumnFrom2DArr(arr, columnIndex) {\n const column: Array = [];\n for (let i = 0; i < arr.length; i++) {\n column.push(arr[i][columnIndex]);\n }\n return column;\n}\n\nexport function multiplyTransformMatrices(mat1, mat2) {\n const product: Array = [];\n const size = mat1.length;\n for (let row = 0; row < size; row++) {\n product.push([]);\n for (let col = 0; col < size; col++) {\n product[row].push(dot(mat1[row], getColumnFrom2DArr(mat2, col)));\n }\n }\n return product;\n}\n\nexport function buildRotationMatrix(rotation, center) {\n const cosA = Math.cos(rotation);\n const sinA = Math.sin(rotation);\n const rotationMatrix = [[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]];\n const translationMatrix = buildTranslationMatrix(center[0], center[1]);\n const translationTimesRotation = multiplyTransformMatrices(translationMatrix, rotationMatrix);\n const negativeTranslationMatrix = buildTranslationMatrix(-center[0], -center[1]);\n return multiplyTransformMatrices(translationTimesRotation, negativeTranslationMatrix);\n}\n\nexport function invertTransformMatrix(matrix) {\n const rotationComponent = [[matrix[0][0], matrix[1][0]], [matrix[0][1], matrix[1][1]]];\n const translationComponent = [matrix[0][2], matrix[1][2]];\n const invertedTranslation = [\n -dot(rotationComponent[0], translationComponent),\n -dot(rotationComponent[1], translationComponent),\n ];\n return [\n rotationComponent[0].concat(invertedTranslation[0]),\n rotationComponent[1].concat(invertedTranslation[1]),\n [0, 0, 1],\n ];\n}\n\nexport function rotatePoint(homogeneousCoordinate, rotationMatrix) {\n return [\n dot(homogeneousCoordinate, rotationMatrix[0]),\n dot(homogeneousCoordinate, rotationMatrix[1]),\n ];\n}\n", "import * as tf from '../../dist/tfjs.esm.js';\nimport * as box from './box';\nimport * as util from './util';\nimport type * as detector from './handdetector';\nimport type { Tensor, GraphModel } from '../tfjs/types';\nimport { env } from '../env';\n\nconst palmBoxEnlargeFactor = 5; // default 3\nconst handBoxEnlargeFactor = 1.65; // default 1.65\nconst palmLandmarkIds = [0, 5, 9, 13, 17, 1, 2];\nconst palmLandmarksPalmBase = 0;\nconst palmLandmarksMiddleFingerBase = 2;\n\nexport class HandPipeline {\n handDetector: detector.HandDetector;\n handPoseModel: GraphModel;\n inputSize: number;\n storedBoxes: Array<{ startPoint: number[]; endPoint: number[]; palmLandmarks: number[]; confidence: number } | null>;\n skipped: number;\n detectedHands: number;\n\n constructor(handDetector, handPoseModel) {\n this.handDetector = handDetector;\n this.handPoseModel = handPoseModel;\n this.inputSize = this.handPoseModel && this.handPoseModel.inputs[0].shape ? this.handPoseModel.inputs[0].shape[2] : 0;\n this.storedBoxes = [];\n this.skipped = 0;\n this.detectedHands = 0;\n }\n\n // eslint-disable-next-line class-methods-use-this\n calculateLandmarksBoundingBox(landmarks) {\n const xs = landmarks.map((d) => d[0]);\n const ys = landmarks.map((d) => d[1]);\n const startPoint = [Math.min(...xs), Math.min(...ys)];\n const endPoint = [Math.max(...xs), Math.max(...ys)];\n return { startPoint, endPoint };\n }\n\n getBoxForPalmLandmarks(palmLandmarks, rotationMatrix) {\n const rotatedPalmLandmarks = palmLandmarks.map((coord) => util.rotatePoint([...coord, 1], rotationMatrix));\n const boxAroundPalm = this.calculateLandmarksBoundingBox(rotatedPalmLandmarks);\n return box.enlargeBox(box.squarifyBox(boxAroundPalm), palmBoxEnlargeFactor);\n }\n\n getBoxForHandLandmarks(landmarks) {\n const boundingBox = this.calculateLandmarksBoundingBox(landmarks);\n const boxAroundHand = box.enlargeBox(box.squarifyBox(boundingBox), handBoxEnlargeFactor);\n boxAroundHand.palmLandmarks = [];\n for (let i = 0; i < palmLandmarkIds.length; i++) {\n boxAroundHand.palmLandmarks.push(landmarks[palmLandmarkIds[i]].slice(0, 2));\n }\n return boxAroundHand;\n }\n\n transformRawCoords(rawCoords, box2, angle, rotationMatrix) {\n const boxSize = box.getBoxSize(box2);\n const scaleFactor = [boxSize[0] / this.inputSize, boxSize[1] / this.inputSize, (boxSize[0] + boxSize[1]) / this.inputSize / 2];\n const coordsScaled = rawCoords.map((coord) => [\n scaleFactor[0] * (coord[0] - this.inputSize / 2),\n scaleFactor[1] * (coord[1] - this.inputSize / 2),\n scaleFactor[2] * coord[2],\n ]);\n const coordsRotationMatrix = util.buildRotationMatrix(angle, [0, 0]);\n const coordsRotated = coordsScaled.map((coord) => {\n const rotated = util.rotatePoint(coord, coordsRotationMatrix);\n return [...rotated, coord[2]];\n });\n const inverseRotationMatrix = util.invertTransformMatrix(rotationMatrix);\n const boxCenter = [...box.getBoxCenter(box2), 1];\n const originalBoxCenter = [\n util.dot(boxCenter, inverseRotationMatrix[0]),\n util.dot(boxCenter, inverseRotationMatrix[1]),\n ];\n return coordsRotated.map((coord) => [\n Math.trunc(coord[0] + originalBoxCenter[0]),\n Math.trunc(coord[1] + originalBoxCenter[1]),\n Math.trunc(coord[2]),\n ]);\n }\n\n async estimateHands(image, config) {\n let useFreshBox = false;\n\n // run new detector every skipFrames unless we only want box to start with\n let boxes;\n\n // console.log('handpipeline:estimateHands:skip criteria', this.skipped, config.hand.skipFrames, !config.hand.landmarks, !config.skipFrame); // should skip hand detector?\n if ((this.skipped === 0) || (this.skipped > config.hand.skipFrames) || !config.hand.landmarks || !config.skipFrame) {\n boxes = await this.handDetector.estimateHandBounds(image, config);\n this.skipped = 0;\n }\n if (config.skipFrame) this.skipped++;\n\n // if detector result count doesn't match current working set, use it to reset current working set\n if (boxes && (boxes.length > 0) && ((boxes.length !== this.detectedHands) && (this.detectedHands !== config.hand.maxDetected) || !config.hand.landmarks)) {\n this.detectedHands = 0;\n this.storedBoxes = [...boxes];\n // for (const possible of boxes) this.storedBoxes.push(possible);\n if (this.storedBoxes.length > 0) useFreshBox = true;\n }\n const hands: Array<{ landmarks: number[], confidence: number, boxConfidence: number, fingerConfidence: number, box: { topLeft: number[], bottomRight: number[] } }> = [];\n\n // go through working set of boxes\n for (let i = 0; i < this.storedBoxes.length; i++) {\n const currentBox = this.storedBoxes[i];\n if (!currentBox) continue;\n if (config.hand.landmarks) {\n const angle = config.hand.rotation ? util.computeRotation(currentBox.palmLandmarks[palmLandmarksPalmBase], currentBox.palmLandmarks[palmLandmarksMiddleFingerBase]) : 0;\n const palmCenter = box.getBoxCenter(currentBox);\n const palmCenterNormalized = [palmCenter[0] / image.shape[2], palmCenter[1] / image.shape[1]];\n const rotatedImage = config.hand.rotation && env.kernels.includes('rotatewithoffset') ? tf.image.rotateWithOffset(image, angle, 0, palmCenterNormalized) : image.clone();\n const rotationMatrix = util.buildRotationMatrix(-angle, palmCenter);\n const newBox = useFreshBox ? this.getBoxForPalmLandmarks(currentBox.palmLandmarks, rotationMatrix) : currentBox;\n const croppedInput = box.cutBoxFromImageAndResize(newBox, rotatedImage, [this.inputSize, this.inputSize]);\n const handImage = tf.div(croppedInput, 255);\n tf.dispose(croppedInput);\n tf.dispose(rotatedImage);\n const [confidenceT, keypoints] = await this.handPoseModel.predict(handImage) as Array;\n tf.dispose(handImage);\n const confidence = (await confidenceT.data())[0];\n tf.dispose(confidenceT);\n if (confidence >= config.hand.minConfidence / 4) {\n const keypointsReshaped = tf.reshape(keypoints, [-1, 3]);\n const rawCoords = await keypointsReshaped.array();\n tf.dispose(keypoints);\n tf.dispose(keypointsReshaped);\n const coords = this.transformRawCoords(rawCoords, newBox, angle, rotationMatrix);\n const nextBoundingBox = this.getBoxForHandLandmarks(coords);\n this.storedBoxes[i] = { ...nextBoundingBox, confidence };\n const result = {\n landmarks: coords,\n confidence,\n boxConfidence: currentBox.confidence,\n fingerConfidence: confidence,\n box: { topLeft: nextBoundingBox.startPoint, bottomRight: nextBoundingBox.endPoint },\n };\n hands.push(result);\n } else {\n // console.log('handpipeline:estimateHands low', confidence);\n this.storedBoxes[i] = null;\n }\n tf.dispose(keypoints);\n } else {\n // const enlarged = box.enlargeBox(box.squarifyBox(box.shiftBox(currentBox, HAND_BOX_SHIFT_VECTOR)), handBoxEnlargeFactor);\n const enlarged = box.enlargeBox(box.squarifyBox(currentBox), handBoxEnlargeFactor);\n const result = {\n confidence: currentBox.confidence,\n boxConfidence: currentBox.confidence,\n fingerConfidence: 0,\n box: { topLeft: enlarged.startPoint, bottomRight: enlarged.endPoint },\n landmarks: [],\n };\n hands.push(result);\n }\n }\n this.storedBoxes = this.storedBoxes.filter((a) => a !== null);\n this.detectedHands = hands.length;\n if (hands.length > config.hand.maxDetected) hands.length = config.hand.maxDetected;\n return hands;\n }\n}\n", "const Finger = {\n thumb: 0,\n index: 1,\n middle: 2,\n ring: 3,\n pinky: 4,\n all: [0, 1, 2, 3, 4], // just for convenience\n nameMapping: { 0: 'thumb', 1: 'index', 2: 'middle', 3: 'ring', 4: 'pinky' },\n // Describes mapping of joints based on the 21 points returned by handpose.\n // [0] Palm\n // [1-4] Thumb\n // [5-8] Index\n // [9-12] Middle\n // [13-16] Ring\n // [17-20] Pinky\n pointsMapping: {\n 0: [[0, 1], [1, 2], [2, 3], [3, 4]],\n 1: [[0, 5], [5, 6], [6, 7], [7, 8]],\n 2: [[0, 9], [9, 10], [10, 11], [11, 12]],\n 3: [[0, 13], [13, 14], [14, 15], [15, 16]],\n 4: [[0, 17], [17, 18], [18, 19], [19, 20]],\n },\n getName: (value) => Finger.nameMapping[value],\n getPoints: (value) => Finger.pointsMapping[value],\n};\n\nconst FingerCurl = {\n none: 0,\n half: 1,\n full: 2,\n nameMapping: { 0: 'none', 1: 'half', 2: 'full' },\n getName: (value) => FingerCurl.nameMapping[value],\n};\n\nconst FingerDirection = {\n verticalUp: 0,\n verticalDown: 1,\n horizontalLeft: 2,\n horizontalRight: 3,\n diagonalUpRight: 4,\n diagonalUpLeft: 5,\n diagonalDownRight: 6,\n diagonalDownLeft: 7,\n nameMapping: { 0: 'verticalUp', 1: 'verticalDown', 2: 'horizontalLeft', 3: 'horizontalRight', 4: 'diagonalUpRight', 5: 'diagonalUpLeft', 6: 'diagonalDownRight', 7: 'diagonalDownLeft' },\n getName: (value) => FingerDirection.nameMapping[value],\n};\n\nexport { Finger, FingerCurl, FingerDirection };\n", "import { Finger, FingerCurl, FingerDirection } from './description';\n\nconst options = {\n // curl estimation\n HALF_CURL_START_LIMIT: 60.0,\n NO_CURL_START_LIMIT: 130.0,\n // direction estimation\n DISTANCE_VOTE_POWER: 1.1,\n SINGLE_ANGLE_VOTE_POWER: 0.9,\n TOTAL_ANGLE_VOTE_POWER: 1.6,\n};\n\nfunction calculateSlope(point1x, point1y, point2x, point2y) {\n const value = (point1y - point2y) / (point1x - point2x);\n let slope = Math.atan(value) * 180 / Math.PI;\n if (slope <= 0) slope = -slope;\n else if (slope > 0) slope = 180 - slope;\n return slope;\n}\n\n// point1, point2 are 2d or 3d point arrays (xy[z])\n// returns either a single scalar (2d) or array of two slopes (3d)\nfunction getSlopes(point1, point2) {\n if (!point1 || !point2) return [0, 0];\n const slopeXY = calculateSlope(point1[0], point1[1], point2[0], point2[1]);\n if (point1.length === 2) return slopeXY;\n const slopeYZ = calculateSlope(point1[1], point1[2], point2[1], point2[2]);\n return [slopeXY, slopeYZ];\n}\n\nfunction angleOrientationAt(angle, weightageAt = 1.0) {\n let isVertical = 0;\n let isDiagonal = 0;\n let isHorizontal = 0;\n if (angle >= 75.0 && angle <= 105.0) isVertical = 1 * weightageAt;\n else if (angle >= 25.0 && angle <= 155.0) isDiagonal = 1 * weightageAt;\n else isHorizontal = 1 * weightageAt;\n return [isVertical, isDiagonal, isHorizontal];\n}\n\nfunction estimateFingerCurl(startPoint, midPoint, endPoint) {\n const start_mid_x_dist = startPoint[0] - midPoint[0];\n const start_end_x_dist = startPoint[0] - endPoint[0];\n const mid_end_x_dist = midPoint[0] - endPoint[0];\n const start_mid_y_dist = startPoint[1] - midPoint[1];\n const start_end_y_dist = startPoint[1] - endPoint[1];\n const mid_end_y_dist = midPoint[1] - endPoint[1];\n const start_mid_z_dist = startPoint[2] - midPoint[2];\n const start_end_z_dist = startPoint[2] - endPoint[2];\n const mid_end_z_dist = midPoint[2] - endPoint[2];\n const start_mid_dist = Math.sqrt(start_mid_x_dist * start_mid_x_dist + start_mid_y_dist * start_mid_y_dist + start_mid_z_dist * start_mid_z_dist);\n const start_end_dist = Math.sqrt(start_end_x_dist * start_end_x_dist + start_end_y_dist * start_end_y_dist + start_end_z_dist * start_end_z_dist);\n const mid_end_dist = Math.sqrt(mid_end_x_dist * mid_end_x_dist + mid_end_y_dist * mid_end_y_dist + mid_end_z_dist * mid_end_z_dist);\n let cos_in = (mid_end_dist * mid_end_dist + start_mid_dist * start_mid_dist - start_end_dist * start_end_dist) / (2 * mid_end_dist * start_mid_dist);\n if (cos_in > 1.0) cos_in = 1.0;\n else if (cos_in < -1.0) cos_in = -1.0;\n let angleOfCurve = Math.acos(cos_in);\n angleOfCurve = (57.2958 * angleOfCurve) % 180;\n let fingerCurl;\n if (angleOfCurve > options.NO_CURL_START_LIMIT) fingerCurl = FingerCurl.none;\n else if (angleOfCurve > options.HALF_CURL_START_LIMIT) fingerCurl = FingerCurl.half;\n else fingerCurl = FingerCurl.full;\n return fingerCurl;\n}\n\nfunction estimateHorizontalDirection(start_end_x_dist, start_mid_x_dist, mid_end_x_dist, max_dist_x) {\n let estimatedDirection;\n if (max_dist_x === Math.abs(start_end_x_dist)) {\n if (start_end_x_dist > 0) estimatedDirection = FingerDirection.horizontalLeft;\n else estimatedDirection = FingerDirection.horizontalRight;\n } else if (max_dist_x === Math.abs(start_mid_x_dist)) {\n if (start_mid_x_dist > 0) estimatedDirection = FingerDirection.horizontalLeft;\n else estimatedDirection = FingerDirection.horizontalRight;\n } else {\n if (mid_end_x_dist > 0) estimatedDirection = FingerDirection.horizontalLeft;\n else estimatedDirection = FingerDirection.horizontalRight;\n }\n return estimatedDirection;\n}\n\nfunction estimateVerticalDirection(start_end_y_dist, start_mid_y_dist, mid_end_y_dist, max_dist_y) {\n let estimatedDirection;\n if (max_dist_y === Math.abs(start_end_y_dist)) {\n if (start_end_y_dist < 0) estimatedDirection = FingerDirection.verticalDown;\n else estimatedDirection = FingerDirection.verticalUp;\n } else if (max_dist_y === Math.abs(start_mid_y_dist)) {\n if (start_mid_y_dist < 0) estimatedDirection = FingerDirection.verticalDown;\n else estimatedDirection = FingerDirection.verticalUp;\n } else {\n if (mid_end_y_dist < 0) estimatedDirection = FingerDirection.verticalDown;\n else estimatedDirection = FingerDirection.verticalUp;\n }\n return estimatedDirection;\n}\n\nfunction estimateDiagonalDirection(start_end_y_dist, start_mid_y_dist, mid_end_y_dist, max_dist_y, start_end_x_dist, start_mid_x_dist, mid_end_x_dist, max_dist_x) {\n let estimatedDirection;\n const reqd_vertical_direction = estimateVerticalDirection(start_end_y_dist, start_mid_y_dist, mid_end_y_dist, max_dist_y);\n const reqd_horizontal_direction = estimateHorizontalDirection(start_end_x_dist, start_mid_x_dist, mid_end_x_dist, max_dist_x);\n if (reqd_vertical_direction === FingerDirection.verticalUp) {\n if (reqd_horizontal_direction === FingerDirection.horizontalLeft) estimatedDirection = FingerDirection.diagonalUpLeft;\n else estimatedDirection = FingerDirection.diagonalUpRight;\n } else {\n if (reqd_horizontal_direction === FingerDirection.horizontalLeft) estimatedDirection = FingerDirection.diagonalDownLeft;\n else estimatedDirection = FingerDirection.diagonalDownRight;\n }\n return estimatedDirection;\n}\n\nfunction calculateFingerDirection(startPoint, midPoint, endPoint, fingerSlopes) {\n const start_mid_x_dist = startPoint[0] - midPoint[0];\n const start_end_x_dist = startPoint[0] - endPoint[0];\n const mid_end_x_dist = midPoint[0] - endPoint[0];\n const start_mid_y_dist = startPoint[1] - midPoint[1];\n const start_end_y_dist = startPoint[1] - endPoint[1];\n const mid_end_y_dist = midPoint[1] - endPoint[1];\n const max_dist_x = Math.max(Math.abs(start_mid_x_dist), Math.abs(start_end_x_dist), Math.abs(mid_end_x_dist));\n const max_dist_y = Math.max(Math.abs(start_mid_y_dist), Math.abs(start_end_y_dist), Math.abs(mid_end_y_dist));\n let voteVertical = 0.0;\n let voteDiagonal = 0.0;\n let voteHorizontal = 0.0;\n const start_end_x_y_dist_ratio = max_dist_y / (max_dist_x + 0.00001);\n if (start_end_x_y_dist_ratio > 1.5) voteVertical += options.DISTANCE_VOTE_POWER;\n else if (start_end_x_y_dist_ratio > 0.66) voteDiagonal += options.DISTANCE_VOTE_POWER;\n else voteHorizontal += options.DISTANCE_VOTE_POWER;\n const start_mid_dist = Math.sqrt(start_mid_x_dist * start_mid_x_dist + start_mid_y_dist * start_mid_y_dist);\n const start_end_dist = Math.sqrt(start_end_x_dist * start_end_x_dist + start_end_y_dist * start_end_y_dist);\n const mid_end_dist = Math.sqrt(mid_end_x_dist * mid_end_x_dist + mid_end_y_dist * mid_end_y_dist);\n const max_dist = Math.max(start_mid_dist, start_end_dist, mid_end_dist);\n let calc_start_point_x = startPoint[0];\n let calc_start_point_y = startPoint[1];\n let calc_end_point_x = endPoint[0];\n let calc_end_point_y = endPoint[1];\n if (max_dist === start_mid_dist) {\n calc_end_point_x = endPoint[0];\n calc_end_point_y = endPoint[1];\n } else if (max_dist === mid_end_dist) {\n calc_start_point_x = midPoint[0];\n calc_start_point_y = midPoint[1];\n }\n const calcStartPoint = [calc_start_point_x, calc_start_point_y];\n const calcEndPoint = [calc_end_point_x, calc_end_point_y];\n const totalAngle = getSlopes(calcStartPoint, calcEndPoint);\n const votes = angleOrientationAt(totalAngle, options.TOTAL_ANGLE_VOTE_POWER);\n voteVertical += votes[0];\n voteDiagonal += votes[1];\n voteHorizontal += votes[2];\n for (const fingerSlope of fingerSlopes) {\n const fingerVotes = angleOrientationAt(fingerSlope, options.SINGLE_ANGLE_VOTE_POWER);\n voteVertical += fingerVotes[0];\n voteDiagonal += fingerVotes[1];\n voteHorizontal += fingerVotes[2];\n }\n // in case of tie, highest preference goes to Vertical,\n // followed by horizontal and then diagonal\n let estimatedDirection;\n if (voteVertical === Math.max(voteVertical, voteDiagonal, voteHorizontal)) {\n estimatedDirection = estimateVerticalDirection(start_end_y_dist, start_mid_y_dist, mid_end_y_dist, max_dist_y);\n } else if (voteHorizontal === Math.max(voteDiagonal, voteHorizontal)) {\n estimatedDirection = estimateHorizontalDirection(start_end_x_dist, start_mid_x_dist, mid_end_x_dist, max_dist_x);\n } else {\n estimatedDirection = estimateDiagonalDirection(start_end_y_dist, start_mid_y_dist, mid_end_y_dist, max_dist_y, start_end_x_dist, start_mid_x_dist, mid_end_x_dist, max_dist_x);\n }\n return estimatedDirection;\n}\n\nexport function estimate(landmarks) {\n // step 1: calculate slopes\n const slopesXY: Array = [];\n const slopesYZ: Array = [];\n const fingerCurls: Array = [];\n const fingerDirections: Array = [];\n if (!landmarks) return { curls: fingerCurls, directions: fingerDirections };\n\n // step 1: calculate slopes\n for (const finger of Finger.all) {\n const points = Finger.getPoints(finger);\n const slopeAtXY: Array = [];\n const slopeAtYZ: Array = [];\n for (const point of points) {\n const point1 = landmarks[point[0]];\n const point2 = landmarks[point[1]];\n // calculate single slope\n const slopes = getSlopes(point1, point2);\n const slopeXY = slopes[0];\n const slopeYZ = slopes[1];\n slopeAtXY.push(slopeXY);\n slopeAtYZ.push(slopeYZ);\n }\n slopesXY.push(slopeAtXY);\n slopesYZ.push(slopeAtYZ);\n }\n\n // step 2: calculate orientations\n for (const finger of Finger.all) {\n // start finger predictions from palm - except for thumb\n const pointIndexAt = (finger === Finger.thumb) ? 1 : 0;\n const fingerPointsAt = Finger.getPoints(finger);\n const startPoint = landmarks[fingerPointsAt[pointIndexAt][0]];\n const midPoint = landmarks[fingerPointsAt[pointIndexAt + 1][1]];\n const endPoint = landmarks[fingerPointsAt[3][1]];\n // check if finger is curled\n const fingerCurled = estimateFingerCurl(startPoint, midPoint, endPoint);\n const fingerPosition = calculateFingerDirection(startPoint, midPoint, endPoint, slopesXY[finger].slice(pointIndexAt));\n fingerCurls[finger] = fingerCurled;\n fingerDirections[finger] = fingerPosition;\n }\n return { curls: fingerCurls, directions: fingerDirections };\n}\n", "export default class Gesture {\n name;\n curls;\n directions;\n weights;\n weightsRelative;\n\n constructor(name) {\n // name (should be unique)\n this.name = name;\n this.curls = {};\n this.directions = {};\n this.weights = [1.0, 1.0, 1.0, 1.0, 1.0];\n this.weightsRelative = [1.0, 1.0, 1.0, 1.0, 1.0];\n }\n\n addCurl(finger, curl, confidence) {\n if (typeof this.curls[finger] === 'undefined') this.curls[finger] = [];\n this.curls[finger].push([curl, confidence]);\n }\n\n addDirection(finger, position, confidence) {\n if (!this.directions[finger]) this.directions[finger] = [];\n this.directions[finger].push([position, confidence]);\n }\n\n setWeight(finger, weight) {\n this.weights[finger] = weight;\n // recalculate relative weights\n const total = this.weights.reduce((a, b) => a + b, 0);\n this.weightsRelative = this.weights.map((el) => el * 5 / total);\n }\n\n matchAgainst(detectedCurls, detectedDirections) {\n let confidence = 0.0;\n // look at the detected curl of each finger and compare with\n // the expected curl of this finger inside current gesture\n for (const fingerIdx in detectedCurls) {\n const detectedCurl = detectedCurls[fingerIdx];\n const expectedCurls = this.curls[fingerIdx];\n if (typeof expectedCurls === 'undefined') {\n // no curl description available for this finger\n // add default confidence of \"1\"\n confidence += this.weightsRelative[fingerIdx];\n continue;\n }\n // compare to each possible curl of this specific finger\n for (const [expectedCurl, score] of expectedCurls) {\n if (detectedCurl === expectedCurl) {\n confidence += score * this.weightsRelative[fingerIdx];\n break;\n }\n }\n }\n // same for detected direction of each finger\n for (const fingerIdx in detectedDirections) {\n const detectedDirection = detectedDirections[fingerIdx];\n const expectedDirections = this.directions[fingerIdx];\n if (typeof expectedDirections === 'undefined') {\n // no direction description available for this finger\n // add default confidence of \"1\"\n confidence += this.weightsRelative[fingerIdx];\n continue;\n }\n // compare to each possible direction of this specific finger\n for (const [expectedDirection, score] of expectedDirections) {\n if (detectedDirection === expectedDirection) {\n confidence += score * this.weightsRelative[fingerIdx];\n break;\n }\n }\n }\n return confidence / 10;\n }\n}\n", "import { Finger, FingerCurl, FingerDirection } from './description';\nimport Gesture from './gesture';\n\n// describe thumbs up gesture \uD83D\uDC4D\nconst ThumbsUp = new Gesture('thumbs up');\nThumbsUp.addCurl(Finger.thumb, FingerCurl.none, 1.0);\nThumbsUp.addDirection(Finger.thumb, FingerDirection.verticalUp, 1.0);\nThumbsUp.addDirection(Finger.thumb, FingerDirection.diagonalUpLeft, 0.25);\nThumbsUp.addDirection(Finger.thumb, FingerDirection.diagonalUpRight, 0.25);\nfor (const finger of [Finger.index, Finger.middle, Finger.ring, Finger.pinky]) {\n ThumbsUp.addCurl(finger, FingerCurl.full, 1.0);\n ThumbsUp.addDirection(finger, FingerDirection.horizontalLeft, 1.0);\n ThumbsUp.addDirection(finger, FingerDirection.horizontalRight, 1.0);\n}\n\n// describe Victory gesture \u270C\uFE0F\nconst Victory = new Gesture('victory');\nVictory.addCurl(Finger.thumb, FingerCurl.half, 0.5);\nVictory.addCurl(Finger.thumb, FingerCurl.none, 0.5);\nVictory.addDirection(Finger.thumb, FingerDirection.verticalUp, 1.0);\nVictory.addDirection(Finger.thumb, FingerDirection.diagonalUpLeft, 1.0);\nVictory.addCurl(Finger.index, FingerCurl.none, 1.0);\nVictory.addDirection(Finger.index, FingerDirection.verticalUp, 0.75);\nVictory.addDirection(Finger.index, FingerDirection.diagonalUpLeft, 1.0);\nVictory.addCurl(Finger.middle, FingerCurl.none, 1.0);\nVictory.addDirection(Finger.middle, FingerDirection.verticalUp, 1.0);\nVictory.addDirection(Finger.middle, FingerDirection.diagonalUpLeft, 0.75);\nVictory.addCurl(Finger.ring, FingerCurl.full, 1.0);\nVictory.addDirection(Finger.ring, FingerDirection.verticalUp, 0.2);\nVictory.addDirection(Finger.ring, FingerDirection.diagonalUpLeft, 1.0);\nVictory.addDirection(Finger.ring, FingerDirection.horizontalLeft, 0.2);\nVictory.addCurl(Finger.pinky, FingerCurl.full, 1.0);\nVictory.addDirection(Finger.pinky, FingerDirection.verticalUp, 0.2);\nVictory.addDirection(Finger.pinky, FingerDirection.diagonalUpLeft, 1.0);\nVictory.addDirection(Finger.pinky, FingerDirection.horizontalLeft, 0.2);\nVictory.setWeight(Finger.index, 2);\nVictory.setWeight(Finger.middle, 2);\n\nexport default [ThumbsUp, Victory];\n", "// based on \n\nimport * as estimator from './estimator';\nimport { Finger, FingerCurl, FingerDirection } from './description';\nimport Gestures from './gestures';\n\nconst minConfidence = 0.7;\n\nexport function analyze(keypoints) { // get estimations of curl / direction for each finger\n if (!keypoints || keypoints.length === 0) return null;\n const estimatorRes = estimator.estimate(keypoints);\n const landmarks = {};\n for (const fingerIdx of Finger.all) {\n landmarks[Finger.getName(fingerIdx)] = {\n curl: FingerCurl.getName(estimatorRes.curls[fingerIdx]),\n direction: FingerDirection.getName(estimatorRes.directions[fingerIdx]),\n };\n }\n // console.log('finger landmarks', landmarks);\n return landmarks;\n}\n\nexport function match(keypoints) { // compare gesture description to each known gesture\n const poses: Array<{ name: string, confidence: number }> = [];\n if (!keypoints || keypoints.length === 0) return poses;\n const estimatorRes = estimator.estimate(keypoints);\n for (const gesture of Gestures) {\n const confidence = gesture.matchAgainst(estimatorRes.curls, estimatorRes.directions);\n if (confidence >= minConfidence) poses.push({ name: gesture.name, confidence });\n }\n // console.log('finger poses', poses);\n return poses;\n}\n", "/**\n * HandPose module entry point\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as handdetector from './handdetector';\nimport * as handpipeline from './handpipeline';\nimport * as fingerPose from '../fingerpose/fingerpose';\nimport type { HandResult } from '../result';\nimport type { Tensor, GraphModel } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nconst meshAnnotations = {\n thumb: [1, 2, 3, 4],\n index: [5, 6, 7, 8],\n middle: [9, 10, 11, 12],\n ring: [13, 14, 15, 16],\n pinky: [17, 18, 19, 20],\n palm: [0],\n};\n\nlet handDetectorModel: GraphModel | null;\nlet handPoseModel: GraphModel | null;\nlet handPipeline: handpipeline.HandPipeline;\n\nexport async function predict(input: Tensor, config: Config): Promise {\n const predictions = await handPipeline.estimateHands(input, config);\n if (!predictions) return [];\n const hands: Array = [];\n for (let i = 0; i < predictions.length; i++) {\n const annotations = {};\n if (predictions[i].landmarks) {\n for (const key of Object.keys(meshAnnotations)) {\n annotations[key] = meshAnnotations[key].map((index) => predictions[i].landmarks[index]);\n }\n }\n\n const keypoints = predictions[i].landmarks as unknown as Array<[number, number, number]>;\n\n let box: [number, number, number, number] = [Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, 0, 0]; // maximums so conditionals work\n let boxRaw: [number, number, number, number] = [0, 0, 0, 0];\n if (keypoints && keypoints.length > 0) { // if we have landmarks, calculate box based on landmarks\n for (const pt of keypoints) {\n if (pt[0] < box[0]) box[0] = pt[0];\n if (pt[1] < box[1]) box[1] = pt[1];\n if (pt[0] > box[2]) box[2] = pt[0];\n if (pt[1] > box[3]) box[3] = pt[1];\n }\n box[2] -= box[0];\n box[3] -= box[1];\n boxRaw = [box[0] / (input.shape[2] || 0), box[1] / (input.shape[1] || 0), box[2] / (input.shape[2] || 0), box[3] / (input.shape[1] || 0)];\n } else { // otherwise use box from prediction\n box = predictions[i].box ? [\n Math.trunc(Math.max(0, predictions[i].box.topLeft[0])),\n Math.trunc(Math.max(0, predictions[i].box.topLeft[1])),\n Math.trunc(Math.min((input.shape[2] || 0), predictions[i].box.bottomRight[0]) - Math.max(0, predictions[i].box.topLeft[0])),\n Math.trunc(Math.min((input.shape[1] || 0), predictions[i].box.bottomRight[1]) - Math.max(0, predictions[i].box.topLeft[1])),\n ] : [0, 0, 0, 0];\n boxRaw = [\n (predictions[i].box.topLeft[0]) / (input.shape[2] || 0),\n (predictions[i].box.topLeft[1]) / (input.shape[1] || 0),\n (predictions[i].box.bottomRight[0] - predictions[i].box.topLeft[0]) / (input.shape[2] || 0),\n (predictions[i].box.bottomRight[1] - predictions[i].box.topLeft[1]) / (input.shape[1] || 0),\n ];\n }\n const landmarks = fingerPose.analyze(keypoints);\n hands.push({\n id: i,\n score: Math.round(100 * predictions[i].confidence) / 100,\n boxScore: Math.round(100 * predictions[i].boxConfidence) / 100,\n fingerScore: Math.round(100 * predictions[i].fingerConfidence) / 100,\n label: 'hand',\n box,\n boxRaw,\n keypoints,\n annotations: annotations as HandResult['annotations'],\n landmarks: landmarks as HandResult['landmarks'],\n });\n }\n return hands;\n}\n\nexport async function load(config: Config): Promise<[GraphModel | null, GraphModel | null]> {\n if (env.initial) {\n handDetectorModel = null;\n handPoseModel = null;\n }\n if (!handDetectorModel || !handPoseModel) {\n [handDetectorModel, handPoseModel] = await Promise.all([\n config.hand.enabled ? tf.loadGraphModel(join(config.modelBasePath, config.hand.detector?.modelPath || ''), { fromTFHub: (config.hand.detector?.modelPath || '').includes('tfhub.dev') }) as unknown as GraphModel : null,\n config.hand.landmarks ? tf.loadGraphModel(join(config.modelBasePath, config.hand.skeleton?.modelPath || ''), { fromTFHub: (config.hand.skeleton?.modelPath || '').includes('tfhub.dev') }) as unknown as GraphModel : null,\n ]);\n if (config.hand.enabled) {\n if (!handDetectorModel || !handDetectorModel['modelUrl']) log('load model failed:', config.hand.detector?.modelPath || '');\n else if (config.debug) log('load model:', handDetectorModel['modelUrl']);\n if (!handPoseModel || !handPoseModel['modelUrl']) log('load model failed:', config.hand.skeleton?.modelPath || '');\n else if (config.debug) log('load model:', handPoseModel['modelUrl']);\n }\n } else {\n if (config.debug) log('cached model:', handDetectorModel['modelUrl']);\n if (config.debug) log('cached model:', handPoseModel['modelUrl']);\n }\n const handDetector = new handdetector.HandDetector(handDetectorModel);\n handPipeline = new handpipeline.HandPipeline(handDetector, handPoseModel);\n return [handDetectorModel, handPoseModel];\n}\n", "/**\n * Hand Detection and Segmentation\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport type { HandResult } from '../result';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\nimport * as fingerPose from '../fingerpose/fingerpose';\n\nconst models: [GraphModel | null, GraphModel | null] = [null, null];\nconst modelOutputNodes = ['StatefulPartitionedCall/Postprocessor/Slice', 'StatefulPartitionedCall/Postprocessor/ExpandDims_1'];\nconst inputSize = [[0, 0], [0, 0]];\n\nconst classes = [\n 'hand',\n 'fist',\n 'pinch',\n 'point',\n 'face',\n 'tip',\n 'pinchtip',\n];\n\nlet skipped = 0;\nlet outputSize;\n\ntype HandDetectResult = {\n id: number,\n score: number,\n box: [number, number, number, number],\n boxRaw: [number, number, number, number],\n label: string,\n yxBox: [number, number, number, number],\n}\n\nconst cache: {\n handBoxes: Array,\n fingerBoxes: Array\n tmpBoxes: Array\n} = {\n handBoxes: [],\n fingerBoxes: [],\n tmpBoxes: [],\n};\n\nconst fingerMap = {\n thumb: [1, 2, 3, 4],\n index: [5, 6, 7, 8],\n middle: [9, 10, 11, 12],\n ring: [13, 14, 15, 16],\n pinky: [17, 18, 19, 20],\n palm: [0],\n};\n\nexport async function load(config: Config): Promise<[GraphModel, GraphModel]> {\n if (env.initial) {\n models[0] = null;\n models[1] = null;\n }\n if (!models[0]) {\n models[0] = await tf.loadGraphModel(join(config.modelBasePath, config.hand.detector?.modelPath || '')) as unknown as GraphModel;\n const inputs = Object.values(models[0].modelSignature['inputs']);\n inputSize[0][0] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[1].size) : 0;\n inputSize[0][1] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;\n if (!models[0] || !models[0]['modelUrl']) log('load model failed:', config.object.modelPath);\n else if (config.debug) log('load model:', models[0]['modelUrl']);\n } else if (config.debug) log('cached model:', models[0]['modelUrl']);\n if (!models[1]) {\n models[1] = await tf.loadGraphModel(join(config.modelBasePath, config.hand.skeleton?.modelPath || '')) as unknown as GraphModel;\n const inputs = Object.values(models[1].modelSignature['inputs']);\n inputSize[1][0] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[1].size) : 0;\n inputSize[1][1] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;\n if (!models[1] || !models[1]['modelUrl']) log('load model failed:', config.object.modelPath);\n else if (config.debug) log('load model:', models[1]['modelUrl']);\n } else if (config.debug) log('cached model:', models[1]['modelUrl']);\n return models as [GraphModel, GraphModel];\n}\n\nasync function detectHands(input: Tensor, config: Config): Promise {\n const hands: HandDetectResult[] = [];\n if (!input || !models[0]) return hands;\n const t: Record = {};\n const ratio = (input.shape[2] || 1) / (input.shape[1] || 1);\n const height = Math.min(Math.round((input.shape[1] || 0) / 8) * 8, 512); // use dynamic input size but cap at 1024\n const width = Math.round(height * ratio / 8) * 8;\n t.resize = tf.image.resizeBilinear(input, [height, width]); // todo: resize with padding\n t.cast = tf.cast(t.resize, 'int32');\n [t.rawScores, t.rawBoxes] = await models[0].executeAsync(t.cast, modelOutputNodes) as Tensor[];\n t.boxes = tf.squeeze(t.rawBoxes, [0, 2]);\n t.scores = tf.squeeze(t.rawScores, [0]);\n const classScores = tf.unstack(t.scores, 1);\n let id = 0;\n for (let i = 0; i < classScores.length; i++) {\n if (i !== 0 && i !== 1) continue;\n t.nms = await tf.image.nonMaxSuppressionAsync(t.boxes, classScores[i], config.hand.maxDetected, config.hand.iouThreshold, config.hand.minConfidence);\n const nms = await t.nms.data();\n tf.dispose(t.nms);\n for (const res of Array.from(nms)) { // generates results for each class\n const boxSlice = tf.slice(t.boxes, res, 1);\n const yxBox = await boxSlice.data();\n const boxRaw: [number, number, number, number] = [yxBox[1], yxBox[0], yxBox[3] - yxBox[1], yxBox[2] - yxBox[0]];\n const box: [number, number, number, number] = [Math.trunc(boxRaw[0] * outputSize[0]), Math.trunc(boxRaw[1] * outputSize[1]), Math.trunc(boxRaw[2] * outputSize[0]), Math.trunc(boxRaw[3] * outputSize[1])];\n tf.dispose(boxSlice);\n const scoreSlice = tf.slice(classScores[i], res, 1);\n const score = (await scoreSlice.data())[0];\n tf.dispose(scoreSlice);\n const hand: HandDetectResult = { id: id++, score, box, boxRaw, label: classes[i], yxBox };\n hands.push(hand);\n }\n }\n classScores.forEach((tensor) => tf.dispose(tensor));\n Object.keys(t).forEach((tensor) => tf.dispose(t[tensor]));\n hands.sort((a, b) => b.score - a.score);\n if (hands.length > (config.hand.maxDetected || 1)) hands.length = (config.hand.maxDetected || 1);\n return hands;\n}\n\nconst boxScaleFact = 1.5; // hand finger model prefers slighly larger box\nfunction updateBoxes(h, keypoints) {\n const finger = [keypoints.map((pt) => pt[0]), keypoints.map((pt) => pt[1])]; // all fingers coords\n const minmax = [Math.min(...finger[0]), Math.max(...finger[0]), Math.min(...finger[1]), Math.max(...finger[1])]; // find min and max coordinates for x and y of all fingers\n const center = [(minmax[0] + minmax[1]) / 2, (minmax[2] + minmax[3]) / 2]; // find center x and y coord of all fingers\n const diff = Math.max(center[0] - minmax[0], center[1] - minmax[2], -center[0] + minmax[1], -center[1] + minmax[3]) * boxScaleFact; // largest distance from center in any direction\n h.box = [\n Math.trunc(center[0] - diff),\n Math.trunc(center[1] - diff),\n Math.trunc(2 * diff),\n Math.trunc(2 * diff),\n ] as [number, number, number, number];\n h.boxRaw = [ // work backwards\n h.box[0] / outputSize[0],\n h.box[1] / outputSize[1],\n h.box[2] / outputSize[0],\n h.box[3] / outputSize[1],\n ] as [number, number, number, number];\n h.yxBox = [ // work backwards\n h.boxRaw[1],\n h.boxRaw[0],\n h.boxRaw[3] + h.boxRaw[1],\n h.boxRaw[2] + h.boxRaw[0],\n ] as [number, number, number, number];\n}\n\nasync function detectFingers(input: Tensor, h: HandDetectResult, config: Config): Promise {\n const hand: HandResult = {\n id: h.id,\n score: Math.round(100 * h.score) / 100,\n boxScore: Math.round(100 * h.score) / 100,\n fingerScore: 0,\n box: h.box,\n boxRaw: h.boxRaw,\n label: h.label,\n keypoints: [],\n landmarks: {} as HandResult['landmarks'],\n annotations: {} as HandResult['annotations'],\n };\n if (!input || !models[1]) return hand; // something is wrong\n if (config.hand.landmarks) {\n const t: Record = {};\n if (!h.yxBox) return hand;\n t.crop = tf.image.cropAndResize(input, [h.yxBox], [0], [inputSize[1][0], inputSize[1][1]], 'bilinear');\n t.cast = tf.cast(t.crop, 'float32');\n t.div = tf.div(t.cast, 255);\n [t.score, t.keypoints] = models[1].execute(t.div) as Tensor[];\n const score = Math.round(100 * (await t.score.data())[0] / 100);\n if (score > (config.hand.minConfidence || 0)) {\n hand.fingerScore = score;\n t.reshaped = tf.reshape(t.keypoints, [-1, 3]);\n const rawCoords = await t.reshaped.array() as number[];\n hand.keypoints = (rawCoords as number[]).map((coord) => [\n (h.box[2] * coord[0] / inputSize[1][0]) + h.box[0],\n (h.box[3] * coord[1] / inputSize[1][1]) + h.box[1],\n (h.box[2] + h.box[3]) / 2 / inputSize[1][0] * coord[2],\n ]);\n updateBoxes(h, hand.keypoints); // replace detected box with box calculated around keypoints\n hand.box = h.box;\n hand.landmarks = fingerPose.analyze(hand.keypoints) as HandResult['landmarks']; // calculate finger landmarks\n for (const key of Object.keys(fingerMap)) { // map keypoints to per-finger annotations\n hand.annotations[key] = fingerMap[key].map((index) => (hand.landmarks && hand.keypoints[index] ? hand.keypoints[index] : null));\n }\n cache.tmpBoxes.push(h); // if finger detection is enabled, only update cache if fingers are detected\n }\n Object.keys(t).forEach((tensor) => tf.dispose(t[tensor]));\n }\n return hand;\n}\n\nexport async function predict(input: Tensor, config: Config): Promise {\n outputSize = [input.shape[2] || 0, input.shape[1] || 0];\n let hands: Array = [];\n cache.tmpBoxes = []; // clear temp cache\n if (!config.hand.landmarks) cache.fingerBoxes = cache.handBoxes; // if hand detection only reset finger boxes cache\n if ((skipped < (config.hand.skipFrames || 0)) && config.skipFrame) { // just run finger detection while reusing cached boxes\n skipped++;\n hands = await Promise.all(cache.fingerBoxes.map((hand) => detectFingers(input, hand, config))); // run from finger box cache\n // console.log('SKIP', skipped, hands.length, cache.handBoxes.length, cache.fingerBoxes.length, cache.tmpBoxes.length);\n } else { // calculate new boxes and run finger detection\n skipped = 0;\n hands = await Promise.all(cache.fingerBoxes.map((hand) => detectFingers(input, hand, config))); // run from finger box cache\n // console.log('CACHE', skipped, hands.length, cache.handBoxes.length, cache.fingerBoxes.length, cache.tmpBoxes.length);\n if (hands.length !== config.hand.maxDetected) { // run hand detection only if we dont have enough hands in cache\n cache.handBoxes = await detectHands(input, config);\n const newHands = await Promise.all(cache.handBoxes.map((hand) => detectFingers(input, hand, config)));\n hands = hands.concat(newHands);\n // console.log('DETECT', skipped, hands.length, cache.handBoxes.length, cache.fingerBoxes.length, cache.tmpBoxes.length);\n }\n }\n cache.fingerBoxes = [...cache.tmpBoxes]; // repopulate cache with validated hands\n return hands as HandResult[];\n}\n\n/*\n- Live Site: \n- TFJS Port: \n- Original: \n- Writeup: \n*/\n", "export const full = [\n 'nose',\n 'leftEyeInside',\n 'leftEye',\n 'leftEyeOutside',\n 'rightEyeInside',\n 'rightEye',\n 'rightEyeOutside',\n 'leftEar',\n 'rightEar',\n 'leftMouth',\n 'rightMouth',\n 'leftShoulder',\n 'rightShoulder',\n 'leftElbow',\n 'rightElbow',\n 'leftWrist',\n 'rightWrist',\n 'leftPalm',\n 'rightPalm',\n 'leftIndex',\n 'rightIndex',\n 'leftPinky',\n 'rightPinky',\n 'leftHip',\n 'rightHip',\n 'leftKnee',\n 'rightKnee',\n 'leftAnkle',\n 'rightAnkle',\n 'leftHeel',\n 'rightHeel',\n 'leftFoot',\n 'rightFoot',\n 'midHip',\n 'forehead',\n 'leftThumb',\n 'leftHand',\n 'rightThumb',\n 'rightHand',\n];\n\nexport const upper = [\n 'nose',\n 'leftEyeInside',\n 'leftEye',\n 'leftEyeOutside',\n 'rightEyeInside',\n 'rightEye',\n 'rightEyeOutside',\n 'leftEar',\n 'rightEar',\n 'leftMouth',\n 'rightMouth',\n 'leftShoulder',\n 'rightShoulder',\n 'leftElbow',\n 'rightElbow',\n 'left:15',\n 'right:16',\n 'left:17',\n 'right:18',\n 'left:19',\n 'right:20',\n 'left:21',\n 'right:22',\n 'leftChest',\n 'rightChest',\n 'neck',\n 'forehead',\n 'left:27',\n 'right:28',\n 'left:29',\n 'right:30',\n];\n", "/**\n * BlazePose Module\n */\n\n// paper: https://ai.googleblog.com/2020/08/on-device-real-time-body-pose-tracking.html\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as annotations from './annotations';\nimport type { Tensor, GraphModel } from '../tfjs/types';\nimport type { BodyResult } from '../result';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model: GraphModel | null;\n\nexport async function load(config: Config): Promise {\n if (env.initial) model = null;\n if (!model) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath || '')) as unknown as GraphModel;\n model['width'] = parseInt(model['signature'].inputs['input_1:0'].tensorShape.dim[2].size);\n model['height'] = parseInt(model['signature'].inputs['input_1:0'].tensorShape.dim[1].size);\n if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n\nexport async function predict(image: Tensor, config: Config): Promise {\n if (!model) return [];\n if (!config.body.enabled) return [];\n const imgSize = { width: (image.shape[2] || 0), height: (image.shape[1] || 0) };\n const resize = tf.image.resizeBilinear(image, [model['width'], model['height']], false);\n const normalize = tf.div(resize, [255.0]);\n tf.dispose(resize);\n const resT = await model.predict(normalize) as Array;\n const findT = resT.find((t) => (t.size === 195 || t.size === 155));\n const points = await findT?.data() || []; // order of output tensors may change between models, full has 195 and upper has 155 items\n resT.forEach((t) => tf.dispose(t));\n tf.dispose(normalize);\n const keypoints: Array<{ id, part, position: [number, number, number], positionRaw: [number, number, number], score, presence }> = [];\n const labels = points?.length === 195 ? annotations.full : annotations.upper; // full model has 39 keypoints, upper has 31 keypoints\n const depth = 5; // each points has x,y,z,visibility,presence\n for (let i = 0; i < points.length / depth; i++) {\n keypoints.push({\n id: i,\n part: labels[i],\n position: [\n Math.trunc(imgSize.width * points[depth * i + 0] / 255), // return normalized x value istead of 0..255\n Math.trunc(imgSize.height * points[depth * i + 1] / 255), // return normalized y value istead of 0..255\n Math.trunc(points[depth * i + 2]) + 0, // fix negative zero\n ],\n positionRaw: [\n points[depth * i + 0] / 255, // return x value normalized to 0..1\n points[depth * i + 1] / 255, // return y value normalized to 0..1\n points[depth * i + 2] + 0, // fix negative zero\n ],\n score: (100 - Math.trunc(100 / (1 + Math.exp(points[depth * i + 3])))) / 100, // reverse sigmoid value\n presence: (100 - Math.trunc(100 / (1 + Math.exp(points[depth * i + 4])))) / 100, // reverse sigmoid value\n });\n }\n const x = keypoints.map((a) => a.position[0]);\n const y = keypoints.map((a) => a.position[1]);\n const box: [number, number, number, number] = [\n Math.min(...x),\n Math.min(...y),\n Math.max(...x) - Math.min(...x),\n Math.max(...y) - Math.min(...x),\n ];\n const boxRaw: [number, number, number, number] = [0, 0, 0, 0]; // not yet implemented\n const score = keypoints.reduce((prev, curr) => (curr.score > prev ? curr.score : prev), 0);\n return [{ id: 0, score, box, boxRaw, keypoints }];\n}\n", "/**\n * EfficientPose Module\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport type { BodyResult } from '../result';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model: GraphModel | null;\n\ntype Keypoints = { score: number, part: string, position: [number, number], positionRaw: [number, number] };\n\nconst keypoints: Array = [];\nlet box: [number, number, number, number] = [0, 0, 0, 0];\nlet boxRaw: [number, number, number, number] = [0, 0, 0, 0];\nlet score = 0;\nlet skipped = Number.MAX_SAFE_INTEGER;\n\nconst bodyParts = ['head', 'neck', 'rightShoulder', 'rightElbow', 'rightWrist', 'chest', 'leftShoulder', 'leftElbow', 'leftWrist', 'pelvis', 'rightHip', 'rightKnee', 'rightAnkle', 'leftHip', 'leftKnee', 'leftAnkle'];\n\nexport async function load(config: Config): Promise {\n if (env.initial) model = null;\n if (!model) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath || '')) as unknown as GraphModel;\n if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n\n// performs argmax and max functions on a 2d tensor\nfunction max2d(inputs, minScore) {\n const [width, height] = inputs.shape;\n return tf.tidy(() => {\n const mod = (a, b) => tf.sub(a, tf.mul(tf.div(a, tf.scalar(b, 'int32')), tf.scalar(b, 'int32'))); // modulus op implemented in tf\n const reshaped = tf.reshape(inputs, [height * width]); // combine all data\n const newScore = tf.max(reshaped, 0).dataSync()[0]; // get highest score // inside tf.tidy\n if (newScore > minScore) { // skip coordinate calculation is score is too low\n const coords = tf.argMax(reshaped, 0);\n const x = mod(coords, width).dataSync()[0]; // inside tf.tidy\n const y = tf.div(coords, tf.scalar(width, 'int32')).dataSync()[0]; // inside tf.tidy\n return [x, y, newScore];\n }\n return [0, 0, newScore];\n });\n}\n\nexport async function predict(image: Tensor, config: Config): Promise {\n if ((skipped < (config.body?.skipFrames || 0)) && config.skipFrame && Object.keys(keypoints).length > 0) {\n skipped++;\n return [{ id: 0, score, box, boxRaw, keypoints }];\n }\n skipped = 0;\n return new Promise(async (resolve) => {\n const tensor = tf.tidy(() => {\n if (!model?.inputs[0].shape) return null;\n const resize = tf.image.resizeBilinear(image, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false);\n const enhance = tf.mul(resize, 2);\n const norm = enhance.sub(1);\n return norm;\n });\n\n let resT;\n if (config.body.enabled) resT = await model?.predict(tensor);\n tf.dispose(tensor);\n\n if (resT) {\n keypoints.length = 0;\n const squeeze = resT.squeeze();\n tf.dispose(resT);\n // body parts are basically just a stack of 2d tensors\n const stack = squeeze.unstack(2);\n tf.dispose(squeeze);\n // process each unstacked tensor as a separate body part\n for (let id = 0; id < stack.length; id++) {\n // actual processing to get coordinates and score\n const [x, y, partScore] = max2d(stack[id], config.body.minConfidence);\n if (score > (config.body?.minConfidence || 0)) {\n keypoints.push({\n score: Math.round(100 * partScore) / 100,\n part: bodyParts[id],\n positionRaw: [ // normalized to 0..1\n // @ts-ignore model is not undefined here\n x / model.inputs[0].shape[2], y / model.inputs[0].shape[1],\n ],\n position: [ // normalized to input image size\n // @ts-ignore model is not undefined here\n Math.round(image.shape[2] * x / model.inputs[0].shape[2]), Math.round(image.shape[1] * y / model.inputs[0].shape[1]),\n ],\n });\n }\n }\n stack.forEach((s) => tf.dispose(s));\n }\n score = keypoints.reduce((prev, curr) => (curr.score > prev ? curr.score : prev), 0);\n const x = keypoints.map((a) => a.position[0]);\n const y = keypoints.map((a) => a.position[1]);\n box = [\n Math.min(...x),\n Math.min(...y),\n Math.max(...x) - Math.min(...x),\n Math.max(...y) - Math.min(...y),\n ];\n const xRaw = keypoints.map((a) => a.positionRaw[0]);\n const yRaw = keypoints.map((a) => a.positionRaw[1]);\n boxRaw = [\n Math.min(...xRaw),\n Math.min(...yRaw),\n Math.max(...xRaw) - Math.min(...xRaw),\n Math.max(...yRaw) - Math.min(...yRaw),\n ];\n resolve([{ id: 0, score, box, boxRaw, keypoints }]);\n });\n}\n", "/**\n * EfficientPose Module\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport type { BodyResult } from '../result';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model: GraphModel | null;\n\ntype Keypoints = { score: number, part: string, position: [number, number], positionRaw: [number, number] };\nconst keypoints: Array = [];\ntype Person = { id: number, score: number, box: [number, number, number, number], boxRaw: [number, number, number, number], keypoints: Array }\n\nlet box: [number, number, number, number] = [0, 0, 0, 0];\nlet boxRaw: [number, number, number, number] = [0, 0, 0, 0];\nlet score = 0;\nlet skipped = Number.MAX_SAFE_INTEGER;\n\nconst bodyParts = ['nose', 'leftEye', 'rightEye', 'leftEar', 'rightEar', 'leftShoulder', 'rightShoulder', 'leftElbow', 'rightElbow', 'leftWrist', 'rightWrist', 'leftHip', 'rightHip', 'leftKnee', 'rightKnee', 'leftAnkle', 'rightAnkle'];\n\nexport async function load(config: Config): Promise {\n if (env.initial) model = null;\n if (!model) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath || '')) as unknown as GraphModel;\n if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n\nasync function parseSinglePose(res, config, image) {\n keypoints.length = 0;\n const kpt = res[0][0];\n for (let id = 0; id < kpt.length; id++) {\n score = kpt[id][2];\n if (score > config.body.minConfidence) {\n keypoints.push({\n score: Math.round(100 * score) / 100,\n part: bodyParts[id],\n positionRaw: [ // normalized to 0..1\n kpt[id][1],\n kpt[id][0],\n ],\n position: [ // normalized to input image size\n Math.round((image.shape[2] || 0) * kpt[id][1]),\n Math.round((image.shape[1] || 0) * kpt[id][0]),\n ],\n });\n }\n }\n score = keypoints.reduce((prev, curr) => (curr.score > prev ? curr.score : prev), 0);\n const x = keypoints.map((a) => a.position[0]);\n const y = keypoints.map((a) => a.position[1]);\n box = [\n Math.min(...x),\n Math.min(...y),\n Math.max(...x) - Math.min(...x),\n Math.max(...y) - Math.min(...y),\n ];\n const xRaw = keypoints.map((a) => a.positionRaw[0]);\n const yRaw = keypoints.map((a) => a.positionRaw[1]);\n boxRaw = [\n Math.min(...xRaw),\n Math.min(...yRaw),\n Math.max(...xRaw) - Math.min(...xRaw),\n Math.max(...yRaw) - Math.min(...yRaw),\n ];\n const persons: Array = [];\n persons.push({ id: 0, score, box, boxRaw, keypoints });\n return persons;\n}\n\nasync function parseMultiPose(res, config, image) {\n const persons: Array = [];\n for (let p = 0; p < res[0].length; p++) {\n const kpt = res[0][p];\n score = Math.round(100 * kpt[51 + 4]) / 100;\n // eslint-disable-next-line no-continue\n if (score < config.body.minConfidence) continue;\n keypoints.length = 0;\n for (let i = 0; i < 17; i++) {\n const partScore = Math.round(100 * kpt[3 * i + 2]) / 100;\n if (partScore > config.body.minConfidence) {\n keypoints.push({\n part: bodyParts[i],\n score: partScore,\n positionRaw: [\n kpt[3 * i + 1],\n kpt[3 * i + 0],\n ],\n position: [\n Math.trunc(kpt[3 * i + 1] * (image.shape[2] || 0)),\n Math.trunc(kpt[3 * i + 0] * (image.shape[1] || 0)),\n ],\n });\n }\n }\n boxRaw = [kpt[51 + 1], kpt[51 + 0], kpt[51 + 3] - kpt[51 + 1], kpt[51 + 2] - kpt[51 + 0]];\n persons.push({\n id: p,\n score,\n boxRaw,\n box: [\n Math.trunc(boxRaw[0] * (image.shape[2] || 0)),\n Math.trunc(boxRaw[1] * (image.shape[1] || 0)),\n Math.trunc(boxRaw[2] * (image.shape[2] || 0)),\n Math.trunc(boxRaw[3] * (image.shape[1] || 0)),\n ],\n keypoints,\n });\n }\n return persons;\n}\n\nexport async function predict(image: Tensor, config: Config): Promise {\n if ((skipped < (config.body.skipFrames || 0)) && config.skipFrame && Object.keys(keypoints).length > 0) {\n skipped++;\n return [{ id: 0, score, box, boxRaw, keypoints }];\n }\n skipped = 0;\n return new Promise(async (resolve) => {\n const tensor = tf.tidy(() => {\n if (!model?.inputs[0].shape) return null;\n let inputSize = model.inputs[0].shape[2];\n if (inputSize === -1) inputSize = 256;\n const resize = tf.image.resizeBilinear(image, [inputSize, inputSize], false);\n const cast = tf.cast(resize, 'int32');\n return cast;\n });\n\n let resT;\n if (config.body.enabled) resT = await model?.predict(tensor);\n tf.dispose(tensor);\n\n if (!resT) resolve([]);\n const res = await resT.array();\n let persons;\n if (resT.shape[2] === 17) persons = await parseSinglePose(res, config, image);\n else if (resT.shape[2] === 56) persons = await parseMultiPose(res, config, image);\n tf.dispose(resT);\n\n resolve(persons);\n });\n}\n", "/**\n * CoCo Labels used by object detection modules\n */\nexport const labels = [\n { class: 1, label: 'person' },\n { class: 2, label: 'bicycle' },\n { class: 3, label: 'car' },\n { class: 4, label: 'motorcycle' },\n { class: 5, label: 'airplane' },\n { class: 6, label: 'bus' },\n { class: 7, label: 'train' },\n { class: 8, label: 'truck' },\n { class: 9, label: 'boat' },\n { class: 10, label: 'traffic light' },\n { class: 11, label: 'fire hydrant' },\n { class: 12, label: 'stop sign' },\n { class: 13, label: 'parking meter' },\n { class: 14, label: 'bench' },\n { class: 15, label: 'bird' },\n { class: 16, label: 'cat' },\n { class: 17, label: 'dog' },\n { class: 18, label: 'horse' },\n { class: 19, label: 'sheep' },\n { class: 20, label: 'cow' },\n { class: 21, label: 'elephant' },\n { class: 22, label: 'bear' },\n { class: 23, label: 'zebra' },\n { class: 24, label: 'giraffe' },\n { class: 25, label: 'backpack' },\n { class: 26, label: 'umbrella' },\n { class: 27, label: 'handbag' },\n { class: 28, label: 'tie' },\n { class: 29, label: 'suitcase' },\n { class: 30, label: 'frisbee' },\n { class: 31, label: 'skis' },\n { class: 32, label: 'snowboard' },\n { class: 33, label: 'sports ball' },\n { class: 34, label: 'kite' },\n { class: 35, label: 'baseball bat' },\n { class: 36, label: 'baseball glove' },\n { class: 37, label: 'skateboard' },\n { class: 38, label: 'surfboard' },\n { class: 39, label: 'tennis racket' },\n { class: 40, label: 'bottle' },\n { class: 41, label: 'wine glass' },\n { class: 42, label: 'cup' },\n { class: 43, label: 'fork' },\n { class: 44, label: 'knife' },\n { class: 45, label: 'spoon' },\n { class: 46, label: 'bowl' },\n { class: 47, label: 'banana' },\n { class: 48, label: 'apple' },\n { class: 49, label: 'sandwich' },\n { class: 50, label: 'orange' },\n { class: 51, label: 'broccoli' },\n { class: 52, label: 'carrot' },\n { class: 53, label: 'hot dog' },\n { class: 54, label: 'pizza' },\n { class: 55, label: 'donut' },\n { class: 56, label: 'cake' },\n { class: 57, label: 'chair' },\n { class: 58, label: 'couch' },\n { class: 59, label: 'potted plant' },\n { class: 60, label: 'bed' },\n { class: 61, label: 'dining table' },\n { class: 62, label: 'toilet' },\n { class: 63, label: 'tv' },\n { class: 64, label: 'laptop' },\n { class: 65, label: 'mouse' },\n { class: 66, label: 'remote' },\n { class: 67, label: 'keyboard' },\n { class: 68, label: 'cell phone' },\n { class: 69, label: 'microwave' },\n { class: 70, label: 'oven' },\n { class: 71, label: 'toaster' },\n { class: 72, label: 'sink' },\n { class: 73, label: 'refrigerator' },\n { class: 74, label: 'book' },\n { class: 75, label: 'clock' },\n { class: 76, label: 'vase' },\n { class: 77, label: 'scissors' },\n { class: 78, label: 'teddy bear' },\n { class: 79, label: 'hair drier' },\n { class: 80, label: 'toothbrush' },\n];\n", "/**\n * NanoDet object detection module\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport { labels } from './labels';\nimport type { ObjectResult } from '../result';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model;\nlet last: Array = [];\nlet skipped = Number.MAX_SAFE_INTEGER;\n\nconst scaleBox = 2.5; // increase box size\n\nexport async function load(config: Config): Promise {\n if (!model || env.initial) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.object.modelPath || ''));\n const inputs = Object.values(model.modelSignature['inputs']);\n model.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;\n if (!model.inputSize) throw new Error(`cannot determine model inputSize: ${config.object.modelPath}`);\n if (!model || !model.modelUrl) log('load model failed:', config.object.modelPath);\n else if (config.debug) log('load model:', model.modelUrl);\n } else if (config.debug) log('cached model:', model.modelUrl);\n return model;\n}\n\nasync function process(res, inputSize, outputShape, config) {\n let id = 0;\n let results: Array = [];\n for (const strideSize of [1, 2, 4]) { // try each stride size as it detects large/medium/small objects\n // find scores, boxes, classes\n tf.tidy(async () => { // wrap in tidy to automatically deallocate temp tensors\n const baseSize = strideSize * 13; // 13x13=169, 26x26=676, 52x52=2704\n // find boxes and scores output depending on stride\n const scoresT = res.find((a) => (a.shape[1] === (baseSize ** 2) && a.shape[2] === labels.length))?.squeeze();\n const featuresT = res.find((a) => (a.shape[1] === (baseSize ** 2) && a.shape[2] < labels.length))?.squeeze();\n const boxesMax = featuresT.reshape([-1, 4, featuresT.shape[1] / 4]); // reshape [output] to [4, output / 4] where number is number of different features inside each stride\n const boxIdx = await boxesMax.argMax(2).array(); // what we need is indexes of features with highest scores, not values itself\n const scores = await scoresT.array(); // optionally use exponential scores or just as-is\n for (let i = 0; i < scoresT.shape[0]; i++) { // total strides (x * y matrix)\n for (let j = 0; j < scoresT.shape[1]; j++) { // one score for each class\n const score = scores[i][j]; // get score for current position\n if (score > config.object.minConfidence && j !== 61) {\n const cx = (0.5 + Math.trunc(i % baseSize)) / baseSize; // center.x normalized to range 0..1\n const cy = (0.5 + Math.trunc(i / baseSize)) / baseSize; // center.y normalized to range 0..1\n const boxOffset = boxIdx[i].map((a) => a * (baseSize / strideSize / inputSize)); // just grab indexes of features with highest scores\n const [x, y] = [\n cx - (scaleBox / strideSize * boxOffset[0]),\n cy - (scaleBox / strideSize * boxOffset[1]),\n ];\n const [w, h] = [\n cx + (scaleBox / strideSize * boxOffset[2]) - x,\n cy + (scaleBox / strideSize * boxOffset[3]) - y,\n ];\n let boxRaw = [x, y, w, h]; // results normalized to range 0..1\n boxRaw = boxRaw.map((a) => Math.max(0, Math.min(a, 1))); // fix out-of-bounds coords\n const box = [ // results normalized to input image pixels\n boxRaw[0] * outputShape[0],\n boxRaw[1] * outputShape[1],\n boxRaw[2] * outputShape[0],\n boxRaw[3] * outputShape[1],\n ];\n const result = {\n id: id++,\n // strideSize,\n score: Math.round(100 * score) / 100,\n class: j + 1,\n label: labels[j].label,\n // center: [Math.trunc(outputShape[0] * cx), Math.trunc(outputShape[1] * cy)],\n // centerRaw: [cx, cy],\n box: (box.map((a) => Math.trunc(a))) as [number, number, number, number],\n boxRaw: boxRaw as [number, number, number, number],\n };\n results.push(result);\n }\n }\n }\n });\n }\n // deallocate tensors\n res.forEach((t) => tf.dispose(t));\n\n // normally nms is run on raw results, but since boxes need to be calculated this way we skip calulcation of\n // unnecessary boxes and run nms only on good candidates (basically it just does IOU analysis as scores are already filtered)\n const nmsBoxes = results.map((a) => [a.boxRaw[1], a.boxRaw[0], a.boxRaw[3], a.boxRaw[2]]); // switches coordinates from x,y to y,x as expected by tf.nms\n const nmsScores = results.map((a) => a.score);\n let nmsIdx: Array = [];\n if (nmsBoxes && nmsBoxes.length > 0) {\n const nms = await tf.image.nonMaxSuppressionAsync(nmsBoxes, nmsScores, config.object.maxDetected, config.object.iouThreshold, config.object.minConfidence);\n nmsIdx = await nms.data();\n tf.dispose(nms);\n }\n\n // filter & sort results\n results = results\n .filter((_val, idx) => nmsIdx.includes(idx))\n .sort((a, b) => (b.score - a.score));\n\n return results;\n}\n\nexport async function predict(image: Tensor, config: Config): Promise {\n if ((skipped < (config.object.skipFrames || 0)) && config.skipFrame && (last.length > 0)) {\n skipped++;\n return last;\n }\n skipped = 0;\n if (!env.kernels.includes('mod') || !env.kernels.includes('sparsetodense')) return last;\n return new Promise(async (resolve) => {\n const outputSize = [image.shape[2], image.shape[1]];\n const resize = tf.image.resizeBilinear(image, [model.inputSize, model.inputSize], false);\n const norm = tf.div(resize, 255);\n const transpose = norm.transpose([0, 3, 1, 2]);\n tf.dispose(norm);\n tf.dispose(resize);\n\n let objectT;\n if (config.object.enabled) objectT = await model.predict(transpose);\n tf.dispose(transpose);\n\n const obj = await process(objectT, model.inputSize, outputSize, config);\n last = obj;\n resolve(obj);\n });\n}\n", "/**\n * CenterNet object detection module\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport { labels } from './labels';\nimport type { ObjectResult } from '../result';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model: GraphModel | null;\nlet inputSize = 0;\nlet last: ObjectResult[] = [];\nlet skipped = Number.MAX_SAFE_INTEGER;\n\nexport async function load(config: Config): Promise {\n if (env.initial) model = null;\n if (!model) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.object.modelPath || '')) as unknown as GraphModel;\n const inputs = Object.values(model.modelSignature['inputs']);\n inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;\n if (!model || !model['modelUrl']) log('load model failed:', config.object.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n\nasync function process(res: Tensor | null, outputShape, config: Config) {\n if (!res) return [];\n const results: Array = [];\n const detections = await res.array();\n const squeezeT = tf.squeeze(res);\n tf.dispose(res);\n const arr = tf.split(squeezeT, 6, 1); // x1, y1, x2, y2, score, class\n tf.dispose(squeezeT);\n const stackT = tf.stack([arr[1], arr[0], arr[3], arr[2]], 1); // reorder dims as tf.nms expects y, x\n const boxesT = tf.squeeze(stackT);\n tf.dispose(stackT);\n const scoresT = tf.squeeze(arr[4]);\n const classesT = tf.squeeze(arr[5]);\n arr.forEach((t) => tf.dispose(t));\n const nmsT = await tf.image.nonMaxSuppressionAsync(boxesT, scoresT, config.object.maxDetected, config.object.iouThreshold, config.object.minConfidence);\n tf.dispose(boxesT);\n tf.dispose(scoresT);\n tf.dispose(classesT);\n const nms = await nmsT.data();\n tf.dispose(nmsT);\n let i = 0;\n for (const id of nms) {\n const score = Math.trunc(100 * detections[0][id][4]) / 100;\n const classVal = detections[0][id][5];\n const label = labels[classVal].label;\n const [x, y] = [\n detections[0][id][0] / inputSize,\n detections[0][id][1] / inputSize,\n ];\n const boxRaw = [\n x,\n y,\n detections[0][id][2] / inputSize - x,\n detections[0][id][3] / inputSize - y,\n ] as [number, number, number, number];\n const box = [\n Math.trunc(boxRaw[0] * outputShape[0]),\n Math.trunc(boxRaw[1] * outputShape[1]),\n Math.trunc(boxRaw[2] * outputShape[0]),\n Math.trunc(boxRaw[3] * outputShape[1]),\n ] as [number, number, number, number];\n results.push({ id: i++, score, class: classVal, label, box, boxRaw });\n }\n return results;\n}\n\nexport async function predict(input: Tensor, config: Config): Promise {\n if ((skipped < (config.object.skipFrames || 0)) && config.skipFrame && (last.length > 0)) {\n skipped++;\n return last;\n }\n skipped = 0;\n if (!env.kernels.includes('mod') || !env.kernels.includes('sparsetodense')) return last;\n return new Promise(async (resolve) => {\n const outputSize = [input.shape[2], input.shape[1]];\n const resize = tf.image.resizeBilinear(input, [inputSize, inputSize]);\n const objectT = config.object.enabled ? model?.execute(resize, ['tower_0/detections']) as Tensor : null;\n tf.dispose(resize);\n\n const obj = await process(objectT, outputSize, config);\n last = obj;\n\n resolve(obj);\n });\n}\n", "/**\n * EfficientPose Module\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as image from '../image/image';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\ntype Input = Tensor | typeof Image | ImageData | ImageBitmap | HTMLImageElement | HTMLMediaElement | HTMLVideoElement | HTMLCanvasElement | OffscreenCanvas;\n\nlet model: GraphModel;\nlet busy = false;\n\nexport async function load(config: Config): Promise {\n if (!model || env.initial) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.segmentation.modelPath || '')) as unknown as GraphModel;\n if (!model || !model['modelUrl']) log('load model failed:', config.segmentation.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n\nexport async function predict(input: { tensor: Tensor | null, canvas: OffscreenCanvas | HTMLCanvasElement | null }, config: Config)\n: Promise<{ data: Uint8ClampedArray | null, canvas: HTMLCanvasElement | OffscreenCanvas | null, alpha: HTMLCanvasElement | OffscreenCanvas | null }> {\n const width = input.tensor?.shape[2] || 0;\n const height = input.tensor?.shape[1] || 0;\n if (!input.tensor || !model || !model.inputs[0].shape) return { data: null, canvas: null, alpha: null };\n const resizeInput = tf.image.resizeBilinear(input.tensor, [model.inputs[0].shape[1], model.inputs[0].shape[2]], false);\n const norm = tf.div(resizeInput, 255);\n const res = model.predict(norm) as Tensor;\n // meet output: 1,256,256,1\n // selfie output: 1,144,256,2\n tf.dispose(resizeInput);\n tf.dispose(norm);\n\n const squeeze = tf.squeeze(res, 0);\n tf.dispose(res);\n let dataT;\n if (squeeze.shape[2] === 2) {\n // model meet has two channels for fg and bg\n const softmax = squeeze.softmax();\n const [bg, fg] = tf.unstack(softmax, 2);\n const expand = tf.expandDims(fg, 2);\n const pad = tf.expandDims(expand, 0);\n tf.dispose(softmax);\n tf.dispose(bg);\n tf.dispose(fg);\n // running sofmax before unstack creates 2x2 matrix so we only take upper-left quadrant\n const crop = tf.image.cropAndResize(pad, [[0, 0, 0.5, 0.5]], [0], [width, height]);\n // otherwise run softmax after unstack and use standard resize\n // resizeOutput = tf.image.resizeBilinear(expand, [input.tensor?.shape[1], input.tensor?.shape[2]]);\n dataT = tf.squeeze(crop, 0);\n tf.dispose(crop);\n tf.dispose(expand);\n tf.dispose(pad);\n } else { // model selfie has a single channel that we can use directly\n dataT = tf.image.resizeBilinear(squeeze, [height, width]);\n }\n tf.dispose(squeeze);\n const data = await dataT.dataSync();\n\n if (env.node) {\n tf.dispose(dataT);\n return { data, canvas: null, alpha: null }; // running in nodejs so return alpha array as-is\n }\n\n const alphaCanvas = image.canvas(width, height);\n await tf.browser.toPixels(dataT, alphaCanvas);\n tf.dispose(dataT);\n const alphaCtx = alphaCanvas.getContext('2d') as CanvasRenderingContext2D;\n if (config.segmentation.blur && config.segmentation.blur > 0) alphaCtx.filter = `blur(${config.segmentation.blur}px)`; // use css filter for bluring, can be done with gaussian blur manually instead\n const alphaData = alphaCtx.getImageData(0, 0, width, height);\n\n // original canvas where only alpha shows\n const compositeCanvas = image.canvas(width, height);\n const compositeCtx = compositeCanvas.getContext('2d') as CanvasRenderingContext2D;\n if (input.canvas) compositeCtx.drawImage(input.canvas, 0, 0);\n compositeCtx.globalCompositeOperation = 'darken'; // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation // best options are: darken, color-burn, multiply\n if (config.segmentation.blur && config.segmentation.blur > 0) compositeCtx.filter = `blur(${config.segmentation.blur}px)`; // use css filter for bluring, can be done with gaussian blur manually instead\n compositeCtx.drawImage(alphaCanvas, 0, 0);\n compositeCtx.globalCompositeOperation = 'source-over'; // reset composite operation\n compositeCtx.filter = 'none'; // reset css filter\n const compositeData = compositeCtx.getImageData(0, 0, width, height);\n for (let i = 0; i < width * height; i++) compositeData.data[4 * i + 3] = alphaData.data[4 * i + 0]; // copy original alpha value to new composite canvas\n compositeCtx.putImageData(compositeData, 0, 0);\n\n return { data, canvas: compositeCanvas, alpha: alphaCanvas };\n}\n\nexport async function process(input: Input, background: Input | undefined, config: Config)\n: Promise<{ data: Uint8ClampedArray | null, canvas: HTMLCanvasElement | OffscreenCanvas | null, alpha: HTMLCanvasElement | OffscreenCanvas | null }> {\n if (busy) return { data: null, canvas: null, alpha: null };\n busy = true;\n if (!model) await load(config);\n const inputImage = image.process(input, config);\n const segmentation = await predict(inputImage, config);\n tf.dispose(inputImage.tensor);\n let mergedCanvas: HTMLCanvasElement | OffscreenCanvas | null = null;\n\n if (background && segmentation.canvas) { // draw background with segmentation as overlay if background is present\n mergedCanvas = image.canvas(inputImage.canvas?.width || 0, inputImage.canvas?.height || 0);\n const bgImage = image.process(background, config);\n tf.dispose(bgImage.tensor);\n const ctxMerge = mergedCanvas.getContext('2d') as CanvasRenderingContext2D;\n // ctxMerge.globalCompositeOperation = 'source-over';\n ctxMerge.drawImage(bgImage.canvas as HTMLCanvasElement, 0, 0, mergedCanvas.width, mergedCanvas.height);\n // ctxMerge.globalCompositeOperation = 'source-atop';\n ctxMerge.drawImage(segmentation.canvas as HTMLCanvasElement, 0, 0);\n // ctxMerge.globalCompositeOperation = 'source-over';\n }\n\n busy = false;\n return { data: segmentation.data, canvas: mergedCanvas || segmentation.canvas, alpha: segmentation.alpha };\n}\n", "import { log } from './helpers';\nimport type { GraphModel } from './tfjs/types';\nimport * as facemesh from './blazeface/facemesh';\nimport * as faceres from './faceres/faceres';\nimport * as emotion from './emotion/emotion';\nimport * as posenet from './posenet/posenet';\nimport * as handpose from './handpose/handpose';\nimport * as handtrack from './handtrack/handtrack';\nimport * as blazepose from './blazepose/blazepose';\nimport * as efficientpose from './efficientpose/efficientpose';\nimport * as movenet from './movenet/movenet';\nimport * as nanodet from './object/nanodet';\nimport * as centernet from './object/centernet';\nimport * as segmentation from './segmentation/segmentation';\nimport { env } from './env';\n// import * as agegenderrace from './gear/agegenderrace';\n\nexport function reset(instance) {\n // if (instance.config.debug) log('resetting loaded models');\n instance.models = {\n face: null, // array of models\n handpose: null, // array of models\n handtrack: null, // array of models\n posenet: null,\n blazepose: null,\n efficientpose: null,\n movenet: null,\n age: null,\n gender: null,\n emotion: null,\n embedding: null,\n nanodet: null,\n centernet: null,\n faceres: null,\n segmentation: null,\n };\n}\n\n/** Load method preloads all instance.configured models on-demand */\nexport async function load(instance) {\n if (env.initial) reset(instance);\n if (instance.config.async) { // load models concurrently\n [\n instance.models.face,\n instance.models.emotion,\n instance.models.handpose,\n instance.models.handtrack,\n instance.models.posenet,\n instance.models.blazepose,\n instance.models.efficientpose,\n instance.models.movenet,\n instance.models.nanodet,\n instance.models.centernet,\n instance.models.faceres,\n instance.models.segmentation,\n // instance.models.agegenderrace,\n ] = await Promise.all([\n instance.models.face || (instance.config.face.enabled ? facemesh.load(instance.config) : null),\n instance.models.emotion || ((instance.config.face.enabled && instance.config.face.emotion.enabled) ? emotion.load(instance.config) : null),\n instance.models.handpose || (instance.config.hand.enabled && instance.config.hand.detector.modelPath.includes('handdetect') ? handpose.load(instance.config) : null),\n instance.models.handtrack || (instance.config.hand.enabled && instance.config.hand.detector.modelPath.includes('handtrack') ? handtrack.load(instance.config) : null),\n instance.models.posenet || (instance.config.body.enabled && instance.config.body.modelPath.includes('posenet') ? posenet.load(instance.config) : null),\n instance.models.blazepose || (instance.config.body.enabled && instance.config.body.modelPath.includes('blazepose') ? blazepose.load(instance.config) : null),\n instance.models.efficientpose || (instance.config.body.enabled && instance.config.body.modelPath.includes('efficientpose') ? efficientpose.load(instance.config) : null),\n instance.models.movenet || (instance.config.body.enabled && instance.config.body.modelPath.includes('movenet') ? movenet.load(instance.config) : null),\n instance.models.nanodet || (instance.config.object.enabled && instance.config.object.modelPath.includes('nanodet') ? nanodet.load(instance.config) : null),\n instance.models.centernet || (instance.config.object.enabled && instance.config.object.modelPath.includes('centernet') ? centernet.load(instance.config) : null),\n instance.models.faceres || ((instance.config.face.enabled && instance.config.face.description.enabled) ? faceres.load(instance.config) : null),\n instance.models.segmentation || (instance.config.segmentation.enabled ? segmentation.load(instance.config) : null),\n // instance.models.agegenderrace || ((instance.config.face.enabled && instance.config.face.agegenderrace.enabled) ? agegenderrace.load(instance.config) : null),\n ]);\n } else { // load models sequentially\n if (instance.config.face.enabled && !instance.models.face) instance.models.face = await facemesh.load(instance.config);\n if (instance.config.face.enabled && instance.config.face.emotion.enabled && !instance.models.emotion) instance.models.emotion = await emotion.load(instance.config);\n if (instance.config.hand.enabled && !instance.models.handpose && instance.config.hand.detector.modelPath.includes('handdetect')) instance.models.handpose = await handpose.load(instance.config);\n if (instance.config.hand.enabled && !instance.models.handtrack && instance.config.hand.detector.modelPath.includes('handtrack')) instance.models.handtrack = await handtrack.load(instance.config);\n if (instance.config.body.enabled && !instance.models.posenet && instance.config.body.modelPath.includes('posenet')) instance.models.posenet = await posenet.load(instance.config);\n if (instance.config.body.enabled && !instance.models.blazepose && instance.config.body.modelPath.includes('blazepose')) instance.models.blazepose = await blazepose.load(instance.config);\n if (instance.config.body.enabled && !instance.models.efficientpose && instance.config.body.modelPath.includes('efficientpose')) instance.models.efficientpose = await blazepose.load(instance.config);\n if (instance.config.body.enabled && !instance.models.movenet && instance.config.body.modelPath.includes('movenet')) instance.models.movenet = await movenet.load(instance.config);\n if (instance.config.object.enabled && !instance.models.nanodet && instance.config.object.modelPath.includes('nanodet')) instance.models.nanodet = await nanodet.load(instance.config);\n if (instance.config.object.enabled && !instance.models.centernet && instance.config.object.modelPath.includes('centernet')) instance.models.centernet = await centernet.load(instance.config);\n if (instance.config.face.enabled && instance.config.face.description.enabled && !instance.models.faceres) instance.models.faceres = await faceres.load(instance.config);\n if (instance.config.segmentation.enabled && !instance.models.segmentation) instance.models.segmentation = await segmentation.load(instance.config);\n // if (instance.config.face.enabled && instance.config.face.agegenderrace.enabled && !instance.models.agegenderrace) instance.models.agegenderrace = await agegenderrace.load(instance.config);\n }\n}\n\nexport async function validate(instance) {\n interface Op { name: string, category: string, op: string }\n const simpleOps = ['const', 'placeholder', 'noop', 'pad', 'squeeze', 'add', 'sub', 'mul', 'div'];\n for (const defined of Object.keys(instance.models)) {\n if (instance.models[defined]) { // check if model is loaded\n let models: GraphModel[] = [];\n if (Array.isArray(instance.models[defined])) {\n models = instance.models[defined]\n .filter((model) => (model !== null))\n .map((model) => ((model && model.executor) ? model : model.model));\n } else {\n models = [instance.models[defined]];\n }\n for (const model of models) {\n if (!model) {\n if (instance.config.debug) log('model marked as loaded but not defined:', defined);\n continue;\n }\n const ops: string[] = [];\n // @ts-ignore // executor is a private method\n const executor = model?.executor;\n if (executor && executor.graph.nodes) {\n for (const kernel of Object.values(executor.graph.nodes)) {\n const op = (kernel as Op).op.toLowerCase();\n if (!ops.includes(op)) ops.push(op);\n }\n } else {\n if (!executor && instance.config.debug) log('model signature not determined:', defined);\n }\n const missing: string[] = [];\n for (const op of ops) {\n if (!simpleOps.includes(op) // exclude simple ops\n && !instance.env.kernels.includes(op) // check actual kernel ops\n && !instance.env.kernels.includes(op.replace('_', '')) // check variation without _\n && !instance.env.kernels.includes(op.replace('native', '')) // check standard variation\n && !instance.env.kernels.includes(op.replace('v2', ''))) { // check non-versioned variation\n missing.push(op);\n }\n }\n // log('model validation ops:', defined, ops);\n if (missing.length > 0 && instance.config.debug) log('model validation:', defined, missing);\n }\n }\n }\n}\n", "/**\n * Module that analyzes person age\n * Obsolete\n */\n\nimport { log, now } from './helpers';\nimport * as tf from '../dist/tfjs.esm.js';\nimport * as facemesh from './blazeface/facemesh';\nimport * as emotion from './emotion/emotion';\nimport * as faceres from './faceres/faceres';\nimport type { FaceResult } from './result';\nimport type { Tensor } from './tfjs/types';\n\n// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\nconst rad2deg = (theta) => Math.round((theta * 180) / Math.PI);\n\nconst calculateGaze = (face): { bearing: number, strength: number } => {\n const radians = (pt1, pt2) => Math.atan2(pt1[1] - pt2[1], pt1[0] - pt2[0]); // function to calculate angle between any two points\n if (!face.annotations['rightEyeIris'] || !face.annotations['leftEyeIris']) return { bearing: 0, strength: 0 };\n\n const offsetIris = [0, -0.1]; // iris center may not align with average of eye extremes\n const eyeRatio = 1; // factor to normalize changes x vs y\n\n const left = face.mesh[33][2] > face.mesh[263][2]; // pick left or right eye depending which one is closer bazed on outsize point z axis\n const irisCenter = left ? face.mesh[473] : face.mesh[468];\n const eyeCenter = left // eye center is average of extreme points on x axis for both x and y, ignoring y extreme points as eyelids naturally open/close more when gazing up/down so relative point is less precise\n ? [(face.mesh[133][0] + face.mesh[33][0]) / 2, (face.mesh[133][1] + face.mesh[33][1]) / 2]\n : [(face.mesh[263][0] + face.mesh[362][0]) / 2, (face.mesh[263][1] + face.mesh[362][1]) / 2];\n const eyeSize = left // eye size is difference between extreme points for both x and y, used to normalize & squarify eye dimensions\n ? [face.mesh[133][0] - face.mesh[33][0], face.mesh[23][1] - face.mesh[27][1]]\n : [face.mesh[263][0] - face.mesh[362][0], face.mesh[253][1] - face.mesh[257][1]];\n\n const eyeDiff = [ // x distance between extreme point and center point normalized with eye size\n (eyeCenter[0] - irisCenter[0]) / eyeSize[0] - offsetIris[0],\n eyeRatio * (irisCenter[1] - eyeCenter[1]) / eyeSize[1] - offsetIris[1],\n ];\n let strength = Math.sqrt((eyeDiff[0] ** 2) + (eyeDiff[1] ** 2)); // vector length is a diagonal between two differences\n strength = Math.min(strength, face.boxRaw[2] / 2, face.boxRaw[3] / 2); // limit strength to half of box size to avoid clipping due to low precision\n const bearing = (radians([0, 0], eyeDiff) + (Math.PI / 2)) % Math.PI; // using eyeDiff instead eyeCenter/irisCenter combo due to manual adjustments and rotate clockwise 90degrees\n\n return { bearing, strength };\n};\n\nconst calculateFaceAngle = (face, imageSize): {\n angle: { pitch: number, yaw: number, roll: number },\n matrix: [number, number, number, number, number, number, number, number, number],\n gaze: { bearing: number, strength: number },\n} => {\n // const degrees = (theta) => Math.abs(((theta * 180) / Math.PI) % 360);\n const normalize = (v) => { // normalize vector\n const length = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);\n v[0] /= length;\n v[1] /= length;\n v[2] /= length;\n return v;\n };\n const subVectors = (a, b) => { // vector subtraction (a - b)\n const x = a[0] - b[0];\n const y = a[1] - b[1];\n const z = a[2] - b[2];\n return [x, y, z];\n };\n const crossVectors = (a, b) => { // vector cross product (a x b)\n const x = a[1] * b[2] - a[2] * b[1];\n const y = a[2] * b[0] - a[0] * b[2];\n const z = a[0] * b[1] - a[1] * b[0];\n return [x, y, z];\n };\n // 3x3 rotation matrix to Euler angles based on https://www.geometrictools.com/Documentation/EulerAngles.pdf\n const rotationMatrixToEulerAngle = (r) => {\n // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\n const [r00, r01, r02, r10, r11, r12, r20, r21, r22] = r;\n let thetaX: number;\n let thetaY: number;\n let thetaZ: number;\n if (r10 < 1) { // YZX calculation\n if (r10 > -1) {\n thetaZ = Math.asin(r10);\n thetaY = Math.atan2(-r20, r00);\n thetaX = Math.atan2(-r12, r11);\n } else {\n thetaZ = -Math.PI / 2;\n thetaY = -Math.atan2(r21, r22);\n thetaX = 0;\n }\n } else {\n thetaZ = Math.PI / 2;\n thetaY = Math.atan2(r21, r22);\n thetaX = 0;\n }\n if (isNaN(thetaX)) thetaX = 0;\n if (isNaN(thetaY)) thetaY = 0;\n if (isNaN(thetaZ)) thetaZ = 0;\n return { pitch: 2 * -thetaX, yaw: 2 * -thetaY, roll: 2 * -thetaZ };\n };\n // simple Euler angle calculation based existing 3D mesh\n // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\n const meshToEulerAngle = (mesh) => {\n const radians = (a1, a2, b1, b2) => Math.atan2(b2 - a2, b1 - a1);\n // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\n const angle = {\n // values are in radians in range of -pi/2 to pi/2 which is -90 to +90 degrees, value of 0 means center\n // pitch is face move up/down\n pitch: radians(mesh[10][1], mesh[10][2], mesh[152][1], mesh[152][2]), // looking at y,z of top and bottom points of the face\n // yaw is face turn left/right\n yaw: radians(mesh[33][0], mesh[33][2], mesh[263][0], mesh[263][2]), // looking at x,z of outside corners of leftEye and rightEye\n // roll is face lean left/right\n roll: radians(mesh[33][0], mesh[33][1], mesh[263][0], mesh[263][1]), // looking at x,y of outside corners of leftEye and rightEye\n };\n return angle;\n };\n\n // initialize gaze and mesh\n const mesh = face.meshRaw;\n if (!mesh || mesh.length < 300) return { angle: { pitch: 0, yaw: 0, roll: 0 }, matrix: [1, 0, 0, 0, 1, 0, 0, 0, 1], gaze: { bearing: 0, strength: 0 } };\n\n const size = Math.max(face.boxRaw[2] * imageSize[0], face.boxRaw[3] * imageSize[1]) / 1.5;\n // top, bottom, left, right\n const pts = [mesh[10], mesh[152], mesh[234], mesh[454]].map((pt) => [\n // make the xyz coordinates proportional, independent of the image/box size\n pt[0] * imageSize[0] / size,\n pt[1] * imageSize[1] / size,\n pt[2],\n ]);\n\n const y_axis = normalize(subVectors(pts[1], pts[0]));\n let x_axis = normalize(subVectors(pts[3], pts[2]));\n const z_axis = normalize(crossVectors(x_axis, y_axis));\n // adjust x_axis to make sure that all axes are perpendicular to each other\n x_axis = crossVectors(y_axis, z_axis);\n\n // Rotation Matrix from Axis Vectors - http://renderdan.blogspot.com/2006/05/rotation-matrix-from-axis-vectors.html\n // 3x3 rotation matrix is flatten to array in row-major order. Note that the rotation represented by this matrix is inverted.\n const matrix: [number, number, number, number, number, number, number, number, number] = [\n x_axis[0], x_axis[1], x_axis[2],\n y_axis[0], y_axis[1], y_axis[2],\n z_axis[0], z_axis[1], z_axis[2],\n ];\n const angle = rotationMatrixToEulerAngle(matrix);\n // const angle = meshToEulerAngle(mesh);\n\n // we have iris keypoints so we can calculate gaze direction\n const gaze = mesh.length === 478 ? calculateGaze(face) : { bearing: 0, strength: 0 };\n\n return { angle, matrix, gaze };\n};\n\nexport const detectFace = async (parent /* instance of human */, input: Tensor): Promise => {\n // run facemesh, includes blazeface and iris\n // eslint-disable-next-line no-async-promise-executor\n let timeStamp;\n let ageRes;\n let gearRes;\n let genderRes;\n let emotionRes;\n let embeddingRes;\n let descRes;\n const faceRes: Array = [];\n parent.state = 'run:face';\n timeStamp = now();\n const faces = await facemesh.predict(input, parent.config);\n parent.performance.face = Math.trunc(now() - timeStamp);\n if (!input.shape || input.shape.length !== 4) return [];\n if (!faces) return [];\n // for (const face of faces) {\n for (let i = 0; i < faces.length; i++) {\n parent.analyze('Get Face');\n\n // is something went wrong, skip the face\n // @ts-ignore possibly undefied\n if (!faces[i].tensor || faces[i].tensor['isDisposedInternal']) {\n log('Face object is disposed:', faces[i].tensor);\n continue;\n }\n\n const rotation = calculateFaceAngle(faces[i], [input.shape[2], input.shape[1]]);\n\n // run emotion, inherits face from blazeface\n parent.analyze('Start Emotion:');\n if (parent.config.async) {\n emotionRes = parent.config.face.emotion.enabled ? emotion.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : {};\n } else {\n parent.state = 'run:emotion';\n timeStamp = now();\n emotionRes = parent.config.face.emotion.enabled ? await emotion.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : {};\n parent.performance.emotion = Math.trunc(now() - timeStamp);\n }\n parent.analyze('End Emotion:');\n\n // run gear, inherits face from blazeface\n /*\n parent.analyze('Start GEAR:');\n if (parent.config.async) {\n gearRes = parent.config.face.agegenderrace.enabled ? agegenderrace.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : {};\n } else {\n parent.state = 'run:gear';\n timeStamp = now();\n gearRes = parent.config.face.agegenderrace.enabled ? await agegenderrace.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : {};\n parent.performance.emotion = Math.trunc(now() - timeStamp);\n }\n parent.analyze('End GEAR:');\n */\n\n // run emotion, inherits face from blazeface\n parent.analyze('Start Description:');\n if (parent.config.async) {\n descRes = parent.config.face.description.enabled ? faceres.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : [];\n } else {\n parent.state = 'run:description';\n timeStamp = now();\n descRes = parent.config.face.description.enabled ? await faceres.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : [];\n parent.performance.embedding = Math.trunc(now() - timeStamp);\n }\n parent.analyze('End Description:');\n\n // if async wait for results\n if (parent.config.async) {\n [ageRes, genderRes, emotionRes, embeddingRes, descRes, gearRes] = await Promise.all([ageRes, genderRes, emotionRes, embeddingRes, descRes, gearRes]);\n }\n\n parent.analyze('Finish Face:');\n\n // calculate iris distance\n // iris: array[ center, left, top, right, bottom]\n if (!parent.config.face.iris.enabled && faces[i]?.annotations?.leftEyeIris && faces[i]?.annotations?.rightEyeIris) {\n delete faces[i].annotations.leftEyeIris;\n delete faces[i].annotations.rightEyeIris;\n }\n const irisSize = (faces[i].annotations?.leftEyeIris && faces[i].annotations?.rightEyeIris)\n /* note: average human iris size is 11.7mm */\n ? Math.max(Math.abs(faces[i].annotations.leftEyeIris[3][0] - faces[i].annotations.leftEyeIris[1][0]), Math.abs(faces[i].annotations.rightEyeIris[4][1] - faces[i].annotations.rightEyeIris[2][1])) / input.shape[2]\n : 0;\n\n // optionally return tensor\n const tensor = parent.config.face.detector.return ? tf.squeeze(faces[i].tensor) : null;\n // dispose original face tensor\n tf.dispose(faces[i].tensor);\n // delete temp face image\n if (faces[i].tensor) delete faces[i].tensor;\n // combine results\n faceRes.push({\n ...faces[i],\n id: i,\n age: descRes.age,\n gender: descRes.gender,\n genderScore: descRes.genderScore,\n embedding: descRes.descriptor,\n emotion: emotionRes,\n iris: irisSize !== 0 ? Math.trunc(500 / irisSize / 11.7) / 100 : 0,\n rotation,\n tensor,\n });\n parent.analyze('End Face');\n }\n parent.analyze('End FaceMesh:');\n if (parent.config.async) {\n if (parent.performance.face) delete parent.performance.face;\n if (parent.performance.age) delete parent.performance.age;\n if (parent.performance.gender) delete parent.performance.gender;\n if (parent.performance.emotion) delete parent.performance.emotion;\n }\n return faceRes;\n};\n", "/**\n * Gesture detection module\n */\n\nimport type { GestureResult } from '../result';\nimport * as fingerPose from '../fingerpose/fingerpose';\n\n/**\n * @typedef FaceGesture\n */\nexport type FaceGesture =\n `facing ${'left' | 'center' | 'right'}`\n | `blink ${'left' | 'right'} eye`\n | `mouth ${number}% open`\n | `head ${'up' | 'down'}`;\n\n/**\n * @typedef IrisGesture\n */\nexport type IrisGesture =\n 'facing center'\n | `looking ${'left' | 'right' | 'up' | 'down'}`\n | 'looking center';\n\n/**\n * @typedef BodyGesture\n */\nexport type BodyGesture =\n `leaning ${'left' | 'right'}`\n | `raise ${'left' | 'right'} hand`\n | 'i give up';\n\n/**\n * @typedef BodyGesture\n */\nexport type HandGesture =\n `${'thumb' | 'index' | 'middle' | 'ring' | 'pinky'} forward`\n | `${'thumb' | 'index' | 'middle' | 'ring' | 'pinky'} up`\n | 'victory'\n | 'thumbs up';\n\nexport const body = (res): GestureResult[] => {\n if (!res) return [];\n const gestures: Array<{ body: number, gesture: BodyGesture }> = [];\n for (let i = 0; i < res.length; i++) {\n // raising hands\n const leftWrist = res[i].keypoints.find((a) => (a.part === 'leftWrist'));\n const rightWrist = res[i].keypoints.find((a) => (a.part === 'rightWrist'));\n const nose = res[i].keypoints.find((a) => (a.part === 'nose'));\n if (nose && leftWrist && rightWrist && (leftWrist.position.y < nose.position.y) && (rightWrist.position.y < nose.position.y)) gestures.push({ body: i, gesture: 'i give up' });\n else if (nose && leftWrist && (leftWrist.position.y < nose.position.y)) gestures.push({ body: i, gesture: 'raise left hand' });\n else if (nose && rightWrist && (rightWrist.position.y < nose.position.y)) gestures.push({ body: i, gesture: 'raise right hand' });\n\n // leaning\n const leftShoulder = res[i].keypoints.find((a) => (a.part === 'leftShoulder'));\n const rightShoulder = res[i].keypoints.find((a) => (a.part === 'rightShoulder'));\n if (leftShoulder && rightShoulder) gestures.push({ body: i, gesture: `leaning ${(leftShoulder.position.y > rightShoulder.position.y) ? 'left' : 'right'}` });\n }\n return gestures;\n};\n\nexport const face = (res): GestureResult[] => {\n if (!res) return [];\n const gestures: Array<{ face: number, gesture: FaceGesture }> = [];\n for (let i = 0; i < res.length; i++) {\n if (res[i].mesh && res[i].mesh.length > 0) {\n const eyeFacing = res[i].mesh[33][2] - res[i].mesh[263][2];\n if (Math.abs(eyeFacing) < 10) gestures.push({ face: i, gesture: 'facing center' });\n else gestures.push({ face: i, gesture: `facing ${eyeFacing < 0 ? 'left' : 'right'}` });\n const openLeft = Math.abs(res[i].mesh[374][1] - res[i].mesh[386][1]) / Math.abs(res[i].mesh[443][1] - res[i].mesh[450][1]); // center of eye inner lid y coord div center of wider eye border y coord\n if (openLeft < 0.2) gestures.push({ face: i, gesture: 'blink left eye' });\n const openRight = Math.abs(res[i].mesh[145][1] - res[i].mesh[159][1]) / Math.abs(res[i].mesh[223][1] - res[i].mesh[230][1]); // center of eye inner lid y coord div center of wider eye border y coord\n if (openRight < 0.2) gestures.push({ face: i, gesture: 'blink right eye' });\n const mouthOpen = Math.min(100, 500 * Math.abs(res[i].mesh[13][1] - res[i].mesh[14][1]) / Math.abs(res[i].mesh[10][1] - res[i].mesh[152][1]));\n if (mouthOpen > 10) gestures.push({ face: i, gesture: `mouth ${Math.trunc(mouthOpen)}% open` });\n const chinDepth = res[i].mesh[152][2];\n if (Math.abs(chinDepth) > 10) gestures.push({ face: i, gesture: `head ${chinDepth < 0 ? 'up' : 'down'}` });\n }\n }\n return gestures;\n};\n\nexport const iris = (res): GestureResult[] => {\n if (!res) return [];\n const gestures: Array<{ iris: number, gesture: IrisGesture }> = [];\n for (let i = 0; i < res.length; i++) {\n if (!res[i].annotations || !res[i].annotations.leftEyeIris || !res[i].annotations.rightEyeIris) continue;\n const sizeXLeft = res[i].annotations.leftEyeIris[3][0] - res[i].annotations.leftEyeIris[1][0];\n const sizeYLeft = res[i].annotations.leftEyeIris[4][1] - res[i].annotations.leftEyeIris[2][1];\n const areaLeft = Math.abs(sizeXLeft * sizeYLeft);\n\n const sizeXRight = res[i].annotations.rightEyeIris[3][0] - res[i].annotations.rightEyeIris[1][0];\n const sizeYRight = res[i].annotations.rightEyeIris[4][1] - res[i].annotations.rightEyeIris[2][1];\n const areaRight = Math.abs(sizeXRight * sizeYRight);\n\n let center = false;\n const difference = Math.abs(areaLeft - areaRight) / Math.max(areaLeft, areaRight);\n if (difference < 0.25) {\n center = true;\n gestures.push({ iris: i, gesture: 'facing center' });\n }\n\n const rightIrisCenterX = Math.abs(res[i].mesh[33][0] - res[i].annotations.rightEyeIris[0][0]) / res[i].box[2];\n const leftIrisCenterX = Math.abs(res[i].mesh[263][0] - res[i].annotations.leftEyeIris[0][0]) / res[i].box[2];\n if (leftIrisCenterX > 0.06 || rightIrisCenterX > 0.06) center = false;\n if (leftIrisCenterX > 0.06) gestures.push({ iris: i, gesture: 'looking right' });\n if (rightIrisCenterX > 0.06) gestures.push({ iris: i, gesture: 'looking left' });\n\n const rightIrisCenterY = Math.abs(res[i].mesh[145][1] - res[i].annotations.rightEyeIris[0][1]) / res[i].box[3];\n const leftIrisCenterY = Math.abs(res[i].mesh[374][1] - res[i].annotations.leftEyeIris[0][1]) / res[i].box[3];\n if (leftIrisCenterY < 0.01 || rightIrisCenterY < 0.01 || leftIrisCenterY > 0.022 || rightIrisCenterY > 0.022) center = false;\n if (leftIrisCenterY < 0.01 || rightIrisCenterY < 0.01) gestures.push({ iris: i, gesture: 'looking down' });\n if (leftIrisCenterY > 0.022 || rightIrisCenterY > 0.022) gestures.push({ iris: i, gesture: 'looking up' });\n\n // still center;\n if (center) gestures.push({ iris: i, gesture: 'looking center' });\n }\n return gestures;\n};\n\nexport const hand = (res): GestureResult[] => {\n if (!res) return [];\n const gestures: Array<{ hand: number, gesture: HandGesture }> = [];\n for (let i = 0; i < res.length; i++) {\n const fingers: Array<{ name: string, position: number }> = [];\n if (res[i]['annotations']) {\n for (const [finger, pos] of Object.entries(res[i]['annotations'])) {\n if (finger !== 'palmBase' && Array.isArray(pos) && pos[0]) fingers.push({ name: finger.toLowerCase(), position: pos[0] }); // get tip of each finger\n }\n }\n if (fingers && fingers.length > 0) {\n const closest = fingers.reduce((best, a) => (best.position[2] < a.position[2] ? best : a));\n gestures.push({ hand: i, gesture: `${closest.name} forward` as HandGesture });\n const highest = fingers.reduce((best, a) => (best.position[1] < a.position[1] ? best : a));\n gestures.push({ hand: i, gesture: `${highest.name} up` as HandGesture });\n }\n if (res[i]['keypoints']) {\n const poses = fingerPose.match(res[i]['keypoints']);\n for (const pose of poses) gestures.push({ hand: i, gesture: pose.name as HandGesture });\n }\n }\n return gestures;\n};\n", "/**\n * Module that implements helper draw functions, exposed as human.draw\n */\n\nimport { TRI468 as triangulation } from './blazeface/coords';\nimport { mergeDeep, now } from './helpers';\nimport type { Result, FaceResult, BodyResult, HandResult, ObjectResult, GestureResult, PersonResult } from './result';\n\n/**\n * Draw Options\n * Accessed via `human.draw.options` or provided per each draw method as the drawOptions optional parameter\n * -color: draw color\n * -labelColor: color for labels\n * -shadowColor: optional shadow color for labels\n * -font: font for labels\n * -lineHeight: line height for labels, used for multi-line labels,\n * -lineWidth: width of any lines,\n * -pointSize: size of any point,\n * -roundRect: for boxes, round corners by this many pixels,\n * -drawPoints: should points be drawn,\n * -drawLabels: should labels be drawn,\n * -drawBoxes: should boxes be drawn,\n * -drawPolygons: should polygons be drawn,\n * -fillPolygons: should drawn polygons be filled,\n * -useDepth: use z-axis coordinate as color shade,\n * -useCurves: draw polygons as cures or as lines,\n * -bufferedOutput: experimental: allows to call draw methods multiple times for each detection and interpolate results between results thus achieving smoother animations\n */\nexport interface DrawOptions {\n color: string,\n labelColor: string,\n shadowColor: string,\n font: string,\n lineHeight: number,\n lineWidth: number,\n pointSize: number,\n roundRect: number,\n drawPoints: boolean,\n drawLabels: boolean,\n drawBoxes: boolean,\n drawPolygons: boolean,\n drawGaze: boolean,\n fillPolygons: boolean,\n useDepth: boolean,\n useCurves: boolean,\n bufferedOutput: boolean,\n}\n\nexport const options: DrawOptions = {\n color: 'rgba(173, 216, 230, 0.6)', // 'lightblue' with light alpha channel\n labelColor: 'rgba(173, 216, 230, 1)', // 'lightblue' with dark alpha channel\n shadowColor: 'black',\n font: 'small-caps 14px \"Segoe UI\"',\n lineHeight: 18,\n lineWidth: 4,\n pointSize: 2,\n roundRect: 8,\n drawPoints: false,\n drawLabels: true,\n drawBoxes: true,\n drawPolygons: true,\n drawGaze: true,\n fillPolygons: false,\n useDepth: true,\n useCurves: false,\n bufferedOutput: true,\n};\n\nconst getCanvasContext = (input) => {\n if (input && input.getContext) return input.getContext('2d');\n throw new Error('invalid canvas');\n};\n\nconst rad2deg = (theta) => Math.round((theta * 180) / Math.PI);\n\nfunction point(ctx, x, y, z = 0, localOptions) {\n ctx.fillStyle = localOptions.useDepth && z ? `rgba(${127.5 + (2 * z)}, ${127.5 - (2 * z)}, 255, 0.3)` : localOptions.color;\n ctx.beginPath();\n ctx.arc(x, y, localOptions.pointSize, 0, 2 * Math.PI);\n ctx.fill();\n}\n\nfunction rect(ctx, x, y, width, height, localOptions) {\n ctx.beginPath();\n if (localOptions.useCurves) {\n const cx = (x + x + width) / 2;\n const cy = (y + y + height) / 2;\n ctx.ellipse(cx, cy, width / 2, height / 2, 0, 0, 2 * Math.PI);\n } else {\n ctx.lineWidth = localOptions.lineWidth;\n ctx.moveTo(x + localOptions.roundRect, y);\n ctx.lineTo(x + width - localOptions.roundRect, y);\n ctx.quadraticCurveTo(x + width, y, x + width, y + localOptions.roundRect);\n ctx.lineTo(x + width, y + height - localOptions.roundRect);\n ctx.quadraticCurveTo(x + width, y + height, x + width - localOptions.roundRect, y + height);\n ctx.lineTo(x + localOptions.roundRect, y + height);\n ctx.quadraticCurveTo(x, y + height, x, y + height - localOptions.roundRect);\n ctx.lineTo(x, y + localOptions.roundRect);\n ctx.quadraticCurveTo(x, y, x + localOptions.roundRect, y);\n ctx.closePath();\n }\n ctx.stroke();\n}\n\nfunction lines(ctx, points: [number, number, number?][] = [], localOptions) {\n if (points === undefined || points.length === 0) return;\n ctx.beginPath();\n ctx.moveTo(points[0][0], points[0][1]);\n for (const pt of points) {\n const z = pt[2] || 0;\n ctx.strokeStyle = localOptions.useDepth && z ? `rgba(${127.5 + (2 * z)}, ${127.5 - (2 * z)}, 255, 0.3)` : localOptions.color;\n ctx.fillStyle = localOptions.useDepth && z ? `rgba(${127.5 + (2 * z)}, ${127.5 - (2 * z)}, 255, 0.3)` : localOptions.color;\n ctx.lineTo(pt[0], Math.round(pt[1]));\n }\n ctx.stroke();\n if (localOptions.fillPolygons) {\n ctx.closePath();\n ctx.fill();\n }\n}\n\nfunction curves(ctx, points: [number, number, number?][] = [], localOptions) {\n if (points === undefined || points.length === 0) return;\n if (!localOptions.useCurves || points.length <= 2) {\n lines(ctx, points, localOptions);\n return;\n }\n ctx.moveTo(points[0][0], points[0][1]);\n for (let i = 0; i < points.length - 2; i++) {\n const xc = (points[i][0] + points[i + 1][0]) / 2;\n const yc = (points[i][1] + points[i + 1][1]) / 2;\n ctx.quadraticCurveTo(points[i][0], points[i][1], xc, yc);\n }\n ctx.quadraticCurveTo(points[points.length - 2][0], points[points.length - 2][1], points[points.length - 1][0], points[points.length - 1][1]);\n ctx.stroke();\n if (localOptions.fillPolygons) {\n ctx.closePath();\n ctx.fill();\n }\n}\n\nexport async function gesture(inCanvas: HTMLCanvasElement | OffscreenCanvas, result: Array, drawOptions?: Partial) {\n const localOptions = mergeDeep(options, drawOptions);\n if (!result || !inCanvas) return;\n const ctx = getCanvasContext(inCanvas);\n ctx.font = localOptions.font;\n ctx.fillStyle = localOptions.color;\n let i = 1;\n for (let j = 0; j < result.length; j++) {\n let where: unknown[] = []; // what&where is a record\n let what: unknown[] = []; // what&where is a record\n [where, what] = Object.entries(result[j]);\n if ((what.length > 1) && ((what[1] as string).length > 0)) {\n const who = where[1] as number > 0 ? `#${where[1]}` : '';\n const label = `${where[0]} ${who}: ${what[1]}`;\n if (localOptions.shadowColor && localOptions.shadowColor !== '') {\n ctx.fillStyle = localOptions.shadowColor;\n ctx.fillText(label, 8, 2 + (i * localOptions.lineHeight));\n }\n ctx.fillStyle = localOptions.labelColor;\n ctx.fillText(label, 6, 0 + (i * localOptions.lineHeight));\n i += 1;\n }\n }\n}\n\nexport async function face(inCanvas: HTMLCanvasElement | OffscreenCanvas, result: Array, drawOptions?: Partial) {\n const localOptions = mergeDeep(options, drawOptions);\n if (!result || !inCanvas) return;\n const ctx = getCanvasContext(inCanvas);\n for (const f of result) {\n ctx.font = localOptions.font;\n ctx.strokeStyle = localOptions.color;\n ctx.fillStyle = localOptions.color;\n if (localOptions.drawBoxes) rect(ctx, f.box[0], f.box[1], f.box[2], f.box[3], localOptions);\n // silly hack since fillText does not suport new line\n const labels:string[] = [];\n labels.push(`face: ${Math.trunc(100 * f.score)}%`);\n if (f.genderScore) labels.push(`${f.gender || ''} ${Math.trunc(100 * f.genderScore)}%`);\n if (f.age) labels.push(`age: ${f.age || ''}`);\n if (f.iris) labels.push(`distance: ${f.iris}`);\n if (f.emotion && f.emotion.length > 0) {\n const emotion = f.emotion.map((a) => `${Math.trunc(100 * a.score)}% ${a.emotion}`);\n if (emotion.length > 3) emotion.length = 3;\n labels.push(emotion.join(' '));\n }\n if (f.rotation && f.rotation.angle && f.rotation.gaze) {\n if (f.rotation.angle.roll) labels.push(`roll: ${rad2deg(f.rotation.angle.roll)}\u00B0 yaw:${rad2deg(f.rotation.angle.yaw)}\u00B0 pitch:${rad2deg(f.rotation.angle.pitch)}\u00B0`);\n if (f.rotation.gaze.bearing) labels.push(`gaze: ${rad2deg(f.rotation.gaze.bearing)}\u00B0`);\n }\n if (labels.length === 0) labels.push('face');\n ctx.fillStyle = localOptions.color;\n for (let i = labels.length - 1; i >= 0; i--) {\n const x = Math.max(f.box[0], 0);\n const y = i * localOptions.lineHeight + f.box[1];\n if (localOptions.shadowColor && localOptions.shadowColor !== '') {\n ctx.fillStyle = localOptions.shadowColor;\n ctx.fillText(labels[i], x + 5, y + 16);\n }\n ctx.fillStyle = localOptions.labelColor;\n ctx.fillText(labels[i], x + 4, y + 15);\n }\n ctx.lineWidth = 1;\n if (f.mesh && f.mesh.length > 0) {\n if (localOptions.drawPoints) {\n for (const pt of f.mesh) point(ctx, pt[0], pt[1], pt[2], localOptions);\n // for (const pt of f.meshRaw) point(ctx, pt[0] * inCanvas.offsetWidth, pt[1] * inCanvas.offsetHeight, pt[2]);\n }\n if (localOptions.drawPolygons) {\n ctx.lineWidth = 1;\n for (let i = 0; i < triangulation.length / 3; i++) {\n const points = [\n triangulation[i * 3 + 0],\n triangulation[i * 3 + 1],\n triangulation[i * 3 + 2],\n ].map((index) => f.mesh[index]);\n lines(ctx, points, localOptions);\n }\n // iris: array[center, left, top, right, bottom]\n if (f.annotations && f.annotations['leftEyeIris']) {\n ctx.strokeStyle = localOptions.useDepth ? 'rgba(255, 200, 255, 0.3)' : localOptions.color;\n ctx.beginPath();\n const sizeX = Math.abs(f.annotations['leftEyeIris'][3][0] - f.annotations['leftEyeIris'][1][0]) / 2;\n const sizeY = Math.abs(f.annotations['leftEyeIris'][4][1] - f.annotations['leftEyeIris'][2][1]) / 2;\n ctx.ellipse(f.annotations['leftEyeIris'][0][0], f.annotations['leftEyeIris'][0][1], sizeX, sizeY, 0, 0, 2 * Math.PI);\n ctx.stroke();\n if (localOptions.fillPolygons) {\n ctx.fillStyle = localOptions.useDepth ? 'rgba(255, 255, 200, 0.3)' : localOptions.color;\n ctx.fill();\n }\n }\n if (f.annotations && f.annotations['rightEyeIris']) {\n ctx.strokeStyle = localOptions.useDepth ? 'rgba(255, 200, 255, 0.3)' : localOptions.color;\n ctx.beginPath();\n const sizeX = Math.abs(f.annotations['rightEyeIris'][3][0] - f.annotations['rightEyeIris'][1][0]) / 2;\n const sizeY = Math.abs(f.annotations['rightEyeIris'][4][1] - f.annotations['rightEyeIris'][2][1]) / 2;\n ctx.ellipse(f.annotations['rightEyeIris'][0][0], f.annotations['rightEyeIris'][0][1], sizeX, sizeY, 0, 0, 2 * Math.PI);\n ctx.stroke();\n if (localOptions.fillPolygons) {\n ctx.fillStyle = localOptions.useDepth ? 'rgba(255, 255, 200, 0.3)' : localOptions.color;\n ctx.fill();\n }\n }\n if (localOptions.drawGaze && f.rotation?.gaze?.strength && f.rotation?.gaze?.bearing && f.annotations['leftEyeIris'] && f.annotations['rightEyeIris'] && f.annotations['leftEyeIris'][0] && f.annotations['rightEyeIris'][0]) {\n ctx.strokeStyle = 'pink';\n ctx.beginPath();\n\n const leftGaze = [\n f.annotations['leftEyeIris'][0][0] + (Math.sin(f.rotation.gaze.bearing) * f.rotation.gaze.strength * f.box[3]),\n f.annotations['leftEyeIris'][0][1] + (Math.cos(f.rotation.gaze.bearing) * f.rotation.gaze.strength * f.box[2]),\n ];\n ctx.moveTo(f.annotations['leftEyeIris'][0][0], f.annotations['leftEyeIris'][0][1]);\n ctx.lineTo(leftGaze[0], leftGaze[1]);\n\n const rightGaze = [\n f.annotations['rightEyeIris'][0][0] + (Math.sin(f.rotation.gaze.bearing) * f.rotation.gaze.strength * f.box[3]),\n f.annotations['rightEyeIris'][0][1] + (Math.cos(f.rotation.gaze.bearing) * f.rotation.gaze.strength * f.box[2]),\n ];\n ctx.moveTo(f.annotations['rightEyeIris'][0][0], f.annotations['rightEyeIris'][0][1]);\n ctx.lineTo(rightGaze[0], rightGaze[1]);\n\n ctx.stroke();\n }\n }\n }\n }\n}\n\nexport async function body(inCanvas: HTMLCanvasElement | OffscreenCanvas, result: Array, drawOptions?: Partial) {\n const localOptions = mergeDeep(options, drawOptions);\n if (!result || !inCanvas) return;\n const ctx = getCanvasContext(inCanvas);\n ctx.lineJoin = 'round';\n for (let i = 0; i < result.length; i++) {\n ctx.strokeStyle = localOptions.color;\n ctx.fillStyle = localOptions.color;\n ctx.lineWidth = localOptions.lineWidth;\n ctx.font = localOptions.font;\n if (localOptions.drawBoxes && result[i].box && result[i].box?.length === 4) {\n rect(ctx, result[i].box[0], result[i].box[1], result[i].box[2], result[i].box[3], localOptions);\n if (localOptions.drawLabels) {\n if (localOptions.shadowColor && localOptions.shadowColor !== '') {\n ctx.fillStyle = localOptions.shadowColor;\n ctx.fillText(`body ${100 * result[i].score}%`, result[i].box[0] + 3, 1 + result[i].box[1] + localOptions.lineHeight, result[i].box[2]);\n }\n ctx.fillStyle = localOptions.labelColor;\n ctx.fillText(`body ${100 * result[i].score}%`, result[i].box[0] + 2, 0 + result[i].box[1] + localOptions.lineHeight, result[i].box[2]);\n }\n }\n if (localOptions.drawPoints) {\n for (let pt = 0; pt < result[i].keypoints.length; pt++) {\n ctx.fillStyle = localOptions.useDepth && result[i].keypoints[pt].position[2] ? `rgba(${127.5 + (2 * (result[i].keypoints[pt].position[2] || 0))}, ${127.5 - (2 * (result[i].keypoints[pt].position[2] || 0))}, 255, 0.5)` : localOptions.color;\n point(ctx, result[i].keypoints[pt].position[0], result[i].keypoints[pt].position[1], 0, localOptions);\n }\n }\n if (localOptions.drawLabels) {\n ctx.font = localOptions.font;\n if (result[i].keypoints) {\n for (const pt of result[i].keypoints) {\n ctx.fillStyle = localOptions.useDepth && pt.position[2] ? `rgba(${127.5 + (2 * pt.position[2])}, ${127.5 - (2 * pt.position[2])}, 255, 0.5)` : localOptions.color;\n ctx.fillText(`${pt.part} ${Math.trunc(100 * pt.score)}%`, pt.position[0] + 4, pt.position[1] + 4);\n }\n }\n }\n if (localOptions.drawPolygons && result[i].keypoints) {\n let part;\n const points: [number, number, number?][] = [];\n // shoulder line\n points.length = 0;\n part = result[i].keypoints.find((a) => a.part === 'leftShoulder');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'rightShoulder');\n if (part) points.push([part.position[0], part.position[1]]);\n curves(ctx, points, localOptions);\n // torso main\n points.length = 0;\n part = result[i].keypoints.find((a) => a.part === 'rightShoulder');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'rightHip');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'leftHip');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'leftShoulder');\n if (part) points.push([part.position[0], part.position[1]]);\n if (points.length === 4) lines(ctx, points, localOptions); // only draw if we have complete torso\n // leg left\n points.length = 0;\n part = result[i].keypoints.find((a) => a.part === 'leftHip');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'leftKnee');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'leftAnkle');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'leftHeel');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'leftFoot');\n if (part) points.push([part.position[0], part.position[1]]);\n curves(ctx, points, localOptions);\n // leg right\n points.length = 0;\n part = result[i].keypoints.find((a) => a.part === 'rightHip');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'rightKnee');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'rightAnkle');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'rightHeel');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'rightFoot');\n if (part) points.push([part.position[0], part.position[1]]);\n curves(ctx, points, localOptions);\n // arm left\n points.length = 0;\n part = result[i].keypoints.find((a) => a.part === 'leftShoulder');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'leftElbow');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'leftWrist');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'leftPalm');\n if (part) points.push([part.position[0], part.position[1]]);\n curves(ctx, points, localOptions);\n // arm right\n points.length = 0;\n part = result[i].keypoints.find((a) => a.part === 'rightShoulder');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'rightElbow');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'rightWrist');\n if (part) points.push([part.position[0], part.position[1]]);\n part = result[i].keypoints.find((a) => a.part === 'rightPalm');\n if (part) points.push([part.position[0], part.position[1]]);\n curves(ctx, points, localOptions);\n // draw all\n }\n }\n}\n\nexport async function hand(inCanvas: HTMLCanvasElement | OffscreenCanvas, result: Array, drawOptions?: Partial) {\n const localOptions = mergeDeep(options, drawOptions);\n if (!result || !inCanvas) return;\n const ctx = getCanvasContext(inCanvas);\n ctx.lineJoin = 'round';\n ctx.font = localOptions.font;\n for (const h of result) {\n if (localOptions.drawBoxes) {\n ctx.strokeStyle = localOptions.color;\n ctx.fillStyle = localOptions.color;\n rect(ctx, h.box[0], h.box[1], h.box[2], h.box[3], localOptions);\n if (localOptions.drawLabels) {\n if (localOptions.shadowColor && localOptions.shadowColor !== '') {\n ctx.fillStyle = localOptions.shadowColor;\n ctx.fillText(`${h.label}:${Math.trunc(100 * h.score)}%`, h.box[0] + 3, 1 + h.box[1] + localOptions.lineHeight, h.box[2]);\n }\n ctx.fillStyle = localOptions.labelColor;\n ctx.fillText(`${h.label}:${Math.trunc(100 * h.score)}%`, h.box[0] + 2, 0 + h.box[1] + localOptions.lineHeight, h.box[2]);\n }\n ctx.stroke();\n }\n if (localOptions.drawPoints) {\n if (h.keypoints && h.keypoints.length > 0) {\n for (const pt of h.keypoints) {\n ctx.fillStyle = localOptions.useDepth ? `rgba(${127.5 + (2 * pt[2])}, ${127.5 - (2 * pt[2])}, 255, 0.5)` : localOptions.color;\n point(ctx, pt[0], pt[1], 0, localOptions);\n }\n }\n }\n if (localOptions.drawLabels && h.annotations) {\n const addHandLabel = (part, title) => {\n if (!part || part.length === 0 || !part[0]) return;\n ctx.fillStyle = localOptions.useDepth ? `rgba(${127.5 + (2 * part[part.length - 1][2])}, ${127.5 - (2 * part[part.length - 1][2])}, 255, 0.5)` : localOptions.color;\n ctx.fillText(title, part[part.length - 1][0] + 4, part[part.length - 1][1] + 4);\n };\n ctx.font = localOptions.font;\n addHandLabel(h.annotations['index'], 'index');\n addHandLabel(h.annotations['middle'], 'middle');\n addHandLabel(h.annotations['ring'], 'ring');\n addHandLabel(h.annotations['pinky'], 'pinky');\n addHandLabel(h.annotations['thumb'], 'thumb');\n addHandLabel(h.annotations['palm'], 'palm');\n }\n if (localOptions.drawPolygons && h.annotations) {\n const addHandLine = (part) => {\n if (!part || part.length === 0 || !part[0]) return;\n for (let i = 0; i < part.length; i++) {\n ctx.beginPath();\n ctx.strokeStyle = localOptions.useDepth ? `rgba(${127.5 + (2 * part[i][2])}, ${127.5 - (2 * part[i][2])}, 255, 0.5)` : localOptions.color;\n ctx.moveTo(part[i > 0 ? i - 1 : 0][0], part[i > 0 ? i - 1 : 0][1]);\n ctx.lineTo(part[i][0], part[i][1]);\n ctx.stroke();\n }\n };\n ctx.lineWidth = localOptions.lineWidth;\n addHandLine(h.annotations['index']);\n addHandLine(h.annotations['middle']);\n addHandLine(h.annotations['ring']);\n addHandLine(h.annotations['pinky']);\n addHandLine(h.annotations['thumb']);\n // addPart(h.annotations.palm);\n }\n }\n}\n\nexport async function object(inCanvas: HTMLCanvasElement | OffscreenCanvas, result: Array, drawOptions?: Partial) {\n const localOptions = mergeDeep(options, drawOptions);\n if (!result || !inCanvas) return;\n const ctx = getCanvasContext(inCanvas);\n ctx.lineJoin = 'round';\n ctx.font = localOptions.font;\n for (const h of result) {\n if (localOptions.drawBoxes) {\n ctx.strokeStyle = localOptions.color;\n ctx.fillStyle = localOptions.color;\n rect(ctx, h.box[0], h.box[1], h.box[2], h.box[3], localOptions);\n if (localOptions.drawLabels) {\n const label = `${h.label} ${Math.round(100 * h.score)}%`;\n if (localOptions.shadowColor && localOptions.shadowColor !== '') {\n ctx.fillStyle = localOptions.shadowColor;\n ctx.fillText(label, h.box[0] + 3, 1 + h.box[1] + localOptions.lineHeight, h.box[2]);\n }\n ctx.fillStyle = localOptions.labelColor;\n ctx.fillText(label, h.box[0] + 2, 0 + h.box[1] + localOptions.lineHeight, h.box[2]);\n }\n ctx.stroke();\n }\n }\n}\n\nexport async function person(inCanvas: HTMLCanvasElement | OffscreenCanvas, result: Array, drawOptions?: Partial) {\n const localOptions = mergeDeep(options, drawOptions);\n if (!result || !inCanvas) return;\n const ctx = getCanvasContext(inCanvas);\n ctx.lineJoin = 'round';\n ctx.font = localOptions.font;\n\n for (let i = 0; i < result.length; i++) {\n if (localOptions.drawBoxes) {\n ctx.strokeStyle = localOptions.color;\n ctx.fillStyle = localOptions.color;\n rect(ctx, result[i].box[0], result[i].box[1], result[i].box[2], result[i].box[3], localOptions);\n if (localOptions.drawLabels) {\n const label = `person #${i}`;\n if (localOptions.shadowColor && localOptions.shadowColor !== '') {\n ctx.fillStyle = localOptions.shadowColor;\n ctx.fillText(label, result[i].box[0] + 3, 1 + result[i].box[1] + localOptions.lineHeight, result[i].box[2]);\n }\n ctx.fillStyle = localOptions.labelColor;\n ctx.fillText(label, result[i].box[0] + 2, 0 + result[i].box[1] + localOptions.lineHeight, result[i].box[2]);\n }\n ctx.stroke();\n }\n }\n}\n\nexport async function canvas(input: HTMLCanvasElement | OffscreenCanvas | HTMLImageElement | HTMLMediaElement | HTMLVideoElement, output: HTMLCanvasElement) {\n if (!input || !output) return;\n const ctx = getCanvasContext(output);\n ctx.drawImage(input, 0, 0);\n}\n\nexport async function all(inCanvas: HTMLCanvasElement | OffscreenCanvas, result: Result, drawOptions?: Partial) {\n if (!result || !result.performance || !result || !inCanvas) return null;\n const timestamp = now();\n const localOptions = mergeDeep(options, drawOptions);\n const promise = Promise.all([\n face(inCanvas, result.face, localOptions),\n body(inCanvas, result.body, localOptions),\n hand(inCanvas, result.hand, localOptions),\n object(inCanvas, result.object, localOptions),\n gesture(inCanvas, result.gesture, localOptions), // gestures do not have buffering\n // person(inCanvas, result.persons, localOptions); // already included above\n ]);\n result.performance.draw = Math.trunc(now() - timestamp);\n return promise;\n}\n", "/**\n * Module that analyzes existing results and recombines them into a unified person object\n */\n\nimport type { FaceResult, BodyResult, HandResult, GestureResult, PersonResult } from './result';\n\nexport function join(faces: Array, bodies: Array, hands: Array, gestures: Array, shape: Array | undefined): Array {\n let id = 0;\n const persons: Array = [];\n for (const face of faces) { // person is defined primarily by face and then we append other objects as found\n const person: PersonResult = { id: id++, face, body: null, hands: { left: null, right: null }, gestures: [], box: [0, 0, 0, 0] };\n for (const body of bodies) {\n if (face.box[0] > body.box[0] // x within body\n && face.box[0] < body.box[0] + body.box[2]\n && face.box[1] + face.box[3] > body.box[1] // y within body\n && face.box[1] + face.box[3] < body.box[1] + body.box[3]) {\n person.body = body;\n }\n }\n if (person.body) { // only try to join hands if body is found\n for (const hand of hands) {\n if (hand.box[0] + hand.box[2] > person.body.box[0] // x within body for left hand\n && hand.box[0] + hand.box[2] < person.body.box[0] + person.body.box[2]\n && hand.box[1] + hand.box[3] > person.body.box[1] // x within body for left hand\n && hand.box[1] + hand.box[3] < person.body.box[1] + person.body.box[3]) {\n if (person.hands) person.hands.left = hand;\n }\n if (hand.box[0] < person.body.box[0] + person.body.box[2] // x within body for right hand\n && hand.box[0] > person.body.box[0]\n && hand.box[1] + hand.box[3] > person.body.box[1] // x within body for right hand\n && hand.box[1] + hand.box[3] < person.body.box[1] + person.body.box[3]) {\n if (person.hands) person.hands.right = hand;\n }\n }\n }\n for (const gesture of gestures) { // append all gestures according to ids\n if (gesture['face'] !== undefined && gesture['face'] === face.id) person.gestures?.push(gesture);\n else if (gesture['iris'] !== undefined && gesture['iris'] === face.id) person.gestures?.push(gesture);\n else if (gesture['body'] !== undefined && gesture['body'] === person.body?.id) person.gestures?.push(gesture);\n else if (gesture['hand'] !== undefined && gesture['hand'] === person.hands?.left?.id) person.gestures?.push(gesture);\n else if (gesture['hand'] !== undefined && gesture['hand'] === person.hands?.right?.id) person.gestures?.push(gesture);\n }\n\n // create new overarching box from all boxes beloning to person\n const x: number[] = [];\n const y: number[] = [];\n const extractXY = (box: [number, number, number, number] | undefined) => { // extract all [x, y] coordinates from boxes [x, y, width, height]\n if (box && box.length === 4) {\n x.push(box[0], box[0] + box[2]);\n y.push(box[1], box[1] + box[3]);\n }\n };\n extractXY(person.face?.box);\n extractXY(person.body?.box);\n extractXY(person.hands?.left?.box);\n extractXY(person.hands?.right?.box);\n const minX = Math.min(...x);\n const minY = Math.min(...y);\n person.box = [minX, minY, Math.max(...x) - minX, Math.max(...y) - minY]; // create new overarching box\n\n // shape is known so we calculate boxRaw as well\n if (shape && shape[1] && shape[2]) person.boxRaw = [person.box[0] / shape[2], person.box[1] / shape[1], person.box[2] / shape[2], person.box[3] / shape[1]];\n\n persons.push(person);\n }\n return persons;\n}\n", "/**\n * Module that interpolates results for smoother animations\n */\n\nimport type { Result, FaceResult, BodyResult, HandResult, ObjectResult, GestureResult, PersonResult } from './result';\n\nconst bufferedResult: Result = { face: [], body: [], hand: [], gesture: [], object: [], persons: [], performance: {}, timestamp: 0 };\n\nexport function calc(newResult: Result): Result {\n if (!newResult) return { face: [], body: [], hand: [], gesture: [], object: [], persons: [], performance: {}, timestamp: 0 };\n // each record is only updated using deep clone when number of detected record changes, otherwise it will converge by itself\n // otherwise bufferedResult is a shallow clone of result plus updated local calculated values\n // thus mixing by-reference and by-value assignments to minimize memory operations\n\n const elapsed = Date.now() - newResult.timestamp;\n // curve fitted: buffer = 8 - ln(delay)\n // interpolation formula: current = ((buffer - 1) * previous + live) / buffer\n // - at 50ms delay buffer = ~4.1 => 28% towards live data\n // - at 250ms delay buffer = ~2.5 => 40% towards live data\n // - at 500ms delay buffer = ~1.8 => 55% towards live data\n // - at 750ms delay buffer = ~1.4 => 71% towards live data\n // - at 1sec delay buffer = 1 which means live data is used\n const bufferedFactor = elapsed < 1000 ? 8 - Math.log(elapsed + 1) : 1;\n\n bufferedResult.canvas = newResult.canvas;\n\n // interpolate body results\n if (!bufferedResult.body || (newResult.body.length !== bufferedResult.body.length)) {\n bufferedResult.body = JSON.parse(JSON.stringify(newResult.body as BodyResult[])); // deep clone once\n } else {\n for (let i = 0; i < newResult.body.length; i++) {\n const box = newResult.body[i].box // update box\n .map((b, j) => ((bufferedFactor - 1) * bufferedResult.body[i].box[j] + b) / bufferedFactor) as [number, number, number, number];\n const boxRaw = newResult.body[i].boxRaw // update boxRaw\n .map((b, j) => ((bufferedFactor - 1) * bufferedResult.body[i].boxRaw[j] + b) / bufferedFactor) as [number, number, number, number];\n const keypoints = (newResult.body[i].keypoints // update keypoints\n .map((keypoint, j) => ({\n score: keypoint.score,\n part: keypoint.part,\n position: [\n bufferedResult.body[i].keypoints[j] ? ((bufferedFactor - 1) * bufferedResult.body[i].keypoints[j].position[0] + keypoint.position[0]) / bufferedFactor : keypoint.position[0],\n bufferedResult.body[i].keypoints[j] ? ((bufferedFactor - 1) * bufferedResult.body[i].keypoints[j].position[1] + keypoint.position[1]) / bufferedFactor : keypoint.position[1],\n ],\n positionRaw: [\n bufferedResult.body[i].keypoints[j] ? ((bufferedFactor - 1) * bufferedResult.body[i].keypoints[j].positionRaw[0] + keypoint.positionRaw[0]) / bufferedFactor : keypoint.position[0],\n bufferedResult.body[i].keypoints[j] ? ((bufferedFactor - 1) * bufferedResult.body[i].keypoints[j].positionRaw[1] + keypoint.positionRaw[1]) / bufferedFactor : keypoint.position[1],\n ],\n }))) as Array<{ score: number, part: string, position: [number, number, number?], positionRaw: [number, number, number?] }>;\n bufferedResult.body[i] = { ...newResult.body[i], box, boxRaw, keypoints }; // shallow clone plus updated values\n }\n }\n\n // interpolate hand results\n if (!bufferedResult.hand || (newResult.hand.length !== bufferedResult.hand.length)) {\n bufferedResult.hand = JSON.parse(JSON.stringify(newResult.hand as HandResult[])); // deep clone once\n } else {\n for (let i = 0; i < newResult.hand.length; i++) {\n const box = (newResult.hand[i].box// update box\n .map((b, j) => ((bufferedFactor - 1) * bufferedResult.hand[i].box[j] + b) / bufferedFactor)) as [number, number, number, number];\n const boxRaw = (newResult.hand[i].boxRaw // update boxRaw\n .map((b, j) => ((bufferedFactor - 1) * bufferedResult.hand[i].boxRaw[j] + b) / bufferedFactor)) as [number, number, number, number];\n if (bufferedResult.hand[i].keypoints.length !== newResult.hand[i].keypoints.length) bufferedResult.hand[i].keypoints = newResult.hand[i].keypoints; // reset keypoints as previous frame did not have them\n const keypoints = newResult.hand[i].keypoints && newResult.hand[i].keypoints.length > 0 ? newResult.hand[i].keypoints // update landmarks\n .map((landmark, j) => landmark\n .map((coord, k) => (((bufferedFactor - 1) * bufferedResult.hand[i].keypoints[j][k] + coord) / bufferedFactor)) as [number, number, number])\n : [];\n const annotations = {};\n if (Object.keys(bufferedResult.hand[i].annotations).length !== Object.keys(newResult.hand[i].annotations).length) bufferedResult.hand[i].annotations = newResult.hand[i].annotations; // reset annotations as previous frame did not have them\n if (newResult.hand[i].annotations) {\n for (const key of Object.keys(newResult.hand[i].annotations)) { // update annotations\n annotations[key] = newResult.hand[i].annotations[key] && newResult.hand[i].annotations[key][0]\n ? newResult.hand[i].annotations[key].map((val, j) => val.map((coord, k) => ((bufferedFactor - 1) * bufferedResult.hand[i].annotations[key][j][k] + coord) / bufferedFactor))\n : null;\n }\n }\n bufferedResult.hand[i] = { ...newResult.hand[i], box, boxRaw, keypoints, annotations: annotations as HandResult['annotations'] }; // shallow clone plus updated values\n }\n }\n\n // interpolate face results\n if (!bufferedResult.face || (newResult.face.length !== bufferedResult.face.length)) {\n bufferedResult.face = JSON.parse(JSON.stringify(newResult.face as FaceResult[])); // deep clone once\n } else {\n for (let i = 0; i < newResult.face.length; i++) {\n const box = (newResult.face[i].box // update box\n .map((b, j) => ((bufferedFactor - 1) * bufferedResult.face[i].box[j] + b) / bufferedFactor)) as [number, number, number, number];\n const boxRaw = (newResult.face[i].boxRaw // update boxRaw\n .map((b, j) => ((bufferedFactor - 1) * bufferedResult.face[i].boxRaw[j] + b) / bufferedFactor)) as [number, number, number, number];\n const rotation: {\n matrix: [number, number, number, number, number, number, number, number, number],\n angle: { roll: number, yaw: number, pitch: number },\n gaze: { bearing: number, strength: number }\n } = { matrix: [0, 0, 0, 0, 0, 0, 0, 0, 0], angle: { roll: 0, yaw: 0, pitch: 0 }, gaze: { bearing: 0, strength: 0 } };\n rotation.matrix = newResult.face[i].rotation?.matrix as [number, number, number, number, number, number, number, number, number];\n rotation.angle = {\n roll: ((bufferedFactor - 1) * (bufferedResult.face[i].rotation?.angle?.roll || 0) + (newResult.face[i].rotation?.angle?.roll || 0)) / bufferedFactor,\n yaw: ((bufferedFactor - 1) * (bufferedResult.face[i].rotation?.angle?.yaw || 0) + (newResult.face[i].rotation?.angle?.yaw || 0)) / bufferedFactor,\n pitch: ((bufferedFactor - 1) * (bufferedResult.face[i].rotation?.angle?.pitch || 0) + (newResult.face[i].rotation?.angle?.pitch || 0)) / bufferedFactor,\n };\n rotation.gaze = {\n // not fully correct due projection on circle, also causes wrap-around draw on jump from negative to positive\n bearing: ((bufferedFactor - 1) * (bufferedResult.face[i].rotation?.gaze?.bearing || 0) + (newResult.face[i].rotation?.gaze?.bearing || 0)) / bufferedFactor,\n strength: ((bufferedFactor - 1) * (bufferedResult.face[i].rotation?.gaze?.strength || 0) + (newResult.face[i].rotation?.gaze?.strength || 0)) / bufferedFactor,\n };\n bufferedResult.face[i] = { ...newResult.face[i], rotation, box, boxRaw }; // shallow clone plus updated values\n }\n }\n\n // interpolate object detection results\n if (!bufferedResult.object || (newResult.object.length !== bufferedResult.object.length)) {\n bufferedResult.object = JSON.parse(JSON.stringify(newResult.object as ObjectResult[])); // deep clone once\n } else {\n for (let i = 0; i < newResult.object.length; i++) {\n const box = (newResult.object[i].box // update box\n .map((b, j) => ((bufferedFactor - 1) * bufferedResult.object[i].box[j] + b) / bufferedFactor)) as [number, number, number, number];\n const boxRaw = (newResult.object[i].boxRaw // update boxRaw\n .map((b, j) => ((bufferedFactor - 1) * bufferedResult.object[i].boxRaw[j] + b) / bufferedFactor)) as [number, number, number, number];\n bufferedResult.object[i] = { ...newResult.object[i], box, boxRaw }; // shallow clone plus updated values\n }\n }\n\n // interpolate person results\n if (newResult.persons) {\n const newPersons = newResult.persons; // trigger getter function\n if (!bufferedResult.persons || (newPersons.length !== bufferedResult.persons.length)) {\n bufferedResult.persons = JSON.parse(JSON.stringify(newPersons as PersonResult[]));\n } else {\n for (let i = 0; i < newPersons.length; i++) { // update person box, we don't update the rest as it's updated as reference anyhow\n bufferedResult.persons[i].box = (newPersons[i].box\n .map((box, j) => ((bufferedFactor - 1) * bufferedResult.persons[i].box[j] + box) / bufferedFactor)) as [number, number, number, number];\n }\n }\n }\n\n // just copy latest gestures without interpolation\n if (newResult.gesture) bufferedResult.gesture = newResult.gesture as GestureResult[];\n if (newResult.performance) bufferedResult.performance = newResult.performance;\n\n return bufferedResult;\n}\n", "/**\n * Custom TFJS backend for Human based on WebGL\n * Not used by default\n */\n\nimport { log } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as image from '../image/image';\nimport * as models from '../models';\n// import { env } from '../env';\n\nexport const config = {\n name: 'humangl',\n priority: 999,\n canvas: null,\n gl: null,\n extensions: [],\n webGLattr: { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.2\n alpha: false,\n antialias: false,\n premultipliedAlpha: false,\n preserveDrawingBuffer: false,\n depth: false,\n stencil: false,\n failIfMajorPerformanceCaveat: false,\n desynchronized: true,\n },\n};\n\nfunction extensions(): void {\n /*\n https://www.khronos.org/registry/webgl/extensions/\n https://webglreport.com/?v=2\n */\n const gl = config.gl;\n if (!gl) return;\n config.extensions = gl.getSupportedExtensions() as string[];\n // gl.getExtension('KHR_parallel_shader_compile');\n}\n\n/**\n * Registers custom WebGL2 backend to be used by Human library\n *\n * @returns void\n */\nexport async function register(instance): Promise {\n // force backend reload if gl context is not valid\n if (instance.config.backend !== 'humangl') return;\n if ((config.name in tf.engine().registry) && (!config.gl || !config.gl.getParameter(config.gl.VERSION))) {\n log('error: humangl backend invalid context');\n models.reset(instance);\n /*\n log('resetting humangl backend');\n await tf.removeBackend(config.name);\n await register(instance); // re-register\n */\n }\n if (!tf.findBackend(config.name)) {\n try {\n config.canvas = await image.canvas(100, 100);\n } catch (err) {\n log('error: cannot create canvas:', err);\n return;\n }\n try {\n config.gl = config.canvas?.getContext('webgl2', config.webGLattr) as WebGL2RenderingContext;\n if (config.canvas) {\n config.canvas.addEventListener('webglcontextlost', async (e) => {\n log('error: humangl:', e.type);\n // log('gpu memory usage:', instance.tf.engine().backendInstance.numBytesInGPU);\n log('possible browser memory leak using webgl');\n instance.emit('error');\n throw new Error('browser webgl error');\n /*\n log('resetting humangl backend');\n env.initial = true;\n models.reset(instance);\n await tf.removeBackend(config.name);\n await register(instance); // re-register\n */\n });\n config.canvas.addEventListener('webglcontextrestored', (e) => {\n log('error: humangl context restored:', e);\n });\n config.canvas.addEventListener('webglcontextcreationerror', (e) => {\n log('error: humangl context create:', e);\n });\n }\n } catch (err) {\n log('error: cannot get WebGL context:', err);\n return;\n }\n try {\n tf.setWebGLContext(2, config.gl);\n } catch (err) {\n log('error: cannot set WebGL context:', err);\n return;\n }\n const current = tf.backend().getGPGPUContext ? tf.backend().getGPGPUContext().gl : null;\n if (current) {\n log(`humangl webgl version:${current.getParameter(current.VERSION)} renderer:${current.getParameter(current.RENDERER)}`);\n } else {\n log('error: no current gl context:', current, config.gl);\n return;\n }\n try {\n const ctx = new tf.GPGPUContext(config.gl);\n tf.registerBackend(config.name, () => new tf.MathBackendWebGL(ctx), config.priority);\n } catch (err) {\n log('error: cannot register WebGL backend:', err);\n return;\n }\n try {\n const kernels = tf.getKernelsForBackend('webgl');\n kernels.forEach((kernelConfig) => {\n const newKernelConfig = { ...kernelConfig, backendName: config.name };\n tf.registerKernel(newKernelConfig);\n });\n } catch (err) {\n log('error: cannot update WebGL backend registration:', err);\n return;\n }\n try {\n tf.ENV.set('WEBGL_VERSION', 2);\n } catch (err) {\n log('error: cannot set WebGL backend flags:', err);\n return;\n }\n extensions();\n log('backend registered:', config.name);\n }\n}\n", "import { log, now } from '../helpers';\nimport * as humangl from './humangl';\nimport * as env from '../env';\nimport * as tf from '../../dist/tfjs.esm.js';\n\nexport async function check(instance, force = false) {\n instance.state = 'backend';\n if (force || env.env.initial || (instance.config.backend && (instance.config.backend.length > 0) && (tf.getBackend() !== instance.config.backend))) {\n const timeStamp = now();\n\n if (instance.config.backend && instance.config.backend.length > 0) {\n // detect web worker\n // @ts-ignore ignore missing type for WorkerGlobalScope as that is the point\n if (typeof window === 'undefined' && typeof WorkerGlobalScope !== 'undefined' && instance.config.debug) {\n if (instance.config.debug) log('running inside web worker');\n }\n\n // force browser vs node backend\n if (env.env.browser && instance.config.backend === 'tensorflow') {\n if (instance.config.debug) log('override: backend set to tensorflow while running in browser');\n instance.config.backend = 'humangl';\n }\n if (env.env.node && (instance.config.backend === 'webgl' || instance.config.backend === 'humangl')) {\n if (instance.config.debug) log(`override: backend set to ${instance.config.backend} while running in nodejs`);\n instance.config.backend = 'tensorflow';\n }\n\n // handle webgpu\n if (env.env.browser && instance.config.backend === 'webgpu') {\n if (typeof navigator === 'undefined' || typeof navigator['gpu'] === 'undefined') {\n log('override: backend set to webgpu but browser does not support webgpu');\n instance.config.backend = 'humangl';\n } else {\n const adapter = await navigator['gpu'].requestAdapter();\n if (instance.config.debug) log('enumerated webgpu adapter:', adapter);\n }\n }\n\n // check available backends\n if (instance.config.backend === 'humangl') await humangl.register(instance);\n const available = Object.keys(tf.engine().registryFactory);\n if (instance.config.debug) log('available backends:', available);\n\n if (!available.includes(instance.config.backend)) {\n log(`error: backend ${instance.config.backend} not found in registry`);\n instance.config.backend = env.env.node ? 'tensorflow' : 'humangl';\n if (instance.config.debug) log(`override: setting backend ${instance.config.backend}`);\n }\n\n if (instance.config.debug) log('setting backend:', instance.config.backend);\n\n // handle wasm\n if (instance.config.backend === 'wasm') {\n if (instance.config.debug) log('wasm path:', instance.config.wasmPath);\n if (typeof tf?.setWasmPaths !== 'undefined') await tf.setWasmPaths(instance.config.wasmPath);\n else throw new Error('wasm backend is not loaded');\n const simd = await tf.env().getAsync('WASM_HAS_SIMD_SUPPORT');\n const mt = await tf.env().getAsync('WASM_HAS_MULTITHREAD_SUPPORT');\n if (instance.config.debug) log(`wasm execution: ${simd ? 'SIMD' : 'no SIMD'} ${mt ? 'multithreaded' : 'singlethreaded'}`);\n if (instance.config.debug && !simd) log('warning: wasm simd support is not enabled');\n }\n\n try {\n await tf.setBackend(instance.config.backend);\n await tf.ready();\n } catch (err) {\n log('error: cannot set backend:', instance.config.backend, err);\n return false;\n }\n }\n\n // handle webgl & humangl\n if (tf.getBackend() === 'humangl') {\n tf.ENV.set('CHECK_COMPUTATION_FOR_ERRORS', false);\n tf.ENV.set('WEBGL_CPU_FORWARD', true);\n tf.ENV.set('WEBGL_PACK_DEPTHWISECONV', false);\n tf.ENV.set('WEBGL_USE_SHAPES_UNIFORMS', true);\n // if (!instance.config.object.enabled) tf.ENV.set('WEBGL_FORCE_F16_TEXTURES', true); // safe to use 16bit precision\n if (typeof instance.config['deallocate'] !== 'undefined' && instance.config['deallocate']) { // hidden param\n log('changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:', true);\n tf.ENV.set('WEBGL_DELETE_TEXTURE_THRESHOLD', 0);\n }\n // @ts-ignore getGPGPUContext only exists on WebGL backend\n const gl = await tf.backend().getGPGPUContext().gl;\n if (instance.config.debug) log(`gl version:${gl.getParameter(gl.VERSION)} renderer:${gl.getParameter(gl.RENDERER)}`);\n }\n\n // wait for ready\n tf.enableProdMode();\n await tf.ready();\n instance.performance.backend = Math.trunc(now() - timeStamp);\n instance.config.backend = tf.getBackend();\n\n env.get(); // update env on backend init\n instance.env = env.env;\n }\n return true;\n}\n", "/**\n * Embedded sample images used during warmup in dataURL format\n */\n\n// data:image/jpeg;base64,\nexport const face = `\n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`;\n\n// data:image/jpeg;base64,\nexport const body = `\n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\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAa2p1UYo5adbz+xbxMlvqJ1OqjDHLXree0ejmzNrWm953tPmTPWbWneZ7yoy5YhjrXXTjH8s75N\nmtkyxt0VZM2/m175N1V03yTKubMLXVXybeYLLX2VXy7eam+b0bOg4VquJW+rry4/O9uyZOq3UjVm\n9r25axMzPaIdvhns1kzbZddM0p5Y47z8/R2+HcF03Doi1a8+Xzvbv+TotJnjDXkt+K8ODHp8cY8N\nIpSO0RCwF2YAAAAAAAAACvUZYw6fJkntWN3k8dfHz2vLucdz8mkjFE9bz1+UOZosX1UzPm0nqI/W\nMYo9FlcPNklfFGeH/NshLGun+Cz6PtHZtVZWlRLS+jxPkRpIn7rdoupHTdA5s6SI+7H6Mfo+32Y2\n+To3neSIiZ7A0IjPXpXLePlMotGW3272t85datKzHZjbTVnsDj+FG/2Y/RlGP4R+jo20u7H6N1Ql\no+H8I/REY957R+jpfReiK6eOYHLtj2tttH6KrY/6Y/R2c+kjeJiFVtLG24hxpw7/AHY/RRkw9O37\nO99Hrt1YX0tfOBLjcGp4XF8c+u8fs9c4dcVcGemSI61nd3IneN1orQAAAAAAAAAAAAABFqxes1tE\nTE9JiUgPKcX4RbRXnNgiZwWnrH4XPi28PdXpW9JraImsxtMS8pxXhF9DecuGJtgmf+1TWW2N/la1\nL7N7T5e3Vy6W3hsYcvLbqzbO9jvvCzvDR0+XeO7crO6FmGSvRThy/RtVXJ92elvk2rRvDUzU7pl4\nizsd2J3jeBpcNz+Lg5LT7+Pp+Xk3W7js5eAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs0NTrN96Yp6edkW8Wzm6+LNTq4pvTHO9vOfRoWtt\n1mes95YWvs1s2fZldddOczLPLn2ju0MmebT3YZc2/mpm3qqllN1drsbZIhr3yzvtHf4AsvlYYseb\nV5Yx4KTe0+UQ6nDvZ3UazbJqd8OKeu33peq0eh0+hxcmnxxWPOfOfm0mP+steT/ji8N9mKY9suum\nL37+HHaPm9DSlaVitKxWsdohI0Y22gAgAAAAAAAAAABXnyRhw3yT92Nwef4xm8bVzET0rPJH5d12\n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\nAOZE/OsPS29nuH27YrV+VpeV9pdPXhOtw49NG9Mld55+vXcTPd42I47qo7xSfyWV9oM8d8VJ/VxM\nd8l46xWF9cV7en6o/qLfxp2I9ob+eCv/AHMo9op89P8A/wBORGmyT5R+qfo2X8P7n9Q/jTsx7RR5\n6ef+4/8AuHftg/8A6cWcOSO9J/WEbWr3pY7Efzp2Lcfv5YK/9zWy8d1E/ZpSv5Oba1/+Hb9lc+LP\nbFt87I7E/wAabWbiurvEx4nL/pjZzc2bJkn372t85ZXx55/BX85lucC0vPxnTxlnnjm32mOiZqUu\nLJ2p4TwnVavNWaYbRTfre0bQ99pcH0bT0xb78vmtiIiNojaErMwAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAHnfarF7umzRHaZrLjYrdIen9ocPi8JyTt1xzF4eUw23rCm3R4r6bMy\nwt6kdTaWLdjswmNoZontsCm0K5XWjopnuDC0dGpqG5bs08/daKV672MjbSaif6oh6Z5f2LtvptRX\n0tEvUN3Jfo8f7cYve0eX4zV7B5z20xc/C8eSPuZIRficfXlcPaG7ino08HWIbePpLF2NuiyOyrHK\n3fZFSwuovHVfaVF4QK5YWTM9UT0EKry6Ps1Tn4zjn8NZn9nOtLseydObiWW34cf918fWfk+PYANn\nKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAq1WKM+ly4p+/WYeBxTNd6zG0xO0\nvobw3FcP0bi2em20Tbmj5Srr418V9sa2Z7qKyzi07MXUylhaU7yjqhLCeiq3ddaFNxFYW7NLNG8t\nzya+WO6Va9J7FW66mvwidnrXiPY3Ny8RyUn71Jj9Ht3RPjk19HK9pMHj8D1ER3rHN+jqqtTjjNps\nuOe16zAifXzfTz7kNyndpYazS9qT0mszDdoxrsi6m8LazMq6zDOsq1ZEyrt1WWlXaUCqyq0rbKbi\nFdp6PReyFd8uqv8ACsfy83aXrPZHHto89/xX2/SP/dpj6y8vx6EBq5gAAAAAAAAAAAAAAAAAAAAA\n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\nNO67NbkhzNVnmInqzaOZrL93JyZeV0M1++7S02jvxDWxhxx033tPpC8Z6rrezWjmZyazJG2/u03h\n2vFibTHoqvamiwVwY+nLGzV0+SZ1Mx8G0/45tOhzJ5lXMc3UVXRdlF1HP+iYsDPLPPy49/tz1+Te\npSIr0ho6ak5Ms5J8o2q6NImOrHV7XX488ypzTtHXo0s9t6zG7c1G1qz6ubeZiZ3UatXJG3yauSO7\ncvMTEx5tPLb3prPRMVr0HB8vicNxf0+7+kt+LOJwTJyY/Bnz3tH93X36N58cWvq6LSyiyndMSlC7\nmZcymLJiwLosmJVRLKLAtiU7q4lMSCzc3YxJuDMRuAlKAEgAAAlAkAAAAAABKAEgAAAAAJAAAAAA\nAAAAAAAEgAAAAAAAAAAAAAkAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAhIAAACAAAASgAAAAAAEAAAA\nhGzJAImGMwzQDDZjNVuyNgUTVhNGxysZqDVmiu1G5NN2M4waM0+DCaN2cbGcQNGaMZq3JxMJxA1J\nqx2bU4kU09slorWNwa20z02RXHbJbl26QvtFovbHWkxEdJt5y2MOHlr2U1W3jx+1hiw8vSO63lmI\nXRTaEWmtY6snRHO1VpmJ+DjavpSZl2s8b7y4HFcnh0n0gha5ebJN55KRM2mdoiPN6fh+kpwXh0Wy\nRHj5Otp/s5Ps1p62y31+em9aTMYt/OfVfxTiPjZ52naI7fBrI5t66xz5+a1rW7yx0eSL6iZjtEOX\nqNbSletom3lENjh2fbHzbbWt3iVozruc+5ztWubf4M4ybpQ2Oboyrva0Vjza8WdDR4OkXt3n9ldX\nkaePP9VtYqctYhdvt5oivTeCZ2YOxXk6ubqMfV0b9mrljfqlFcq88k7z2U5axeItDa1OPessuC8P\nya7XRWYnwqdbT/ZMilvIu4dpslNdixXja8Y5tt85djZdbDWnGOesRtXFtuw6T27No5Kx2OrKYQlC\nExKJgBnEpiyvdlEgsizKLKollFgWxLKJVRLKJBbEp3VxLKJBnuMWQJEbpBIAAAJAAAABIAAAAAAA\nlAJAAAAAAAAAAAAAASAAAAAAAAAAAAAJAAAABAJABAlAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAA\nAAABAJQAAAAgAABAAI2EoBGyJhkgGPKxmqxAKpownHC+YRMdN5BrTj67R3bOn01o7p01Iv71u89o\n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\n2Q==`;\n", "import { log, now, mergeDeep } from './helpers';\nimport * as sample from './sample';\nimport * as tf from '../dist/tfjs.esm.js';\nimport * as image from './image/image';\nimport type { Config } from './config';\nimport type { Result } from './result';\nimport { env } from './env';\n\nasync function warmupBitmap(instance) {\n const b64toBlob = (base64: string, type = 'application/octet-stream') => fetch(`data:${type};base64,${base64}`).then((res) => res.blob());\n let blob;\n let res;\n switch (instance.config.warmup) {\n case 'face': blob = await b64toBlob(sample.face); break;\n case 'body':\n case 'full': blob = await b64toBlob(sample.body); break;\n default: blob = null;\n }\n if (blob) {\n const bitmap = await createImageBitmap(blob);\n res = await instance.detect(bitmap, instance.config);\n bitmap.close();\n }\n return res;\n}\n\nasync function warmupCanvas(instance) {\n return new Promise((resolve) => {\n let src;\n // let size = 0;\n switch (instance.config.warmup) {\n case 'face':\n // size = 256;\n src = 'data:image/jpeg;base64,' + sample.face;\n break;\n case 'full':\n case 'body':\n // size = 1200;\n src = 'data:image/jpeg;base64,' + sample.body;\n break;\n default:\n src = null;\n }\n // src = encodeURI('../assets/human-sample-upper.jpg');\n let img;\n if (typeof Image !== 'undefined') img = new Image();\n // @ts-ignore env.image is an external monkey-patch\n else if (env.Image) img = new env.Image();\n img.onload = async () => {\n const canvas = image.canvas(img.naturalWidth, img.naturalHeight);\n if (!canvas) {\n log('Warmup: Canvas not found');\n resolve({});\n } else {\n const ctx = canvas.getContext('2d');\n if (ctx) ctx.drawImage(img, 0, 0);\n // const data = ctx?.getImageData(0, 0, canvas.height, canvas.width);\n const tensor = await instance.image(canvas);\n const res = await instance.detect(tensor.tensor, instance.config);\n resolve(res);\n }\n };\n if (src) img.src = src;\n else resolve(null);\n });\n}\n\nasync function warmupNode(instance) {\n const atob = (str: string) => Buffer.from(str, 'base64');\n let img;\n if (instance.config.warmup === 'face') img = atob(sample.face);\n if (instance.config.warmup === 'body' || instance.config.warmup === 'full') img = atob(sample.body);\n if (!img) return null;\n let res;\n if (typeof tf['node'] !== 'undefined') {\n const data = tf['node'].decodeJpeg(img);\n const expanded = data.expandDims(0);\n instance.tf.dispose(data);\n // log('Input:', expanded);\n res = await instance.detect(expanded, instance.config);\n instance.tf.dispose(expanded);\n } else {\n if (instance.config.debug) log('Warmup tfjs-node not loaded');\n /*\n const input = await canvasJS.loadImage(img);\n const canvas = canvasJS.createCanvas(input.width, input.height);\n const ctx = canvas.getContext('2d');\n ctx.drawImage(img, 0, 0, input.width, input.height);\n res = await instance.detect(input, instance.config);\n */\n }\n return res;\n}\n\n/** Warmup method pre-initializes all configured models for faster inference\n * - can take significant time on startup\n * - only used for `webgl` and `humangl` backends\n * @param userConfig?: Config\n*/\nexport async function warmup(instance, userConfig?: Partial): Promise {\n const t0 = now();\n instance.state = 'warmup';\n if (userConfig) instance.config = mergeDeep(instance.config, userConfig) as Config;\n if (!instance.config.warmup || instance.config.warmup === 'none') return { error: 'null' };\n let res;\n return new Promise(async (resolve) => {\n if (typeof createImageBitmap === 'function') res = await warmupBitmap(instance);\n else if (typeof Image !== 'undefined' || env.Canvas !== undefined) res = await warmupCanvas(instance);\n else res = await warmupNode(instance);\n const t1 = now();\n if (instance.config.debug) log('Warmup', instance.config.warmup, Math.round(t1 - t0), 'ms');\n instance.emit('warmup');\n resolve(res);\n });\n}\n", "/**\n * Human main module\n */\n\nimport { log, now, mergeDeep, validate } from './helpers';\nimport { Config, defaults } from './config';\nimport type { Result, FaceResult, HandResult, BodyResult, ObjectResult, GestureResult, PersonResult } from './result';\nimport * as tf from '../dist/tfjs.esm.js';\nimport * as models from './models';\nimport * as face from './face';\nimport * as facemesh from './blazeface/facemesh';\nimport * as faceres from './faceres/faceres';\nimport * as posenet from './posenet/posenet';\nimport * as handtrack from './handtrack/handtrack';\nimport * as handpose from './handpose/handpose';\nimport * as blazepose from './blazepose/blazepose';\nimport * as efficientpose from './efficientpose/efficientpose';\nimport * as movenet from './movenet/movenet';\nimport * as nanodet from './object/nanodet';\nimport * as centernet from './object/centernet';\nimport * as segmentation from './segmentation/segmentation';\nimport * as gesture from './gesture/gesture';\nimport * as image from './image/image';\nimport * as draw from './draw';\nimport * as persons from './persons';\nimport * as interpolate from './interpolate';\nimport * as env from './env';\nimport * as backend from './tfjs/backend';\nimport * as humangl from './tfjs/humangl';\nimport * as app from '../package.json';\nimport * as warmups from './warmup';\nimport type { Tensor, GraphModel } from './tfjs/types';\nimport type { DrawOptions } from './draw';\n\n// export types\nexport * from './config';\nexport * from './result';\nexport type { DrawOptions } from './draw';\nexport { env, Env } from './env';\n\n/** Defines all possible input types for **Human** detection\n * @typedef Input Type\n */\nexport type Input = Tensor | ImageData | ImageBitmap | HTMLImageElement | HTMLMediaElement | HTMLVideoElement | HTMLCanvasElement | OffscreenCanvas;\n\n/** Events dispatched by `human.events`\n *\n * - `create`: triggered when Human object is instantiated\n * - `load`: triggered when models are loaded (explicitly or on-demand)\n * - `image`: triggered when input image is processed\n * - `result`: triggered when detection is complete\n * - `warmup`: triggered when warmup is complete\n */\nexport type Events = 'create' | 'load' | 'image' | 'result' | 'warmup' | 'error';\n\n/** Error message\n * @typedef Error Type\n */\nexport type Error = { error: string };\n\n/** Instance of TensorFlow/JS\n * @external\n */\nexport type TensorFlow = typeof tf;\n\n/** **Human** library main class\n *\n * All methods and properties are available only as members of Human class\n *\n * - Configuration object definition: {@link Config}\n * - Results object definition: {@link Result}\n * - Possible inputs: {@link Input}\n *\n * @param userConfig: {@link Config}\n * @return instance\n */\nexport class Human {\n /** Current version of Human library in *semver* format */\n version: string;\n\n /** Current configuration\n * - Details: {@link Config}\n */\n config: Config;\n\n /** Last known result of detect run\n * - Can be accessed anytime after initial detection\n */\n result: Result;\n\n /** Current state of Human library\n * - Can be polled to determine operations that are currently executed\n * - Progresses through: 'config', 'check', 'backend', 'load', 'run:', 'idle'\n */\n state: string;\n\n /** currenty processed image tensor and canvas */\n process: { tensor: Tensor | null, canvas: OffscreenCanvas | HTMLCanvasElement | null };\n\n /** Instance of TensorFlow/JS used by Human\n * - Can be embedded or externally provided\n * @internal\n */\n tf: TensorFlow;\n\n /** Object containing environment information used for diagnostics */\n env: env.Env;\n\n /** Draw helper classes that can draw detected objects on canvas using specified draw\n * - options: {@link DrawOptions} global settings for all draw operations, can be overriden for each draw method\n * - face: draw detected faces\n * - body: draw detected people and body parts\n * - hand: draw detected hands and hand parts\n * - canvas: draw processed canvas which is a processed copy of the input\n * - all: meta-function that performs: canvas, face, body, hand\n */\n draw: { canvas, face, body, hand, gesture, object, person, all, options: DrawOptions };\n\n /** Currently loaded models\n * @internal\n */\n models: {\n face: [unknown, GraphModel | null, GraphModel | null] | null,\n posenet: GraphModel | null,\n blazepose: GraphModel | null,\n efficientpose: GraphModel | null,\n movenet: GraphModel | null,\n handpose: [GraphModel | null, GraphModel | null] | null,\n handtrack: [GraphModel | null, GraphModel | null] | null,\n age: GraphModel | null,\n gender: GraphModel | null,\n emotion: GraphModel | null,\n embedding: GraphModel | null,\n nanodet: GraphModel | null,\n centernet: GraphModel | null,\n faceres: GraphModel | null,\n segmentation: GraphModel | null,\n };\n\n /** Container for events dispatched by Human\n *\n * Possible events:\n * - `create`: triggered when Human object is instantiated\n * - `load`: triggered when models are loaded (explicitly or on-demand)\n * - `image`: triggered when input image is processed\n * - `result`: triggered when detection is complete\n * - `warmup`: triggered when warmup is complete\n * - `error`: triggered on some errors\n */\n events: EventTarget;\n /** Reference face triangualtion array of 468 points, used for triangle references between points */\n faceTriangulation: typeof facemesh.triangulation;\n /** Refernce UV map of 468 values, used for 3D mapping of the face mesh */\n faceUVMap: typeof facemesh.uvmap;\n /** Performance object that contains values for all recently performed operations */\n performance: Record; // perf members are dynamically defined as needed\n #numTensors: number;\n #analyzeMemoryLeaks: boolean;\n #checkSanity: boolean;\n /** WebGL debug info */\n gl: Record;\n // definition end\n\n /** Constructor for **Human** library that is futher used for all operations\n *\n * @param userConfig: {@link Config}\n *\n * @return instance\n */\n constructor(userConfig?: Partial) {\n env.get();\n this.env = env.env;\n defaults.wasmPath = `https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${tf.version_core}/dist/`;\n defaults.modelBasePath = this.env.browser ? '../models/' : 'file://models/';\n defaults.backend = this.env.browser ? 'humangl' : 'tensorflow';\n this.version = app.version; // expose version property on instance of class\n Object.defineProperty(this, 'version', { value: app.version }); // expose version property directly on class itself\n this.config = JSON.parse(JSON.stringify(defaults));\n Object.seal(this.config);\n if (userConfig) this.config = mergeDeep(this.config, userConfig);\n validate(defaults, this.config);\n this.tf = tf;\n this.state = 'idle';\n this.#numTensors = 0;\n this.#analyzeMemoryLeaks = false;\n this.#checkSanity = false;\n this.performance = { backend: 0, load: 0, image: 0, frames: 0, cached: 0, changed: 0, total: 0, draw: 0 };\n this.events = new EventTarget();\n // object that contains all initialized models\n this.models = {\n face: null, // array of models\n handpose: null, // array of models\n handtrack: null, // array of models\n posenet: null,\n blazepose: null,\n efficientpose: null,\n movenet: null,\n age: null,\n gender: null,\n emotion: null,\n embedding: null,\n nanodet: null,\n centernet: null,\n faceres: null,\n segmentation: null,\n };\n // reexport draw methods\n this.draw = {\n options: draw.options as DrawOptions,\n canvas: (input: HTMLCanvasElement | OffscreenCanvas | HTMLImageElement | HTMLMediaElement | HTMLVideoElement, output: HTMLCanvasElement) => draw.canvas(input, output),\n face: (output: HTMLCanvasElement | OffscreenCanvas, result: FaceResult[], options?: Partial) => draw.face(output, result, options),\n body: (output: HTMLCanvasElement | OffscreenCanvas, result: BodyResult[], options?: Partial) => draw.body(output, result, options),\n hand: (output: HTMLCanvasElement | OffscreenCanvas, result: HandResult[], options?: Partial) => draw.hand(output, result, options),\n gesture: (output: HTMLCanvasElement | OffscreenCanvas, result: GestureResult[], options?: Partial) => draw.gesture(output, result, options),\n object: (output: HTMLCanvasElement | OffscreenCanvas, result: ObjectResult[], options?: Partial) => draw.object(output, result, options),\n person: (output: HTMLCanvasElement | OffscreenCanvas, result: PersonResult[], options?: Partial) => draw.person(output, result, options),\n all: (output: HTMLCanvasElement | OffscreenCanvas, result: Result, options?: Partial) => draw.all(output, result, options),\n };\n this.result = { face: [], body: [], hand: [], gesture: [], object: [], performance: {}, timestamp: 0, persons: [] };\n // export access to image processing\n // @ts-ignore eslint-typescript cannot correctly infer type in anonymous function\n this.process = { tensor: null, canvas: null };\n // export raw access to underlying models\n this.faceTriangulation = facemesh.triangulation;\n this.faceUVMap = facemesh.uvmap;\n // set gl info\n this.gl = humangl.config;\n // include platform info\n this.emit('create');\n }\n\n // helper function: measure tensor leak\n /** @hidden */\n analyze = (...msg: string[]) => {\n if (!this.#analyzeMemoryLeaks) return;\n const currentTensors = this.tf.engine().state.numTensors;\n const previousTensors = this.#numTensors;\n this.#numTensors = currentTensors;\n const leaked = currentTensors - previousTensors;\n if (leaked !== 0) log(...msg, leaked);\n }\n\n // quick sanity check on inputs\n /** @hidden */\n #sanity = (input: Input): null | string => {\n if (!this.#checkSanity) return null;\n if (!input) return 'input is not defined';\n if (this.env.node && !(input instanceof tf.Tensor)) return 'input must be a tensor';\n try {\n this.tf.getBackend();\n } catch {\n return 'backend not loaded';\n }\n return null;\n }\n\n /** Reset configuration to default values */\n reset = () => {\n const currentBackend = this.config.backend; // save backend;\n this.config = JSON.parse(JSON.stringify(defaults));\n this.config.backend = currentBackend;\n }\n\n /** Validate current configuration schema */\n validate = (userConfig?: Partial) => validate(defaults, userConfig || this.config);\n\n /** Process input as return canvas and tensor\n *\n * @param input: {@link Input}\n * @returns { tensor, canvas }\n */\n image = (input: Input) => image.process(input, this.config);\n\n /** Simmilarity method calculates simmilarity between two provided face descriptors (face embeddings)\n * - Calculation is based on normalized Minkowski distance between two descriptors\n * - Default is Euclidean distance which is Minkowski distance of 2nd order\n *\n * @param embedding1: face descriptor as array of numbers\n * @param embedding2: face descriptor as array of numbers\n * @returns similarity: number\n */\n // eslint-disable-next-line class-methods-use-this\n similarity(embedding1: Array, embedding2: Array): number {\n return faceres.similarity(embedding1, embedding2);\n }\n\n /** Segmentation method takes any input and returns processed canvas with body segmentation\n * - Optional parameter background is used to fill the background with specific input\n * - Segmentation is not triggered as part of detect process\n *\n * Returns:\n * - `data` as raw data array with per-pixel segmentation values\n * - `canvas` as canvas which is input image filtered with segementation data and optionally merged with background image. canvas alpha values are set to segmentation values for easy merging\n * - `alpha` as grayscale canvas that represents segmentation alpha values\n *\n * @param input: {@link Input}\n * @param background?: {@link Input}\n * @returns { data, canvas, alpha }\n */\n async segmentation(input: Input, background?: Input): Promise<{ data: Uint8ClampedArray | null, canvas: HTMLCanvasElement | OffscreenCanvas | null, alpha: HTMLCanvasElement | OffscreenCanvas | null }> {\n return segmentation.process(input, background, this.config);\n }\n\n /** Enhance method performs additional enhacements to face image previously detected for futher processing\n *\n * @param input: Tensor as provided in human.result.face[n].tensor\n * @returns Tensor\n */\n // eslint-disable-next-line class-methods-use-this\n enhance(input: Tensor): Tensor | null {\n return faceres.enhance(input);\n }\n\n /** Math method find best match between provided face descriptor and predefined database of known descriptors\n *\n * @param faceEmbedding: face descriptor previsouly calculated on any face\n * @param db: array of mapping of face descriptors to known values\n * @param threshold: minimum score for matching to be considered in the result\n * @returns best match\n */\n // eslint-disable-next-line class-methods-use-this\n match(faceEmbedding: Array, db: Array<{ name: string, source: string, embedding: number[] }>, threshold = 0): { name: string, source: string, similarity: number, embedding: number[] } {\n return faceres.match(faceEmbedding, db, threshold);\n }\n\n /** Explicit backend initialization\n * - Normally done implicitly during initial load phase\n * - Call to explictly register and initialize TFJS backend without any other operations\n * - Use when changing backend during runtime\n *\n * @return Promise\n */\n async init() {\n await backend.check(this, true);\n await this.tf.ready();\n env.set(this.env);\n }\n\n /** Load method preloads all configured models on-demand\n * - Not explicitly required as any required model is load implicitly on it's first run\n *\n * @param userConfig?: {@link Config}\n * @return Promise\n */\n async load(userConfig?: Partial) {\n this.state = 'load';\n const timeStamp = now();\n const count = Object.values(this.models).filter((model) => model).length;\n if (userConfig) this.config = mergeDeep(this.config, userConfig) as Config;\n\n if (env.env.initial) { // print version info on first run and check for correct backend setup\n if (this.config.debug) log(`version: ${this.version}`);\n if (this.config.debug) log(`tfjs version: ${this.tf.version_core}`);\n if (!await backend.check(this)) log('error: backend check failed');\n await tf.ready();\n if (this.env.browser) {\n if (this.config.debug) log('configuration:', this.config);\n if (this.config.debug) log('tf flags:', this.tf.ENV.flags);\n }\n }\n\n await models.load(this); // actually loads models\n if (env.env.initial && this.config.debug) log('tf engine state:', this.tf.engine().state.numBytes, 'bytes', this.tf.engine().state.numTensors, 'tensors'); // print memory stats on first run\n env.env.initial = false;\n\n const loaded = Object.values(this.models).filter((model) => model).length;\n if (loaded !== count) { // number of loaded models changed\n await models.validate(this); // validate kernel ops used by model against current backend\n this.emit('load');\n }\n\n const current = Math.trunc(now() - timeStamp);\n if (current > (this.performance.load as number || 0)) this.performance.load = current;\n }\n\n // emit event\n /** @hidden */\n emit = (event: string) => this.events?.dispatchEvent(new Event(event));\n\n /** Runs interpolation using last known result and returns smoothened result\n * Interpolation is based on time since last known result so can be called independently\n *\n * @param result?: {@link Result} optional use specific result set to run interpolation on\n * @returns result: {@link Result}\n */\n next(result: Result = this.result) {\n return interpolate.calc(result) as Result;\n }\n\n /** Warmup method pre-initializes all configured models for faster inference\n * - can take significant time on startup\n * - only used for `webgl` and `humangl` backends\n * @param userConfig?: {@link Config}\n * @returns result: {@link Result}\n */\n async warmup(userConfig?: Partial): Promise {\n return warmups.warmup(this, userConfig) as Promise;\n }\n\n /** Main detection method\n * - Analyze configuration: {@link Config}\n * - Pre-process input: {@link Input}\n * - Run inference for all configured models\n * - Process and return result: {@link Result}\n *\n * @param input: {@link Input}\n * @param userConfig?: {@link Config}\n * @returns result: {@link Result}\n */\n async detect(input: Input, userConfig?: Partial): Promise {\n // detection happens inside a promise\n this.state = 'detect';\n return new Promise(async (resolve) => {\n this.state = 'config';\n let timeStamp;\n let elapsedTime;\n\n // update configuration\n this.config = mergeDeep(this.config, userConfig) as Config;\n\n // sanity checks\n this.state = 'check';\n const error = this.#sanity(input);\n if (error) {\n log(error, input);\n resolve({ error });\n }\n\n const timeStart = now();\n\n // configure backend if needed\n await backend.check(this);\n\n // load models if enabled\n await this.load();\n\n timeStamp = now();\n this.state = 'image';\n const img = image.process(input, this.config) as { canvas: HTMLCanvasElement | OffscreenCanvas, tensor: Tensor };\n this.process = img;\n this.performance.image = Math.trunc(now() - timeStamp);\n this.analyze('Get Image:');\n\n // segmentation is only run explicitly via human.segmentation() which calls segmentation.process()\n /*\n if (this.config.segmentation.enabled && process && img.tensor && img.canvas) {\n this.analyze('Start Segmentation:');\n this.state = 'detect:segmentation';\n timeStamp = now();\n const seg = await segmentation.predict(img, this.config);\n img = { canvas: seg.canvas, tensor: seg.tensor };\n elapsedTime = Math.trunc(now() - timeStamp);\n if (elapsedTime > 0) this.performance.segmentation = elapsedTime;\n this.analyze('End Segmentation:');\n }\n */\n\n if (!img.tensor) {\n if (this.config.debug) log('could not convert input to tensor');\n resolve({ error: 'could not convert input to tensor' });\n return;\n }\n this.emit('image');\n\n timeStamp = now();\n this.config.skipFrame = await image.skip(this.config, img.tensor);\n if (!this.performance.frames) this.performance.frames = 0;\n if (!this.performance.cached) this.performance.cached = 0;\n (this.performance.frames as number)++;\n if (this.config.skipFrame) this.performance.cached++;\n this.performance.changed = Math.trunc(now() - timeStamp);\n this.analyze('Check Changed:');\n\n // prepare where to store model results\n // keep them with weak typing as it can be promise or not\n let faceRes: FaceResult[] | Promise | never[] = [];\n let bodyRes: BodyResult[] | Promise | never[] = [];\n let handRes: HandResult[] | Promise | never[] = [];\n let objectRes: ObjectResult[] | Promise | never[] = [];\n\n // run face detection followed by all models that rely on face bounding box: face mesh, age, gender, emotion\n this.state = 'detect:face';\n if (this.config.async) {\n faceRes = this.config.face.enabled ? face.detectFace(this, img.tensor) : [];\n if (this.performance.face) delete this.performance.face;\n } else {\n timeStamp = now();\n faceRes = this.config.face.enabled ? await face.detectFace(this, img.tensor) : [];\n elapsedTime = Math.trunc(now() - timeStamp);\n if (elapsedTime > 0) this.performance.face = elapsedTime;\n }\n\n // run body: can be posenet, blazepose, efficientpose, movenet\n this.analyze('Start Body:');\n this.state = 'detect:body';\n if (this.config.async) {\n if (this.config.body.modelPath?.includes('posenet')) bodyRes = this.config.body.enabled ? posenet.predict(img.tensor, this.config) : [];\n else if (this.config.body.modelPath?.includes('blazepose')) bodyRes = this.config.body.enabled ? blazepose.predict(img.tensor, this.config) : [];\n else if (this.config.body.modelPath?.includes('efficientpose')) bodyRes = this.config.body.enabled ? efficientpose.predict(img.tensor, this.config) : [];\n else if (this.config.body.modelPath?.includes('movenet')) bodyRes = this.config.body.enabled ? movenet.predict(img.tensor, this.config) : [];\n if (this.performance.body) delete this.performance.body;\n } else {\n timeStamp = now();\n if (this.config.body.modelPath?.includes('posenet')) bodyRes = this.config.body.enabled ? await posenet.predict(img.tensor, this.config) : [];\n else if (this.config.body.modelPath?.includes('blazepose')) bodyRes = this.config.body.enabled ? await blazepose.predict(img.tensor, this.config) : [];\n else if (this.config.body.modelPath?.includes('efficientpose')) bodyRes = this.config.body.enabled ? await efficientpose.predict(img.tensor, this.config) : [];\n else if (this.config.body.modelPath?.includes('movenet')) bodyRes = this.config.body.enabled ? await movenet.predict(img.tensor, this.config) : [];\n elapsedTime = Math.trunc(now() - timeStamp);\n if (elapsedTime > 0) this.performance.body = elapsedTime;\n }\n this.analyze('End Body:');\n\n // run handpose\n this.analyze('Start Hand:');\n this.state = 'detect:hand';\n if (this.config.async) {\n if (this.config.hand.detector?.modelPath?.includes('handdetect')) handRes = this.config.hand.enabled ? handpose.predict(img.tensor, this.config) : [];\n else if (this.config.hand.detector?.modelPath?.includes('handtrack')) handRes = this.config.hand.enabled ? handtrack.predict(img.tensor, this.config) : [];\n if (this.performance.hand) delete this.performance.hand;\n } else {\n timeStamp = now();\n if (this.config.hand.detector?.modelPath?.includes('handdetect')) handRes = this.config.hand.enabled ? await handpose.predict(img.tensor, this.config) : [];\n else if (this.config.hand.detector?.modelPath?.includes('handtrack')) handRes = this.config.hand.enabled ? await handtrack.predict(img.tensor, this.config) : [];\n elapsedTime = Math.trunc(now() - timeStamp);\n if (elapsedTime > 0) this.performance.hand = elapsedTime;\n }\n this.analyze('End Hand:');\n\n // run nanodet\n this.analyze('Start Object:');\n this.state = 'detect:object';\n if (this.config.async) {\n if (this.config.object.modelPath?.includes('nanodet')) objectRes = this.config.object.enabled ? nanodet.predict(img.tensor, this.config) : [];\n else if (this.config.object.modelPath?.includes('centernet')) objectRes = this.config.object.enabled ? centernet.predict(img.tensor, this.config) : [];\n if (this.performance.object) delete this.performance.object;\n } else {\n timeStamp = now();\n if (this.config.object.modelPath?.includes('nanodet')) objectRes = this.config.object.enabled ? await nanodet.predict(img.tensor, this.config) : [];\n else if (this.config.object.modelPath?.includes('centernet')) objectRes = this.config.object.enabled ? await centernet.predict(img.tensor, this.config) : [];\n elapsedTime = Math.trunc(now() - timeStamp);\n if (elapsedTime > 0) this.performance.object = elapsedTime;\n }\n this.analyze('End Object:');\n\n // if async wait for results\n this.state = 'detect:await';\n if (this.config.async) [faceRes, bodyRes, handRes, objectRes] = await Promise.all([faceRes, bodyRes, handRes, objectRes]);\n\n // run gesture analysis last\n this.state = 'detect:gesture';\n let gestureRes: GestureResult[] = [];\n if (this.config.gesture.enabled) {\n timeStamp = now();\n gestureRes = [...gesture.face(faceRes), ...gesture.body(bodyRes), ...gesture.hand(handRes), ...gesture.iris(faceRes)];\n if (!this.config.async) this.performance.gesture = Math.trunc(now() - timeStamp);\n else if (this.performance.gesture) delete this.performance.gesture;\n }\n\n this.performance.total = Math.trunc(now() - timeStart);\n const shape = this.process?.tensor?.shape || [];\n this.result = {\n face: faceRes as FaceResult[],\n body: bodyRes as BodyResult[],\n hand: handRes as HandResult[],\n gesture: gestureRes,\n object: objectRes as ObjectResult[],\n performance: this.performance,\n canvas: this.process.canvas,\n timestamp: Date.now(),\n get persons() { return persons.join(faceRes as FaceResult[], bodyRes as BodyResult[], handRes as HandResult[], gestureRes, shape); },\n };\n\n // finally dispose input tensor\n tf.dispose(img.tensor);\n\n // log('Result:', result);\n this.emit('detect');\n this.state = 'idle';\n resolve(this.result);\n });\n }\n}\n\n/** Class Human as default export */\nexport { Human as default };\n"],
- "mappings": "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CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,iBAAiB;AAAA,EAClB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,iBAAiB;AAAA,EAClB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,iBAAiB;AAAA,EAClB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,iBAAiB;AAAA,EAClB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,iBAAiB;AAAA,EAClB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,iBAAiB;AAAA,EAClB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,kBAAkB;AAAA,EACnB,CAAC,gBAAgB;AAAA,EACjB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,kBAAkB;AAAA,EACnB,CAAC,iBAAiB;AAAA,EAClB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA,EACpB,CAAC,mBAAmB;AAAA;AAGf,IAAM,SAAS;AAAA,EACpB;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EACtJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAClJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EACrJ;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAC7I;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAClJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EACrJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EACpJ;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAG;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnJ;AAAA,EAAK;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAC9I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACtJ;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAClJ;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACrJ;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACpJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAClJ;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EACnJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAChJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAChJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC7I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAClJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC7I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnJ;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACpJ;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAClJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAClJ;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAChJ;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EACpJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EACrJ;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACpJ;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC9I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EACpJ;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACrJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EACpJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACpJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC9I;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAG;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAI;AAAA,EAClJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC9I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAChJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAChJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC9I;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC/I;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAChJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAClJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACpJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACjJ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,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AG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,UAAU,GAAG;AAAA,EAClB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,SAAS,GAAG;AAAA,EACjB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA,EAChB,EAAE,GAAG,QAAQ,GAAG;AAAA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AO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACpB,EAAE,OAAO,IAAI,OAAO;AAAA,EACp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FF,IAAM,QAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0Jb,IAAM,QAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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",
+ "sourcesContent": ["/**\n * Simple helper functions used accross codebase\n */\n\n// helper function: join two paths\nexport function join(folder: string, file: string): string {\n const separator = folder.endsWith('/') ? '' : '/';\n const skipJoin = file.startsWith('.') || file.startsWith('/') || file.startsWith('http:') || file.startsWith('https:') || file.startsWith('file:');\n const path = skipJoin ? `${file}` : `${folder}${separator}${file}`;\n if (!path.toLocaleLowerCase().includes('.json')) throw new Error(`modelpath error: ${path} expecting json file`);\n return path;\n}\n\n// helper function: wrapper around console output\nexport function log(...msg): void {\n const dt = new Date();\n const ts = `${dt.getHours().toString().padStart(2, '0')}:${dt.getMinutes().toString().padStart(2, '0')}:${dt.getSeconds().toString().padStart(2, '0')}.${dt.getMilliseconds().toString().padStart(3, '0')}`;\n // eslint-disable-next-line no-console\n if (msg) console.log(ts, 'Human:', ...msg);\n}\n\n// helper function: gets elapsed time on both browser and nodejs\nexport const now = () => {\n if (typeof performance !== 'undefined') return performance.now();\n return parseInt((Number(process.hrtime.bigint()) / 1000 / 1000).toString());\n};\n\n// helper function: checks current config validity\nexport function validate(defaults, config, parent = 'config', msgs: Array<{ reason: string, where: string, expected?: string }> = []) {\n for (const key of Object.keys(config)) {\n if (typeof config[key] === 'object') {\n validate(defaults[key], config[key], key, msgs);\n } else {\n const defined = defaults && (typeof defaults[key] !== 'undefined');\n if (!defined) msgs.push({ reason: 'unknown property', where: `${parent}.${key} = ${config[key]}` });\n const same = defaults && typeof defaults[key] === typeof config[key];\n if (defined && !same) msgs.push({ reason: 'property type mismatch', where: `${parent}.${key} = ${config[key]}`, expected: typeof defaults[key] });\n }\n // ok = ok && defined && same;\n }\n if (config.debug && parent === 'config' && msgs.length > 0) log('invalid configuration', msgs);\n return msgs;\n}\n\n// helper function: perform deep merge of multiple objects so it allows full inheriance with overrides\nexport function mergeDeep(...objects) {\n const isObject = (obj) => obj && typeof obj === 'object';\n return objects.reduce((prev, obj) => {\n Object.keys(obj || {}).forEach((key) => {\n const pVal = prev[key];\n const oVal = obj[key];\n if (Array.isArray(pVal) && Array.isArray(oVal)) prev[key] = pVal.concat(...oVal);\n else if (isObject(pVal) && isObject(oVal)) prev[key] = mergeDeep(pVal, oVal);\n else prev[key] = oVal;\n });\n return prev;\n }, {});\n}\n\n// helper function: return min and max from input array\nexport const minmax = (data: Array) => data.reduce((acc: Array, val) => {\n acc[0] = (acc[0] === undefined || val < acc[0]) ? val : acc[0];\n acc[1] = (acc[1] === undefined || val > acc[1]) ? val : acc[1];\n return acc;\n}, []);\n\n// helper function: async wait\nexport async function wait(time) {\n const waiting = new Promise((resolve) => setTimeout(() => resolve(true), time));\n await waiting;\n}\n", "/* eslint-disable indent */\n/* eslint-disable no-multi-spaces */\n\n/** Dectector part of face configuration */\nexport interface FaceDetectorConfig {\n modelPath: string,\n rotation: boolean,\n maxDetected: number,\n skipFrames: number,\n minConfidence: number,\n iouThreshold: number,\n return: boolean,\n}\n\n/** Mesh part of face configuration */\nexport interface FaceMeshConfig {\n enabled: boolean,\n modelPath: string,\n}\n\n/** Iris part of face configuration */\nexport interface FaceIrisConfig {\n enabled: boolean,\n modelPath: string,\n}\n\n/** Description or face embedding part of face configuration\n * - also used by age and gender detection\n */\nexport interface FaceDescriptionConfig {\n enabled: boolean,\n modelPath: string,\n skipFrames: number,\n minConfidence: number,\n}\n\n/** Emotion part of face configuration */\nexport interface FaceEmotionConfig {\n enabled: boolean,\n minConfidence: number,\n skipFrames: number,\n modelPath: string,\n}\n\n/** Controlls and configures all face-specific options:\n * - face detection, face mesh detection, age, gender, emotion detection and face description\n *\n * Parameters:\n * - enabled: true/false\n * - modelPath: path for each of face models\n * - minConfidence: threshold for discarding a prediction\n * - iouThreshold: ammount of overlap between two detected objects before one object is removed\n * - maxDetected: maximum number of faces detected in the input, should be set to the minimum number for performance\n * - rotation: use calculated rotated face image or just box with rotation as-is, false means higher performance, but incorrect mesh mapping on higher face angles\n * - return: return extracted face as tensor for futher user processing, in which case user is reponsible for manually disposing the tensor\n*/\nexport interface FaceConfig {\n enabled: boolean,\n detector: Partial,\n mesh: Partial,\n iris: Partial,\n description: Partial,\n emotion: Partial,\n}\n\n/** Controlls and configures all body detection specific options\n *\n * Parameters:\n * - enabled: true/false\n * - modelPath: body pose model, can be absolute path or relative to modelBasePath\n * - minConfidence: threshold for discarding a prediction\n * - maxDetected: maximum number of people detected in the input, should be set to the minimum number for performance\n *\n * Changing `modelPath` will change module responsible for hand detection and tracking\n * Allowed values are 'posenet.json', 'blazepose.json', 'efficientpose.json', 'movenet-lightning.json', 'movenet-thunder.json', 'movenet-multipose.json'\n*/\nexport interface BodyConfig {\n enabled: boolean,\n modelPath: string,\n maxDetected: number,\n minConfidence: number,\n skipFrames: number,\n}\n\n/** Controlls and configures all hand detection specific options\n *\n * Parameters:\n * - enabled: true/false\n * - landmarks: detect hand landmarks or just hand boundary box\n * - modelPath: paths for hand detector and hand skeleton models, can be absolute path or relative to modelBasePath\n * - minConfidence: threshold for discarding a prediction\n * - iouThreshold: ammount of overlap between two detected objects before one object is removed\n * - maxDetected: maximum number of hands detected in the input, should be set to the minimum number for performance\n * - rotation: use best-guess rotated hand image or just box with rotation as-is, false means higher performance, but incorrect finger mapping if hand is inverted\n *\n * Changing `detector.modelPath` will change module responsible for hand detection and tracking\n * Allowed values are `handdetect.json` and `handtrack.json`\n*/\nexport interface HandConfig {\n enabled: boolean,\n rotation: boolean,\n skipFrames: number,\n minConfidence: number,\n iouThreshold: number,\n maxDetected: number,\n landmarks: boolean,\n detector: {\n modelPath?: string,\n },\n skeleton: {\n modelPath?: string,\n },\n}\n\n/** Controlls and configures all object detection specific options\n * - enabled: true/false\n * - modelPath: object detection model, can be absolute path or relative to modelBasePath\n * - minConfidence: minimum score that detection must have to return as valid object\n * - iouThreshold: ammount of overlap between two detected objects before one object is removed\n * - maxDetected: maximum number of detections to return\n *\n * Changing `modelPath` will change module responsible for hand detection and tracking\n * Allowed values are `mb3-centernet.json` and `nanodet.json`\n*/\nexport interface ObjectConfig {\n enabled: boolean,\n modelPath: string,\n minConfidence: number,\n iouThreshold: number,\n maxDetected: number,\n skipFrames: number,\n}\n\n/** Controlls and configures all body segmentation module\n * removes background from input containing person\n * if segmentation is enabled it will run as preprocessing task before any other model\n * alternatively leave it disabled and use it on-demand using human.segmentation method which can\n * remove background or replace it with user-provided background\n *\n * - enabled: true/false\n * - modelPath: object detection model, can be absolute path or relative to modelBasePath\n * - blur: blur segmentation output by pixels for more realistic image\n *\n * Changing `modelPath` will change module responsible for hand detection and tracking\n * Allowed values are `selfie.json` and `meet.json`\n\n*/\nexport interface SegmentationConfig {\n enabled: boolean,\n modelPath: string,\n blur: number,\n}\n\n/** Run input through image filters before inference\n * - available only in Browser environments\n * - image filters run with near-zero latency as they are executed on the GPU using WebGL\n*/\nexport interface FilterConfig {\n enabled: boolean,\n /** Resize input width\n * - if both width and height are set to 0, there is no resizing\n * - if just one is set, second one is scaled automatically\n * - if both are set, values are used as-is\n */\n width: number,\n /** Resize input height\n * - if both width and height are set to 0, there is no resizing\n * - if just one is set, second one is scaled automatically\n * - if both are set, values are used as-is\n */\n height: number,\n /** Return processed canvas imagedata in result */\n return: boolean,\n /** Flip input as mirror image */\n flip: boolean,\n /** Range: -1 (darken) to 1 (lighten) */\n brightness: number,\n /** Range: -1 (reduce contrast) to 1 (increase contrast) */\n contrast: number,\n /** Range: 0 (no sharpening) to 1 (maximum sharpening) */\n sharpness: number,\n /** Range: 0 (no blur) to N (blur radius in pixels) */\n blur: number\n /** Range: -1 (reduce saturation) to 1 (increase saturation) */\n saturation: number,\n /** Range: 0 (no change) to 360 (hue rotation in degrees) */\n hue: number,\n /** Image negative */\n negative: boolean,\n /** Image sepia colors */\n sepia: boolean,\n /** Image vintage colors */\n vintage: boolean,\n /** Image kodachrome colors */\n kodachrome: boolean,\n /** Image technicolor colors */\n technicolor: boolean,\n /** Image polaroid camera effect */\n polaroid: boolean,\n /** Range: 0 (no pixelate) to N (number of pixels to pixelate) */\n pixelate: number,\n}\n\n/** Controlls gesture detection */\nexport interface GestureConfig {\n enabled: boolean,\n}\n\n/**\n * Configuration interface definition for **Human** library\n *\n * Contains all configurable parameters\n * @typedef Config\n */\nexport interface Config {\n /** Backend used for TFJS operations */\n backend: '' | 'cpu' | 'wasm' | 'webgl' | 'humangl' | 'tensorflow' | 'webgpu',\n // backend: string;\n\n /** Path to *.wasm files if backend is set to `wasm` */\n wasmPath: string,\n\n /** Print debug statements to console */\n debug: boolean,\n\n /** Perform model loading and inference concurrently or sequentially */\n async: boolean,\n\n /** What to use for `human.warmup()`\n * - warmup pre-initializes all models for faster inference but can take significant time on startup\n */\n warmup: 'none' | 'face' | 'full' | 'body',\n // warmup: string;\n\n /** Base model path (typically starting with file://, http:// or https://) for all models\n * - individual modelPath values are relative to this path\n */\n modelBasePath: string,\n\n /** Cache sensitivity\n * - values 0..1 where 0.01 means reset cache if input changed more than 1%\n * - set to 0 to disable caching\n */\n cacheSensitivity: number;\n\n /** Internal Variable */\n skipFrame: boolean;\n\n /** Run input through image filters before inference\n * - image filters run with near-zero latency as they are executed on the GPU\n */\n filter: Partial,\n // type definition end\n\n gesture: Partial;\n\n face: Partial,\n\n body: Partial,\n\n hand: Partial,\n\n object: Partial,\n\n segmentation: Partial,\n}\n\n/**\n * [See all default Config values...](https://github.com/vladmandic/human/blob/main/src/config.ts#L244)\n *\n */\nconst config: Config = {\n backend: '', // select tfjs backend to use, leave empty to use default backend\n // for browser environments: 'webgl', 'wasm', 'cpu', or 'humangl' (which is a custom version of webgl)\n // for nodejs environments: 'tensorflow', 'wasm', 'cpu'\n // default set to `humangl` for browsers and `tensorflow` for nodejs\n modelBasePath: '', // base path for all models\n // default set to `../models/` for browsers and `file://models/` for nodejs\n wasmPath: '', // path for wasm binaries, only used for backend: wasm\n // default set to download from jsdeliv during Human class instantiation\n debug: true, // print additional status messages to console\n async: true, // execute enabled models in parallel\n warmup: 'full', // what to use for human.warmup(), can be 'none', 'face', 'full'\n // warmup pre-initializes all models for faster inference but can take\n // significant time on startup\n // only used for `webgl` and `humangl` backends\n cacheSensitivity: 0.75, // cache sensitivity\n // values 0..1 where 0.01 means reset cache if input changed more than 1%\n // set to 0 to disable caching\n skipFrame: false, // internal & dynamic\n filter: { // run input through image filters before inference\n // image filters run with near-zero latency as they are executed on the GPU\n enabled: true, // enable image pre-processing filters\n width: 0, // resize input width\n height: 0, // resize input height\n // if both width and height are set to 0, there is no resizing\n // if just one is set, second one is scaled automatically\n // if both are set, values are used as-is\n flip: false, // flip input as mirror image\n return: true, // return processed canvas imagedata in result\n brightness: 0, // range: -1 (darken) to 1 (lighten)\n contrast: 0, // range: -1 (reduce contrast) to 1 (increase contrast)\n sharpness: 0, // range: 0 (no sharpening) to 1 (maximum sharpening)\n blur: 0, // range: 0 (no blur) to N (blur radius in pixels)\n saturation: 0, // range: -1 (reduce saturation) to 1 (increase saturation)\n hue: 0, // range: 0 (no change) to 360 (hue rotation in degrees)\n negative: false, // image negative\n sepia: false, // image sepia colors\n vintage: false, // image vintage colors\n kodachrome: false, // image kodachrome colors\n technicolor: false, // image technicolor colors\n polaroid: false, // image polaroid camera effect\n pixelate: 0, // range: 0 (no pixelate) to N (number of pixels to pixelate)\n },\n\n gesture: {\n enabled: true, // enable gesture recognition based on model results\n },\n\n face: {\n enabled: true, // controls if specified modul is enabled\n // face.enabled is required for all face models:\n // detector, mesh, iris, age, gender, emotion\n // (note: module is not loaded until it is required)\n detector: {\n modelPath: 'blazeface.json', // detector model, can be absolute path or relative to modelBasePath\n rotation: true, // use best-guess rotated face image or just box with rotation as-is\n // false means higher performance, but incorrect mesh mapping if face angle is above 20 degrees\n // this parameter is not valid in nodejs\n maxDetected: 15, // maximum number of faces detected in the input\n // should be set to the minimum number for performance\n skipFrames: 15, // how many max frames to go without re-running the face bounding box detector\n // only used when cacheSensitivity is not zero\n // e.g., if model is running st 25 FPS, we can re-use existing bounding\n // box for updated face analysis as the head probably hasn't moved much\n // in short time (10 * 1/25 = 0.25 sec)\n minConfidence: 0.2, // threshold for discarding a prediction\n iouThreshold: 0.1, // ammount of overlap between two detected objects before one object is removed\n return: false, // return extracted face as tensor\n // in which case user is reponsible for disposing the tensor\n },\n\n mesh: {\n enabled: true,\n modelPath: 'facemesh.json', // facemesh model, can be absolute path or relative to modelBasePath\n },\n\n iris: {\n enabled: true,\n modelPath: 'iris.json', // face iris model\n // can be either absolute path or relative to modelBasePath\n },\n\n description: {\n enabled: true, // to improve accuracy of face description extraction it is\n // recommended to enable detector.rotation and mesh.enabled\n modelPath: 'faceres.json', // face description model\n // can be either absolute path or relative to modelBasePath\n skipFrames: 11, // how many max frames to go without re-running the detector\n // only used when cacheSensitivity is not zero\n minConfidence: 0.1, // threshold for discarding a prediction\n },\n\n emotion: {\n enabled: true,\n minConfidence: 0.1, // threshold for discarding a prediction\n skipFrames: 17, // how max many frames to go without re-running the detector\n // only used when cacheSensitivity is not zero\n modelPath: 'emotion.json', // face emotion model, can be absolute path or relative to modelBasePath\n },\n },\n\n body: {\n enabled: true,\n modelPath: 'movenet-lightning.json', // body model, can be absolute path or relative to modelBasePath\n // can be 'posenet', 'blazepose', 'efficientpose', 'movenet-lightning', 'movenet-thunder'\n maxDetected: 1, // maximum number of people detected in the input\n // should be set to the minimum number for performance\n // only valid for posenet as other models detects single pose\n minConfidence: 0.2, // threshold for discarding a prediction\n skipFrames: 1, // how many max frames to go without re-running the detector\n // only used when cacheSensitivity is not zero\n},\n\n hand: {\n enabled: true,\n rotation: true, // use best-guess rotated hand image or just box with rotation as-is\n // false means higher performance, but incorrect finger mapping if hand is inverted\n skipFrames: 18, // how many max frames to go without re-running the hand bounding box detector\n // only used when cacheSensitivity is not zero\n // e.g., if model is running st 25 FPS, we can re-use existing bounding\n // box for updated hand skeleton analysis as the hand probably\n // hasn't moved much in short time (10 * 1/25 = 0.25 sec)\n minConfidence: 0.8, // threshold for discarding a prediction\n iouThreshold: 0.2, // ammount of overlap between two detected objects before one object is removed\n maxDetected: 1, // maximum number of hands detected in the input\n // should be set to the minimum number for performance\n landmarks: true, // detect hand landmarks or just hand boundary box\n detector: {\n modelPath: 'handdetect.json', // hand detector model, can be absolute path or relative to modelBasePath\n // can be 'handdetect' or 'handtrack'\n },\n skeleton: {\n modelPath: 'handskeleton.json', // hand skeleton model, can be absolute path or relative to modelBasePath\n },\n },\n\n object: {\n enabled: false,\n modelPath: 'mb3-centernet.json', // experimental: object detection model, can be absolute path or relative to modelBasePath\n // can be 'mb3-centernet' or 'nanodet'\n minConfidence: 0.2, // threshold for discarding a prediction\n iouThreshold: 0.4, // ammount of overlap between two detected objects before one object is removed\n maxDetected: 10, // maximum number of objects detected in the input\n skipFrames: 19, // how many max frames to go without re-running the detector\n // only used when cacheSensitivity is not zero\n },\n\n segmentation: {\n enabled: false, // controlls and configures all body segmentation module\n // removes background from input containing person\n // if segmentation is enabled it will run as preprocessing task before any other model\n // alternatively leave it disabled and use it on-demand using human.segmentation method which can\n // remove background or replace it with user-provided background\n modelPath: 'selfie.json', // experimental: object detection model, can be absolute path or relative to modelBasePath\n // can be 'selfie' or 'meet'\n blur: 8, // blur segmentation output by n pixels for more realistic image\n },\n};\nexport { config as defaults };\n", "/*\n Human\n homepage: \n author: '\n*/\n\n// tfjs/tf-browser.ts\nexport * from \"@tensorflow/tfjs/dist/index.js\";\nexport * from \"@tensorflow/tfjs-backend-webgl/dist/index.js\";\nexport * from \"@tensorflow/tfjs-backend-wasm/dist/index.js\";\n\n// dist/tfjs.version.js\nvar version = \"3.9.0\";\nvar version2 = \"3.9.0\";\nvar version3 = \"3.9.0\";\nvar version4 = \"3.9.0\";\nvar version5 = \"3.9.0\";\nvar version6 = \"3.9.0\";\nvar version7 = \"3.9.0\";\nvar version8 = \"3.9.0\";\nvar version9 = {\n tfjs: version,\n \"tfjs-core\": version2,\n \"tfjs-data\": version3,\n \"tfjs-layers\": version4,\n \"tfjs-converter\": version5,\n \"tfjs-backend-cpu\": version6,\n \"tfjs-backend-webgl\": version7,\n \"tfjs-backend-wasm\": version8\n};\nexport {\n version9 as version\n};\n", "import * as tf from '../../dist/tfjs.esm.js';\n\nexport function scaleBoxCoordinates(box, factor) {\n const startPoint = [box.startPoint[0] * factor[0], box.startPoint[1] * factor[1]];\n const endPoint = [box.endPoint[0] * factor[0], box.endPoint[1] * factor[1]];\n return { startPoint, endPoint };\n}\n\nexport function getBoxSize(box): [number, number] {\n return [\n Math.abs(box.endPoint[0] - box.startPoint[0]),\n Math.abs(box.endPoint[1] - box.startPoint[1]),\n ];\n}\n\nexport function getBoxCenter(box): [number, number] {\n return [\n box.startPoint[0] + (box.endPoint[0] - box.startPoint[0]) / 2,\n box.startPoint[1] + (box.endPoint[1] - box.startPoint[1]) / 2,\n ];\n}\n\nexport function cutBoxFromImageAndResize(box, image, cropSize) {\n const h = image.shape[1];\n const w = image.shape[2];\n const boxes = [[\n box.startPoint[1] / h,\n box.startPoint[0] / w,\n box.endPoint[1] / h,\n box.endPoint[0] / w,\n ]];\n return tf.image.cropAndResize(image, boxes, [0], cropSize);\n}\n\nexport function enlargeBox(box, factor = 1.5) {\n const center = getBoxCenter(box);\n const size = getBoxSize(box);\n const newHalfSize: [number, number] = [factor * size[0] / 2, factor * size[1] / 2];\n const startPoint = [center[0] - newHalfSize[0], center[1] - newHalfSize[1]];\n const endPoint = [center[0] + newHalfSize[0], center[1] + newHalfSize[1]];\n return { startPoint, endPoint, landmarks: box.landmarks };\n}\n\nexport function squarifyBox(box) {\n const centers = getBoxCenter(box);\n const size = getBoxSize(box);\n const maxEdge = Math.max(...size);\n const halfSize = maxEdge / 2;\n const startPoint = [Math.round(centers[0] - halfSize), Math.round(centers[1] - halfSize)];\n const endPoint = [Math.round(centers[0] + halfSize), Math.round(centers[1] + halfSize)];\n return { startPoint, endPoint, landmarks: box.landmarks };\n}\n\nexport function calculateLandmarksBoundingBox(landmarks) {\n const xs = landmarks.map((d) => d[0]);\n const ys = landmarks.map((d) => d[1]);\n const startPoint = [Math.min(...xs), Math.min(...ys)];\n const endPoint = [Math.max(...xs), Math.max(...ys)];\n return { startPoint, endPoint, landmarks };\n}\n\nexport const disposeBox = (t) => {\n tf.dispose(t.startPoint);\n tf.dispose(t.endPoint);\n};\n\nexport const createBox = (startEndTensor) => ({\n startPoint: tf.slice(startEndTensor, [0, 0], [-1, 2]),\n endPoint: tf.slice(startEndTensor, [0, 2], [-1, 2]),\n});\n", "export const IDENTITY_MATRIX = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];\n/**\n * Normalizes the provided angle to the range -pi to pi.\n * @param angle The angle in radians to be normalized.\n */\nexport function normalizeRadians(angle) {\n return angle - 2 * Math.PI * Math.floor((angle + Math.PI) / (2 * Math.PI));\n}\n\n/**\n * Computes the angle of rotation between two anchor points.\n * @param point1 First anchor point\n * @param point2 Second anchor point\n */\nexport function computeRotation(point1, point2) {\n const radians = Math.PI / 2 - Math.atan2(-(point2[1] - point1[1]), point2[0] - point1[0]);\n return normalizeRadians(radians);\n}\n\nexport function radToDegrees(rad) {\n return rad * 180 / Math.PI;\n}\n\nexport function buildTranslationMatrix(x, y) {\n return [[1, 0, x], [0, 1, y], [0, 0, 1]];\n}\n\nexport function dot(v1, v2) {\n let product = 0;\n for (let i = 0; i < v1.length; i++) {\n product += v1[i] * v2[i];\n }\n return product;\n}\n\nexport function getColumnFrom2DArr(arr, columnIndex) {\n const column: Array = [];\n for (let i = 0; i < arr.length; i++) {\n column.push(arr[i][columnIndex]);\n }\n return column;\n}\n\nexport function multiplyTransformMatrices(mat1, mat2) {\n const product: Array = [];\n const size = mat1.length;\n for (let row = 0; row < size; row++) {\n product.push([]);\n for (let col = 0; col < size; col++) {\n product[row].push(dot(mat1[row], getColumnFrom2DArr(mat2, col)));\n }\n }\n return product;\n}\n\nexport function buildRotationMatrix(rotation, center) {\n const cosA = Math.cos(rotation);\n const sinA = Math.sin(rotation);\n const rotationMatrix = [[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]];\n const translationMatrix = buildTranslationMatrix(center[0], center[1]);\n const translationTimesRotation = multiplyTransformMatrices(translationMatrix, rotationMatrix);\n const negativeTranslationMatrix = buildTranslationMatrix(-center[0], -center[1]);\n return multiplyTransformMatrices(translationTimesRotation, negativeTranslationMatrix);\n}\n\nexport function invertTransformMatrix(matrix) {\n const rotationComponent = [[matrix[0][0], matrix[1][0]], [matrix[0][1], matrix[1][1]]];\n const translationComponent = [matrix[0][2], matrix[1][2]];\n const invertedTranslation = [\n -dot(rotationComponent[0], translationComponent),\n -dot(rotationComponent[1], translationComponent),\n ];\n return [\n rotationComponent[0].concat(invertedTranslation[0]),\n rotationComponent[1].concat(invertedTranslation[1]),\n [0, 0, 1],\n ];\n}\n\nexport function rotatePoint(homogeneousCoordinate, rotationMatrix) {\n return [\n dot(homogeneousCoordinate, rotationMatrix[0]),\n dot(homogeneousCoordinate, rotationMatrix[1]),\n ];\n}\n\nexport function xyDistanceBetweenPoints(a, b) {\n return Math.sqrt(((a[0] - b[0]) ** 2) + ((a[1] - b[1]) ** 2));\n}\n\nexport function generateAnchors(inputSize) {\n const spec = { strides: [inputSize / 16, inputSize / 8], anchors: [2, 6] };\n const anchors: Array<[number, number]> = [];\n for (let i = 0; i < spec.strides.length; i++) {\n const stride = spec.strides[i];\n const gridRows = Math.floor((inputSize + stride - 1) / stride);\n const gridCols = Math.floor((inputSize + stride - 1) / stride);\n const anchorsNum = spec.anchors[i];\n for (let gridY = 0; gridY < gridRows; gridY++) {\n const anchorY = stride * (gridY + 0.5);\n for (let gridX = 0; gridX < gridCols; gridX++) {\n const anchorX = stride * (gridX + 0.5);\n for (let n = 0; n < anchorsNum; n++) {\n anchors.push([anchorX, anchorY]);\n }\n }\n }\n }\n return anchors;\n}\n", "import { log, join, mergeDeep } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as box from './box';\nimport * as util from './util';\nimport type { Config } from '../config';\nimport type { Tensor, GraphModel } from '../tfjs/types';\n\nconst keypointsCount = 6;\n\nfunction decodeBounds(boxOutputs, anchors, inputSize) {\n const boxStarts = tf.slice(boxOutputs, [0, 1], [-1, 2]);\n const centers = tf.add(boxStarts, anchors);\n const boxSizes = tf.slice(boxOutputs, [0, 3], [-1, 2]);\n const boxSizesNormalized = tf.div(boxSizes, inputSize);\n const centersNormalized = tf.div(centers, inputSize);\n const halfBoxSize = tf.div(boxSizesNormalized, 2);\n const starts = tf.sub(centersNormalized, halfBoxSize);\n const ends = tf.add(centersNormalized, halfBoxSize);\n const startNormalized = tf.mul(starts, inputSize);\n const endNormalized = tf.mul(ends, inputSize);\n const concatAxis = 1;\n return tf.concat2d([startNormalized, endNormalized], concatAxis);\n}\n\nexport class BlazeFaceModel {\n model: GraphModel;\n anchorsData: [number, number][];\n anchors: Tensor;\n inputSize: number;\n config: Config;\n\n constructor(model, config: Config) {\n this.model = model;\n this.anchorsData = util.generateAnchors(model.inputs[0].shape[1]);\n this.anchors = tf.tensor2d(this.anchorsData);\n this.inputSize = model.inputs[0].shape[2];\n this.config = config;\n }\n\n async getBoundingBoxes(inputImage: Tensor, userConfig: Config) {\n // sanity check on input\n if ((!inputImage) || (inputImage['isDisposedInternal']) || (inputImage.shape.length !== 4) || (inputImage.shape[1] < 1) || (inputImage.shape[2] < 1)) return { boxes: [] };\n const [batch, boxes, scores] = tf.tidy(() => {\n const resizedImage = tf.image.resizeBilinear(inputImage, [this.inputSize, this.inputSize]);\n const normalizedImage = tf.sub(tf.div(resizedImage, 127.5), 0.5);\n const res = this.model.execute(normalizedImage);\n let batchOut;\n if (Array.isArray(res)) { // are we using tfhub or pinto converted model?\n const sorted = res.sort((a, b) => a.size - b.size);\n const concat384 = tf.concat([sorted[0], sorted[2]], 2); // dim: 384, 1 + 16\n const concat512 = tf.concat([sorted[1], sorted[3]], 2); // dim: 512, 1 + 16\n const concat = tf.concat([concat512, concat384], 1);\n batchOut = tf.squeeze(concat, 0);\n } else {\n batchOut = tf.squeeze(res); // when using tfhub model\n }\n const boxesOut = decodeBounds(batchOut, this.anchors, [this.inputSize, this.inputSize]);\n const logits = tf.slice(batchOut, [0, 0], [-1, 1]);\n const scoresOut = tf.squeeze(tf.sigmoid(logits)); // inside tf.tidy\n return [batchOut, boxesOut, scoresOut];\n });\n\n this.config = mergeDeep(this.config, userConfig) as Config;\n\n const nmsTensor = await tf.image.nonMaxSuppressionAsync(boxes, scores, (this.config.face.detector?.maxDetected || 0), (this.config.face.detector?.iouThreshold || 0), (this.config.face.detector?.minConfidence || 0));\n const nms = await nmsTensor.array();\n tf.dispose(nmsTensor);\n const annotatedBoxes: Array<{ box: { startPoint: Tensor, endPoint: Tensor }, landmarks: Tensor, anchor: [number, number] | undefined, confidence: number }> = [];\n const scoresData = await scores.data();\n for (let i = 0; i < nms.length; i++) {\n const confidence = scoresData[nms[i]];\n if (confidence > (this.config.face.detector?.minConfidence || 0)) {\n const boundingBox = tf.slice(boxes, [nms[i], 0], [1, -1]);\n const landmarks = tf.tidy(() => tf.reshape(tf.squeeze(tf.slice(batch, [nms[i], keypointsCount - 1], [1, -1])), [keypointsCount, -1]));\n annotatedBoxes.push({ box: box.createBox(boundingBox), landmarks, anchor: this.anchorsData[nms[i]], confidence });\n tf.dispose(boundingBox);\n }\n }\n tf.dispose(batch);\n tf.dispose(boxes);\n tf.dispose(scores);\n\n return {\n boxes: annotatedBoxes,\n scaleFactor: [inputImage.shape[2] / this.inputSize, inputImage.shape[1] / this.inputSize],\n };\n }\n}\n\nexport async function load(config: Config) {\n const model = await tf.loadGraphModel(join(config.modelBasePath, config.face.detector?.modelPath || ''), { fromTFHub: (config.face.detector?.modelPath || '').includes('tfhub.dev') });\n const blazeFace = new BlazeFaceModel(model, config);\n if (!model || !model.modelUrl) log('load model failed:', config.face.detector?.modelPath || '');\n else if (config.debug) log('load model:', model.modelUrl);\n return blazeFace;\n}\n", "export const MESH_ANNOTATIONS = {\n silhouette: [\n 10, 338, 297, 332, 284, 251, 389, 356, 454, 323, 361, 288,\n 397, 365, 379, 378, 400, 377, 152, 148, 176, 149, 150, 136,\n 172, 58, 132, 93, 234, 127, 162, 21, 54, 103, 67, 109,\n ],\n lipsUpperOuter: [61, 185, 40, 39, 37, 0, 267, 269, 270, 409, 291],\n lipsLowerOuter: [146, 91, 181, 84, 17, 314, 405, 321, 375, 291],\n lipsUpperInner: [78, 191, 80, 81, 82, 13, 312, 311, 310, 415, 308],\n lipsLowerInner: [78, 95, 88, 178, 87, 14, 317, 402, 318, 324, 308],\n rightEyeUpper0: [246, 161, 160, 159, 158, 157, 173],\n rightEyeLower0: [33, 7, 163, 144, 145, 153, 154, 155, 133],\n rightEyeUpper1: [247, 30, 29, 27, 28, 56, 190],\n rightEyeLower1: [130, 25, 110, 24, 23, 22, 26, 112, 243],\n rightEyeUpper2: [113, 225, 224, 223, 222, 221, 189],\n rightEyeLower2: [226, 31, 228, 229, 230, 231, 232, 233, 244],\n rightEyeLower3: [143, 111, 117, 118, 119, 120, 121, 128, 245],\n rightEyebrowUpper: [156, 70, 63, 105, 66, 107, 55, 193],\n rightEyebrowLower: [35, 124, 46, 53, 52, 65],\n rightEyeIris: [473, 474, 475, 476, 477],\n leftEyeUpper0: [466, 388, 387, 386, 385, 384, 398],\n leftEyeLower0: [263, 249, 390, 373, 374, 380, 381, 382, 362],\n leftEyeUpper1: [467, 260, 259, 257, 258, 286, 414],\n leftEyeLower1: [359, 255, 339, 254, 253, 252, 256, 341, 463],\n leftEyeUpper2: [342, 445, 444, 443, 442, 441, 413],\n leftEyeLower2: [446, 261, 448, 449, 450, 451, 452, 453, 464],\n leftEyeLower3: [372, 340, 346, 347, 348, 349, 350, 357, 465],\n leftEyebrowUpper: [383, 300, 293, 334, 296, 336, 285, 417],\n leftEyebrowLower: [265, 353, 276, 283, 282, 295],\n leftEyeIris: [468, 469, 470, 471, 472],\n midwayBetweenEyes: [168],\n noseTip: [1],\n noseBottom: [2],\n noseRightCorner: [98],\n noseLeftCorner: [327],\n rightCheek: [205],\n leftCheek: [425],\n};\n\nexport const MESH_TO_IRIS_INDICES_MAP = [ // A mapping from facemesh model keypoints to iris model keypoints.\n { key: 'EyeUpper0', indices: [9, 10, 11, 12, 13, 14, 15] },\n { key: 'EyeUpper1', indices: [25, 26, 27, 28, 29, 30, 31] },\n { key: 'EyeUpper2', indices: [41, 42, 43, 44, 45, 46, 47] },\n { key: 'EyeLower0', indices: [0, 1, 2, 3, 4, 5, 6, 7, 8] },\n { key: 'EyeLower1', indices: [16, 17, 18, 19, 20, 21, 22, 23, 24] },\n { key: 'EyeLower2', indices: [32, 33, 34, 35, 36, 37, 38, 39, 40] },\n { key: 'EyeLower3', indices: [54, 55, 56, 57, 58, 59, 60, 61, 62] },\n // { key: 'EyebrowUpper', indices: [63, 64, 65, 66, 67, 68, 69, 70] },\n // { key: 'EyebrowLower', indices: [48, 49, 50, 51, 52, 53] },\n];\n\nexport const UV468 = [\n [0.499976992607117, 0.652534008026123],\n [0.500025987625122, 0.547487020492554],\n [0.499974012374878, 0.602371990680695],\n [0.482113003730774, 0.471979022026062],\n [0.500150978565216, 0.527155995368958],\n [0.499909996986389, 0.498252987861633],\n [0.499523013830185, 0.40106201171875],\n [0.289712011814117, 0.380764007568359],\n [0.499954998493195, 0.312398016452789],\n [0.499987006187439, 0.269918978214264],\n [0.500023007392883, 0.107050001621246],\n [0.500023007392883, 0.666234016418457],\n [0.5000159740448, 0.679224014282227],\n [0.500023007392883, 0.692348003387451],\n [0.499976992607117, 0.695277988910675],\n [0.499976992607117, 0.70593398809433],\n [0.499976992607117, 0.719385027885437],\n [0.499976992607117, 0.737019002437592],\n [0.499967992305756, 0.781370997428894],\n [0.499816000461578, 0.562981009483337],\n [0.473773002624512, 0.573909997940063],\n [0.104906998574734, 0.254140973091125],\n [0.365929991006851, 0.409575998783112],\n [0.338757991790771, 0.41302502155304],\n [0.311120003461838, 0.409460008144379],\n [0.274657994508743, 0.389131009578705],\n [0.393361985683441, 0.403706014156342],\n [0.345234006643295, 0.344011008739471],\n [0.370094001293182, 0.346076011657715],\n [0.319321990013123, 0.347265005111694],\n [0.297903001308441, 0.353591024875641],\n [0.24779200553894, 0.410809993743896],\n [0.396889001131058, 0.842755019664764],\n [0.280097991228104, 0.375599980354309],\n [0.106310002505779, 0.399955987930298],\n [0.2099249958992, 0.391353011131287],\n [0.355807989835739, 0.534406006336212],\n [0.471751004457474, 0.65040397644043],\n [0.474155008792877, 0.680191993713379],\n [0.439785003662109, 0.657229006290436],\n [0.414617002010345, 0.66654098033905],\n [0.450374007225037, 0.680860996246338],\n [0.428770989179611, 0.682690978050232],\n [0.374971002340317, 0.727805018424988],\n [0.486716985702515, 0.547628998756409],\n [0.485300987958908, 0.527395009994507],\n [0.257764995098114, 0.314490020275116],\n [0.401223003864288, 0.455172002315521],\n [0.429818987846375, 0.548614978790283],\n [0.421351999044418, 0.533740997314453],\n [0.276895999908447, 0.532056987285614],\n [0.483370006084442, 0.499586999416351],\n [0.33721199631691, 0.282882988452911],\n [0.296391993761063, 0.293242990970612],\n [0.169294998049736, 0.193813979625702],\n [0.447580009698868, 0.302609980106354],\n [0.392390012741089, 0.353887975215912],\n [0.354490011930466, 0.696784019470215],\n [0.067304998636246, 0.730105042457581],\n [0.442739009857178, 0.572826027870178],\n [0.457098007202148, 0.584792017936707],\n [0.381974011659622, 0.694710969924927],\n [0.392388999462128, 0.694203019142151],\n [0.277076005935669, 0.271932005882263],\n [0.422551989555359, 0.563233017921448],\n [0.385919004678726, 0.281364023685455],\n [0.383103013038635, 0.255840003490448],\n [0.331431001424789, 0.119714021682739],\n [0.229923993349075, 0.232002973556519],\n [0.364500999450684, 0.189113974571228],\n [0.229622006416321, 0.299540996551514],\n [0.173287004232407, 0.278747975826263],\n [0.472878992557526, 0.666198015213013],\n [0.446828007698059, 0.668527007102966],\n [0.422762006521225, 0.673889994621277],\n [0.445307999849319, 0.580065965652466],\n [0.388103008270264, 0.693961024284363],\n [0.403039008378983, 0.706539988517761],\n [0.403629004955292, 0.693953037261963],\n [0.460041999816895, 0.557139039039612],\n [0.431158006191254, 0.692366003990173],\n [0.452181994915009, 0.692366003990173],\n [0.475387006998062, 0.692366003990173],\n [0.465828001499176, 0.779190003871918],\n [0.472328990697861, 0.736225962638855],\n [0.473087012767792, 0.717857003211975],\n [0.473122000694275, 0.704625964164734],\n [0.473033010959625, 0.695277988910675],\n [0.427942007780075, 0.695277988910675],\n [0.426479011774063, 0.703539967536926],\n [0.423162013292313, 0.711845993995667],\n [0.4183090031147, 0.720062971115112],\n [0.390094995498657, 0.639572978019714],\n [0.013953999616206, 0.560034036636353],\n [0.499913990497589, 0.58014702796936],\n [0.413199990987778, 0.69539999961853],\n [0.409626007080078, 0.701822996139526],\n [0.468080013990402, 0.601534962654114],\n [0.422728985548019, 0.585985004901886],\n [0.463079988956451, 0.593783974647522],\n [0.37211999297142, 0.47341400384903],\n [0.334562003612518, 0.496073007583618],\n [0.411671012639999, 0.546965003013611],\n [0.242175996303558, 0.14767599105835],\n [0.290776997804642, 0.201445996761322],\n [0.327338010072708, 0.256527006626129],\n [0.399509996175766, 0.748921036720276],\n [0.441727995872498, 0.261676013469696],\n [0.429764986038208, 0.187834024429321],\n [0.412198007106781, 0.108901023864746],\n [0.288955003023148, 0.398952007293701],\n [0.218936994671822, 0.435410976409912],\n [0.41278201341629, 0.398970007896423],\n [0.257135003805161, 0.355440020561218],\n [0.427684992551804, 0.437960982322693],\n [0.448339998722076, 0.536936044692993],\n [0.178560003638268, 0.45755398273468],\n [0.247308000922203, 0.457193970680237],\n [0.286267012357712, 0.467674970626831],\n [0.332827985286713, 0.460712015628815],\n [0.368755996227264, 0.447206974029541],\n [0.398963987827301, 0.432654976844788],\n [0.476410001516342, 0.405806005001068],\n [0.189241006970406, 0.523923993110657],\n [0.228962004184723, 0.348950982093811],\n [0.490725994110107, 0.562400996685028],\n [0.404670000076294, 0.485132992267609],\n [0.019469000399113, 0.401564002037048],\n [0.426243007183075, 0.420431017875671],\n [0.396993011236191, 0.548797011375427],\n [0.266469985246658, 0.376977026462555],\n [0.439121007919312, 0.51895797252655],\n [0.032313998788595, 0.644356966018677],\n [0.419054001569748, 0.387154996395111],\n [0.462783008813858, 0.505746960639954],\n [0.238978996872902, 0.779744982719421],\n [0.198220998048782, 0.831938028335571],\n [0.107550002634525, 0.540755033493042],\n [0.183610007166862, 0.740257024765015],\n [0.134409993886948, 0.333683013916016],\n [0.385764002799988, 0.883153975009918],\n [0.490967005491257, 0.579378008842468],\n [0.382384985685349, 0.508572995662689],\n [0.174399003386497, 0.397670984268188],\n [0.318785011768341, 0.39623498916626],\n [0.343364000320435, 0.400596976280212],\n [0.396100014448166, 0.710216999053955],\n [0.187885001301765, 0.588537991046906],\n [0.430987000465393, 0.944064974784851],\n [0.318993002176285, 0.898285031318665],\n [0.266247987747192, 0.869701027870178],\n [0.500023007392883, 0.190576016902924],\n [0.499976992607117, 0.954452991485596],\n [0.366169989109039, 0.398822009563446],\n [0.393207013607025, 0.39553701877594],\n [0.410373002290726, 0.391080021858215],\n [0.194993004202843, 0.342101991176605],\n [0.388664990663528, 0.362284004688263],\n [0.365961998701096, 0.355970978736877],\n [0.343364000320435, 0.355356991291046],\n [0.318785011768341, 0.35834002494812],\n [0.301414996385574, 0.363156020641327],\n [0.058132998645306, 0.319076001644135],\n [0.301414996385574, 0.387449026107788],\n [0.499987989664078, 0.618434011936188],\n [0.415838003158569, 0.624195992946625],\n [0.445681989192963, 0.566076993942261],\n [0.465844005346298, 0.620640993118286],\n [0.49992299079895, 0.351523995399475],\n [0.288718998432159, 0.819945991039276],\n [0.335278987884521, 0.852819979190826],\n [0.440512001514435, 0.902418971061707],\n [0.128294005990028, 0.791940987110138],\n [0.408771991729736, 0.373893976211548],\n [0.455606997013092, 0.451801002025604],\n [0.499877005815506, 0.908990025520325],\n [0.375436991453171, 0.924192011356354],\n [0.11421000212431, 0.615022003650665],\n [0.448662012815475, 0.695277988910675],\n [0.4480200111866, 0.704632043838501],\n [0.447111994028091, 0.715808033943176],\n [0.444831997156143, 0.730794012546539],\n [0.430011987686157, 0.766808986663818],\n [0.406787008047104, 0.685672998428345],\n [0.400738000869751, 0.681069016456604],\n [0.392399996519089, 0.677703022956848],\n [0.367855995893478, 0.663918972015381],\n [0.247923001646996, 0.601333022117615],\n [0.452769994735718, 0.420849978923798],\n [0.43639200925827, 0.359887003898621],\n [0.416164010763168, 0.368713974952698],\n [0.413385987281799, 0.692366003990173],\n [0.228018000721931, 0.683571994304657],\n [0.468268007040024, 0.352671027183533],\n [0.411361992359161, 0.804327011108398],\n [0.499989002943039, 0.469825029373169],\n [0.479153990745544, 0.442654013633728],\n [0.499974012374878, 0.439637005329132],\n [0.432112008333206, 0.493588984012604],\n [0.499886006116867, 0.866917014122009],\n [0.49991300702095, 0.821729004383087],\n [0.456548988819122, 0.819200992584229],\n [0.344549000263214, 0.745438992977142],\n [0.37890899181366, 0.574010014533997],\n [0.374292999505997, 0.780184984207153],\n [0.319687992334366, 0.570737957954407],\n [0.357154995203018, 0.604269981384277],\n [0.295284003019333, 0.621580958366394],\n [0.447750002145767, 0.862477004528046],\n [0.410986006259918, 0.508723020553589],\n [0.31395098567009, 0.775308012962341],\n [0.354128003120422, 0.812552988529205],\n [0.324548006057739, 0.703992962837219],\n [0.189096003770828, 0.646299958229065],\n [0.279776990413666, 0.71465802192688],\n [0.1338230073452, 0.682700991630554],\n [0.336768001317978, 0.644733011722565],\n [0.429883986711502, 0.466521978378296],\n [0.455527991056442, 0.548622965812683],\n [0.437114000320435, 0.558896005153656],\n [0.467287987470627, 0.529924988746643],\n [0.414712011814117, 0.335219979286194],\n [0.37704598903656, 0.322777986526489],\n [0.344107985496521, 0.320150971412659],\n [0.312875986099243, 0.32233202457428],\n [0.283526003360748, 0.333190023899078],\n [0.241245999932289, 0.382785975933075],\n [0.102986000478268, 0.468762993812561],\n [0.267612010240555, 0.424560010433197],\n [0.297879010438919, 0.433175981044769],\n [0.333433985710144, 0.433878004550934],\n [0.366427004337311, 0.426115989685059],\n [0.396012008190155, 0.416696012020111],\n [0.420121014118195, 0.41022801399231],\n [0.007561000064015, 0.480777025222778],\n [0.432949006557465, 0.569517970085144],\n [0.458638995885849, 0.479089021682739],\n [0.473466008901596, 0.545744001865387],\n [0.476087987422943, 0.563830018043518],\n [0.468472003936768, 0.555056989192963],\n [0.433990985155106, 0.582361996173859],\n [0.483518004417419, 0.562983989715576],\n [0.482482999563217, 0.57784903049469],\n [0.42645001411438, 0.389798998832703],\n [0.438998997211456, 0.39649498462677],\n [0.450067013502121, 0.400434017181396],\n [0.289712011814117, 0.368252992630005],\n [0.276670008897781, 0.363372981548309],\n [0.517862021923065, 0.471948027610779],\n [0.710287988185883, 0.380764007568359],\n [0.526226997375488, 0.573909997940063],\n [0.895093023777008, 0.254140973091125],\n [0.634069979190826, 0.409575998783112],\n [0.661242008209229, 0.41302502155304],\n [0.688880026340485, 0.409460008144379],\n [0.725341975688934, 0.389131009578705],\n [0.606630027294159, 0.40370500087738],\n [0.654766023159027, 0.344011008739471],\n [0.629905998706818, 0.346076011657715],\n [0.680678009986877, 0.347265005111694],\n [0.702096998691559, 0.353591024875641],\n [0.75221198797226, 0.410804986953735],\n [0.602918028831482, 0.842862963676453],\n [0.719901978969574, 0.375599980354309],\n [0.893692970275879, 0.399959981441498],\n [0.790081977844238, 0.391354024410248],\n [0.643998026847839, 0.534487962722778],\n [0.528249025344849, 0.65040397644043],\n [0.525849997997284, 0.680191040039062],\n [0.560214996337891, 0.657229006290436],\n [0.585384011268616, 0.66654098033905],\n [0.549625992774963, 0.680860996246338],\n [0.57122802734375, 0.682691991329193],\n [0.624852001667023, 0.72809898853302],\n [0.513050019741058, 0.547281980514526],\n [0.51509702205658, 0.527251958847046],\n [0.742246985435486, 0.314507007598877],\n [0.598631024360657, 0.454979002475739],\n [0.570338010787964, 0.548575043678284],\n [0.578631997108459, 0.533622980117798],\n [0.723087012767792, 0.532054007053375],\n [0.516445994377136, 0.499638974666595],\n [0.662801027297974, 0.282917976379395],\n [0.70362401008606, 0.293271005153656],\n [0.830704987049103, 0.193813979625702],\n [0.552385985851288, 0.302568018436432],\n [0.607609987258911, 0.353887975215912],\n [0.645429015159607, 0.696707010269165],\n [0.932694971561432, 0.730105042457581],\n [0.557260990142822, 0.572826027870178],\n [0.542901992797852, 0.584792017936707],\n [0.6180260181427, 0.694710969924927],\n [0.607590973377228, 0.694203019142151],\n [0.722943007946014, 0.271963000297546],\n [0.577413976192474, 0.563166975975037],\n [0.614082992076874, 0.281386971473694],\n [0.616907000541687, 0.255886018276215],\n [0.668509006500244, 0.119913995265961],\n [0.770092010498047, 0.232020974159241],\n [0.635536015033722, 0.189248979091644],\n [0.77039098739624, 0.299556016921997],\n [0.826722025871277, 0.278755009174347],\n [0.527121007442474, 0.666198015213013],\n [0.553171992301941, 0.668527007102966],\n [0.577238023281097, 0.673889994621277],\n [0.554691970348358, 0.580065965652466],\n [0.611896991729736, 0.693961024284363],\n [0.59696102142334, 0.706539988517761],\n [0.596370995044708, 0.693953037261963],\n [0.539958000183105, 0.557139039039612],\n [0.568841993808746, 0.692366003990173],\n [0.547818005084991, 0.692366003990173],\n [0.52461302280426, 0.692366003990173],\n [0.534089982509613, 0.779141008853912],\n [0.527670979499817, 0.736225962638855],\n [0.526912987232208, 0.717857003211975],\n [0.526877999305725, 0.704625964164734],\n [0.526966989040375, 0.695277988910675],\n [0.572058022022247, 0.695277988910675],\n [0.573521018028259, 0.703539967536926],\n [0.57683801651001, 0.711845993995667],\n [0.581691026687622, 0.720062971115112],\n [0.609944999217987, 0.639909982681274],\n [0.986046016216278, 0.560034036636353],\n [0.5867999792099, 0.69539999961853],\n [0.590372025966644, 0.701822996139526],\n [0.531915009021759, 0.601536989212036],\n [0.577268004417419, 0.585934996604919],\n [0.536915004253387, 0.593786001205444],\n [0.627542972564697, 0.473352015018463],\n [0.665585994720459, 0.495950996875763],\n [0.588353991508484, 0.546862006187439],\n [0.757824003696442, 0.14767599105835],\n [0.709249973297119, 0.201507985591888],\n [0.672684013843536, 0.256581008434296],\n [0.600408971309662, 0.74900496006012],\n [0.55826598405838, 0.261672019958496],\n [0.570303976535797, 0.187870979309082],\n [0.588165998458862, 0.109044015407562],\n [0.711045026779175, 0.398952007293701],\n [0.781069993972778, 0.435405015945435],\n [0.587247014045715, 0.398931980133057],\n [0.742869973182678, 0.355445981025696],\n [0.572156012058258, 0.437651991844177],\n [0.55186802148819, 0.536570012569427],\n [0.821442008018494, 0.457556009292603],\n [0.752701997756958, 0.457181990146637],\n [0.71375697851181, 0.467626988887787],\n [0.66711300611496, 0.460672974586487],\n [0.631101012229919, 0.447153985500336],\n [0.6008620262146, 0.432473003864288],\n [0.523481011390686, 0.405627012252808],\n [0.810747981071472, 0.523926019668579],\n [0.771045982837677, 0.348959028720856],\n [0.509127020835876, 0.562718033790588],\n [0.595292985439301, 0.485023975372314],\n [0.980530977249146, 0.401564002037048],\n [0.573499977588654, 0.420000016689301],\n [0.602994978427887, 0.548687994480133],\n [0.733529984951019, 0.376977026462555],\n [0.560611009597778, 0.519016981124878],\n [0.967685997486115, 0.644356966018677],\n [0.580985009670258, 0.387160003185272],\n [0.537728011608124, 0.505385041236877],\n [0.760966002941132, 0.779752969741821],\n [0.801778972148895, 0.831938028335571],\n [0.892440974712372, 0.54076099395752],\n [0.816350996494293, 0.740260004997253],\n [0.865594983100891, 0.333687007427216],\n [0.614073991775513, 0.883246004581451],\n [0.508952975273132, 0.579437971115112],\n [0.617941975593567, 0.508316040039062],\n [0.825608015060425, 0.397674977779388],\n [0.681214988231659, 0.39623498916626],\n [0.656635999679565, 0.400596976280212],\n [0.603900015354156, 0.710216999053955],\n [0.81208598613739, 0.588539004325867],\n [0.56801301240921, 0.944564998149872],\n [0.681007981300354, 0.898285031318665],\n [0.733752012252808, 0.869701027870178],\n [0.633830010890961, 0.398822009563446],\n [0.606792986392975, 0.39553701877594],\n [0.589659988880157, 0.391062021255493],\n [0.805015981197357, 0.342108011245728],\n [0.611334979534149, 0.362284004688263],\n [0.634037971496582, 0.355970978736877],\n [0.656635999679565, 0.355356991291046],\n [0.681214988231659, 0.35834002494812],\n [0.698584973812103, 0.363156020641327],\n [0.941866993904114, 0.319076001644135],\n [0.698584973812103, 0.387449026107788],\n [0.584177017211914, 0.624107003211975],\n [0.554318010807037, 0.566076993942261],\n [0.534153997898102, 0.62064003944397],\n [0.711217999458313, 0.819975018501282],\n [0.664629995822906, 0.852871000766754],\n [0.559099972248077, 0.902631998062134],\n [0.871706008911133, 0.791940987110138],\n [0.591234028339386, 0.373893976211548],\n [0.544341027736664, 0.451583981513977],\n [0.624562978744507, 0.924192011356354],\n [0.88577002286911, 0.615028977394104],\n [0.551338016986847, 0.695277988910675],\n [0.551980018615723, 0.704632043838501],\n [0.552887976169586, 0.715808033943176],\n [0.555167973041534, 0.730794012546539],\n [0.569944024085999, 0.767035007476807],\n [0.593203008174896, 0.685675978660583],\n [0.599261999130249, 0.681069016456604],\n [0.607599973678589, 0.677703022956848],\n [0.631937980651855, 0.663500010967255],\n [0.752032995223999, 0.601315021514893],\n [0.547226011753082, 0.420395016670227],\n [0.563543975353241, 0.359827995300293],\n [0.583841025829315, 0.368713974952698],\n [0.586614012718201, 0.692366003990173],\n [0.771915018558502, 0.683578014373779],\n [0.531597018241882, 0.352482974529266],\n [0.588370978832245, 0.804440975189209],\n [0.52079701423645, 0.442565023899078],\n [0.567984998226166, 0.493479013442993],\n [0.543282985687256, 0.819254994392395],\n [0.655317008495331, 0.745514988899231],\n [0.621008992195129, 0.574018001556396],\n [0.625559985637665, 0.78031200170517],\n [0.680198013782501, 0.570719003677368],\n [0.64276397228241, 0.604337990283966],\n [0.704662978649139, 0.621529996395111],\n [0.552012026309967, 0.862591981887817],\n [0.589071989059448, 0.508637011051178],\n [0.685944974422455, 0.775357007980347],\n [0.645735025405884, 0.812640011310577],\n [0.675342977046967, 0.703978002071381],\n [0.810858011245728, 0.646304965019226],\n [0.72012197971344, 0.714666962623596],\n [0.866151988506317, 0.682704985141754],\n [0.663187026977539, 0.644596993923187],\n [0.570082008838654, 0.466325998306274],\n [0.544561982154846, 0.548375964164734],\n [0.562758982181549, 0.558784961700439],\n [0.531987011432648, 0.530140042304993],\n [0.585271000862122, 0.335177004337311],\n [0.622952997684479, 0.32277899980545],\n [0.655896008014679, 0.320163011550903],\n [0.687132000923157, 0.322345972061157],\n [0.716481983661652, 0.333200991153717],\n [0.758756995201111, 0.382786989212036],\n [0.897013008594513, 0.468769013881683],\n [0.732392013072968, 0.424547016620636],\n [0.70211398601532, 0.433162987232208],\n [0.66652500629425, 0.433866024017334],\n [0.633504986763, 0.426087975502014],\n [0.603875994682312, 0.416586995124817],\n [0.579657971858978, 0.409945011138916],\n [0.992439985275269, 0.480777025222778],\n [0.567192018032074, 0.569419980049133],\n [0.54136598110199, 0.478899002075195],\n [0.526564002037048, 0.546118021011353],\n [0.523913025856018, 0.563830018043518],\n [0.531529009342194, 0.555056989192963],\n [0.566035985946655, 0.582329034805298],\n [0.51631098985672, 0.563053965568542],\n [0.5174720287323, 0.577877044677734],\n [0.573594987392426, 0.389806985855103],\n [0.560697972774506, 0.395331978797913],\n [0.549755990505219, 0.399751007556915],\n [0.710287988185883, 0.368252992630005],\n [0.723330020904541, 0.363372981548309],\n];\n\nexport const TRI468 = [\n 127, 34, 139, 11, 0, 37, 232, 231, 120, 72, 37, 39, 128, 121, 47, 232, 121, 128, 104, 69, 67, 175, 171, 148, 157, 154, 155, 118, 50, 101, 73, 39, 40, 9,\n 151, 108, 48, 115, 131, 194, 204, 211, 74, 40, 185, 80, 42, 183, 40, 92, 186, 230, 229, 118, 202, 212, 214, 83, 18, 17, 76, 61, 146, 160, 29, 30, 56,\n 157, 173, 106, 204, 194, 135, 214, 192, 203, 165, 98, 21, 71, 68, 51, 45, 4, 144, 24, 23, 77, 146, 91, 205, 50, 187, 201, 200, 18, 91, 106, 182, 90, 91,\n 181, 85, 84, 17, 206, 203, 36, 148, 171, 140, 92, 40, 39, 193, 189, 244, 159, 158, 28, 247, 246, 161, 236, 3, 196, 54, 68, 104, 193, 168, 8, 117,\n 228, 31, 189, 193, 55, 98, 97, 99, 126, 47, 100, 166, 79, 218, 155, 154, 26, 209, 49, 131, 135, 136, 150, 47, 126, 217, 223, 52, 53, 45, 51, 134, 211,\n 170, 140, 67, 69, 108, 43, 106, 91, 230, 119, 120, 226, 130, 247, 63, 53, 52, 238, 20, 242, 46, 70, 156, 78, 62, 96, 46, 53, 63, 143, 34, 227, 173,\n 155, 133, 123, 117, 111, 44, 125, 19, 236, 134, 51, 216, 206, 205, 154, 153, 22, 39, 37, 167, 200, 201, 208, 36, 142, 100, 57, 212, 202, 20, 60, 99, 28,\n 158, 157, 35, 226, 113, 160, 159, 27, 204, 202, 210, 113, 225, 46, 43, 202, 204, 62, 76, 77, 137, 123, 116, 41, 38, 72, 203, 129, 142, 64, 98, 240, 49,\n 102, 64, 41, 73, 74, 212, 216, 207, 42, 74, 184, 169, 170, 211, 170, 149, 176, 105, 66, 69, 122, 6, 168, 123, 147, 187, 96, 77, 90, 65, 55, 107, 89,\n 90, 180, 101, 100, 120, 63, 105, 104, 93, 137, 227, 15, 86, 85, 129, 102, 49, 14, 87, 86, 55, 8, 9, 100, 47, 121, 145, 23, 22, 88, 89, 179, 6, 122,\n 196, 88, 95, 96, 138, 172, 136, 215, 58, 172, 115, 48, 219, 42, 80, 81, 195, 3, 51, 43, 146, 61, 171, 175, 199, 81, 82, 38, 53, 46, 225, 144, 163, 110,\n 246, 33, 7, 52, 65, 66, 229, 228, 117, 34, 127, 234, 107, 108, 69, 109, 108, 151, 48, 64, 235, 62, 78, 191, 129, 209, 126, 111, 35, 143, 163, 161, 246,\n 117, 123, 50, 222, 65, 52, 19, 125, 141, 221, 55, 65, 3, 195, 197, 25, 7, 33, 220, 237, 44, 70, 71, 139, 122, 193, 245, 247, 130, 33, 71, 21, 162,\n 153, 158, 159, 170, 169, 150, 188, 174, 196, 216, 186, 92, 144, 160, 161, 2, 97, 167, 141, 125, 241, 164, 167, 37, 72, 38, 12, 145, 159, 160, 38, 82, 13,\n 63, 68, 71, 226, 35, 111, 158, 153, 154, 101, 50, 205, 206, 92, 165, 209, 198, 217, 165, 167, 97, 220, 115, 218, 133, 112, 243, 239, 238, 241, 214,\n 135, 169, 190, 173, 133, 171, 208, 32, 125, 44, 237, 86, 87, 178, 85, 86, 179, 84, 85, 180, 83, 84, 181, 201, 83, 182, 137, 93, 132, 76, 62, 183, 61,\n 76, 184, 57, 61, 185, 212, 57, 186, 214, 207, 187, 34, 143, 156, 79, 239, 237, 123, 137, 177, 44, 1, 4, 201, 194, 32, 64, 102, 129, 213, 215, 138, 59,\n 166, 219, 242, 99, 97, 2, 94, 141, 75, 59, 235, 24, 110, 228, 25, 130, 226, 23, 24, 229, 22, 23, 230, 26, 22, 231, 112, 26, 232, 189, 190, 243, 221, 56,\n 190, 28, 56, 221, 27, 28, 222, 29, 27, 223, 30, 29, 224, 247, 30, 225, 238, 79, 20, 166, 59, 75, 60, 75, 240, 147, 177, 215, 20, 79, 166, 187, 147, 213,\n 112, 233, 244, 233, 128, 245, 128, 114, 188, 114, 217, 174, 131, 115, 220, 217, 198, 236, 198, 131, 134, 177, 132, 58, 143, 35, 124, 110, 163, 7, 228,\n 110, 25, 356, 389, 368, 11, 302, 267, 452, 350, 349, 302, 303, 269, 357, 343, 277, 452, 453, 357, 333, 332, 297, 175, 152, 377, 384, 398, 382, 347,\n 348, 330, 303, 304, 270, 9, 336, 337, 278, 279, 360, 418, 262, 431, 304, 408, 409, 310, 415, 407, 270, 409, 410, 450, 348, 347, 422, 430, 434, 313,\n 314, 17, 306, 307, 375, 387, 388, 260, 286, 414, 398, 335, 406, 418, 364, 367, 416, 423, 358, 327, 251, 284, 298, 281, 5, 4, 373, 374, 253, 307, 320,\n 321, 425, 427, 411, 421, 313, 18, 321, 405, 406, 320, 404, 405, 315, 16, 17, 426, 425, 266, 377, 400, 369, 322, 391, 269, 417, 465, 464, 386, 257, 258,\n 466, 260, 388, 456, 399, 419, 284, 332, 333, 417, 285, 8, 346, 340, 261, 413, 441, 285, 327, 460, 328, 355, 371, 329, 392, 439, 438, 382, 341, 256,\n 429, 420, 360, 364, 394, 379, 277, 343, 437, 443, 444, 283, 275, 440, 363, 431, 262, 369, 297, 338, 337, 273, 375, 321, 450, 451, 349, 446, 342, 467,\n 293, 334, 282, 458, 461, 462, 276, 353, 383, 308, 324, 325, 276, 300, 293, 372, 345, 447, 382, 398, 362, 352, 345, 340, 274, 1, 19, 456, 248, 281, 436,\n 427, 425, 381, 256, 252, 269, 391, 393, 200, 199, 428, 266, 330, 329, 287, 273, 422, 250, 462, 328, 258, 286, 384, 265, 353, 342, 387, 259, 257, 424,\n 431, 430, 342, 353, 276, 273, 335, 424, 292, 325, 307, 366, 447, 345, 271, 303, 302, 423, 266, 371, 294, 455, 460, 279, 278, 294, 271, 272, 304, 432,\n 434, 427, 272, 407, 408, 394, 430, 431, 395, 369, 400, 334, 333, 299, 351, 417, 168, 352, 280, 411, 325, 319, 320, 295, 296, 336, 319, 403, 404, 330,\n 348, 349, 293, 298, 333, 323, 454, 447, 15, 16, 315, 358, 429, 279, 14, 15, 316, 285, 336, 9, 329, 349, 350, 374, 380, 252, 318, 402, 403, 6, 197, 419,\n 318, 319, 325, 367, 364, 365, 435, 367, 397, 344, 438, 439, 272, 271, 311, 195, 5, 281, 273, 287, 291, 396, 428, 199, 311, 271, 268, 283, 444, 445,\n 373, 254, 339, 263, 466, 249, 282, 334, 296, 449, 347, 346, 264, 447, 454, 336, 296, 299, 338, 10, 151, 278, 439, 455, 292, 407, 415, 358, 371, 355,\n 340, 345, 372, 390, 249, 466, 346, 347, 280, 442, 443, 282, 19, 94, 370, 441, 442, 295, 248, 419, 197, 263, 255, 359, 440, 275, 274, 300, 383, 368,\n 351, 412, 465, 263, 467, 466, 301, 368, 389, 380, 374, 386, 395, 378, 379, 412, 351, 419, 436, 426, 322, 373, 390, 388, 2, 164, 393, 370, 462, 461,\n 164, 0, 267, 302, 11, 12, 374, 373, 387, 268, 12, 13, 293, 300, 301, 446, 261, 340, 385, 384, 381, 330, 266, 425, 426, 423, 391, 429, 355, 437, 391,\n 327, 326, 440, 457, 438, 341, 382, 362, 459, 457, 461, 434, 430, 394, 414, 463, 362, 396, 369, 262, 354, 461, 457, 316, 403, 402, 315, 404, 403, 314,\n 405, 404, 313, 406, 405, 421, 418, 406, 366, 401, 361, 306, 408, 407, 291, 409, 408, 287, 410, 409, 432, 436, 410, 434, 416, 411, 264, 368, 383, 309,\n 438, 457, 352, 376, 401, 274, 275, 4, 421, 428, 262, 294, 327, 358, 433, 416, 367, 289, 455, 439, 462, 370, 326, 2, 326, 370, 305, 460, 455, 254,\n 449, 448, 255, 261, 446, 253, 450, 449, 252, 451, 450, 256, 452, 451, 341, 453, 452, 413, 464, 463, 441, 413, 414, 258, 442, 441, 257, 443, 442, 259,\n 444, 443, 260, 445, 444, 467, 342, 445, 459, 458, 250, 289, 392, 290, 290, 328, 460, 376, 433, 435, 250, 290, 392, 411, 416, 433, 341, 463, 464, 453,\n 464, 465, 357, 465, 412, 343, 412, 399, 360, 363, 440, 437, 399, 456, 420, 456, 363, 401, 435, 288, 372, 383, 353, 339, 255, 249, 448, 261, 255, 133,\n 243, 190, 133, 155, 112, 33, 246, 247, 33, 130, 25, 398, 384, 286, 362, 398, 414, 362, 463, 341, 263, 359, 467, 263, 249, 255, 466, 467, 260, 75, 60,\n 166, 238, 239, 79, 162, 127, 139, 72, 11, 37, 121, 232, 120, 73, 72, 39, 114, 128, 47, 233, 232, 128, 103, 104, 67, 152, 175, 148, 173, 157, 155,\n 119, 118, 101, 74, 73, 40, 107, 9, 108, 49, 48, 131, 32, 194, 211, 184, 74, 185, 191, 80, 183, 185, 40, 186, 119, 230, 118, 210, 202, 214, 84, 83, 17,\n 77, 76, 146, 161, 160, 30, 190, 56, 173, 182, 106, 194, 138, 135, 192, 129, 203, 98, 54, 21, 68, 5, 51, 4, 145, 144, 23, 90, 77, 91, 207, 205, 187, 83,\n 201, 18, 181, 91, 182, 180, 90, 181, 16, 85, 17, 205, 206, 36, 176, 148, 140, 165, 92, 39, 245, 193, 244, 27, 159, 28, 30, 247, 161, 174, 236, 196,\n 103, 54, 104, 55, 193, 8, 111, 117, 31, 221, 189, 55, 240, 98, 99, 142, 126, 100, 219, 166, 218, 112, 155, 26, 198, 209, 131, 169, 135, 150, 114, 47,\n 217, 224, 223, 53, 220, 45, 134, 32, 211, 140, 109, 67, 108, 146, 43, 91, 231, 230, 120, 113, 226, 247, 105, 63, 52, 241, 238, 242, 124, 46, 156, 95,\n 78, 96, 70, 46, 63, 116, 143, 227, 116, 123, 111, 1, 44, 19, 3, 236, 51, 207, 216, 205, 26, 154, 22, 165, 39, 167, 199, 200, 208, 101, 36, 100, 43,\n 57, 202, 242, 20, 99, 56, 28, 157, 124, 35, 113, 29, 160, 27, 211, 204, 210, 124, 113, 46, 106, 43, 204, 96, 62, 77, 227, 137, 116, 73, 41, 72, 36, 203,\n 142, 235, 64, 240, 48, 49, 64, 42, 41, 74, 214, 212, 207, 183, 42, 184, 210, 169, 211, 140, 170, 176, 104, 105, 69, 193, 122, 168, 50, 123, 187, 89, 96,\n 90, 66, 65, 107, 179, 89, 180, 119, 101, 120, 68, 63, 104, 234, 93, 227, 16, 15, 85, 209, 129, 49, 15, 14, 86, 107, 55, 9, 120, 100, 121, 153, 145, 22,\n 178, 88, 179, 197, 6, 196, 89, 88, 96, 135, 138, 136, 138, 215, 172, 218, 115, 219, 41, 42, 81, 5, 195, 51, 57, 43, 61, 208, 171, 199, 41, 81, 38,\n 224, 53, 225, 24, 144, 110, 105, 52, 66, 118, 229, 117, 227, 34, 234, 66, 107, 69, 10, 109, 151, 219, 48, 235, 183, 62, 191, 142, 129, 126, 116, 111,\n 143, 7, 163, 246, 118, 117, 50, 223, 222, 52, 94, 19, 141, 222, 221, 65, 196, 3, 197, 45, 220, 44, 156, 70, 139, 188, 122, 245, 139, 71, 162, 145,\n 153, 159, 149, 170, 150, 122, 188, 196, 206, 216, 92, 163, 144, 161, 164, 2, 167, 242, 141, 241, 0, 164, 37, 11, 72, 12, 144, 145, 160, 12, 38, 13, 70,\n 63, 71, 31, 226, 111, 157, 158, 154, 36, 101, 205, 203, 206, 165, 126, 209, 217, 98, 165, 97, 237, 220, 218, 237, 239, 241, 210, 214, 169, 140, 171, 32,\n 241, 125, 237, 179, 86, 178, 180, 85, 179, 181, 84, 180, 182, 83, 181, 194, 201, 182, 177, 137, 132, 184, 76, 183, 185, 61, 184, 186, 57, 185, 216, 212,\n 186, 192, 214, 187, 139, 34, 156, 218, 79, 237, 147, 123, 177, 45, 44, 4, 208, 201, 32, 98, 64, 129, 192, 213, 138, 235, 59, 219, 141, 242, 97, 97, 2,\n 141, 240, 75, 235, 229, 24, 228, 31, 25, 226, 230, 23, 229, 231, 22, 230, 232, 26, 231, 233, 112, 232, 244, 189, 243, 189, 221, 190, 222, 28, 221,\n 223, 27, 222, 224, 29, 223, 225, 30, 224, 113, 247, 225, 99, 60, 240, 213, 147, 215, 60, 20, 166, 192, 187, 213, 243, 112, 244, 244, 233, 245, 245,\n 128, 188, 188, 114, 174, 134, 131, 220, 174, 217, 236, 236, 198, 134, 215, 177, 58, 156, 143, 124, 25, 110, 7, 31, 228, 25, 264, 356, 368, 0, 11, 267,\n 451, 452, 349, 267, 302, 269, 350, 357, 277, 350, 452, 357, 299, 333, 297, 396, 175, 377, 381, 384, 382, 280, 347, 330, 269, 303, 270, 151, 9, 337,\n 344, 278, 360, 424, 418, 431, 270, 304, 409, 272, 310, 407, 322, 270, 410, 449, 450, 347, 432, 422, 434, 18, 313, 17, 291, 306, 375, 259, 387, 260,\n 424, 335, 418, 434, 364, 416, 391, 423, 327, 301, 251, 298, 275, 281, 4, 254, 373, 253, 375, 307, 321, 280, 425, 411, 200, 421, 18, 335, 321, 406,\n 321, 320, 405, 314, 315, 17, 423, 426, 266, 396, 377, 369, 270, 322, 269, 413, 417, 464, 385, 386, 258, 248, 456, 419, 298, 284, 333, 168, 417, 8,\n 448, 346, 261, 417, 413, 285, 326, 327, 328, 277, 355, 329, 309, 392, 438, 381, 382, 256, 279, 429, 360, 365, 364, 379, 355, 277, 437, 282, 443, 283,\n 281, 275, 363, 395, 431, 369, 299, 297, 337, 335, 273, 321, 348, 450, 349, 359, 446, 467, 283, 293, 282, 250, 458, 462, 300, 276, 383, 292, 308, 325,\n 283, 276, 293, 264, 372, 447, 346, 352, 340, 354, 274, 19, 363, 456, 281, 426, 436, 425, 380, 381, 252, 267, 269, 393, 421, 200, 428, 371, 266, 329,\n 432, 287, 422, 290, 250, 328, 385, 258, 384, 446, 265, 342, 386, 387, 257, 422, 424, 430, 445, 342, 276, 422, 273, 424, 306, 292, 307, 352, 366, 345,\n 268, 271, 302, 358, 423, 371, 327, 294, 460, 331, 279, 294, 303, 271, 304, 436, 432, 427, 304, 272, 408, 395, 394, 431, 378, 395, 400, 296, 334, 299,\n 6, 351, 168, 376, 352, 411, 307, 325, 320, 285, 295, 336, 320, 319, 404, 329, 330, 349, 334, 293, 333, 366, 323, 447, 316, 15, 315, 331, 358, 279,\n 317, 14, 316, 8, 285, 9, 277, 329, 350, 253, 374, 252, 319, 318, 403, 351, 6, 419, 324, 318, 325, 397, 367, 365, 288, 435, 397, 278, 344, 439, 310,\n 272, 311, 248, 195, 281, 375, 273, 291, 175, 396, 199, 312, 311, 268, 276, 283, 445, 390, 373, 339, 295, 282, 296, 448, 449, 346, 356, 264, 454, 337,\n 336, 299, 337, 338, 151, 294, 278, 455, 308, 292, 415, 429, 358, 355, 265, 340, 372, 388, 390, 466, 352, 346, 280, 295, 442, 282, 354, 19, 370, 285,\n 441, 295, 195, 248, 197, 457, 440, 274, 301, 300, 368, 417, 351, 465, 251, 301, 389, 385, 380, 386, 394, 395, 379, 399, 412, 419, 410, 436, 322, 387,\n 373, 388, 326, 2, 393, 354, 370, 461, 393, 164, 267, 268, 302, 12, 386, 374, 387, 312, 268, 13, 298, 293, 301, 265, 446, 340, 380, 385, 381, 280, 330,\n 425, 322, 426, 391, 420, 429, 437, 393, 391, 326, 344, 440, 438, 458, 459, 461, 364, 434, 394, 428, 396, 262, 274, 354, 457, 317, 316, 402, 316, 315,\n 403, 315, 314, 404, 314, 313, 405, 313, 421, 406, 323, 366, 361, 292, 306, 407, 306, 291, 408, 291, 287, 409, 287, 432, 410, 427, 434, 411, 372, 264,\n 383, 459, 309, 457, 366, 352, 401, 1, 274, 4, 418, 421, 262, 331, 294, 358, 435, 433, 367, 392, 289, 439, 328, 462, 326, 94, 2, 370, 289, 305, 455, 339,\n 254, 448, 359, 255, 446, 254, 253, 449, 253, 252, 450, 252, 256, 451, 256, 341, 452, 414, 413, 463, 286, 441, 414, 286, 258, 441, 258, 257, 442, 257,\n 259, 443, 259, 260, 444, 260, 467, 445, 309, 459, 250, 305, 289, 290, 305, 290, 460, 401, 376, 435, 309, 250, 392, 376, 411, 433, 453, 341, 464, 357,\n 453, 465, 343, 357, 412, 437, 343, 399, 344, 360, 440, 420, 437, 456, 360, 420, 363, 361, 401, 288, 265, 372, 353, 390, 339, 249, 339, 448, 255];\n\nexport const TRI68 = [0, 1, 36, 0, 36, 17, 1, 2, 41, 1, 41, 36, 2, 3, 31, 2, 31, 41, 3, 4, 48, 3, 48, 31, 4, 5, 48, 5, 6, 48, 6, 7, 59, 6, 59, 48, 7, 8, 58, 7, 58, 59,\n 8, 9, 56, 8, 56, 57, 8, 57, 58, 9, 10, 55, 9, 55, 56, 10, 11, 54, 10, 54, 55, 11, 12, 54, 12, 13, 54, 13, 14, 35, 13, 35, 54, 14, 15, 46, 14, 46, 35, 15, 16,\n 45, 15, 45, 46, 16, 26, 45, 17, 36, 18, 18, 37, 19, 18, 36, 37, 19, 38, 20, 19, 37, 38, 20, 39, 21, 20, 38, 39, 21, 39, 27, 22, 42, 23, 22, 27, 42, 23, 43, 24,\n 23, 42, 43, 24, 44, 25, 24, 43, 44, 25, 45, 26, 25, 44, 45, 27, 39, 28, 27, 28, 42, 28, 39, 29, 28, 29, 42, 29, 31, 30, 29, 30, 35, 29, 40, 31, 29, 35, 47, 29,\n 39, 40, 29, 47, 42, 30, 31, 32, 30, 32, 33, 30, 33, 34, 30, 34, 35, 31, 50, 32, 31, 40, 41, 31, 48, 49, 31, 49, 50, 32, 51, 33, 32, 50, 51, 33, 51, 34, 34, 52,\n 35, 34, 51, 52, 35, 46, 47, 35, 52, 53, 35, 53, 54, 36, 41, 37, 37, 40, 38, 37, 41, 40, 38, 40, 39, 42, 47, 43, 43, 47, 44, 44, 46, 45, 44, 47, 46, 48, 60, 49,\n 48, 59, 60, 49, 61, 50, 49, 60, 61, 50, 62, 51, 50, 61, 62, 51, 62, 52, 52, 63, 53, 52, 62, 63, 53, 64, 54, 53, 63, 64, 54, 64, 55, 55, 65, 56, 55, 64, 65, 56,\n 66, 57, 56, 65, 66, 57, 66, 58, 58, 67, 59, 58, 66, 67, 59, 67, 60, 60, 67, 61, 61, 66, 62, 61, 67, 66, 62, 66, 63, 63, 65, 64, 63, 66, 65, 21, 27, 22];\n\nexport const TRI33 = [\n /* eyes */ 0, 8, 7, 7, 8, 1, 2, 10, 9, 9, 10, 3,\n /* brows */ 17, 0, 18, 18, 0, 7, 18, 7, 19, 19, 7, 1, 19, 1, 11, 19, 11, 20, 21, 3, 22, 21, 9, 3, 20, 9, 21, 20, 2, 9, 20, 11, 2,\n /* 4head */ 23, 17, 18, 25, 21, 22, 24, 19, 20, 24, 18, 19, 24, 20, 21, 24, 23, 18, 24, 21, 25,\n /* nose */ 11, 12, 4, 11, 4, 13, 1, 12, 11, 11, 13, 2, 12, 14, 4, 4, 14, 13,\n /* up-lip */ 14, 5, 15, 14, 15, 6, 12, 5, 14, 14, 6, 13,\n /* cheeks */ 8, 12, 1, 2, 13, 10, 8, 26, 12, 10, 13, 27, 26, 5, 12, 13, 6, 27, 0, 26, 8, 10, 27, 3,\n /* chin */ 5, 32, 16, 16, 32, 6, 5, 30, 32, 6, 32, 31,\n /* cont */ 26, 30, 5, 27, 6, 31, 0, 28, 26, 3, 27, 29, 17, 28, 0, 3, 29, 22, 23, 28, 17, 22, 29, 25, 28, 30, 26, 27, 31, 29,\n];\n\nexport const TRI7 = [0, 4, 1, 2, 4, 3, 4, 5, 6];\n\nexport const VTX68 = [\n /* cont */ 127, 234, 132, 58, 172, 150, 149, 148, 152, 377, 378, 379, 397, 288, 361, 454, 356,\n /* brows */ 70, 63, 105, 66, 107, 336, 296, 334, 293, 300,\n /* nose */ 168, 6, 195, 4, 98, 97, 2, 326, 327,\n /* eyes */ 33, 160, 158, 133, 153, 144, 362, 385, 387, 263, 373, 380,\n /* lip */ 57, 40, 37, 0, 267, 270, 287, 321, 314, 17, 84, 91,\n /* mouth */ 78, 81, 13, 311, 308, 402, 14, 178,\n];\n\nexport const VTX33 = [33, 133, 362, 263, 1, 62, 308, 159, 145, 386, 374, 6, 102, 331, 2, 13, 14, 70, 105, 107, 336, 334, 300, 54, 10, 284, 50, 280, 234, 454, 58, 288, 152];\n\nexport const VTX7 = [33, 133, 362, 263, 1, 78, 308];\n\nexport const UV68 = VTX68.map((x) => UV468[x]);\n\nexport const UV33 = VTX33.map((x) => UV468[x]);\n\nexport const UV7 = VTX7.map((x) => UV468[x]);\n", "/*\nWebGLImageFilter by Dominic Szablewski: \n*/\n\n// @ts-nocheck\n\nfunction GLProgram(gl, vertexSource, fragmentSource) {\n const _collect = function (source, prefix, collection) {\n const r = new RegExp('\\\\b' + prefix + ' \\\\w+ (\\\\w+)', 'ig');\n source.replace(r, (match, name) => {\n collection[name] = 0;\n return match;\n });\n };\n\n const _compile = function (source, type) {\n const shader = gl.createShader(type);\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw new Error('filter: gl compile failed', gl.getShaderInfoLog(shader));\n return shader;\n };\n\n this.uniform = {};\n this.attribute = {};\n const _vsh = _compile(vertexSource, gl.VERTEX_SHADER);\n const _fsh = _compile(fragmentSource, gl.FRAGMENT_SHADER);\n this.id = gl.createProgram();\n gl.attachShader(this.id, _vsh);\n gl.attachShader(this.id, _fsh);\n gl.linkProgram(this.id);\n\n if (!gl.getProgramParameter(this.id, gl.LINK_STATUS)) throw new Error('filter: gl link failed', gl.getProgramInfoLog(this.id));\n\n gl.useProgram(this.id);\n // Collect attributes\n _collect(vertexSource, 'attribute', this.attribute);\n for (const a in this.attribute) this.attribute[a] = gl.getAttribLocation(this.id, a);\n // Collect uniforms\n _collect(vertexSource, 'uniform', this.uniform);\n _collect(fragmentSource, 'uniform', this.uniform);\n for (const u in this.uniform) this.uniform[u] = gl.getUniformLocation(this.id, u);\n}\n\n// export const GLImageFilter = function (params) {\nexport function GLImageFilter(params) {\n if (!params) params = { };\n let _drawCount = 0;\n let _sourceTexture = null;\n let _lastInChain = false;\n let _currentFramebufferIndex = -1;\n let _tempFramebuffers = [null, null];\n let _filterChain = [];\n let _width = -1;\n let _height = -1;\n let _vertexBuffer = null;\n let _currentProgram = null;\n const _filter = {};\n const _canvas = params.canvas || document.createElement('canvas');\n // key is the shader program source, value is the compiled program\n const _shaderProgramCache = { };\n const DRAW = { INTERMEDIATE: 1 };\n const gl = _canvas.getContext('webgl');\n if (!gl) throw new Error('filter: context failed');\n\n this.addFilter = function (name) {\n // eslint-disable-next-line prefer-rest-params\n const args = Array.prototype.slice.call(arguments, 1);\n const filter = _filter[name];\n _filterChain.push({ func: filter, args });\n };\n\n this.reset = function () {\n _filterChain = [];\n };\n\n const _resize = function (width, height) {\n // Same width/height? Nothing to do here\n if (width === _width && height === _height) { return; }\n _canvas.width = width;\n _width = width;\n _canvas.height = height;\n _height = height;\n // Create the context if we don't have it yet\n if (!_vertexBuffer) {\n // Create the vertex buffer for the two triangles [x, y, u, v] * 6\n const vertices = new Float32Array([\n -1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0,\n -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0,\n ]);\n // eslint-disable-next-line no-unused-expressions\n (_vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer));\n gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);\n gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);\n }\n gl.viewport(0, 0, _width, _height);\n // Delete old temp framebuffers\n _tempFramebuffers = [null, null];\n };\n\n const _createFramebufferTexture = function (width, height) {\n const fbo = gl.createFramebuffer();\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n const renderbuffer = gl.createRenderbuffer();\n gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);\n const texture = gl.createTexture();\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);\n gl.bindTexture(gl.TEXTURE_2D, null);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n return { fbo, texture };\n };\n\n const _getTempFramebuffer = function (index) {\n _tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);\n return _tempFramebuffers[index];\n };\n\n const _draw = function (flags = null) {\n let source = null;\n let target = null;\n let flipY = false;\n // Set up the source\n if (_drawCount === 0) {\n // First draw call - use the source texture\n source = _sourceTexture;\n } else {\n // All following draw calls use the temp buffer last drawn to\n source = _getTempFramebuffer(_currentFramebufferIndex)?.texture;\n }\n _drawCount++;\n // Set up the target\n if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {\n // Last filter in our chain - draw directly to the WebGL Canvas. We may\n // also have to flip the image vertically now\n target = null;\n flipY = _drawCount % 2 === 0;\n } else {\n // Intermediate draw call - get a temp buffer to draw to\n _currentFramebufferIndex = (_currentFramebufferIndex + 1) % 2;\n target = _getTempFramebuffer(_currentFramebufferIndex)?.fbo;\n }\n // Bind the source and target and draw the two triangles\n gl.bindTexture(gl.TEXTURE_2D, source);\n gl.bindFramebuffer(gl.FRAMEBUFFER, target);\n gl.uniform1f(_currentProgram.uniform.flipY, (flipY ? -1 : 1));\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n };\n\n this.apply = function (image) {\n _resize(image.width, image.height);\n _drawCount = 0;\n // Create the texture for the input image if we haven't yet\n if (!_sourceTexture) _sourceTexture = gl.createTexture();\n gl.bindTexture(gl.TEXTURE_2D, _sourceTexture);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);\n // No filters? Just draw\n if (_filterChain.length === 0) {\n // const program = _compileShader(SHADER.FRAGMENT_IDENTITY);\n _draw();\n return _canvas;\n }\n for (let i = 0; i < _filterChain.length; i++) {\n _lastInChain = (i === _filterChain.length - 1);\n const f = _filterChain[i];\n f.func.apply(this, f.args || []);\n }\n return _canvas;\n };\n\n const _compileShader = function (fragmentSource) {\n if (_shaderProgramCache[fragmentSource]) {\n _currentProgram = _shaderProgramCache[fragmentSource];\n gl.useProgram(_currentProgram.id);\n return _currentProgram;\n }\n // Compile shaders\n const SHADER = {};\n SHADER.VERTEX_IDENTITY = [\n 'precision highp float;',\n 'attribute vec2 pos;',\n 'attribute vec2 uv;',\n 'varying vec2 vUv;',\n 'uniform float flipY;',\n 'void main(void) {',\n 'vUv = uv;',\n 'gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);',\n '}',\n ].join('\\n');\n SHADER.FRAGMENT_IDENTITY = [\n 'precision highp float;',\n 'varying vec2 vUv;',\n 'uniform sampler2D texture;',\n 'void main(void) {',\n 'gl_FragColor = texture2D(texture, vUv);',\n '}',\n ].join('\\n');\n _currentProgram = new GLProgram(gl, SHADER.VERTEX_IDENTITY, fragmentSource);\n const floatSize = Float32Array.BYTES_PER_ELEMENT;\n const vertSize = 4 * floatSize;\n gl.enableVertexAttribArray(_currentProgram.attribute.pos);\n gl.vertexAttribPointer(_currentProgram.attribute.pos, 2, gl.FLOAT, false, vertSize, 0 * floatSize);\n gl.enableVertexAttribArray(_currentProgram.attribute.uv);\n gl.vertexAttribPointer(_currentProgram.attribute.uv, 2, gl.FLOAT, false, vertSize, 2 * floatSize);\n _shaderProgramCache[fragmentSource] = _currentProgram;\n return _currentProgram;\n };\n\n // -------------------------------------------------------------------------\n // Color Matrix Filter\n _filter.colorMatrix = function (matrix) {\n // Create a Float32 Array and normalize the offset component to 0-1\n const m = new Float32Array(matrix);\n m[4] /= 255;\n m[9] /= 255;\n m[14] /= 255;\n m[19] /= 255;\n // Can we ignore the alpha value? Makes things a bit faster.\n const shader = (m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0)\n ? _filter.colorMatrix.SHADER.WITHOUT_ALPHA\n : _filter.colorMatrix.SHADER.WITH_ALPHA;\n const program = _compileShader(shader);\n gl.uniform1fv(program.uniform.m, m);\n _draw();\n };\n _filter.colorMatrix.SHADER = {};\n _filter.colorMatrix.SHADER.WITH_ALPHA = [\n 'precision highp float;',\n 'varying vec2 vUv;',\n 'uniform sampler2D texture;',\n 'uniform float m[20];',\n 'void main(void) {',\n 'vec4 c = texture2D(texture, vUv);',\n 'gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];',\n 'gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];',\n 'gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];',\n 'gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];',\n '}',\n ].join('\\n');\n _filter.colorMatrix.SHADER.WITHOUT_ALPHA = [\n 'precision highp float;',\n 'varying vec2 vUv;',\n 'uniform sampler2D texture;',\n 'uniform float m[20];',\n 'void main(void) {',\n 'vec4 c = texture2D(texture, vUv);',\n 'gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];',\n 'gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];',\n 'gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];',\n 'gl_FragColor.a = c.a;',\n '}',\n ].join('\\n');\n\n _filter.brightness = function (brightness) {\n const b = (brightness || 0) + 1;\n _filter.colorMatrix([\n b, 0, 0, 0, 0,\n 0, b, 0, 0, 0,\n 0, 0, b, 0, 0,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.saturation = function (amount) {\n const x = (amount || 0) * 2 / 3 + 1;\n const y = ((x - 1) * -0.5);\n _filter.colorMatrix([\n x, y, y, 0, 0,\n y, x, y, 0, 0,\n y, y, x, 0, 0,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.desaturate = function () {\n _filter.saturation(-1);\n };\n\n _filter.contrast = function (amount) {\n const v = (amount || 0) + 1;\n const o = -128 * (v - 1);\n\n _filter.colorMatrix([\n v, 0, 0, 0, o,\n 0, v, 0, 0, o,\n 0, 0, v, 0, o,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.negative = function () {\n _filter.contrast(-2);\n };\n\n _filter.hue = function (rotation) {\n rotation = (rotation || 0) / 180 * Math.PI;\n const cos = Math.cos(rotation);\n const sin = Math.sin(rotation);\n const lumR = 0.213;\n const lumG = 0.715;\n const lumB = 0.072;\n\n _filter.colorMatrix([\n lumR + cos * (1 - lumR) + sin * (-lumR), lumG + cos * (-lumG) + sin * (-lumG), lumB + cos * (-lumB) + sin * (1 - lumB), 0, 0,\n lumR + cos * (-lumR) + sin * (0.143), lumG + cos * (1 - lumG) + sin * (0.140), lumB + cos * (-lumB) + sin * (-0.283), 0, 0,\n lumR + cos * (-lumR) + sin * (-(1 - lumR)), lumG + cos * (-lumG) + sin * (lumG), lumB + cos * (1 - lumB) + sin * (lumB), 0, 0,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.desaturateLuminance = function () {\n _filter.colorMatrix([\n 0.2764723, 0.9297080, 0.0938197, 0, -37.1,\n 0.2764723, 0.9297080, 0.0938197, 0, -37.1,\n 0.2764723, 0.9297080, 0.0938197, 0, -37.1,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.sepia = function () {\n _filter.colorMatrix([\n 0.393, 0.7689999, 0.18899999, 0, 0,\n 0.349, 0.6859999, 0.16799999, 0, 0,\n 0.272, 0.5339999, 0.13099999, 0, 0,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.brownie = function () {\n _filter.colorMatrix([\n 0.5997023498159715, 0.34553243048391263, -0.2708298674538042, 0, 47.43192855600873,\n -0.037703249837783157, 0.8609577587992641, 0.15059552388459913, 0, -36.96841498319127,\n 0.24113635128153335, -0.07441037908422492, 0.44972182064877153, 0, -7.562075277591283,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.vintagePinhole = function () {\n _filter.colorMatrix([\n 0.6279345635605994, 0.3202183420819367, -0.03965408211312453, 0, 9.651285835294123,\n 0.02578397704808868, 0.6441188644374771, 0.03259127616149294, 0, 7.462829176470591,\n 0.0466055556782719, -0.0851232987247891, 0.5241648018700465, 0, 5.159190588235296,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.kodachrome = function () {\n _filter.colorMatrix([\n 1.1285582396593525, -0.3967382283601348, -0.03992559172921793, 0, 63.72958762196502,\n -0.16404339962244616, 1.0835251566291304, -0.05498805115633132, 0, 24.732407896706203,\n -0.16786010706155763, -0.5603416277695248, 1.6014850761964943, 0, 35.62982807460946,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.technicolor = function () {\n _filter.colorMatrix([\n 1.9125277891456083, -0.8545344976951645, -0.09155508482755585, 0, 11.793603434377337,\n -0.3087833385928097, 1.7658908555458428, -0.10601743074722245, 0, -70.35205161461398,\n -0.231103377548616, -0.7501899197440212, 1.847597816108189, 0, 30.950940869491138,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.polaroid = function () {\n _filter.colorMatrix([\n 1.438, -0.062, -0.062, 0, 0,\n -0.122, 1.378, -0.122, 0, 0,\n -0.016, -0.016, 1.483, 0, 0,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n _filter.shiftToBGR = function () {\n _filter.colorMatrix([\n 0, 0, 1, 0, 0,\n 0, 1, 0, 0, 0,\n 1, 0, 0, 0, 0,\n 0, 0, 0, 1, 0,\n ]);\n };\n\n // -------------------------------------------------------------------------\n // Convolution Filter\n _filter.convolution = function (matrix) {\n const m = new Float32Array(matrix);\n const pixelSizeX = 1 / _width;\n const pixelSizeY = 1 / _height;\n const program = _compileShader(_filter.convolution.SHADER);\n gl.uniform1fv(program.uniform.m, m);\n gl.uniform2f(program.uniform.px, pixelSizeX, pixelSizeY);\n _draw();\n };\n\n _filter.convolution.SHADER = [\n 'precision highp float;',\n 'varying vec2 vUv;',\n 'uniform sampler2D texture;',\n 'uniform vec2 px;',\n 'uniform float m[9];',\n 'void main(void) {',\n 'vec4 c11 = texture2D(texture, vUv - px);', // top left\n 'vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y));', // top center\n 'vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y));', // top right\n 'vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) );', // mid left\n 'vec4 c22 = texture2D(texture, vUv);', // mid center\n 'vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) );', // mid right\n 'vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) );', // bottom left\n 'vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) );', // bottom center\n 'vec4 c33 = texture2D(texture, vUv + px );', // bottom right\n 'gl_FragColor = ',\n 'c11 * m[0] + c12 * m[1] + c22 * m[2] +',\n 'c21 * m[3] + c22 * m[4] + c23 * m[5] +',\n 'c31 * m[6] + c32 * m[7] + c33 * m[8];',\n 'gl_FragColor.a = c22.a;',\n '}',\n ].join('\\n');\n\n _filter.detectEdges = function () {\n _filter.convolution.call(this, [\n 0, 1, 0,\n 1, -4, 1,\n 0, 1, 0,\n ]);\n };\n\n _filter.sobelX = function () {\n _filter.convolution.call(this, [\n -1, 0, 1,\n -2, 0, 2,\n -1, 0, 1,\n ]);\n };\n\n _filter.sobelY = function () {\n _filter.convolution.call(this, [\n -1, -2, -1,\n 0, 0, 0,\n 1, 2, 1,\n ]);\n };\n\n _filter.sharpen = function (amount) {\n const a = amount || 1;\n _filter.convolution.call(this, [\n 0, -1 * a, 0,\n -1 * a, 1 + 4 * a, -1 * a,\n 0, -1 * a, 0,\n ]);\n };\n\n _filter.emboss = function (size) {\n const s = size || 1;\n _filter.convolution.call(this, [\n -2 * s, -1 * s, 0,\n -1 * s, 1, 1 * s,\n 0, 1 * s, 2 * s,\n ]);\n };\n\n // -------------------------------------------------------------------------\n // Blur Filter\n _filter.blur = function (size) {\n const blurSizeX = (size / 7) / _width;\n const blurSizeY = (size / 7) / _height;\n const program = _compileShader(_filter.blur.SHADER);\n // Vertical\n gl.uniform2f(program.uniform.px, 0, blurSizeY);\n _draw(DRAW.INTERMEDIATE);\n // Horizontal\n gl.uniform2f(program.uniform.px, blurSizeX, 0);\n _draw();\n };\n\n _filter.blur.SHADER = [\n 'precision highp float;',\n 'varying vec2 vUv;',\n 'uniform sampler2D texture;',\n 'uniform vec2 px;',\n 'void main(void) {',\n 'gl_FragColor = vec4(0.0);',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;',\n 'gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;',\n 'gl_FragColor += texture2D(texture, vUv )*0.159576912161;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;',\n 'gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;',\n '}',\n ].join('\\n');\n\n // -------------------------------------------------------------------------\n // Pixelate Filter\n _filter.pixelate = function (size) {\n const blurSizeX = (size) / _width;\n const blurSizeY = (size) / _height;\n const program = _compileShader(_filter.pixelate.SHADER);\n // Horizontal\n gl.uniform2f(program.uniform.size, blurSizeX, blurSizeY);\n _draw();\n };\n\n _filter.pixelate.SHADER = [\n 'precision highp float;',\n 'varying vec2 vUv;',\n 'uniform vec2 size;',\n 'uniform sampler2D texture;',\n 'vec2 pixelate(vec2 coord, vec2 size) {',\n 'return floor( coord / size ) * size;',\n '}',\n 'void main(void) {',\n 'gl_FragColor = vec4(0.0);',\n 'vec2 coord = pixelate(vUv, size);',\n 'gl_FragColor += texture2D(texture, coord);',\n '}',\n ].join('\\n');\n}\n", "/**\n * Image Processing module used by Human\n */\n\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as fxImage from './imagefx';\nimport type { Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\nimport { log } from '../helpers';\n\ntype Input = Tensor | ImageData | ImageBitmap | HTMLImageElement | HTMLMediaElement | HTMLVideoElement | HTMLCanvasElement | OffscreenCanvas | typeof Image | typeof env.Canvas;\n\nconst maxSize = 2048;\n// internal temp canvases\nlet inCanvas;\nlet outCanvas;\n// @ts-ignore // imagefx is js module that should be converted to a class\nlet fx: fxImage.GLImageFilter | null; // instance of imagefx\n\nexport function canvas(width, height): HTMLCanvasElement | OffscreenCanvas {\n let c;\n if (env.browser) {\n if (env.offscreen) {\n c = new OffscreenCanvas(width, height);\n } else {\n c = document.createElement('canvas');\n c.width = width;\n c.height = height;\n }\n } else {\n // @ts-ignore // env.canvas is an external monkey-patch\n c = (typeof env.Canvas !== 'undefined') ? new env.Canvas(width, height) : null;\n }\n // if (!c) throw new Error('cannot create canvas');\n return c;\n}\n\n// process input image and return tensor\n// input can be tensor, imagedata, htmlimageelement, htmlvideoelement\n// input is resized and run through imagefx filter\nexport function process(input: Input, config: Config): { tensor: Tensor | null, canvas: OffscreenCanvas | HTMLCanvasElement | null } {\n let tensor;\n if (!input) {\n // throw new Error('input is missing');\n if (config.debug) log('input is missing');\n return { tensor: null, canvas: null }; // video may become temporarily unavailable due to onresize\n }\n // sanity checks since different browsers do not implement all dom elements\n if (\n !(input instanceof tf.Tensor)\n && !(typeof Image !== 'undefined' && input instanceof Image)\n && !(typeof env.Canvas !== 'undefined' && input instanceof env.Canvas)\n && !(typeof ImageData !== 'undefined' && input instanceof ImageData)\n && !(typeof ImageBitmap !== 'undefined' && input instanceof ImageBitmap)\n && !(typeof HTMLImageElement !== 'undefined' && input instanceof HTMLImageElement)\n && !(typeof HTMLMediaElement !== 'undefined' && input instanceof HTMLMediaElement)\n && !(typeof HTMLVideoElement !== 'undefined' && input instanceof HTMLVideoElement)\n && !(typeof HTMLCanvasElement !== 'undefined' && input instanceof HTMLCanvasElement)\n && !(typeof OffscreenCanvas !== 'undefined' && input instanceof OffscreenCanvas)\n ) {\n throw new Error('input type is not recognized');\n }\n if (input instanceof tf.Tensor) {\n // if input is tensor, use as-is\n if ((input as Tensor)['isDisposedInternal']) throw new Error('input tensor is disposed');\n if ((input as Tensor).shape && (input as Tensor).shape.length === 4 && (input as unknown as Tensor).shape[0] === 1 && (input as unknown as Tensor).shape[3] === 3) tensor = tf.clone(input);\n else throw new Error(`input tensor shape must be [1, height, width, 3] and instead was ${(input as Tensor).shape}`);\n } else {\n // check if resizing will be needed\n if (typeof input['readyState'] !== 'undefined' && input['readyState'] <= 2) {\n if (config.debug) log('input stream is not ready');\n return { tensor: null, canvas: inCanvas }; // video may become temporarily unavailable due to onresize\n }\n const originalWidth = input['naturalWidth'] || input['videoWidth'] || input['width'] || (input['shape'] && (input['shape'][1] > 0));\n const originalHeight = input['naturalHeight'] || input['videoHeight'] || input['height'] || (input['shape'] && (input['shape'][2] > 0));\n if (!originalWidth || !originalHeight) {\n if (config.debug) log('cannot determine input dimensions');\n return { tensor: null, canvas: inCanvas }; // video may become temporarily unavailable due to onresize\n }\n let targetWidth = originalWidth;\n let targetHeight = originalHeight;\n if (targetWidth > maxSize) {\n targetWidth = maxSize;\n targetHeight = targetWidth * originalHeight / originalWidth;\n }\n if (targetHeight > maxSize) {\n targetHeight = maxSize;\n targetWidth = targetHeight * originalWidth / originalHeight;\n }\n\n // create our canvas and resize it if needed\n if ((config.filter.width || 0) > 0) targetWidth = config.filter.width;\n else if ((config.filter.height || 0) > 0) targetWidth = originalWidth * ((config.filter.height || 0) / originalHeight);\n if ((config.filter.height || 0) > 0) targetHeight = config.filter.height;\n else if ((config.filter.width || 0) > 0) targetHeight = originalHeight * ((config.filter.width || 0) / originalWidth);\n if (!targetWidth || !targetHeight) throw new Error('input cannot determine dimension');\n if (!inCanvas || (inCanvas?.width !== targetWidth) || (inCanvas?.height !== targetHeight)) inCanvas = canvas(targetWidth, targetHeight);\n\n // draw input to our canvas\n const ctx = inCanvas.getContext('2d');\n if ((typeof ImageData !== 'undefined') && (input instanceof ImageData)) {\n ctx.putImageData(input, 0, 0);\n } else {\n if (config.filter.flip && typeof ctx.translate !== 'undefined') {\n ctx.translate(originalWidth, 0);\n ctx.scale(-1, 1);\n ctx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, inCanvas?.width, inCanvas?.height);\n ctx.setTransform(1, 0, 0, 1, 0, 0); // resets transforms to defaults\n } else {\n ctx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, inCanvas?.width, inCanvas?.height);\n }\n }\n // imagefx transforms using gl\n if (config.filter.enabled && env.webgl.supported) {\n if (!fx || !outCanvas || (inCanvas.width !== outCanvas.width) || (inCanvas?.height !== outCanvas?.height)) {\n outCanvas = canvas(inCanvas?.width, inCanvas?.height);\n if (outCanvas?.width !== inCanvas?.width) outCanvas.width = inCanvas?.width;\n if (outCanvas?.height !== inCanvas?.height) outCanvas.height = inCanvas?.height;\n // log('created FX filter');\n fx = env.browser ? new fxImage.GLImageFilter({ canvas: outCanvas }) : null; // && (typeof document !== 'undefined')\n }\n if (!fx) return { tensor: null, canvas: inCanvas };\n fx.reset();\n fx.addFilter('brightness', config.filter.brightness); // must have at least one filter enabled\n if (config.filter.contrast !== 0) fx.addFilter('contrast', config.filter.contrast);\n if (config.filter.sharpness !== 0) fx.addFilter('sharpen', config.filter.sharpness);\n if (config.filter.blur !== 0) fx.addFilter('blur', config.filter.blur);\n if (config.filter.saturation !== 0) fx.addFilter('saturation', config.filter.saturation);\n if (config.filter.hue !== 0) fx.addFilter('hue', config.filter.hue);\n if (config.filter.negative) fx.addFilter('negative');\n if (config.filter.sepia) fx.addFilter('sepia');\n if (config.filter.vintage) fx.addFilter('brownie');\n if (config.filter.sepia) fx.addFilter('sepia');\n if (config.filter.kodachrome) fx.addFilter('kodachrome');\n if (config.filter.technicolor) fx.addFilter('technicolor');\n if (config.filter.polaroid) fx.addFilter('polaroid');\n if (config.filter.pixelate !== 0) fx.addFilter('pixelate', config.filter.pixelate);\n fx.apply(inCanvas);\n // read pixel data\n /*\n const gl = outCanvas.getContext('webgl');\n if (gl) {\n const glBuffer = new Uint8Array(outCanvas.width * outCanvas.height * 4);\n const pixBuffer = new Uint8Array(outCanvas.width * outCanvas.height * 3);\n gl.readPixels(0, 0, outCanvas.width, outCanvas.height, gl.RGBA, gl.UNSIGNED_BYTE, glBuffer);\n // gl returns rbga while we only need rgb, so discarding alpha channel\n // gl returns starting point as lower left, so need to invert vertical\n let i = 0;\n for (let y = outCanvas.height - 1; y >= 0; y--) {\n for (let x = 0; x < outCanvas.width; x++) {\n const index = (x + y * outCanvas.width) * 4;\n pixBuffer[i++] = glBuffer[index + 0];\n pixBuffer[i++] = glBuffer[index + 1];\n pixBuffer[i++] = glBuffer[index + 2];\n }\n }\n outCanvas.data = pixBuffer;\n const shape = [outCanvas.height, outCanvas.width, 3];\n const pixels = tf.tensor3d(outCanvas.data, shape, 'float32');\n tensor = tf.expandDims(pixels, 0);\n tf.dispose(pixels);\n }\n */\n } else {\n outCanvas = inCanvas;\n if (fx) fx = null;\n }\n // create tensor from image if tensor is not already defined\n if (!tensor) {\n let pixels;\n if (outCanvas.data) { // if we have data, just convert to tensor\n const shape = [outCanvas.height, outCanvas.width, 3];\n pixels = tf.tensor3d(outCanvas.data, shape, 'float32');\n } else if ((typeof ImageData !== 'undefined') && (outCanvas instanceof ImageData)) { // if input is imagedata, just use it\n pixels = tf.browser ? tf.browser.fromPixels(outCanvas) : null;\n } else if (config.backend === 'webgl' || config.backend === 'humangl') { // tf kernel-optimized method to get imagedata\n // we cant use canvas as-is as it already has a context, so we do a silly one more canvas\n const tempCanvas = canvas(targetWidth, targetHeight);\n tempCanvas.width = targetWidth;\n tempCanvas.height = targetHeight;\n const tempCtx = tempCanvas.getContext('2d');\n tempCtx?.drawImage(outCanvas, 0, 0);\n try {\n pixels = (tf.browser && env.browser) ? tf.browser.fromPixels(tempCanvas) : null;\n } catch (err) {\n throw new Error('browser webgl error');\n }\n } else { // cpu and wasm kernel does not implement efficient fromPixels method\n // we cant use canvas as-is as it already has a context, so we do a silly one more canvas and do fromPixels on ImageData instead\n const tempCanvas = canvas(targetWidth, targetHeight);\n if (!tempCanvas) return { tensor: null, canvas: inCanvas };\n tempCanvas.width = targetWidth;\n tempCanvas.height = targetHeight;\n const tempCtx = tempCanvas.getContext('2d');\n if (!tempCtx) return { tensor: null, canvas: inCanvas };\n tempCtx.drawImage(outCanvas, 0, 0);\n const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);\n if (tf.browser && env.browser) {\n pixels = tf.browser.fromPixels(data);\n } else {\n pixels = tf.tidy(() => {\n const imageData = tf.tensor(Array.from(data.data), [targetWidth, targetHeight, 4]);\n const channels = tf.split(imageData, 4, 2); // split rgba to channels\n const rgb = tf.stack([channels[0], channels[1], channels[2]], 2); // stack channels back to rgb and ignore alpha\n const expand = tf.reshape(rgb, [imageData.shape[0], imageData.shape[1], 3]); // move extra dim from the end of tensor and use it as batch number instead\n return expand;\n });\n }\n }\n if (pixels) {\n const casted = tf.cast(pixels, 'float32');\n tensor = tf.expandDims(casted, 0);\n tf.dispose(pixels);\n tf.dispose(casted);\n } else {\n tensor = tf.zeros([1, targetWidth, targetHeight, 3]);\n throw new Error('cannot create tensor from input');\n }\n }\n }\n return { tensor, canvas: (config.filter.return ? outCanvas : null) };\n}\n\nlet lastInputSum = 0;\nlet lastCacheDiff = 1;\nexport async function skip(config, input: Tensor) {\n if (config.cacheSensitivity === 0) return false;\n const resizeFact = 32;\n if (!input.shape[1] || !input.shape[2]) return false;\n const reduced: Tensor = tf.image.resizeBilinear(input, [Math.trunc(input.shape[1] / resizeFact), Math.trunc(input.shape[2] / resizeFact)]);\n\n // use tensor sum\n /*\n const sumT = this.tf.sum(reduced);\n const sum = await sumT.data()[0] as number;\n sumT.dispose();\n */\n // use js loop sum, faster than uploading tensor to gpu calculating and downloading back\n const reducedData = await reduced.data(); // raw image rgb array\n tf.dispose(reduced);\n let sum = 0;\n for (let i = 0; i < reducedData.length / 3; i++) sum += reducedData[3 * i + 2]; // look only at green value of each pixel\n\n const diff = 100 * (Math.max(sum, lastInputSum) / Math.min(sum, lastInputSum) - 1);\n lastInputSum = sum;\n // if previous frame was skipped, skip this frame if changed more than cacheSensitivity\n // if previous frame was not skipped, then look for cacheSensitivity or difference larger than one in previous frame to avoid resetting cache in subsequent frames unnecessarily\n const skipFrame = diff < Math.max(config.cacheSensitivity, lastCacheDiff);\n // if difference is above 10x threshold, don't use last value to force reset cache for significant change of scenes or images\n lastCacheDiff = diff > 10 * config.cacheSensitivity ? 0 : diff;\n // console.log('skipFrame', skipFrame, this.config.cacheSensitivity, diff);\n return skipFrame;\n}\n", "import * as tf from '../dist/tfjs.esm.js';\nimport * as image from './image/image';\nimport { mergeDeep } from './helpers';\n\nexport type Env = {\n browser: undefined | boolean,\n node: undefined | boolean,\n worker: undefined | boolean,\n platform: undefined | string,\n agent: undefined | string,\n backends: string[],\n initial: boolean,\n tfjs: {\n version: undefined | string,\n },\n offscreen: undefined | boolean,\n wasm: {\n supported: undefined | boolean,\n backend: undefined | boolean,\n simd: undefined | boolean,\n multithread: undefined | boolean,\n },\n webgl: {\n supported: undefined | boolean,\n backend: undefined | boolean,\n version: undefined | string,\n renderer: undefined | string,\n },\n webgpu: {\n supported: undefined | boolean,\n backend: undefined | boolean,\n adapter: undefined | string,\n },\n kernels: string[],\n Canvas: undefined,\n Image: undefined,\n}\n\n// eslint-disable-next-line import/no-mutable-exports\nexport let env: Env = {\n browser: undefined,\n node: undefined,\n worker: undefined,\n platform: undefined,\n agent: undefined,\n initial: true,\n backends: [],\n offscreen: undefined,\n tfjs: {\n version: undefined,\n },\n wasm: {\n supported: undefined,\n backend: undefined,\n simd: undefined,\n multithread: undefined,\n },\n webgl: {\n supported: undefined,\n backend: undefined,\n version: undefined,\n renderer: undefined,\n },\n webgpu: {\n supported: undefined,\n backend: undefined,\n adapter: undefined,\n },\n kernels: [],\n Canvas: undefined,\n Image: undefined,\n};\n\nexport async function cpuInfo() {\n const cpu = { model: '', flags: [] };\n if (env.node && env.platform?.startsWith('linux')) {\n // eslint-disable-next-line global-require\n const fs = require('fs');\n try {\n const data = fs.readFileSync('/proc/cpuinfo').toString();\n for (const line of data.split('\\n')) {\n if (line.startsWith('model name')) {\n cpu.model = line.match(/:(.*)/g)[0].replace(':', '').trim();\n }\n if (line.startsWith('flags')) {\n cpu.flags = line.match(/:(.*)/g)[0].replace(':', '').trim().split(' ').sort();\n }\n }\n } catch { /**/ }\n }\n if (!env['cpu']) Object.defineProperty(env, 'cpu', { value: cpu });\n else env['cpu'] = cpu;\n}\n\nexport async function backendInfo() {\n // analyze backends\n env.backends = Object.keys(tf.engine().registryFactory);\n env.wasm.supported = typeof WebAssembly !== 'undefined';\n env.wasm.backend = env.backends.includes('wasm');\n if (env.wasm.supported && env.wasm.backend && tf.getBackend() === 'wasm') {\n env.wasm.simd = await tf.env().getAsync('WASM_HAS_SIMD_SUPPORT');\n env.wasm.multithread = await tf.env().getAsync('WASM_HAS_MULTITHREAD_SUPPORT');\n }\n\n const c = image.canvas(100, 100);\n const ctx = c ? c.getContext('webgl2') : undefined; // causes too many gl contexts\n // const ctx = typeof tf.backend().getGPGPUContext !== undefined ? tf.backend().getGPGPUContext : null;\n env.webgl.supported = typeof ctx !== 'undefined';\n env.webgl.backend = env.backends.includes('webgl');\n if (env.webgl.supported && env.webgl.backend && (tf.getBackend() === 'webgl' || tf.getBackend() === 'humangl')) {\n // @ts-ignore getGPGPUContext only exists on WebGL backend\n const gl = tf.backend().gpgpu !== 'undefined' ? await tf.backend().getGPGPUContext().gl : null;\n if (gl) {\n env.webgl.version = gl.getParameter(gl.VERSION);\n env.webgl.renderer = gl.getParameter(gl.RENDERER);\n }\n }\n\n env.webgpu.supported = env.browser && typeof navigator['gpu'] !== 'undefined';\n env.webgpu.backend = env.backends.includes('webgpu');\n if (env.webgpu.supported) env.webgpu.adapter = (await navigator['gpu'].requestAdapter())?.name;\n\n // enumerate kernels\n env.kernels = tf.getKernelsForBackend(tf.getBackend()).map((kernel) => kernel.kernelName.toLowerCase());\n}\n\nexport async function get() {\n env.browser = typeof navigator !== 'undefined';\n env.node = typeof process !== 'undefined';\n // @ts-ignore WorkerGlobalScope evaluated in browser only\n env.worker = env.browser ? (typeof WorkerGlobalScope !== 'undefined') : undefined;\n env.tfjs.version = tf.version_core;\n\n // offscreencanvas supported?\n env.offscreen = typeof env.offscreen === 'undefined' ? typeof OffscreenCanvas !== 'undefined' : env.offscreen;\n // get platform and agent\n if (typeof navigator !== 'undefined') {\n const raw = navigator.userAgent.match(/\\(([^()]+)\\)/g);\n if (raw && raw[0]) {\n const platformMatch = raw[0].match(/\\(([^()]+)\\)/g);\n env.platform = (platformMatch && platformMatch[0]) ? platformMatch[0].replace(/\\(|\\)/g, '') : '';\n env.agent = navigator.userAgent.replace(raw[0], '');\n if (env.platform[1]) env.agent = env.agent.replace(raw[1], '');\n env.agent = env.agent.replace(/ /g, ' ');\n }\n } else if (typeof process !== 'undefined') {\n env.platform = `${process.platform} ${process.arch}`;\n env.agent = `NodeJS ${process.version}`;\n }\n await backendInfo();\n\n // get cpu info\n // await cpuInfo();\n}\n\nexport async function set(obj) {\n env = mergeDeep(env, obj);\n}\n", "import * as tf from '../../dist/tfjs.esm.js';\nimport * as bounding from './box';\nimport * as util from './util';\nimport * as coords from './coords';\nimport type { Tensor, GraphModel } from '../tfjs/types';\nimport type { BlazeFaceModel } from './blazeface';\nimport { env } from '../env';\n\nconst leftOutline = coords.MESH_ANNOTATIONS['leftEyeLower0'];\nconst rightOutline = coords.MESH_ANNOTATIONS['rightEyeLower0'];\n\nconst eyeLandmarks = {\n leftBounds: [leftOutline[0], leftOutline[leftOutline.length - 1]],\n rightBounds: [rightOutline[0], rightOutline[rightOutline.length - 1]],\n};\n\nconst meshLandmarks = {\n count: 468,\n mouth: 13,\n symmetryLine: [13, coords.MESH_ANNOTATIONS['midwayBetweenEyes'][0]],\n};\n\nconst blazeFaceLandmarks = {\n leftEye: 0,\n rightEye: 1,\n nose: 2,\n mouth: 3,\n leftEar: 4,\n rightEar: 5,\n symmetryLine: [3, 2],\n};\n\nconst irisLandmarks = {\n upperCenter: 3,\n lowerCenter: 4,\n index: 71,\n numCoordinates: 76,\n};\n\n// Replace the raw coordinates returned by facemesh with refined iris model coordinates\n// Update the z coordinate to be an average of the original and the new.\nfunction replaceRawCoordinates(rawCoords, newCoords, prefix, keys) {\n for (let i = 0; i < coords.MESH_TO_IRIS_INDICES_MAP.length; i++) {\n const { key, indices } = coords.MESH_TO_IRIS_INDICES_MAP[i];\n const originalIndices = coords.MESH_ANNOTATIONS[`${prefix}${key}`];\n if (!keys || keys.includes(key)) {\n for (let j = 0; j < indices.length; j++) {\n const index = indices[j];\n rawCoords[originalIndices[j]] = [\n newCoords[index][0], newCoords[index][1],\n (newCoords[index][2] + rawCoords[originalIndices[j]][2]) / 2,\n ];\n }\n }\n }\n}\n// The Pipeline coordinates between the bounding box and skeleton models.\nexport class Pipeline {\n storedBoxes: Array<{ startPoint: number[], endPoint: number[], landmarks: Array, confidence: number, faceConfidence?: number | undefined }>;\n boundingBoxDetector: BlazeFaceModel; // tf.GraphModel\n meshDetector: GraphModel; // tf.GraphModel\n irisModel: GraphModel; // tf.GraphModel\n boxSize: number;\n meshSize: number;\n irisSize: number;\n irisEnlarge: number;\n skipped: number;\n detectedFaces: number;\n\n constructor(boundingBoxDetector, meshDetector, irisModel) {\n // An array of facial bounding boxes.\n this.storedBoxes = [];\n this.boundingBoxDetector = boundingBoxDetector;\n this.meshDetector = meshDetector;\n this.irisModel = irisModel;\n this.boxSize = boundingBoxDetector?.model?.inputs[0].shape[2] || 0;\n this.meshSize = meshDetector?.inputs[0].shape[2] || boundingBoxDetector?.model?.inputs[0].shape[2];\n this.irisSize = irisModel?.inputs[0].shape[1] || 0;\n this.irisEnlarge = 2.3;\n this.skipped = 0;\n this.detectedFaces = 0;\n }\n\n transformRawCoords(rawCoords, box, angle, rotationMatrix) {\n const boxSize = bounding.getBoxSize({ startPoint: box.startPoint, endPoint: box.endPoint });\n const coordsScaled = rawCoords.map((coord) => ([\n boxSize[0] / this.meshSize * (coord[0] - this.meshSize / 2),\n boxSize[1] / this.meshSize * (coord[1] - this.meshSize / 2),\n coord[2],\n ]));\n const coordsRotationMatrix = (angle !== 0) ? util.buildRotationMatrix(angle, [0, 0]) : util.IDENTITY_MATRIX;\n const coordsRotated = (angle !== 0) ? coordsScaled.map((coord) => ([...util.rotatePoint(coord, coordsRotationMatrix), coord[2]])) : coordsScaled;\n const inverseRotationMatrix = (angle !== 0) ? util.invertTransformMatrix(rotationMatrix) : util.IDENTITY_MATRIX;\n const boxCenter = [...bounding.getBoxCenter({ startPoint: box.startPoint, endPoint: box.endPoint }), 1];\n return coordsRotated.map((coord) => ([\n Math.round(coord[0] + util.dot(boxCenter, inverseRotationMatrix[0])),\n Math.round(coord[1] + util.dot(boxCenter, inverseRotationMatrix[1])),\n Math.round(coord[2]),\n ]));\n }\n\n // eslint-disable-next-line class-methods-use-this\n getLeftToRightEyeDepthDifference(rawCoords) {\n const leftEyeZ = rawCoords[eyeLandmarks.leftBounds[0]][2];\n const rightEyeZ = rawCoords[eyeLandmarks.rightBounds[0]][2];\n return leftEyeZ - rightEyeZ;\n }\n\n // Returns a box describing a cropped region around the eye fit for passing to the iris model.\n getEyeBox(rawCoords, face, eyeInnerCornerIndex, eyeOuterCornerIndex, flip = false) {\n const box = bounding.squarifyBox(bounding.enlargeBox(bounding.calculateLandmarksBoundingBox([rawCoords[eyeInnerCornerIndex], rawCoords[eyeOuterCornerIndex]]), this.irisEnlarge));\n const boxSize = bounding.getBoxSize(box);\n let crop = tf.image.cropAndResize(face, [[\n box.startPoint[1] / this.meshSize,\n box.startPoint[0] / this.meshSize, box.endPoint[1] / this.meshSize,\n box.endPoint[0] / this.meshSize,\n ]], [0], [this.irisSize, this.irisSize]);\n if (flip && env.kernels.includes('flipleftright')) {\n const flipped = tf.image.flipLeftRight(crop); // flipLeftRight is not defined for tfjs-node\n tf.dispose(crop);\n crop = flipped;\n }\n return { box, boxSize, crop };\n }\n\n // Given a cropped image of an eye, returns the coordinates of the contours surrounding the eye and the iris.\n getEyeCoords(eyeData, eyeBox, eyeBoxSize, flip = false) {\n const eyeRawCoords: Array<[number, number, number]> = [];\n for (let i = 0; i < irisLandmarks.numCoordinates; i++) {\n const x = eyeData[i * 3];\n const y = eyeData[i * 3 + 1];\n const z = eyeData[i * 3 + 2];\n eyeRawCoords.push([\n (flip ? (1 - (x / this.irisSize)) : (x / this.irisSize)) * eyeBoxSize[0] + eyeBox.startPoint[0],\n (y / this.irisSize) * eyeBoxSize[1] + eyeBox.startPoint[1], z,\n ]);\n }\n return { rawCoords: eyeRawCoords, iris: eyeRawCoords.slice(irisLandmarks.index) };\n }\n\n // The z-coordinates returned for the iris are unreliable, so we take the z values from the surrounding keypoints.\n // eslint-disable-next-line class-methods-use-this\n getAdjustedIrisCoords(rawCoords, irisCoords, direction) {\n const upperCenterZ = rawCoords[coords.MESH_ANNOTATIONS[`${direction}EyeUpper0`][irisLandmarks.upperCenter]][2];\n const lowerCenterZ = rawCoords[coords.MESH_ANNOTATIONS[`${direction}EyeLower0`][irisLandmarks.lowerCenter]][2];\n const averageZ = (upperCenterZ + lowerCenterZ) / 2;\n // Iris indices: 0: center | 1: right | 2: above | 3: left | 4: below\n return irisCoords.map((coord, i) => {\n let z = averageZ;\n if (i === 2) {\n z = upperCenterZ;\n } else if (i === 4) {\n z = lowerCenterZ;\n }\n return [coord[0], coord[1], z];\n });\n }\n\n correctFaceRotation(config, box, input) {\n const [indexOfMouth, indexOfForehead] = (box.landmarks.length >= meshLandmarks.count) ? meshLandmarks.symmetryLine : blazeFaceLandmarks.symmetryLine;\n const angle: number = util.computeRotation(box.landmarks[indexOfMouth], box.landmarks[indexOfForehead]);\n const faceCenter: [number, number] = bounding.getBoxCenter({ startPoint: box.startPoint, endPoint: box.endPoint });\n const faceCenterNormalized: [number, number] = [faceCenter[0] / input.shape[2], faceCenter[1] / input.shape[1]];\n const rotated = tf.image.rotateWithOffset(input, angle, 0, faceCenterNormalized); // rotateWithOffset is not defined for tfjs-node\n const rotationMatrix = util.buildRotationMatrix(-angle, faceCenter);\n const cut = config.face.mesh.enabled\n ? bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, rotated, [this.meshSize, this.meshSize])\n : bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, rotated, [this.boxSize, this.boxSize]);\n const face = tf.div(cut, 255);\n tf.dispose(cut);\n tf.dispose(rotated);\n return [angle, rotationMatrix, face];\n }\n\n async augmentIris(rawCoords, face) {\n const { box: leftEyeBox, boxSize: leftEyeBoxSize, crop: leftEyeCrop } = this.getEyeBox(rawCoords, face, eyeLandmarks.leftBounds[0], eyeLandmarks.leftBounds[1], true);\n const { box: rightEyeBox, boxSize: rightEyeBoxSize, crop: rightEyeCrop } = this.getEyeBox(rawCoords, face, eyeLandmarks.rightBounds[0], eyeLandmarks.rightBounds[1]);\n const combined = tf.concat([leftEyeCrop, rightEyeCrop]);\n tf.dispose(leftEyeCrop);\n tf.dispose(rightEyeCrop);\n const eyePredictions = this.irisModel.predict(combined) as Tensor;\n tf.dispose(combined);\n const eyePredictionsData = await eyePredictions.data(); // inside tf.tidy\n tf.dispose(eyePredictions);\n const leftEyeData = eyePredictionsData.slice(0, irisLandmarks.numCoordinates * 3);\n const { rawCoords: leftEyeRawCoords, iris: leftIrisRawCoords } = this.getEyeCoords(leftEyeData, leftEyeBox, leftEyeBoxSize, true);\n const rightEyeData = eyePredictionsData.slice(irisLandmarks.numCoordinates * 3);\n const { rawCoords: rightEyeRawCoords, iris: rightIrisRawCoords } = this.getEyeCoords(rightEyeData, rightEyeBox, rightEyeBoxSize);\n const leftToRightEyeDepthDifference = this.getLeftToRightEyeDepthDifference(rawCoords);\n if (Math.abs(leftToRightEyeDepthDifference) < 30) { // User is looking straight ahead.\n replaceRawCoordinates(rawCoords, leftEyeRawCoords, 'left', null);\n replaceRawCoordinates(rawCoords, rightEyeRawCoords, 'right', null);\n // If the user is looking to the left or to the right, the iris coordinates tend to diverge too much from the mesh coordinates for them to be merged\n // So we only update a single contour line above and below the eye.\n } else if (leftToRightEyeDepthDifference < 1) { // User is looking towards the right.\n replaceRawCoordinates(rawCoords, leftEyeRawCoords, 'left', ['EyeUpper0', 'EyeLower0']);\n } else { // User is looking towards the left.\n replaceRawCoordinates(rawCoords, rightEyeRawCoords, 'right', ['EyeUpper0', 'EyeLower0']);\n }\n const adjustedLeftIrisCoords = this.getAdjustedIrisCoords(rawCoords, leftIrisRawCoords, 'left');\n const adjustedRightIrisCoords = this.getAdjustedIrisCoords(rawCoords, rightIrisRawCoords, 'right');\n const newCoords = rawCoords.concat(adjustedLeftIrisCoords).concat(adjustedRightIrisCoords);\n return newCoords;\n }\n\n async predict(input, config) {\n let useFreshBox = false;\n // run new detector every skipFrames unless we only want box to start with\n let detector;\n if ((this.skipped === 0) || (this.skipped > config.face.detector.skipFrames) || !config.face.mesh.enabled || !config.skipFrame) {\n detector = await this.boundingBoxDetector.getBoundingBoxes(input, config);\n this.skipped = 0;\n }\n if (config.skipFrame) this.skipped++;\n\n // if detector result count doesn't match current working set, use it to reset current working set\n if (!config.skipFrame || (detector && detector.boxes && (!config.face.mesh.enabled || (detector.boxes.length !== this.detectedFaces) && (this.detectedFaces !== config.face.detector.maxDetected)))) {\n this.storedBoxes = [];\n this.detectedFaces = 0;\n for (const possible of detector.boxes) {\n const startPoint = await possible.box.startPoint.data();\n const endPoint = await possible.box.endPoint.data();\n const landmarks = await possible.landmarks.array();\n this.storedBoxes.push({ startPoint, endPoint, landmarks, confidence: possible.confidence });\n }\n if (this.storedBoxes.length > 0) useFreshBox = true;\n }\n\n if (useFreshBox) {\n if (!detector || !detector.boxes || (detector.boxes.length === 0)) {\n this.storedBoxes = [];\n this.detectedFaces = 0;\n return null;\n }\n for (let i = 0; i < this.storedBoxes.length; i++) {\n const scaledBox = bounding.scaleBoxCoordinates({ startPoint: this.storedBoxes[i].startPoint, endPoint: this.storedBoxes[i].endPoint }, detector.scaleFactor);\n const enlargedBox = bounding.enlargeBox(scaledBox);\n const squarifiedBox = bounding.squarifyBox(enlargedBox);\n const landmarks = this.storedBoxes[i].landmarks;\n const confidence = this.storedBoxes[i].confidence;\n this.storedBoxes[i] = { ...squarifiedBox, confidence, landmarks };\n }\n }\n if (detector && detector.boxes) {\n detector.boxes.forEach((prediction) => {\n tf.dispose(prediction.box.startPoint);\n tf.dispose(prediction.box.endPoint);\n tf.dispose(prediction.landmarks);\n });\n }\n\n const results: Array<{ mesh, box, faceConfidence, boxConfidence, confidence, image }> = [];\n // for (let i = 0; i < this.storedBoxes.length; i++) {\n const newBoxes: Array<{ startPoint: number[]; endPoint: number[]; landmarks: number[]; confidence: number; faceConfidence?: number | undefined; }> = [];\n for (let box of this.storedBoxes) {\n // let box = this.storedBoxes[i]; // The facial bounding box landmarks could come either from blazeface (if we are using a fresh box), or from the mesh model (if we are reusing an old box).\n let face;\n let angle = 0;\n let rotationMatrix;\n\n if (config.face.detector.rotation && config.face.mesh.enabled && env.kernels.includes('rotatewithoffset')) {\n [angle, rotationMatrix, face] = this.correctFaceRotation(config, box, input);\n } else {\n rotationMatrix = util.IDENTITY_MATRIX;\n const cloned = input.clone();\n const cut = config.face.mesh.enabled\n ? bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, cloned, [this.meshSize, this.meshSize])\n : bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, cloned, [this.boxSize, this.boxSize]);\n face = tf.div(cut, 255);\n tf.dispose(cut);\n tf.dispose(cloned);\n }\n // if we're not going to produce mesh, don't spend time with further processing\n if (!config.face.mesh.enabled) {\n results.push({\n mesh: [],\n box,\n faceConfidence: null,\n boxConfidence: box.confidence,\n confidence: box.confidence,\n image: face,\n });\n } else {\n const [contours, confidence, contourCoords] = this.meshDetector.execute(face) as Array; // The first returned tensor represents facial contours which are already included in the coordinates.\n tf.dispose(contours);\n const faceConfidence = (await confidence.data())[0] as number; // inside tf.tidy\n tf.dispose(confidence);\n const coordsReshaped = tf.reshape(contourCoords, [-1, 3]);\n let rawCoords = await coordsReshaped.array();\n tf.dispose(contourCoords);\n tf.dispose(coordsReshaped);\n if (faceConfidence < config.face.detector.minConfidence) {\n // if (!this.storedBoxes[i]) console.log('2', i, this.storedBoxes.length, this.storedBoxes[i], box, this.storedBoxes);\n // this.storedBoxes[i].confidence = faceConfidence; // reset confidence of cached box\n box.confidence = faceConfidence; // reset confidence of cached box\n tf.dispose(face);\n } else {\n if (config.face.iris.enabled) rawCoords = await this.augmentIris(rawCoords, face);\n\n // override box from detection with one calculated from mesh\n const mesh = this.transformRawCoords(rawCoords, box, angle, rotationMatrix);\n box = { ...bounding.enlargeBox(bounding.calculateLandmarksBoundingBox(mesh), 1.5), confidence: box.confidence }; // redefine box with mesh calculated one\n\n // do rotation one more time with mesh keypoints if we want to return perfect image\n if (config.face.detector.rotation && config.face.mesh.enabled && config.face.description.enabled && env.kernels.includes('rotatewithoffset')) {\n tf.dispose(face); // we'll overwrite original face\n [angle, rotationMatrix, face] = this.correctFaceRotation(config, box, input);\n }\n results.push({\n mesh,\n box,\n faceConfidence,\n boxConfidence: box.confidence,\n confidence: faceConfidence,\n image: face,\n });\n\n // updated stored cache values\n // this.storedBoxes[i] = { ...bounding.squarifyBox(box), confidence: box.confidence, faceConfidence };\n box = { ...bounding.squarifyBox(box), confidence: box.confidence, faceConfidence };\n }\n }\n newBoxes.push(box);\n }\n\n // results = results.filter((a) => a !== null);\n // remove cache entries for detected boxes on low confidence\n if (config.face.mesh.enabled) this.storedBoxes = newBoxes.filter((a) => a.confidence > config.face.detector.minConfidence);\n this.detectedFaces = results.length;\n\n return results;\n }\n}\n", "/**\n * FaceMesh & BlazeFace Module entry point\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as blazeface from './blazeface';\nimport * as facepipeline from './facepipeline';\nimport * as coords from './coords';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { FaceResult } from '../result';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet faceModels: [blazeface.BlazeFaceModel | null, GraphModel | null, GraphModel | null] = [null, null, null];\nlet facePipeline;\n\nexport async function predict(input: Tensor, config: Config): Promise {\n const predictions = await facePipeline.predict(input, config);\n const results: Array = [];\n let id = 0;\n for (const prediction of (predictions || [])) {\n if (!prediction || prediction.isDisposedInternal) continue; // guard against disposed tensors on long running operations such as pause in middle of processing\n const meshRaw = prediction.mesh.map((pt) => [\n pt[0] / (input.shape[2] || 0),\n pt[1] / (input.shape[1] || 0),\n pt[2] / facePipeline.meshSize,\n ]);\n const annotations = {};\n if (prediction.mesh && prediction.mesh.length > 0) {\n for (const key of Object.keys(coords.MESH_ANNOTATIONS)) annotations[key] = coords.MESH_ANNOTATIONS[key].map((index) => prediction.mesh[index]);\n }\n const clampedBox: [number, number, number, number] = prediction.box ? [\n Math.trunc(Math.max(0, prediction.box.startPoint[0])),\n Math.trunc(Math.max(0, prediction.box.startPoint[1])),\n Math.trunc(Math.min((input.shape[2] || 0), prediction.box.endPoint[0]) - Math.max(0, prediction.box.startPoint[0])),\n Math.trunc(Math.min((input.shape[1] || 0), prediction.box.endPoint[1]) - Math.max(0, prediction.box.startPoint[1])),\n ] : [0, 0, 0, 0];\n const boxRaw: [number, number, number, number] = prediction.box ? [\n prediction.box.startPoint[0] / (input.shape[2] || 0),\n prediction.box.startPoint[1] / (input.shape[1] || 0),\n (prediction.box.endPoint[0] - prediction.box.startPoint[0]) / (input.shape[2] || 0),\n (prediction.box.endPoint[1] - prediction.box.startPoint[1]) / (input.shape[1] || 0),\n ] : [0, 0, 0, 0];\n results.push({\n id: id++,\n score: Math.round(100 * prediction.faceConfidence || 100 * prediction.boxConfidence || 0) / 100,\n boxScore: Math.round(100 * prediction.boxConfidence) / 100,\n faceScore: Math.round(100 * prediction.faceConfidence) / 100,\n box: clampedBox,\n boxRaw,\n mesh: prediction.mesh,\n meshRaw,\n annotations,\n tensor: prediction.image,\n });\n }\n return results;\n}\n\nexport async function load(config): Promise<[unknown, GraphModel | null, GraphModel | null]> {\n if (env.initial) faceModels = [null, null, null];\n if ((!faceModels[0] && config.face.enabled) || (!faceModels[1] && config.face.mesh.enabled) || (!faceModels[2] && config.face.iris.enabled) || env.initial) {\n faceModels = await Promise.all([\n (!faceModels[0] && config.face.enabled) ? blazeface.load(config) : null,\n (!faceModels[1] && config.face.mesh.enabled) ? tf.loadGraphModel(join(config.modelBasePath, config.face.mesh.modelPath), { fromTFHub: config.face.mesh.modelPath.includes('tfhub.dev') }) as unknown as GraphModel : null,\n (!faceModels[2] && config.face.iris.enabled) ? tf.loadGraphModel(join(config.modelBasePath, config.face.iris.modelPath), { fromTFHub: config.face.iris.modelPath.includes('tfhub.dev') }) as unknown as GraphModel : null,\n ]);\n if (config.face.mesh.enabled) {\n if (!faceModels[1] || !faceModels[1]['modelUrl']) log('load model failed:', config.face.mesh.modelPath);\n else if (config.debug) log('load model:', faceModels[1]['modelUrl']);\n }\n if (config.face.iris.enabled) {\n if (!faceModels[2] || !faceModels[2]['modelUrl']) log('load model failed:', config.face.iris.modelPath);\n else if (config.debug) log('load model:', faceModels[2]['modelUrl']);\n }\n } else if (config.debug) {\n if (faceModels[0]) log('cached model:', faceModels[0].model['modelUrl']);\n if (faceModels[1]) log('cached model:', faceModels[1]['modelUrl']);\n if (faceModels[2]) log('cached model:', faceModels[2]['modelUrl']);\n }\n facePipeline = new facepipeline.Pipeline(faceModels[0], faceModels[1], faceModels[2]);\n return faceModels;\n}\n\nexport const triangulation = coords.TRI468;\nexport const uvmap = coords.UV468;\n", "/**\n * HSE-FaceRes Module\n * Returns Age, Gender, Descriptor\n * Implements Face simmilarity function\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport type { Tensor, GraphModel } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model: GraphModel | null;\nconst last: Array<{\n age: number,\n gender: string,\n genderScore: number,\n descriptor: number[],\n}> = [];\n\nlet lastCount = 0;\nlet skipped = Number.MAX_SAFE_INTEGER;\n\ntype DB = Array<{ name: string, source: string, embedding: number[] }>;\n\nexport async function load(config: Config): Promise {\n const modelUrl = join(config.modelBasePath, config.face.description?.modelPath || '');\n if (env.initial) model = null;\n if (!model) {\n model = await tf.loadGraphModel(modelUrl) as unknown as GraphModel;\n if (!model) log('load model failed:', config.face.description?.modelPath || '');\n else if (config.debug) log('load model:', modelUrl);\n } else if (config.debug) log('cached model:', modelUrl);\n return model;\n}\n\nexport function similarity(embedding1: Array, embedding2: Array, order = 2): number {\n if (!embedding1 || !embedding2) return 0;\n if (embedding1?.length === 0 || embedding2?.length === 0) return 0;\n if (embedding1?.length !== embedding2?.length) return 0;\n // general minkowski distance, euclidean distance is limited case where order is 2\n const distance = 5.0 * embedding1\n .map((_val, i) => (Math.abs(embedding1[i] - embedding2[i]) ** order)) // distance squared\n .reduce((sum, now) => (sum + now), 0) // sum all distances\n ** (1 / order); // get root of\n const res = Math.max(0, 100 - distance) / 100.0;\n return res;\n}\n\nexport function match(embedding: Array, db: DB, threshold = 0) {\n let best = { similarity: 0, name: '', source: '', embedding: [] as number[] };\n if (!embedding || !db || !Array.isArray(embedding) || !Array.isArray(db)) return best;\n for (const f of db) {\n if (f.embedding && f.name) {\n const perc = similarity(embedding, f.embedding);\n if (perc > threshold && perc > best.similarity) best = { ...f, similarity: perc };\n }\n }\n return best;\n}\n\nexport function enhance(input): Tensor {\n const image = tf.tidy(() => {\n // input received from detector is already normalized to 0..1\n // input is also assumed to be straightened\n const tensor = input.image || input.tensor || input;\n if (!(tensor instanceof tf.Tensor)) return null;\n // do a tight crop of image and resize it to fit the model\n const box = [[0.05, 0.15, 0.85, 0.85]]; // empyrical values for top, left, bottom, right\n // const box = [[0.0, 0.0, 1.0, 1.0]]; // basically no crop for test\n if (!model?.inputs[0].shape) return null; // model has no shape so no point continuing\n const crop = (tensor.shape.length === 3)\n ? tf.image.cropAndResize(tf.expandDims(tensor, 0), box, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]) // add batch dimension if missing\n : tf.image.cropAndResize(tensor, box, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]);\n\n /*\n // just resize to fit the embedding model instead of cropping\n const crop = tf.image.resizeBilinear(tensor, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false);\n */\n\n /*\n // convert to black&white to avoid colorization impact\n const rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when converting to grayscale: https://www.mathworks.com/help/matlab/ref/rgb2gray.html\n const [red, green, blue] = tf.split(crop, 3, 3);\n const redNorm = tf.mul(red, rgb[0]);\n const greenNorm = tf.mul(green, rgb[1]);\n const blueNorm = tf.mul(blue, rgb[2]);\n const grayscale = tf.addN([redNorm, greenNorm, blueNorm]);\n const merge = tf.stack([grayscale, grayscale, grayscale], 3).squeeze(4);\n */\n\n /*\n // increase image pseudo-contrast 100%\n // (or do it per-channel so mean is done on each channel)\n // (or calculate histogram and do it based on histogram)\n const mean = merge.mean();\n const factor = 2;\n const contrast = merge.sub(mean).mul(factor).add(mean);\n */\n\n /*\n // normalize brightness from 0..1\n // silly way of creating pseudo-hdr of image\n const darken = crop.sub(crop.min());\n const lighten = darken.div(darken.max());\n */\n\n const norm = tf.mul(crop, 255);\n\n return norm;\n });\n return image;\n}\n\nexport async function predict(image: Tensor, config: Config, idx, count) {\n if (!model) return null;\n if ((skipped < (config.face.description?.skipFrames || 0)) && config.skipFrame && (lastCount === count) && last[idx]?.age && (last[idx]?.age > 0)) {\n skipped++;\n return last[idx];\n }\n skipped = 0;\n return new Promise(async (resolve) => {\n const enhanced = enhance(image);\n\n let resT;\n const obj = {\n age: 0,\n gender: 'unknown',\n genderScore: 0,\n descriptor: [],\n };\n\n if (config.face.description?.enabled) resT = await model?.predict(enhanced);\n tf.dispose(enhanced);\n\n if (resT) {\n const gender = await resT.find((t) => t.shape[1] === 1).data();\n const confidence = Math.trunc(200 * Math.abs((gender[0] - 0.5))) / 100;\n if (confidence > (config.face.description?.minConfidence || 0)) {\n obj.gender = gender[0] <= 0.5 ? 'female' : 'male';\n obj.genderScore = Math.min(0.99, confidence);\n }\n const argmax = tf.argMax(resT.find((t) => t.shape[1] === 100), 1);\n const age = (await argmax.data())[0];\n tf.dispose(argmax);\n const all = await resT.find((t) => t.shape[1] === 100).data();\n obj.age = Math.round(all[age - 1] > all[age + 1] ? 10 * age - 100 * all[age - 1] : 10 * age + 100 * all[age + 1]) / 10;\n\n const desc = resT.find((t) => t.shape[1] === 1024);\n // const reshape = desc.reshape([128, 8]); // reshape large 1024-element descriptor to 128 x 8\n // const reduce = reshape.logSumExp(1); // reduce 2nd dimension by calculating logSumExp on it which leaves us with 128-element descriptor\n\n const descriptor = await desc.data();\n obj.descriptor = [...descriptor];\n resT.forEach((t) => tf.dispose(t));\n }\n last[idx] = obj;\n lastCount = count;\n resolve(obj);\n });\n}\n", "/**\n * Emotion Module\n */\n\nimport { log, join } from '../helpers';\nimport type { Config } from '../config';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport { env } from '../env';\n\nconst annotations = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral'];\nlet model: GraphModel | null;\n// let last: Array<{ score: number, emotion: string }> = [];\nconst last: Array> = [];\nlet lastCount = 0;\nlet skipped = Number.MAX_SAFE_INTEGER;\n\n// tuning values\nconst rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when converting to grayscale\n\nexport async function load(config: Config): Promise {\n if (env.initial) model = null;\n if (!model) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.face.emotion?.modelPath || '')) as unknown as GraphModel;\n if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n\nexport async function predict(image: Tensor, config: Config, idx, count) {\n if (!model) return null;\n if ((skipped < (config.face.emotion?.skipFrames || 0)) && config.skipFrame && (lastCount === count) && last[idx] && (last[idx].length > 0)) {\n skipped++;\n return last[idx];\n }\n skipped = 0;\n return new Promise(async (resolve) => {\n const resize = tf.image.resizeBilinear(image, [model?.inputs[0].shape ? model.inputs[0].shape[2] : 0, model?.inputs[0].shape ? model.inputs[0].shape[1] : 0], false);\n const [red, green, blue] = tf.split(resize, 3, 3);\n tf.dispose(resize);\n // weighted rgb to grayscale: https://www.mathworks.com/help/matlab/ref/rgb2gray.html\n const redNorm = tf.mul(red, rgb[0]);\n const greenNorm = tf.mul(green, rgb[1]);\n const blueNorm = tf.mul(blue, rgb[2]);\n tf.dispose(red);\n tf.dispose(green);\n tf.dispose(blue);\n const grayscale = tf.addN([redNorm, greenNorm, blueNorm]);\n tf.dispose(redNorm);\n tf.dispose(greenNorm);\n tf.dispose(blueNorm);\n const normalize = tf.tidy(() => tf.mul(tf.sub(grayscale, 0.5), 2));\n tf.dispose(grayscale);\n const obj: Array<{ score: number, emotion: string }> = [];\n if (config.face.emotion?.enabled) {\n const emotionT = await model?.predict(normalize) as Tensor; // result is already in range 0..1, no need for additional activation\n const data = await emotionT.data();\n tf.dispose(emotionT);\n for (let i = 0; i < data.length; i++) {\n if (data[i] > (config.face.emotion?.minConfidence || 0)) obj.push({ score: Math.min(0.99, Math.trunc(100 * data[i]) / 100), emotion: annotations[i] });\n }\n obj.sort((a, b) => b.score - a.score);\n }\n tf.dispose(normalize);\n last[idx] = obj;\n lastCount = count;\n resolve(obj);\n });\n}\n", "export const partNames = [\n 'nose', 'leftEye', 'rightEye', 'leftEar', 'rightEar', 'leftShoulder',\n 'rightShoulder', 'leftElbow', 'rightElbow', 'leftWrist', 'rightWrist',\n 'leftHip', 'rightHip', 'leftKnee', 'rightKnee', 'leftAnkle', 'rightAnkle',\n];\n\nexport const count = partNames.length; // 17 keypoints\n\nexport const partIds = partNames.reduce((result, jointName, i) => {\n result[jointName] = i;\n return result;\n}, {});\n\nconst connectedPartNames = [\n ['leftHip', 'leftShoulder'], ['leftElbow', 'leftShoulder'],\n ['leftElbow', 'leftWrist'], ['leftHip', 'leftKnee'],\n ['leftKnee', 'leftAnkle'], ['rightHip', 'rightShoulder'],\n ['rightElbow', 'rightShoulder'], ['rightElbow', 'rightWrist'],\n ['rightHip', 'rightKnee'], ['rightKnee', 'rightAnkle'],\n ['leftShoulder', 'rightShoulder'], ['leftHip', 'rightHip'],\n];\nexport const connectedPartIndices = connectedPartNames.map(([jointNameA, jointNameB]) => ([partIds[jointNameA], partIds[jointNameB]]));\n\nexport const poseChain = [\n ['nose', 'leftEye'], ['leftEye', 'leftEar'], ['nose', 'rightEye'],\n ['rightEye', 'rightEar'], ['nose', 'leftShoulder'],\n ['leftShoulder', 'leftElbow'], ['leftElbow', 'leftWrist'],\n ['leftShoulder', 'leftHip'], ['leftHip', 'leftKnee'],\n ['leftKnee', 'leftAnkle'], ['nose', 'rightShoulder'],\n ['rightShoulder', 'rightElbow'], ['rightElbow', 'rightWrist'],\n ['rightShoulder', 'rightHip'], ['rightHip', 'rightKnee'],\n ['rightKnee', 'rightAnkle'],\n];\n", "import * as kpt from './keypoints';\nimport type { BodyResult } from '../result';\n\nexport function eitherPointDoesntMeetConfidence(a: number, b: number, minConfidence: number) {\n return (a < minConfidence || b < minConfidence);\n}\n\nexport function getAdjacentKeyPoints(keypoints, minConfidence: number) {\n return kpt.connectedPartIndices.reduce((result, [leftJoint, rightJoint]) => {\n if (eitherPointDoesntMeetConfidence(keypoints[leftJoint].score, keypoints[rightJoint].score, minConfidence)) {\n return result;\n }\n result.push([keypoints[leftJoint], keypoints[rightJoint]]);\n return result;\n }, []);\n}\n\nexport function getBoundingBox(keypoints): [number, number, number, number] {\n const coord = keypoints.reduce(({ maxX, maxY, minX, minY }, { position: { x, y } }) => ({\n maxX: Math.max(maxX, x),\n maxY: Math.max(maxY, y),\n minX: Math.min(minX, x),\n minY: Math.min(minY, y),\n }), {\n maxX: Number.NEGATIVE_INFINITY,\n maxY: Number.NEGATIVE_INFINITY,\n minX: Number.POSITIVE_INFINITY,\n minY: Number.POSITIVE_INFINITY,\n });\n return [coord.minX, coord.minY, coord.maxX - coord.minX, coord.maxY - coord.minY];\n}\n\nexport function scalePoses(poses, [height, width], [inputResolutionHeight, inputResolutionWidth]): Array {\n const scaleY = height / inputResolutionHeight;\n const scaleX = width / inputResolutionWidth;\n const scalePose = (pose, i) => ({\n id: i,\n score: pose.score,\n boxRaw: [pose.box[0] / inputResolutionWidth, pose.box[1] / inputResolutionHeight, pose.box[2] / inputResolutionWidth, pose.box[3] / inputResolutionHeight],\n box: [Math.trunc(pose.box[0] * scaleX), Math.trunc(pose.box[1] * scaleY), Math.trunc(pose.box[2] * scaleX), Math.trunc(pose.box[3] * scaleY)],\n keypoints: pose.keypoints.map(({ score, part, position }) => ({\n score,\n part,\n position: [Math.trunc(position.x * scaleX), Math.trunc(position.y * scaleY)],\n positionRaw: [position.x / inputResolutionHeight, position.y / inputResolutionHeight],\n })),\n });\n const scaledPoses = poses.map((pose, i) => scalePose(pose, i));\n return scaledPoses;\n}\n\n// algorithm based on Coursera Lecture from Algorithms, Part 1: https://www.coursera.org/learn/algorithms-part1/lecture/ZjoSM/heapsort\nexport class MaxHeap {\n priorityQueue: Array; // don't touch\n numberOfElements: number;\n getElementValue: unknown; // function call\n\n constructor(maxSize, getElementValue) {\n this.priorityQueue = new Array(maxSize);\n this.numberOfElements = -1;\n this.getElementValue = getElementValue;\n }\n\n enqueue(x) {\n this.priorityQueue[++this.numberOfElements] = x;\n this.swim(this.numberOfElements);\n }\n\n dequeue() {\n const max = this.priorityQueue[0];\n this.exchange(0, this.numberOfElements--);\n this.sink(0);\n this.priorityQueue[this.numberOfElements + 1] = null;\n return max;\n }\n\n empty() { return this.numberOfElements === -1; }\n\n size() { return this.numberOfElements + 1; }\n\n all() { return this.priorityQueue.slice(0, this.numberOfElements + 1); }\n\n max() { return this.priorityQueue[0]; }\n\n swim(k) {\n while (k > 0 && this.less(Math.floor(k / 2), k)) {\n this.exchange(k, Math.floor(k / 2));\n k = Math.floor(k / 2);\n }\n }\n\n sink(k) {\n while (2 * k <= this.numberOfElements) {\n let j = 2 * k;\n if (j < this.numberOfElements && this.less(j, j + 1)) j++;\n if (!this.less(k, j)) break;\n this.exchange(k, j);\n k = j;\n }\n }\n\n getValueAt(i) {\n // @ts-ignore getter is of unknown type\n return this.getElementValue(this.priorityQueue[i]);\n }\n\n less(i, j) {\n return this.getValueAt(i) < this.getValueAt(j);\n }\n\n exchange(i, j) {\n const t = this.priorityQueue[i];\n this.priorityQueue[i] = this.priorityQueue[j];\n this.priorityQueue[j] = t;\n }\n}\n\nexport function getOffsetPoint(y, x, keypoint, offsets) {\n return {\n y: offsets.get(y, x, keypoint),\n x: offsets.get(y, x, keypoint + kpt.count),\n };\n}\n\nexport function getImageCoords(part, outputStride, offsets) {\n const { heatmapY, heatmapX, id: keypoint } = part;\n const { y, x } = getOffsetPoint(heatmapY, heatmapX, keypoint, offsets);\n return {\n x: part.heatmapX * outputStride + x,\n y: part.heatmapY * outputStride + y,\n };\n}\n\nexport function fillArray(element, size) {\n const result = new Array(size);\n for (let i = 0; i < size; i++) {\n result[i] = element;\n }\n return result;\n}\n\nexport function clamp(a, min, max) {\n if (a < min) return min;\n if (a > max) return max;\n return a;\n}\n\nexport function squaredDistance(y1, x1, y2, x2) {\n const dy = y2 - y1;\n const dx = x2 - x1;\n return dy * dy + dx * dx;\n}\n\nexport function addVectors(a, b) {\n return { x: a.x + b.x, y: a.y + b.y };\n}\n\nexport function clampVector(a, min, max) {\n return { y: clamp(a.y, min, max), x: clamp(a.x, min, max) };\n}\n", "import * as utils from './utils';\nimport * as kpt from './keypoints';\n\nconst localMaximumRadius = 1;\nconst outputStride = 16;\nconst squaredNmsRadius = 50 ** 2;\n\nfunction traverse(edgeId, sourceKeypoint, targetId, scores, offsets, displacements, offsetRefineStep = 2) {\n const getDisplacement = (point) => ({\n y: displacements.get(point.y, point.x, edgeId),\n x: displacements.get(point.y, point.x, (displacements.shape[2] / 2) + edgeId),\n });\n const getStridedIndexNearPoint = (point, height, width) => ({\n y: utils.clamp(Math.round(point.y / outputStride), 0, height - 1),\n x: utils.clamp(Math.round(point.x / outputStride), 0, width - 1),\n });\n\n const [height, width] = scores.shape;\n // Nearest neighbor interpolation for the source->target displacements.\n const sourceKeypointIndices = getStridedIndexNearPoint(sourceKeypoint.position, height, width);\n const displacement = getDisplacement(sourceKeypointIndices);\n const displacedPoint = utils.addVectors(sourceKeypoint.position, displacement);\n let targetKeypoint = displacedPoint;\n for (let i = 0; i < offsetRefineStep; i++) {\n const targetKeypointIndices = getStridedIndexNearPoint(targetKeypoint, height, width);\n const offsetPoint = utils.getOffsetPoint(targetKeypointIndices.y, targetKeypointIndices.x, targetId, offsets);\n targetKeypoint = utils.addVectors(\n { x: targetKeypointIndices.x * outputStride, y: targetKeypointIndices.y * outputStride },\n { x: offsetPoint.x, y: offsetPoint.y },\n );\n }\n const targetKeyPointIndices = getStridedIndexNearPoint(targetKeypoint, height, width);\n const score = scores.get(targetKeyPointIndices.y, targetKeyPointIndices.x, targetId);\n return { position: targetKeypoint, part: kpt.partNames[targetId], score };\n}\n\nexport function decodePose(root, scores, offsets, displacementsFwd, displacementsBwd) {\n const tuples = kpt.poseChain.map(([parentJoinName, childJoinName]) => ([kpt.partIds[parentJoinName], kpt.partIds[childJoinName]]));\n const edgesFwd = tuples.map(([, childJointId]) => childJointId);\n const edgesBwd = tuples.map(([parentJointId]) => parentJointId);\n const numParts = scores.shape[2]; // [21,21,17]\n const numEdges = edgesFwd.length;\n const keypoints = new Array(numParts);\n // Start a new detection instance at the position of the root.\n const rootPoint = utils.getImageCoords(root.part, outputStride, offsets);\n keypoints[root.part.id] = {\n score: root.score,\n part: kpt.partNames[root.part.id],\n position: rootPoint,\n };\n // Decode the part positions upwards in the tree, following the backward displacements.\n for (let edge = numEdges - 1; edge >= 0; --edge) {\n const sourceId = edgesFwd[edge];\n const targetId = edgesBwd[edge];\n if (keypoints[sourceId] && !keypoints[targetId]) {\n keypoints[targetId] = traverse(edge, keypoints[sourceId], targetId, scores, offsets, displacementsBwd);\n }\n }\n // Decode the part positions downwards in the tree, following the forward displacements.\n for (let edge = 0; edge < numEdges; ++edge) {\n const sourceId = edgesBwd[edge];\n const targetId = edgesFwd[edge];\n if (keypoints[sourceId] && !keypoints[targetId]) {\n keypoints[targetId] = traverse(edge, keypoints[sourceId], targetId, scores, offsets, displacementsFwd);\n }\n }\n return keypoints;\n}\n\nfunction scoreIsMaximumInLocalWindow(keypointId, score, heatmapY, heatmapX, scores) {\n const [height, width] = scores.shape;\n let localMaximum = true;\n const yStart = Math.max(heatmapY - localMaximumRadius, 0);\n const yEnd = Math.min(heatmapY + localMaximumRadius + 1, height);\n for (let yCurrent = yStart; yCurrent < yEnd; ++yCurrent) {\n const xStart = Math.max(heatmapX - localMaximumRadius, 0);\n const xEnd = Math.min(heatmapX + localMaximumRadius + 1, width);\n for (let xCurrent = xStart; xCurrent < xEnd; ++xCurrent) {\n if (scores.get(yCurrent, xCurrent, keypointId) > score) {\n localMaximum = false;\n break;\n }\n }\n if (!localMaximum) break;\n }\n return localMaximum;\n}\n\nexport function buildPartWithScoreQueue(minConfidence, scores) {\n const [height, width, numKeypoints] = scores.shape;\n const queue = new utils.MaxHeap(height * width * numKeypoints, ({ score }) => score);\n for (let heatmapY = 0; heatmapY < height; ++heatmapY) {\n for (let heatmapX = 0; heatmapX < width; ++heatmapX) {\n for (let keypointId = 0; keypointId < numKeypoints; ++keypointId) {\n const score = scores.get(heatmapY, heatmapX, keypointId);\n // Only consider parts with score greater or equal to threshold as root candidates.\n if (score < minConfidence) continue;\n // Only consider keypoints whose score is maximum in a local window.\n if (scoreIsMaximumInLocalWindow(keypointId, score, heatmapY, heatmapX, scores)) queue.enqueue({ score, part: { heatmapY, heatmapX, id: keypointId } });\n }\n }\n }\n return queue;\n}\n\nfunction withinRadius(poses, { x, y }, keypointId) {\n return poses.some(({ keypoints }) => {\n const correspondingKeypoint = keypoints[keypointId]?.position;\n if (!correspondingKeypoint) return false;\n return utils.squaredDistance(y, x, correspondingKeypoint.y, correspondingKeypoint.x) <= squaredNmsRadius;\n });\n}\n\nfunction getInstanceScore(existingPoses, keypoints) {\n const notOverlappedKeypointScores = keypoints.reduce((result, { position, score }, keypointId) => {\n if (!withinRadius(existingPoses, position, keypointId)) result += score;\n return result;\n }, 0.0);\n return notOverlappedKeypointScores / keypoints.length;\n}\n\nexport function decode(offsets, scores, displacementsFwd, displacementsBwd, maxDetected, minConfidence) {\n const poses: Array<{ keypoints, box: [number, number, number, number], score: number }> = [];\n const queue = buildPartWithScoreQueue(minConfidence, scores);\n // Generate at most maxDetected object instances per image in decreasing root part score order.\n while (poses.length < maxDetected && !queue.empty()) {\n // The top element in the queue is the next root candidate.\n const root = queue.dequeue();\n // Part-based non-maximum suppression: We reject a root candidate if it is within a disk of `nmsRadius` pixels from the corresponding part of a previously detected instance.\n // @ts-ignore this one is tree walk\n const rootImageCoords = utils.getImageCoords(root.part, outputStride, offsets);\n // @ts-ignore this one is tree walk\n if (withinRadius(poses, rootImageCoords, root.part.id)) continue;\n // Else start a new detection instance at the position of the root.\n let keypoints = decodePose(root, scores, offsets, displacementsFwd, displacementsBwd);\n keypoints = keypoints.filter((a) => a.score > minConfidence);\n const score = getInstanceScore(poses, keypoints);\n const box = utils.getBoundingBox(keypoints);\n if (score > minConfidence) poses.push({ keypoints, box, score: Math.round(100 * score) / 100 });\n }\n return poses;\n}\n", "/**\n * PoseNet module entry point\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as poses from './poses';\nimport * as util from './utils';\nimport type { BodyResult } from '../result';\nimport type { Tensor, GraphModel } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model: GraphModel;\nconst poseNetOutputs = ['MobilenetV1/offset_2/BiasAdd'/* offsets */, 'MobilenetV1/heatmap_2/BiasAdd'/* heatmapScores */, 'MobilenetV1/displacement_fwd_2/BiasAdd'/* displacementFwd */, 'MobilenetV1/displacement_bwd_2/BiasAdd'/* displacementBwd */];\n\nexport async function predict(input: Tensor, config: Config): Promise {\n const res = tf.tidy(() => {\n if (!model.inputs[0].shape) return [];\n const resized = tf.image.resizeBilinear(input, [model.inputs[0].shape[2], model.inputs[0].shape[1]]);\n const normalized = tf.sub(tf.div(tf.cast(resized, 'float32'), 127.5), 1.0);\n const results: Array = model.execute(normalized, poseNetOutputs) as Array;\n const results3d = results.map((y) => tf.squeeze(y, [0]));\n results3d[1] = results3d[1].sigmoid(); // apply sigmoid on scores\n return results3d;\n });\n\n const buffers = await Promise.all(res.map((tensor: Tensor) => tensor.buffer()));\n for (const t of res) tf.dispose(t);\n\n const decoded = await poses.decode(buffers[0], buffers[1], buffers[2], buffers[3], config.body.maxDetected, config.body.minConfidence);\n if (!model.inputs[0].shape) return [];\n const scaled = util.scalePoses(decoded, [input.shape[1], input.shape[2]], [model.inputs[0].shape[2], model.inputs[0].shape[1]]) as BodyResult[];\n return scaled;\n}\n\nexport async function load(config: Config): Promise {\n if (!model || env.initial) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath || '')) as unknown as GraphModel;\n if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n", "import * as tf from '../../dist/tfjs.esm.js';\n\nexport function getBoxSize(box) {\n return [\n Math.abs(box.endPoint[0] - box.startPoint[0]),\n Math.abs(box.endPoint[1] - box.startPoint[1]),\n ];\n}\n\nexport function getBoxCenter(box) {\n return [\n box.startPoint[0] + (box.endPoint[0] - box.startPoint[0]) / 2,\n box.startPoint[1] + (box.endPoint[1] - box.startPoint[1]) / 2,\n ];\n}\n\nexport function cutBoxFromImageAndResize(box, image, cropSize) {\n const h = image.shape[1];\n const w = image.shape[2];\n const boxes = [[\n box.startPoint[1] / h,\n box.startPoint[0] / w,\n box.endPoint[1] / h,\n box.endPoint[0] / w,\n ]];\n return tf.image.cropAndResize(image, boxes, [0], cropSize);\n}\n\nexport function scaleBoxCoordinates(box, factor) {\n const startPoint = [box.startPoint[0] * factor[0], box.startPoint[1] * factor[1]];\n const endPoint = [box.endPoint[0] * factor[0], box.endPoint[1] * factor[1]];\n const palmLandmarks = box.palmLandmarks.map((coord) => {\n const scaledCoord = [coord[0] * factor[0], coord[1] * factor[1]];\n return scaledCoord;\n });\n return { startPoint, endPoint, palmLandmarks, confidence: box.confidence };\n}\n\nexport function enlargeBox(box, factor = 1.5) {\n const center = getBoxCenter(box);\n const size = getBoxSize(box);\n const newHalfSize = [factor * size[0] / 2, factor * size[1] / 2];\n const startPoint = [center[0] - newHalfSize[0], center[1] - newHalfSize[1]];\n const endPoint = [center[0] + newHalfSize[0], center[1] + newHalfSize[1]];\n return { startPoint, endPoint, palmLandmarks: box.palmLandmarks };\n}\n\nexport function squarifyBox(box) {\n const centers = getBoxCenter(box);\n const size = getBoxSize(box);\n const maxEdge = Math.max(...size);\n const halfSize = maxEdge / 2;\n const startPoint = [centers[0] - halfSize, centers[1] - halfSize];\n const endPoint = [centers[0] + halfSize, centers[1] + halfSize];\n return { startPoint, endPoint, palmLandmarks: box.palmLandmarks };\n}\n\nexport function shiftBox(box, shiftFactor) {\n const boxSize = [\n box.endPoint[0] - box.startPoint[0],\n box.endPoint[1] - box.startPoint[1],\n ];\n const shiftVector = [boxSize[0] * shiftFactor[0], boxSize[1] * shiftFactor[1]];\n const startPoint = [box.startPoint[0] + shiftVector[0], box.startPoint[1] + shiftVector[1]];\n const endPoint = [box.endPoint[0] + shiftVector[0], box.endPoint[1] + shiftVector[1]];\n return { startPoint, endPoint, palmLandmarks: box.palmLandmarks };\n}\n", "export const anchors = [\n { x: 0.015625, y: 0.015625 },\n { x: 0.015625, y: 0.015625 },\n { x: 0.046875, y: 0.015625 },\n { x: 0.046875, y: 0.015625 },\n { x: 0.078125, y: 0.015625 },\n { x: 0.078125, y: 0.015625 },\n { x: 0.109375, y: 0.015625 },\n { x: 0.109375, y: 0.015625 },\n { x: 0.140625, y: 0.015625 },\n { x: 0.140625, y: 0.015625 },\n { x: 0.171875, y: 0.015625 },\n { x: 0.171875, y: 0.015625 },\n { x: 0.203125, y: 0.015625 },\n { x: 0.203125, y: 0.015625 },\n { x: 0.234375, y: 0.015625 },\n { x: 0.234375, y: 0.015625 },\n { x: 0.265625, y: 0.015625 },\n { x: 0.265625, y: 0.015625 },\n { x: 0.296875, y: 0.015625 },\n { x: 0.296875, y: 0.015625 },\n { x: 0.328125, y: 0.015625 },\n { x: 0.328125, y: 0.015625 },\n { x: 0.359375, y: 0.015625 },\n { x: 0.359375, y: 0.015625 },\n { x: 0.390625, y: 0.015625 },\n { x: 0.390625, y: 0.015625 },\n { x: 0.421875, y: 0.015625 },\n { x: 0.421875, y: 0.015625 },\n { x: 0.453125, y: 0.015625 },\n { x: 0.453125, y: 0.015625 },\n { x: 0.484375, y: 0.015625 },\n { x: 0.484375, y: 0.015625 },\n { x: 0.515625, y: 0.015625 },\n { x: 0.515625, y: 0.015625 },\n { x: 0.546875, y: 0.015625 },\n { x: 0.546875, y: 0.015625 },\n { x: 0.578125, y: 0.015625 },\n { x: 0.578125, y: 0.015625 },\n { x: 0.609375, y: 0.015625 },\n { x: 0.609375, y: 0.015625 },\n { x: 0.640625, y: 0.015625 },\n { x: 0.640625, y: 0.015625 },\n { x: 0.671875, y: 0.015625 },\n { x: 0.671875, y: 0.015625 },\n { x: 0.703125, y: 0.015625 },\n { x: 0.703125, y: 0.015625 },\n { x: 0.734375, y: 0.015625 },\n { x: 0.734375, y: 0.015625 },\n { x: 0.765625, y: 0.015625 },\n { x: 0.765625, y: 0.015625 },\n { x: 0.796875, y: 0.015625 },\n { x: 0.796875, y: 0.015625 },\n { x: 0.828125, y: 0.015625 },\n { x: 0.828125, y: 0.015625 },\n { x: 0.859375, y: 0.015625 },\n { x: 0.859375, y: 0.015625 },\n { x: 0.890625, y: 0.015625 },\n { x: 0.890625, y: 0.015625 },\n { x: 0.921875, y: 0.015625 },\n { x: 0.921875, y: 0.015625 },\n { x: 0.953125, y: 0.015625 },\n { x: 0.953125, y: 0.015625 },\n { x: 0.984375, y: 0.015625 },\n { x: 0.984375, y: 0.015625 },\n { x: 0.015625, y: 0.046875 },\n { x: 0.015625, y: 0.046875 },\n { x: 0.046875, y: 0.046875 },\n { x: 0.046875, y: 0.046875 },\n { x: 0.078125, y: 0.046875 },\n { x: 0.078125, y: 0.046875 },\n { x: 0.109375, y: 0.046875 },\n { x: 0.109375, y: 0.046875 },\n { x: 0.140625, y: 0.046875 },\n { x: 0.140625, y: 0.046875 },\n { x: 0.171875, y: 0.046875 },\n { x: 0.171875, y: 0.046875 },\n { x: 0.203125, y: 0.046875 },\n { x: 0.203125, y: 0.046875 },\n { x: 0.234375, y: 0.046875 },\n { x: 0.234375, y: 0.046875 },\n { x: 0.265625, y: 0.046875 },\n { x: 0.265625, y: 0.046875 },\n { x: 0.296875, y: 0.046875 },\n { x: 0.296875, y: 0.046875 },\n { x: 0.328125, y: 0.046875 },\n { x: 0.328125, y: 0.046875 },\n { x: 0.359375, y: 0.046875 },\n { x: 0.359375, y: 0.046875 },\n { x: 0.390625, y: 0.046875 },\n { x: 0.390625, y: 0.046875 },\n { x: 0.421875, y: 0.046875 },\n { x: 0.421875, y: 0.046875 },\n { x: 0.453125, y: 0.046875 },\n { x: 0.453125, y: 0.046875 },\n { x: 0.484375, y: 0.046875 },\n { x: 0.484375, y: 0.046875 },\n { x: 0.515625, y: 0.046875 },\n { x: 0.515625, y: 0.046875 },\n { x: 0.546875, y: 0.046875 },\n { x: 0.546875, y: 0.046875 },\n { x: 0.578125, y: 0.046875 },\n { x: 0.578125, y: 0.046875 },\n { x: 0.609375, y: 0.046875 },\n { x: 0.609375, y: 0.046875 },\n { x: 0.640625, y: 0.046875 },\n { x: 0.640625, y: 0.046875 },\n { x: 0.671875, y: 0.046875 },\n { x: 0.671875, y: 0.046875 },\n { x: 0.703125, y: 0.046875 },\n { x: 0.703125, y: 0.046875 },\n { x: 0.734375, y: 0.046875 },\n { x: 0.734375, y: 0.046875 },\n { x: 0.765625, y: 0.046875 },\n { x: 0.765625, y: 0.046875 },\n { x: 0.796875, y: 0.046875 },\n { x: 0.796875, y: 0.046875 },\n { x: 0.828125, y: 0.046875 },\n { x: 0.828125, y: 0.046875 },\n { x: 0.859375, y: 0.046875 },\n { x: 0.859375, y: 0.046875 },\n { x: 0.890625, y: 0.046875 },\n { x: 0.890625, y: 0.046875 },\n { x: 0.921875, y: 0.046875 },\n { x: 0.921875, y: 0.046875 },\n { x: 0.953125, y: 0.046875 },\n { x: 0.953125, y: 0.046875 },\n { x: 0.984375, y: 0.046875 },\n { x: 0.984375, y: 0.046875 },\n { x: 0.015625, y: 0.078125 },\n { x: 0.015625, y: 0.078125 },\n { x: 0.046875, y: 0.078125 },\n { x: 0.046875, y: 0.078125 },\n { x: 0.078125, y: 0.078125 },\n { x: 0.078125, y: 0.078125 },\n { x: 0.109375, y: 0.078125 },\n { x: 0.109375, y: 0.078125 },\n { x: 0.140625, y: 0.078125 },\n { x: 0.140625, y: 0.078125 },\n { x: 0.171875, y: 0.078125 },\n { x: 0.171875, y: 0.078125 },\n { x: 0.203125, y: 0.078125 },\n { x: 0.203125, y: 0.078125 },\n { x: 0.234375, y: 0.078125 },\n { x: 0.234375, y: 0.078125 },\n { x: 0.265625, y: 0.078125 },\n { x: 0.265625, y: 0.078125 },\n { x: 0.296875, y: 0.078125 },\n { x: 0.296875, y: 0.078125 },\n { x: 0.328125, y: 0.078125 },\n { x: 0.328125, y: 0.078125 },\n { x: 0.359375, y: 0.078125 },\n { x: 0.359375, y: 0.078125 },\n { x: 0.390625, y: 0.078125 },\n { x: 0.390625, y: 0.078125 },\n { x: 0.421875, y: 0.078125 },\n { x: 0.421875, y: 0.078125 },\n { x: 0.453125, y: 0.078125 },\n { x: 0.453125, y: 0.078125 },\n { x: 0.484375, y: 0.078125 },\n { x: 0.484375, y: 0.078125 },\n { x: 0.515625, y: 0.078125 },\n { x: 0.515625, y: 0.078125 },\n { x: 0.546875, y: 0.078125 },\n { x: 0.546875, y: 0.078125 },\n { x: 0.578125, y: 0.078125 },\n { x: 0.578125, y: 0.078125 },\n { x: 0.609375, y: 0.078125 },\n { x: 0.609375, y: 0.078125 },\n { x: 0.640625, y: 0.078125 },\n { x: 0.640625, y: 0.078125 },\n { x: 0.671875, y: 0.078125 },\n { x: 0.671875, y: 0.078125 },\n { x: 0.703125, y: 0.078125 },\n { x: 0.703125, y: 0.078125 },\n { x: 0.734375, y: 0.078125 },\n { x: 0.734375, y: 0.078125 },\n { x: 0.765625, y: 0.078125 },\n { x: 0.765625, y: 0.078125 },\n { x: 0.796875, y: 0.078125 },\n { x: 0.796875, y: 0.078125 },\n { x: 0.828125, y: 0.078125 },\n { x: 0.828125, y: 0.078125 },\n { x: 0.859375, y: 0.078125 },\n { x: 0.859375, y: 0.078125 },\n { x: 0.890625, y: 0.078125 },\n { x: 0.890625, y: 0.078125 },\n { x: 0.921875, y: 0.078125 },\n { x: 0.921875, y: 0.078125 },\n { x: 0.953125, y: 0.078125 },\n { x: 0.953125, y: 0.078125 },\n { x: 0.984375, y: 0.078125 },\n { x: 0.984375, y: 0.078125 },\n { x: 0.015625, y: 0.109375 },\n { x: 0.015625, y: 0.109375 },\n { x: 0.046875, y: 0.109375 },\n { x: 0.046875, y: 0.109375 },\n { x: 0.078125, y: 0.109375 },\n { x: 0.078125, y: 0.109375 },\n { x: 0.109375, y: 0.109375 },\n { x: 0.109375, y: 0.109375 },\n { x: 0.140625, y: 0.109375 },\n { x: 0.140625, y: 0.109375 },\n { x: 0.171875, y: 0.109375 },\n { x: 0.171875, y: 0.109375 },\n { x: 0.203125, y: 0.109375 },\n { x: 0.203125, y: 0.109375 },\n { x: 0.234375, y: 0.109375 },\n { x: 0.234375, y: 0.109375 },\n { x: 0.265625, y: 0.109375 },\n { x: 0.265625, y: 0.109375 },\n { x: 0.296875, y: 0.109375 },\n { x: 0.296875, y: 0.109375 },\n { x: 0.328125, y: 0.109375 },\n { x: 0.328125, y: 0.109375 },\n { x: 0.359375, y: 0.109375 },\n { x: 0.359375, y: 0.109375 },\n { x: 0.390625, y: 0.109375 },\n { x: 0.390625, y: 0.109375 },\n { x: 0.421875, y: 0.109375 },\n { x: 0.421875, y: 0.109375 },\n { x: 0.453125, y: 0.109375 },\n { x: 0.453125, y: 0.109375 },\n { x: 0.484375, y: 0.109375 },\n { x: 0.484375, y: 0.109375 },\n { x: 0.515625, y: 0.109375 },\n { x: 0.515625, y: 0.109375 },\n { x: 0.546875, y: 0.109375 },\n { x: 0.546875, y: 0.109375 },\n { x: 0.578125, y: 0.109375 },\n { x: 0.578125, y: 0.109375 },\n { x: 0.609375, y: 0.109375 },\n { x: 0.609375, y: 0.109375 },\n { x: 0.640625, y: 0.109375 },\n { x: 0.640625, y: 0.109375 },\n { x: 0.671875, y: 0.109375 },\n { x: 0.671875, y: 0.109375 },\n { x: 0.703125, y: 0.109375 },\n { x: 0.703125, y: 0.109375 },\n { x: 0.734375, y: 0.109375 },\n { x: 0.734375, y: 0.109375 },\n { x: 0.765625, y: 0.109375 },\n { x: 0.765625, y: 0.109375 },\n { x: 0.796875, y: 0.109375 },\n { x: 0.796875, y: 0.109375 },\n { x: 0.828125, y: 0.109375 },\n { x: 0.828125, y: 0.109375 },\n { x: 0.859375, y: 0.109375 },\n { x: 0.859375, y: 0.109375 },\n { x: 0.890625, y: 0.109375 },\n { x: 0.890625, y: 0.109375 },\n { x: 0.921875, y: 0.109375 },\n { x: 0.921875, y: 0.109375 },\n { x: 0.953125, y: 0.109375 },\n { x: 0.953125, y: 0.109375 },\n { x: 0.984375, y: 0.109375 },\n { x: 0.984375, y: 0.109375 },\n { x: 0.015625, y: 0.140625 },\n { x: 0.015625, y: 0.140625 },\n { x: 0.046875, y: 0.140625 },\n { x: 0.046875, y: 0.140625 },\n { x: 0.078125, y: 0.140625 },\n { x: 0.078125, y: 0.140625 },\n { x: 0.109375, y: 0.140625 },\n { x: 0.109375, y: 0.140625 },\n { x: 0.140625, y: 0.140625 },\n { x: 0.140625, y: 0.140625 },\n { x: 0.171875, y: 0.140625 },\n { x: 0.171875, y: 0.140625 },\n { x: 0.203125, y: 0.140625 },\n { x: 0.203125, y: 0.140625 },\n { x: 0.234375, y: 0.140625 },\n { x: 0.234375, y: 0.140625 },\n { x: 0.265625, y: 0.140625 },\n { x: 0.265625, y: 0.140625 },\n { x: 0.296875, y: 0.140625 },\n { x: 0.296875, y: 0.140625 },\n { x: 0.328125, y: 0.140625 },\n { x: 0.328125, y: 0.140625 },\n { x: 0.359375, y: 0.140625 },\n { x: 0.359375, y: 0.140625 },\n { x: 0.390625, y: 0.140625 },\n { x: 0.390625, y: 0.140625 },\n { x: 0.421875, y: 0.140625 },\n { x: 0.421875, y: 0.140625 },\n { x: 0.453125, y: 0.140625 },\n { x: 0.453125, y: 0.140625 },\n { x: 0.484375, y: 0.140625 },\n { x: 0.484375, y: 0.140625 },\n { x: 0.515625, y: 0.140625 },\n { x: 0.515625, y: 0.140625 },\n { x: 0.546875, y: 0.140625 },\n { x: 0.546875, y: 0.140625 },\n { x: 0.578125, y: 0.140625 },\n { x: 0.578125, y: 0.140625 },\n { x: 0.609375, y: 0.140625 },\n { x: 0.609375, y: 0.140625 },\n { x: 0.640625, y: 0.140625 },\n { x: 0.640625, y: 0.140625 },\n { x: 0.671875, y: 0.140625 },\n { x: 0.671875, y: 0.140625 },\n { x: 0.703125, y: 0.140625 },\n { x: 0.703125, y: 0.140625 },\n { x: 0.734375, y: 0.140625 },\n { x: 0.734375, y: 0.140625 },\n { x: 0.765625, y: 0.140625 },\n { x: 0.765625, y: 0.140625 },\n { x: 0.796875, y: 0.140625 },\n { x: 0.796875, y: 0.140625 },\n { x: 0.828125, y: 0.140625 },\n { x: 0.828125, y: 0.140625 },\n { x: 0.859375, y: 0.140625 },\n { x: 0.859375, y: 0.140625 },\n { x: 0.890625, y: 0.140625 },\n { x: 0.890625, y: 0.140625 },\n { x: 0.921875, y: 0.140625 },\n { x: 0.921875, y: 0.140625 },\n { x: 0.953125, y: 0.140625 },\n { x: 0.953125, y: 0.140625 },\n { x: 0.984375, y: 0.140625 },\n { x: 0.984375, y: 0.140625 },\n { x: 0.015625, y: 0.171875 },\n { x: 0.015625, y: 0.171875 },\n { x: 0.046875, y: 0.171875 },\n { x: 0.046875, y: 0.171875 },\n { x: 0.078125, y: 0.171875 },\n { x: 0.078125, y: 0.171875 },\n { x: 0.109375, y: 0.171875 },\n { x: 0.109375, y: 0.171875 },\n { x: 0.140625, y: 0.171875 },\n { x: 0.140625, y: 0.171875 },\n { x: 0.171875, y: 0.171875 },\n { x: 0.171875, y: 0.171875 },\n { x: 0.203125, y: 0.171875 },\n { x: 0.203125, y: 0.171875 },\n { x: 0.234375, y: 0.171875 },\n { x: 0.234375, y: 0.171875 },\n { x: 0.265625, y: 0.171875 },\n { x: 0.265625, y: 0.171875 },\n { x: 0.296875, y: 0.171875 },\n { x: 0.296875, y: 0.171875 },\n { x: 0.328125, y: 0.171875 },\n { x: 0.328125, y: 0.171875 },\n { x: 0.359375, y: 0.171875 },\n { x: 0.359375, y: 0.171875 },\n { x: 0.390625, y: 0.171875 },\n { x: 0.390625, y: 0.171875 },\n { x: 0.421875, y: 0.171875 },\n { x: 0.421875, y: 0.171875 },\n { x: 0.453125, y: 0.171875 },\n { x: 0.453125, y: 0.171875 },\n { x: 0.484375, y: 0.171875 },\n { x: 0.484375, y: 0.171875 },\n { x: 0.515625, y: 0.171875 },\n { x: 0.515625, y: 0.171875 },\n { x: 0.546875, y: 0.171875 },\n { x: 0.546875, y: 0.171875 },\n { x: 0.578125, y: 0.171875 },\n { x: 0.578125, y: 0.171875 },\n { x: 0.609375, y: 0.171875 },\n { x: 0.609375, y: 0.171875 },\n { x: 0.640625, y: 0.171875 },\n { x: 0.640625, y: 0.171875 },\n { x: 0.671875, y: 0.171875 },\n { x: 0.671875, y: 0.171875 },\n { x: 0.703125, y: 0.171875 },\n { x: 0.703125, y: 0.171875 },\n { x: 0.734375, y: 0.171875 },\n { x: 0.734375, y: 0.171875 },\n { x: 0.765625, y: 0.171875 },\n { x: 0.765625, y: 0.171875 },\n { x: 0.796875, y: 0.171875 },\n { x: 0.796875, y: 0.171875 },\n { x: 0.828125, y: 0.171875 },\n { x: 0.828125, y: 0.171875 },\n { x: 0.859375, y: 0.171875 },\n { x: 0.859375, y: 0.171875 },\n { x: 0.890625, y: 0.171875 },\n { x: 0.890625, y: 0.171875 },\n { x: 0.921875, y: 0.171875 },\n { x: 0.921875, y: 0.171875 },\n { x: 0.953125, y: 0.171875 },\n { x: 0.953125, y: 0.171875 },\n { x: 0.984375, y: 0.171875 },\n { x: 0.984375, y: 0.171875 },\n { x: 0.015625, y: 0.203125 },\n { x: 0.015625, y: 0.203125 },\n { x: 0.046875, y: 0.203125 },\n { x: 0.046875, y: 0.203125 },\n { x: 0.078125, y: 0.203125 },\n { x: 0.078125, y: 0.203125 },\n { x: 0.109375, y: 0.203125 },\n { x: 0.109375, y: 0.203125 },\n { x: 0.140625, y: 0.203125 },\n { x: 0.140625, y: 0.203125 },\n { x: 0.171875, y: 0.203125 },\n { x: 0.171875, y: 0.203125 },\n { x: 0.203125, y: 0.203125 },\n { x: 0.203125, y: 0.203125 },\n { x: 0.234375, y: 0.203125 },\n { x: 0.234375, y: 0.203125 },\n { x: 0.265625, y: 0.203125 },\n { x: 0.265625, y: 0.203125 },\n { x: 0.296875, y: 0.203125 },\n { x: 0.296875, y: 0.203125 },\n { x: 0.328125, y: 0.203125 },\n { x: 0.328125, y: 0.203125 },\n { x: 0.359375, y: 0.203125 },\n { x: 0.359375, y: 0.203125 },\n { x: 0.390625, y: 0.203125 },\n { x: 0.390625, y: 0.203125 },\n { x: 0.421875, y: 0.203125 },\n { x: 0.421875, y: 0.203125 },\n { x: 0.453125, y: 0.203125 },\n { x: 0.453125, y: 0.203125 },\n { x: 0.484375, y: 0.203125 },\n { x: 0.484375, y: 0.203125 },\n { x: 0.515625, y: 0.203125 },\n { x: 0.515625, y: 0.203125 },\n { x: 0.546875, y: 0.203125 },\n { x: 0.546875, y: 0.203125 },\n { x: 0.578125, y: 0.203125 },\n { x: 0.578125, y: 0.203125 },\n { x: 0.609375, y: 0.203125 },\n { x: 0.609375, y: 0.203125 },\n { x: 0.640625, y: 0.203125 },\n { x: 0.640625, y: 0.203125 },\n { x: 0.671875, y: 0.203125 },\n { x: 0.671875, y: 0.203125 },\n { x: 0.703125, y: 0.203125 },\n { x: 0.703125, y: 0.203125 },\n { x: 0.734375, y: 0.203125 },\n { x: 0.734375, y: 0.203125 },\n { x: 0.765625, y: 0.203125 },\n { x: 0.765625, y: 0.203125 },\n { x: 0.796875, y: 0.203125 },\n { x: 0.796875, y: 0.203125 },\n { x: 0.828125, y: 0.203125 },\n { x: 0.828125, y: 0.203125 },\n { x: 0.859375, y: 0.203125 },\n { x: 0.859375, y: 0.203125 },\n { x: 0.890625, y: 0.203125 },\n { x: 0.890625, y: 0.203125 },\n { x: 0.921875, y: 0.203125 },\n { x: 0.921875, y: 0.203125 },\n { x: 0.953125, y: 0.203125 },\n { x: 0.953125, y: 0.203125 },\n { x: 0.984375, y: 0.203125 },\n { x: 0.984375, y: 0.203125 },\n { x: 0.015625, y: 0.234375 },\n { x: 0.015625, y: 0.234375 },\n { x: 0.046875, y: 0.234375 },\n { x: 0.046875, y: 0.234375 },\n { x: 0.078125, y: 0.234375 },\n { x: 0.078125, y: 0.234375 },\n { x: 0.109375, y: 0.234375 },\n { x: 0.109375, y: 0.234375 },\n { x: 0.140625, y: 0.234375 },\n { x: 0.140625, y: 0.234375 },\n { x: 0.171875, y: 0.234375 },\n { x: 0.171875, y: 0.234375 },\n { x: 0.203125, y: 0.234375 },\n { x: 0.203125, y: 0.234375 },\n { x: 0.234375, y: 0.234375 },\n { x: 0.234375, y: 0.234375 },\n { x: 0.265625, y: 0.234375 },\n { x: 0.265625, y: 0.234375 },\n { x: 0.296875, y: 0.234375 },\n { x: 0.296875, y: 0.234375 },\n { x: 0.328125, y: 0.234375 },\n { x: 0.328125, y: 0.234375 },\n { x: 0.359375, y: 0.234375 },\n { x: 0.359375, y: 0.234375 },\n { x: 0.390625, y: 0.234375 },\n { x: 0.390625, y: 0.234375 },\n { x: 0.421875, y: 0.234375 },\n { x: 0.421875, y: 0.234375 },\n { x: 0.453125, y: 0.234375 },\n { x: 0.453125, y: 0.234375 },\n { x: 0.484375, y: 0.234375 },\n { x: 0.484375, y: 0.234375 },\n { x: 0.515625, y: 0.234375 },\n { x: 0.515625, y: 0.234375 },\n { x: 0.546875, y: 0.234375 },\n { x: 0.546875, y: 0.234375 },\n { x: 0.578125, y: 0.234375 },\n { x: 0.578125, y: 0.234375 },\n { x: 0.609375, y: 0.234375 },\n { x: 0.609375, y: 0.234375 },\n { x: 0.640625, y: 0.234375 },\n { x: 0.640625, y: 0.234375 },\n { x: 0.671875, y: 0.234375 },\n { x: 0.671875, y: 0.234375 },\n { x: 0.703125, y: 0.234375 },\n { x: 0.703125, y: 0.234375 },\n { x: 0.734375, y: 0.234375 },\n { x: 0.734375, y: 0.234375 },\n { x: 0.765625, y: 0.234375 },\n { x: 0.765625, y: 0.234375 },\n { x: 0.796875, y: 0.234375 },\n { x: 0.796875, y: 0.234375 },\n { x: 0.828125, y: 0.234375 },\n { x: 0.828125, y: 0.234375 },\n { x: 0.859375, y: 0.234375 },\n { x: 0.859375, y: 0.234375 },\n { x: 0.890625, y: 0.234375 },\n { x: 0.890625, y: 0.234375 },\n { x: 0.921875, y: 0.234375 },\n { x: 0.921875, y: 0.234375 },\n { x: 0.953125, y: 0.234375 },\n { x: 0.953125, y: 0.234375 },\n { x: 0.984375, y: 0.234375 },\n { x: 0.984375, y: 0.234375 },\n { x: 0.015625, y: 0.265625 },\n { x: 0.015625, y: 0.265625 },\n { x: 0.046875, y: 0.265625 },\n { x: 0.046875, y: 0.265625 },\n { x: 0.078125, y: 0.265625 },\n { x: 0.078125, y: 0.265625 },\n { x: 0.109375, y: 0.265625 },\n { x: 0.109375, y: 0.265625 },\n { x: 0.140625, y: 0.265625 },\n { x: 0.140625, y: 0.265625 },\n { x: 0.171875, y: 0.265625 },\n { x: 0.171875, y: 0.265625 },\n { x: 0.203125, y: 0.265625 },\n { x: 0.203125, y: 0.265625 },\n { x: 0.234375, y: 0.265625 },\n { x: 0.234375, y: 0.265625 },\n { x: 0.265625, y: 0.265625 },\n { x: 0.265625, y: 0.265625 },\n { x: 0.296875, y: 0.265625 },\n { x: 0.296875, y: 0.265625 },\n { x: 0.328125, y: 0.265625 },\n { x: 0.328125, y: 0.265625 },\n { x: 0.359375, y: 0.265625 },\n { x: 0.359375, y: 0.265625 },\n { x: 0.390625, y: 0.265625 },\n { x: 0.390625, y: 0.265625 },\n { x: 0.421875, y: 0.265625 },\n { x: 0.421875, y: 0.265625 },\n { x: 0.453125, y: 0.265625 },\n { x: 0.453125, y: 0.265625 },\n { x: 0.484375, y: 0.265625 },\n { x: 0.484375, y: 0.265625 },\n { x: 0.515625, y: 0.265625 },\n { x: 0.515625, y: 0.265625 },\n { x: 0.546875, y: 0.265625 },\n { x: 0.546875, y: 0.265625 },\n { x: 0.578125, y: 0.265625 },\n { x: 0.578125, y: 0.265625 },\n { x: 0.609375, y: 0.265625 },\n { x: 0.609375, y: 0.265625 },\n { x: 0.640625, y: 0.265625 },\n { x: 0.640625, y: 0.265625 },\n { x: 0.671875, y: 0.265625 },\n { x: 0.671875, y: 0.265625 },\n { x: 0.703125, y: 0.265625 },\n { x: 0.703125, y: 0.265625 },\n { x: 0.734375, y: 0.265625 },\n { x: 0.734375, y: 0.265625 },\n { x: 0.765625, y: 0.265625 },\n { x: 0.765625, y: 0.265625 },\n { x: 0.796875, y: 0.265625 },\n { x: 0.796875, y: 0.265625 },\n { x: 0.828125, y: 0.265625 },\n { x: 0.828125, y: 0.265625 },\n { x: 0.859375, y: 0.265625 },\n { x: 0.859375, y: 0.265625 },\n { x: 0.890625, y: 0.265625 },\n { x: 0.890625, y: 0.265625 },\n { x: 0.921875, y: 0.265625 },\n { x: 0.921875, y: 0.265625 },\n { x: 0.953125, y: 0.265625 },\n { x: 0.953125, y: 0.265625 },\n { x: 0.984375, y: 0.265625 },\n { x: 0.984375, y: 0.265625 },\n { x: 0.015625, y: 0.296875 },\n { x: 0.015625, y: 0.296875 },\n { x: 0.046875, y: 0.296875 },\n { x: 0.046875, y: 0.296875 },\n { x: 0.078125, y: 0.296875 },\n { x: 0.078125, y: 0.296875 },\n { x: 0.109375, y: 0.296875 },\n { x: 0.109375, y: 0.296875 },\n { x: 0.140625, y: 0.296875 },\n { x: 0.140625, y: 0.296875 },\n { x: 0.171875, y: 0.296875 },\n { x: 0.171875, y: 0.296875 },\n { x: 0.203125, y: 0.296875 },\n { x: 0.203125, y: 0.296875 },\n { x: 0.234375, y: 0.296875 },\n { x: 0.234375, y: 0.296875 },\n { x: 0.265625, y: 0.296875 },\n { x: 0.265625, y: 0.296875 },\n { x: 0.296875, y: 0.296875 },\n { x: 0.296875, y: 0.296875 },\n { x: 0.328125, y: 0.296875 },\n { x: 0.328125, y: 0.296875 },\n { x: 0.359375, y: 0.296875 },\n { x: 0.359375, y: 0.296875 },\n { x: 0.390625, y: 0.296875 },\n { x: 0.390625, y: 0.296875 },\n { x: 0.421875, y: 0.296875 },\n { x: 0.421875, y: 0.296875 },\n { x: 0.453125, y: 0.296875 },\n { x: 0.453125, y: 0.296875 },\n { x: 0.484375, y: 0.296875 },\n { x: 0.484375, y: 0.296875 },\n { x: 0.515625, y: 0.296875 },\n { x: 0.515625, y: 0.296875 },\n { x: 0.546875, y: 0.296875 },\n { x: 0.546875, y: 0.296875 },\n { x: 0.578125, y: 0.296875 },\n { x: 0.578125, y: 0.296875 },\n { x: 0.609375, y: 0.296875 },\n { x: 0.609375, y: 0.296875 },\n { x: 0.640625, y: 0.296875 },\n { x: 0.640625, y: 0.296875 },\n { x: 0.671875, y: 0.296875 },\n { x: 0.671875, y: 0.296875 },\n { x: 0.703125, y: 0.296875 },\n { x: 0.703125, y: 0.296875 },\n { x: 0.734375, y: 0.296875 },\n { x: 0.734375, y: 0.296875 },\n { x: 0.765625, y: 0.296875 },\n { x: 0.765625, y: 0.296875 },\n { x: 0.796875, y: 0.296875 },\n { x: 0.796875, y: 0.296875 },\n { x: 0.828125, y: 0.296875 },\n { x: 0.828125, y: 0.296875 },\n { x: 0.859375, y: 0.296875 },\n { x: 0.859375, y: 0.296875 },\n { x: 0.890625, y: 0.296875 },\n { x: 0.890625, y: 0.296875 },\n { x: 0.921875, y: 0.296875 },\n { x: 0.921875, y: 0.296875 },\n { x: 0.953125, y: 0.296875 },\n { x: 0.953125, y: 0.296875 },\n { x: 0.984375, y: 0.296875 },\n { x: 0.984375, y: 0.296875 },\n { x: 0.015625, y: 0.328125 },\n { x: 0.015625, y: 0.328125 },\n { x: 0.046875, y: 0.328125 },\n { x: 0.046875, y: 0.328125 },\n { x: 0.078125, y: 0.328125 },\n { x: 0.078125, y: 0.328125 },\n { x: 0.109375, y: 0.328125 },\n { x: 0.109375, y: 0.328125 },\n { x: 0.140625, y: 0.328125 },\n { x: 0.140625, y: 0.328125 },\n { x: 0.171875, y: 0.328125 },\n { x: 0.171875, y: 0.328125 },\n { x: 0.203125, y: 0.328125 },\n { x: 0.203125, y: 0.328125 },\n { x: 0.234375, y: 0.328125 },\n { x: 0.234375, y: 0.328125 },\n { x: 0.265625, y: 0.328125 },\n { x: 0.265625, y: 0.328125 },\n { x: 0.296875, y: 0.328125 },\n { x: 0.296875, y: 0.328125 },\n { x: 0.328125, y: 0.328125 },\n { x: 0.328125, y: 0.328125 },\n { x: 0.359375, y: 0.328125 },\n { x: 0.359375, y: 0.328125 },\n { x: 0.390625, y: 0.328125 },\n { x: 0.390625, y: 0.328125 },\n { x: 0.421875, y: 0.328125 },\n { x: 0.421875, y: 0.328125 },\n { x: 0.453125, y: 0.328125 },\n { x: 0.453125, y: 0.328125 },\n { x: 0.484375, y: 0.328125 },\n { x: 0.484375, y: 0.328125 },\n { x: 0.515625, y: 0.328125 },\n { x: 0.515625, y: 0.328125 },\n { x: 0.546875, y: 0.328125 },\n { x: 0.546875, y: 0.328125 },\n { x: 0.578125, y: 0.328125 },\n { x: 0.578125, y: 0.328125 },\n { x: 0.609375, y: 0.328125 },\n { x: 0.609375, y: 0.328125 },\n { x: 0.640625, y: 0.328125 },\n { x: 0.640625, y: 0.328125 },\n { x: 0.671875, y: 0.328125 },\n { x: 0.671875, y: 0.328125 },\n { x: 0.703125, y: 0.328125 },\n { x: 0.703125, y: 0.328125 },\n { x: 0.734375, y: 0.328125 },\n { x: 0.734375, y: 0.328125 },\n { x: 0.765625, y: 0.328125 },\n { x: 0.765625, y: 0.328125 },\n { x: 0.796875, y: 0.328125 },\n { x: 0.796875, y: 0.328125 },\n { x: 0.828125, y: 0.328125 },\n { x: 0.828125, y: 0.328125 },\n { x: 0.859375, y: 0.328125 },\n { x: 0.859375, y: 0.328125 },\n { x: 0.890625, y: 0.328125 },\n { x: 0.890625, y: 0.328125 },\n { x: 0.921875, y: 0.328125 },\n { x: 0.921875, y: 0.328125 },\n { x: 0.953125, y: 0.328125 },\n { x: 0.953125, y: 0.328125 },\n { x: 0.984375, y: 0.328125 },\n { x: 0.984375, y: 0.328125 },\n { x: 0.015625, y: 0.359375 },\n { x: 0.015625, y: 0.359375 },\n { x: 0.046875, y: 0.359375 },\n { x: 0.046875, y: 0.359375 },\n { x: 0.078125, y: 0.359375 },\n { x: 0.078125, y: 0.359375 },\n { x: 0.109375, y: 0.359375 },\n { x: 0.109375, y: 0.359375 },\n { x: 0.140625, y: 0.359375 },\n { x: 0.140625, y: 0.359375 },\n { x: 0.171875, y: 0.359375 },\n { x: 0.171875, y: 0.359375 },\n { x: 0.203125, y: 0.359375 },\n { x: 0.203125, y: 0.359375 },\n { x: 0.234375, y: 0.359375 },\n { x: 0.234375, y: 0.359375 },\n { x: 0.265625, y: 0.359375 },\n { x: 0.265625, y: 0.359375 },\n { x: 0.296875, y: 0.359375 },\n { x: 0.296875, y: 0.359375 },\n { x: 0.328125, y: 0.359375 },\n { x: 0.328125, y: 0.359375 },\n { x: 0.359375, y: 0.359375 },\n { x: 0.359375, y: 0.359375 },\n { x: 0.390625, y: 0.359375 },\n { x: 0.390625, y: 0.359375 },\n { x: 0.421875, y: 0.359375 },\n { x: 0.421875, y: 0.359375 },\n { x: 0.453125, y: 0.359375 },\n { x: 0.453125, y: 0.359375 },\n { x: 0.484375, y: 0.359375 },\n { x: 0.484375, y: 0.359375 },\n { x: 0.515625, y: 0.359375 },\n { x: 0.515625, y: 0.359375 },\n { x: 0.546875, y: 0.359375 },\n { x: 0.546875, y: 0.359375 },\n { x: 0.578125, y: 0.359375 },\n { x: 0.578125, y: 0.359375 },\n { x: 0.609375, y: 0.359375 },\n { x: 0.609375, y: 0.359375 },\n { x: 0.640625, y: 0.359375 },\n { x: 0.640625, y: 0.359375 },\n { x: 0.671875, y: 0.359375 },\n { x: 0.671875, y: 0.359375 },\n { x: 0.703125, y: 0.359375 },\n { x: 0.703125, y: 0.359375 },\n { x: 0.734375, y: 0.359375 },\n { x: 0.734375, y: 0.359375 },\n { x: 0.765625, y: 0.359375 },\n { x: 0.765625, y: 0.359375 },\n { x: 0.796875, y: 0.359375 },\n { x: 0.796875, y: 0.359375 },\n { x: 0.828125, y: 0.359375 },\n { x: 0.828125, y: 0.359375 },\n { x: 0.859375, y: 0.359375 },\n { x: 0.859375, y: 0.359375 },\n { x: 0.890625, y: 0.359375 },\n { x: 0.890625, y: 0.359375 },\n { x: 0.921875, y: 0.359375 },\n { x: 0.921875, y: 0.359375 },\n { x: 0.953125, y: 0.359375 },\n { x: 0.953125, y: 0.359375 },\n { x: 0.984375, y: 0.359375 },\n { x: 0.984375, y: 0.359375 },\n { x: 0.015625, y: 0.390625 },\n { x: 0.015625, y: 0.390625 },\n { x: 0.046875, y: 0.390625 },\n { x: 0.046875, y: 0.390625 },\n { x: 0.078125, y: 0.390625 },\n { x: 0.078125, y: 0.390625 },\n { x: 0.109375, y: 0.390625 },\n { x: 0.109375, y: 0.390625 },\n { x: 0.140625, y: 0.390625 },\n { x: 0.140625, y: 0.390625 },\n { x: 0.171875, y: 0.390625 },\n { x: 0.171875, y: 0.390625 },\n { x: 0.203125, y: 0.390625 },\n { x: 0.203125, y: 0.390625 },\n { x: 0.234375, y: 0.390625 },\n { x: 0.234375, y: 0.390625 },\n { x: 0.265625, y: 0.390625 },\n { x: 0.265625, y: 0.390625 },\n { x: 0.296875, y: 0.390625 },\n { x: 0.296875, y: 0.390625 },\n { x: 0.328125, y: 0.390625 },\n { x: 0.328125, y: 0.390625 },\n { x: 0.359375, y: 0.390625 },\n { x: 0.359375, y: 0.390625 },\n { x: 0.390625, y: 0.390625 },\n { x: 0.390625, y: 0.390625 },\n { x: 0.421875, y: 0.390625 },\n { x: 0.421875, y: 0.390625 },\n { x: 0.453125, y: 0.390625 },\n { x: 0.453125, y: 0.390625 },\n { x: 0.484375, y: 0.390625 },\n { x: 0.484375, y: 0.390625 },\n { x: 0.515625, y: 0.390625 },\n { x: 0.515625, y: 0.390625 },\n { x: 0.546875, y: 0.390625 },\n { x: 0.546875, y: 0.390625 },\n { x: 0.578125, y: 0.390625 },\n { x: 0.578125, y: 0.390625 },\n { x: 0.609375, y: 0.390625 },\n { x: 0.609375, y: 0.390625 },\n { x: 0.640625, y: 0.390625 },\n { x: 0.640625, y: 0.390625 },\n { x: 0.671875, y: 0.390625 },\n { x: 0.671875, y: 0.390625 },\n { x: 0.703125, y: 0.390625 },\n { x: 0.703125, y: 0.390625 },\n { x: 0.734375, y: 0.390625 },\n { x: 0.734375, y: 0.390625 },\n { x: 0.765625, y: 0.390625 },\n { x: 0.765625, y: 0.390625 },\n { x: 0.796875, y: 0.390625 },\n { x: 0.796875, y: 0.390625 },\n { x: 0.828125, y: 0.390625 },\n { x: 0.828125, y: 0.390625 },\n { x: 0.859375, y: 0.390625 },\n { x: 0.859375, y: 0.390625 },\n { x: 0.890625, y: 0.390625 },\n { x: 0.890625, y: 0.390625 },\n { x: 0.921875, y: 0.390625 },\n { x: 0.921875, y: 0.390625 },\n { x: 0.953125, y: 0.390625 },\n { x: 0.953125, y: 0.390625 },\n { x: 0.984375, y: 0.390625 },\n { x: 0.984375, y: 0.390625 },\n { x: 0.015625, y: 0.421875 },\n { x: 0.015625, y: 0.421875 },\n { x: 0.046875, y: 0.421875 },\n { x: 0.046875, y: 0.421875 },\n { x: 0.078125, y: 0.421875 },\n { x: 0.078125, y: 0.421875 },\n { x: 0.109375, y: 0.421875 },\n { x: 0.109375, y: 0.421875 },\n { x: 0.140625, y: 0.421875 },\n { x: 0.140625, y: 0.421875 },\n { x: 0.171875, y: 0.421875 },\n { x: 0.171875, y: 0.421875 },\n { x: 0.203125, y: 0.421875 },\n { x: 0.203125, y: 0.421875 },\n { x: 0.234375, y: 0.421875 },\n { x: 0.234375, y: 0.421875 },\n { x: 0.265625, y: 0.421875 },\n { x: 0.265625, y: 0.421875 },\n { x: 0.296875, y: 0.421875 },\n { x: 0.296875, y: 0.421875 },\n { x: 0.328125, y: 0.421875 },\n { x: 0.328125, y: 0.421875 },\n { x: 0.359375, y: 0.421875 },\n { x: 0.359375, y: 0.421875 },\n { x: 0.390625, y: 0.421875 },\n { x: 0.390625, y: 0.421875 },\n { x: 0.421875, y: 0.421875 },\n { x: 0.421875, y: 0.421875 },\n { x: 0.453125, y: 0.421875 },\n { x: 0.453125, y: 0.421875 },\n { x: 0.484375, y: 0.421875 },\n { x: 0.484375, y: 0.421875 },\n { x: 0.515625, y: 0.421875 },\n { x: 0.515625, y: 0.421875 },\n { x: 0.546875, y: 0.421875 },\n { x: 0.546875, y: 0.421875 },\n { x: 0.578125, y: 0.421875 },\n { x: 0.578125, y: 0.421875 },\n { x: 0.609375, y: 0.421875 },\n { x: 0.609375, y: 0.421875 },\n { x: 0.640625, y: 0.421875 },\n { x: 0.640625, y: 0.421875 },\n { x: 0.671875, y: 0.421875 },\n { x: 0.671875, y: 0.421875 },\n { x: 0.703125, y: 0.421875 },\n { x: 0.703125, y: 0.421875 },\n { x: 0.734375, y: 0.421875 },\n { x: 0.734375, y: 0.421875 },\n { x: 0.765625, y: 0.421875 },\n { x: 0.765625, y: 0.421875 },\n { x: 0.796875, y: 0.421875 },\n { x: 0.796875, y: 0.421875 },\n { x: 0.828125, y: 0.421875 },\n { x: 0.828125, y: 0.421875 },\n { x: 0.859375, y: 0.421875 },\n { x: 0.859375, y: 0.421875 },\n { x: 0.890625, y: 0.421875 },\n { x: 0.890625, y: 0.421875 },\n { x: 0.921875, y: 0.421875 },\n { x: 0.921875, y: 0.421875 },\n { x: 0.953125, y: 0.421875 },\n { x: 0.953125, y: 0.421875 },\n { x: 0.984375, y: 0.421875 },\n { x: 0.984375, y: 0.421875 },\n { x: 0.015625, y: 0.453125 },\n { x: 0.015625, y: 0.453125 },\n { x: 0.046875, y: 0.453125 },\n { x: 0.046875, y: 0.453125 },\n { x: 0.078125, y: 0.453125 },\n { x: 0.078125, y: 0.453125 },\n { x: 0.109375, y: 0.453125 },\n { x: 0.109375, y: 0.453125 },\n { x: 0.140625, y: 0.453125 },\n { x: 0.140625, y: 0.453125 },\n { x: 0.171875, y: 0.453125 },\n { x: 0.171875, y: 0.453125 },\n { x: 0.203125, y: 0.453125 },\n { x: 0.203125, y: 0.453125 },\n { x: 0.234375, y: 0.453125 },\n { x: 0.234375, y: 0.453125 },\n { x: 0.265625, y: 0.453125 },\n { x: 0.265625, y: 0.453125 },\n { x: 0.296875, y: 0.453125 },\n { x: 0.296875, y: 0.453125 },\n { x: 0.328125, y: 0.453125 },\n { x: 0.328125, y: 0.453125 },\n { x: 0.359375, y: 0.453125 },\n { x: 0.359375, y: 0.453125 },\n { x: 0.390625, y: 0.453125 },\n { x: 0.390625, y: 0.453125 },\n { x: 0.421875, y: 0.453125 },\n { x: 0.421875, y: 0.453125 },\n { x: 0.453125, y: 0.453125 },\n { x: 0.453125, y: 0.453125 },\n { x: 0.484375, y: 0.453125 },\n { x: 0.484375, y: 0.453125 },\n { x: 0.515625, y: 0.453125 },\n { x: 0.515625, y: 0.453125 },\n { x: 0.546875, y: 0.453125 },\n { x: 0.546875, y: 0.453125 },\n { x: 0.578125, y: 0.453125 },\n { x: 0.578125, y: 0.453125 },\n { x: 0.609375, y: 0.453125 },\n { x: 0.609375, y: 0.453125 },\n { x: 0.640625, y: 0.453125 },\n { x: 0.640625, y: 0.453125 },\n { x: 0.671875, y: 0.453125 },\n { x: 0.671875, y: 0.453125 },\n { x: 0.703125, y: 0.453125 },\n { x: 0.703125, y: 0.453125 },\n { x: 0.734375, y: 0.453125 },\n { x: 0.734375, y: 0.453125 },\n { x: 0.765625, y: 0.453125 },\n { x: 0.765625, y: 0.453125 },\n { x: 0.796875, y: 0.453125 },\n { x: 0.796875, y: 0.453125 },\n { x: 0.828125, y: 0.453125 },\n { x: 0.828125, y: 0.453125 },\n { x: 0.859375, y: 0.453125 },\n { x: 0.859375, y: 0.453125 },\n { x: 0.890625, y: 0.453125 },\n { x: 0.890625, y: 0.453125 },\n { x: 0.921875, y: 0.453125 },\n { x: 0.921875, y: 0.453125 },\n { x: 0.953125, y: 0.453125 },\n { x: 0.953125, y: 0.453125 },\n { x: 0.984375, y: 0.453125 },\n { x: 0.984375, y: 0.453125 },\n { x: 0.015625, y: 0.484375 },\n { x: 0.015625, y: 0.484375 },\n { x: 0.046875, y: 0.484375 },\n { x: 0.046875, y: 0.484375 },\n { x: 0.078125, y: 0.484375 },\n { x: 0.078125, y: 0.484375 },\n { x: 0.109375, y: 0.484375 },\n { x: 0.109375, y: 0.484375 },\n { x: 0.140625, y: 0.484375 },\n { x: 0.140625, y: 0.484375 },\n { x: 0.171875, y: 0.484375 },\n { x: 0.171875, y: 0.484375 },\n { x: 0.203125, y: 0.484375 },\n { x: 0.203125, y: 0.484375 },\n { x: 0.234375, y: 0.484375 },\n { x: 0.234375, y: 0.484375 },\n { x: 0.265625, y: 0.484375 },\n { x: 0.265625, y: 0.484375 },\n { x: 0.296875, y: 0.484375 },\n { x: 0.296875, y: 0.484375 },\n { x: 0.328125, y: 0.484375 },\n { x: 0.328125, y: 0.484375 },\n { x: 0.359375, y: 0.484375 },\n { x: 0.359375, y: 0.484375 },\n { x: 0.390625, y: 0.484375 },\n { x: 0.390625, y: 0.484375 },\n { x: 0.421875, y: 0.484375 },\n { x: 0.421875, y: 0.484375 },\n { x: 0.453125, y: 0.484375 },\n { x: 0.453125, y: 0.484375 },\n { x: 0.484375, y: 0.484375 },\n { x: 0.484375, y: 0.484375 },\n { x: 0.515625, y: 0.484375 },\n { x: 0.515625, y: 0.484375 },\n { x: 0.546875, y: 0.484375 },\n { x: 0.546875, y: 0.484375 },\n { x: 0.578125, y: 0.484375 },\n { x: 0.578125, y: 0.484375 },\n { x: 0.609375, y: 0.484375 },\n { x: 0.609375, y: 0.484375 },\n { x: 0.640625, y: 0.484375 },\n { x: 0.640625, y: 0.484375 },\n { x: 0.671875, y: 0.484375 },\n { x: 0.671875, y: 0.484375 },\n { x: 0.703125, y: 0.484375 },\n { x: 0.703125, y: 0.484375 },\n { x: 0.734375, y: 0.484375 },\n { x: 0.734375, y: 0.484375 },\n { x: 0.765625, y: 0.484375 },\n { x: 0.765625, y: 0.484375 },\n { x: 0.796875, y: 0.484375 },\n { x: 0.796875, y: 0.484375 },\n { x: 0.828125, y: 0.484375 },\n { x: 0.828125, y: 0.484375 },\n { x: 0.859375, y: 0.484375 },\n { x: 0.859375, y: 0.484375 },\n { x: 0.890625, y: 0.484375 },\n { x: 0.890625, y: 0.484375 },\n { x: 0.921875, y: 0.484375 },\n { x: 0.921875, y: 0.484375 },\n { x: 0.953125, y: 0.484375 },\n { x: 0.953125, y: 0.484375 },\n { x: 0.984375, y: 0.484375 },\n { x: 0.984375, y: 0.484375 },\n { x: 0.015625, y: 0.515625 },\n { x: 0.015625, y: 0.515625 },\n { x: 0.046875, y: 0.515625 },\n { x: 0.046875, y: 0.515625 },\n { x: 0.078125, y: 0.515625 },\n { x: 0.078125, y: 0.515625 },\n { x: 0.109375, y: 0.515625 },\n { x: 0.109375, y: 0.515625 },\n { x: 0.140625, y: 0.515625 },\n { x: 0.140625, y: 0.515625 },\n { x: 0.171875, y: 0.515625 },\n { x: 0.171875, y: 0.515625 },\n { x: 0.203125, y: 0.515625 },\n { x: 0.203125, y: 0.515625 },\n { x: 0.234375, y: 0.515625 },\n { x: 0.234375, y: 0.515625 },\n { x: 0.265625, y: 0.515625 },\n { x: 0.265625, y: 0.515625 },\n { x: 0.296875, y: 0.515625 },\n { x: 0.296875, y: 0.515625 },\n { x: 0.328125, y: 0.515625 },\n { x: 0.328125, y: 0.515625 },\n { x: 0.359375, y: 0.515625 },\n { x: 0.359375, y: 0.515625 },\n { x: 0.390625, y: 0.515625 },\n { x: 0.390625, y: 0.515625 },\n { x: 0.421875, y: 0.515625 },\n { x: 0.421875, y: 0.515625 },\n { x: 0.453125, y: 0.515625 },\n { x: 0.453125, y: 0.515625 },\n { x: 0.484375, y: 0.515625 },\n { x: 0.484375, y: 0.515625 },\n { x: 0.515625, y: 0.515625 },\n { x: 0.515625, y: 0.515625 },\n { x: 0.546875, y: 0.515625 },\n { x: 0.546875, y: 0.515625 },\n { x: 0.578125, y: 0.515625 },\n { x: 0.578125, y: 0.515625 },\n { x: 0.609375, y: 0.515625 },\n { x: 0.609375, y: 0.515625 },\n { x: 0.640625, y: 0.515625 },\n { x: 0.640625, y: 0.515625 },\n { x: 0.671875, y: 0.515625 },\n { x: 0.671875, y: 0.515625 },\n { x: 0.703125, y: 0.515625 },\n { x: 0.703125, y: 0.515625 },\n { x: 0.734375, y: 0.515625 },\n { x: 0.734375, y: 0.515625 },\n { x: 0.765625, y: 0.515625 },\n { x: 0.765625, y: 0.515625 },\n { x: 0.796875, y: 0.515625 },\n { x: 0.796875, y: 0.515625 },\n { x: 0.828125, y: 0.515625 },\n { x: 0.828125, y: 0.515625 },\n { x: 0.859375, y: 0.515625 },\n { x: 0.859375, y: 0.515625 },\n { x: 0.890625, y: 0.515625 },\n { x: 0.890625, y: 0.515625 },\n { x: 0.921875, y: 0.515625 },\n { x: 0.921875, y: 0.515625 },\n { x: 0.953125, y: 0.515625 },\n { x: 0.953125, y: 0.515625 },\n { x: 0.984375, y: 0.515625 },\n { x: 0.984375, y: 0.515625 },\n { x: 0.015625, y: 0.546875 },\n { x: 0.015625, y: 0.546875 },\n { x: 0.046875, y: 0.546875 },\n { x: 0.046875, y: 0.546875 },\n { x: 0.078125, y: 0.546875 },\n { x: 0.078125, y: 0.546875 },\n { x: 0.109375, y: 0.546875 },\n { x: 0.109375, y: 0.546875 },\n { x: 0.140625, y: 0.546875 },\n { x: 0.140625, y: 0.546875 },\n { x: 0.171875, y: 0.546875 },\n { x: 0.171875, y: 0.546875 },\n { x: 0.203125, y: 0.546875 },\n { x: 0.203125, y: 0.546875 },\n { x: 0.234375, y: 0.546875 },\n { x: 0.234375, y: 0.546875 },\n { x: 0.265625, y: 0.546875 },\n { x: 0.265625, y: 0.546875 },\n { x: 0.296875, y: 0.546875 },\n { x: 0.296875, y: 0.546875 },\n { x: 0.328125, y: 0.546875 },\n { x: 0.328125, y: 0.546875 },\n { x: 0.359375, y: 0.546875 },\n { x: 0.359375, y: 0.546875 },\n { x: 0.390625, y: 0.546875 },\n { x: 0.390625, y: 0.546875 },\n { x: 0.421875, y: 0.546875 },\n { x: 0.421875, y: 0.546875 },\n { x: 0.453125, y: 0.546875 },\n { x: 0.453125, y: 0.546875 },\n { x: 0.484375, y: 0.546875 },\n { x: 0.484375, y: 0.546875 },\n { x: 0.515625, y: 0.546875 },\n { x: 0.515625, y: 0.546875 },\n { x: 0.546875, y: 0.546875 },\n { x: 0.546875, y: 0.546875 },\n { x: 0.578125, y: 0.546875 },\n { x: 0.578125, y: 0.546875 },\n { x: 0.609375, y: 0.546875 },\n { x: 0.609375, y: 0.546875 },\n { x: 0.640625, y: 0.546875 },\n { x: 0.640625, y: 0.546875 },\n { x: 0.671875, y: 0.546875 },\n { x: 0.671875, y: 0.546875 },\n { x: 0.703125, y: 0.546875 },\n { x: 0.703125, y: 0.546875 },\n { x: 0.734375, y: 0.546875 },\n { x: 0.734375, y: 0.546875 },\n { x: 0.765625, y: 0.546875 },\n { x: 0.765625, y: 0.546875 },\n { x: 0.796875, y: 0.546875 },\n { x: 0.796875, y: 0.546875 },\n { x: 0.828125, y: 0.546875 },\n { x: 0.828125, y: 0.546875 },\n { x: 0.859375, y: 0.546875 },\n { x: 0.859375, y: 0.546875 },\n { x: 0.890625, y: 0.546875 },\n { x: 0.890625, y: 0.546875 },\n { x: 0.921875, y: 0.546875 },\n { x: 0.921875, y: 0.546875 },\n { x: 0.953125, y: 0.546875 },\n { x: 0.953125, y: 0.546875 },\n { x: 0.984375, y: 0.546875 },\n { x: 0.984375, y: 0.546875 },\n { x: 0.015625, y: 0.578125 },\n { x: 0.015625, y: 0.578125 },\n { x: 0.046875, y: 0.578125 },\n { x: 0.046875, y: 0.578125 },\n { x: 0.078125, y: 0.578125 },\n { x: 0.078125, y: 0.578125 },\n { x: 0.109375, y: 0.578125 },\n { x: 0.109375, y: 0.578125 },\n { x: 0.140625, y: 0.578125 },\n { x: 0.140625, y: 0.578125 },\n { x: 0.171875, y: 0.578125 },\n { x: 0.171875, y: 0.578125 },\n { x: 0.203125, y: 0.578125 },\n { x: 0.203125, y: 0.578125 },\n { x: 0.234375, y: 0.578125 },\n { x: 0.234375, y: 0.578125 },\n { x: 0.265625, y: 0.578125 },\n { x: 0.265625, y: 0.578125 },\n { x: 0.296875, y: 0.578125 },\n { x: 0.296875, y: 0.578125 },\n { x: 0.328125, y: 0.578125 },\n { x: 0.328125, y: 0.578125 },\n { x: 0.359375, y: 0.578125 },\n { x: 0.359375, y: 0.578125 },\n { x: 0.390625, y: 0.578125 },\n { x: 0.390625, y: 0.578125 },\n { x: 0.421875, y: 0.578125 },\n { x: 0.421875, y: 0.578125 },\n { x: 0.453125, y: 0.578125 },\n { x: 0.453125, y: 0.578125 },\n { x: 0.484375, y: 0.578125 },\n { x: 0.484375, y: 0.578125 },\n { x: 0.515625, y: 0.578125 },\n { x: 0.515625, y: 0.578125 },\n { x: 0.546875, y: 0.578125 },\n { x: 0.546875, y: 0.578125 },\n { x: 0.578125, y: 0.578125 },\n { x: 0.578125, y: 0.578125 },\n { x: 0.609375, y: 0.578125 },\n { x: 0.609375, y: 0.578125 },\n { x: 0.640625, y: 0.578125 },\n { x: 0.640625, y: 0.578125 },\n { x: 0.671875, y: 0.578125 },\n { x: 0.671875, y: 0.578125 },\n { x: 0.703125, y: 0.578125 },\n { x: 0.703125, y: 0.578125 },\n { x: 0.734375, y: 0.578125 },\n { x: 0.734375, y: 0.578125 },\n { x: 0.765625, y: 0.578125 },\n { x: 0.765625, y: 0.578125 },\n { x: 0.796875, y: 0.578125 },\n { x: 0.796875, y: 0.578125 },\n { x: 0.828125, y: 0.578125 },\n { x: 0.828125, y: 0.578125 },\n { x: 0.859375, y: 0.578125 },\n { x: 0.859375, y: 0.578125 },\n { x: 0.890625, y: 0.578125 },\n { x: 0.890625, y: 0.578125 },\n { x: 0.921875, y: 0.578125 },\n { x: 0.921875, y: 0.578125 },\n { x: 0.953125, y: 0.578125 },\n { x: 0.953125, y: 0.578125 },\n { x: 0.984375, y: 0.578125 },\n { x: 0.984375, y: 0.578125 },\n { x: 0.015625, y: 0.609375 },\n { x: 0.015625, y: 0.609375 },\n { x: 0.046875, y: 0.609375 },\n { x: 0.046875, y: 0.609375 },\n { x: 0.078125, y: 0.609375 },\n { x: 0.078125, y: 0.609375 },\n { x: 0.109375, y: 0.609375 },\n { x: 0.109375, y: 0.609375 },\n { x: 0.140625, y: 0.609375 },\n { x: 0.140625, y: 0.609375 },\n { x: 0.171875, y: 0.609375 },\n { x: 0.171875, y: 0.609375 },\n { x: 0.203125, y: 0.609375 },\n { x: 0.203125, y: 0.609375 },\n { x: 0.234375, y: 0.609375 },\n { x: 0.234375, y: 0.609375 },\n { x: 0.265625, y: 0.609375 },\n { x: 0.265625, y: 0.609375 },\n { x: 0.296875, y: 0.609375 },\n { x: 0.296875, y: 0.609375 },\n { x: 0.328125, y: 0.609375 },\n { x: 0.328125, y: 0.609375 },\n { x: 0.359375, y: 0.609375 },\n { x: 0.359375, y: 0.609375 },\n { x: 0.390625, y: 0.609375 },\n { x: 0.390625, y: 0.609375 },\n { x: 0.421875, y: 0.609375 },\n { x: 0.421875, y: 0.609375 },\n { x: 0.453125, y: 0.609375 },\n { x: 0.453125, y: 0.609375 },\n { x: 0.484375, y: 0.609375 },\n { x: 0.484375, y: 0.609375 },\n { x: 0.515625, y: 0.609375 },\n { x: 0.515625, y: 0.609375 },\n { x: 0.546875, y: 0.609375 },\n { x: 0.546875, y: 0.609375 },\n { x: 0.578125, y: 0.609375 },\n { x: 0.578125, y: 0.609375 },\n { x: 0.609375, y: 0.609375 },\n { x: 0.609375, y: 0.609375 },\n { x: 0.640625, y: 0.609375 },\n { x: 0.640625, y: 0.609375 },\n { x: 0.671875, y: 0.609375 },\n { x: 0.671875, y: 0.609375 },\n { x: 0.703125, y: 0.609375 },\n { x: 0.703125, y: 0.609375 },\n { x: 0.734375, y: 0.609375 },\n { x: 0.734375, y: 0.609375 },\n { x: 0.765625, y: 0.609375 },\n { x: 0.765625, y: 0.609375 },\n { x: 0.796875, y: 0.609375 },\n { x: 0.796875, y: 0.609375 },\n { x: 0.828125, y: 0.609375 },\n { x: 0.828125, y: 0.609375 },\n { x: 0.859375, y: 0.609375 },\n { x: 0.859375, y: 0.609375 },\n { x: 0.890625, y: 0.609375 },\n { x: 0.890625, y: 0.609375 },\n { x: 0.921875, y: 0.609375 },\n { x: 0.921875, y: 0.609375 },\n { x: 0.953125, y: 0.609375 },\n { x: 0.953125, y: 0.609375 },\n { x: 0.984375, y: 0.609375 },\n { x: 0.984375, y: 0.609375 },\n { x: 0.015625, y: 0.640625 },\n { x: 0.015625, y: 0.640625 },\n { x: 0.046875, y: 0.640625 },\n { x: 0.046875, y: 0.640625 },\n { x: 0.078125, y: 0.640625 },\n { x: 0.078125, y: 0.640625 },\n { x: 0.109375, y: 0.640625 },\n { x: 0.109375, y: 0.640625 },\n { x: 0.140625, y: 0.640625 },\n { x: 0.140625, y: 0.640625 },\n { x: 0.171875, y: 0.640625 },\n { x: 0.171875, y: 0.640625 },\n { x: 0.203125, y: 0.640625 },\n { x: 0.203125, y: 0.640625 },\n { x: 0.234375, y: 0.640625 },\n { x: 0.234375, y: 0.640625 },\n { x: 0.265625, y: 0.640625 },\n { x: 0.265625, y: 0.640625 },\n { x: 0.296875, y: 0.640625 },\n { x: 0.296875, y: 0.640625 },\n { x: 0.328125, y: 0.640625 },\n { x: 0.328125, y: 0.640625 },\n { x: 0.359375, y: 0.640625 },\n { x: 0.359375, y: 0.640625 },\n { x: 0.390625, y: 0.640625 },\n { x: 0.390625, y: 0.640625 },\n { x: 0.421875, y: 0.640625 },\n { x: 0.421875, y: 0.640625 },\n { x: 0.453125, y: 0.640625 },\n { x: 0.453125, y: 0.640625 },\n { x: 0.484375, y: 0.640625 },\n { x: 0.484375, y: 0.640625 },\n { x: 0.515625, y: 0.640625 },\n { x: 0.515625, y: 0.640625 },\n { x: 0.546875, y: 0.640625 },\n { x: 0.546875, y: 0.640625 },\n { x: 0.578125, y: 0.640625 },\n { x: 0.578125, y: 0.640625 },\n { x: 0.609375, y: 0.640625 },\n { x: 0.609375, y: 0.640625 },\n { x: 0.640625, y: 0.640625 },\n { x: 0.640625, y: 0.640625 },\n { x: 0.671875, y: 0.640625 },\n { x: 0.671875, y: 0.640625 },\n { x: 0.703125, y: 0.640625 },\n { x: 0.703125, y: 0.640625 },\n { x: 0.734375, y: 0.640625 },\n { x: 0.734375, y: 0.640625 },\n { x: 0.765625, y: 0.640625 },\n { x: 0.765625, y: 0.640625 },\n { x: 0.796875, y: 0.640625 },\n { x: 0.796875, y: 0.640625 },\n { x: 0.828125, y: 0.640625 },\n { x: 0.828125, y: 0.640625 },\n { x: 0.859375, y: 0.640625 },\n { x: 0.859375, y: 0.640625 },\n { x: 0.890625, y: 0.640625 },\n { x: 0.890625, y: 0.640625 },\n { x: 0.921875, y: 0.640625 },\n { x: 0.921875, y: 0.640625 },\n { x: 0.953125, y: 0.640625 },\n { x: 0.953125, y: 0.640625 },\n { x: 0.984375, y: 0.640625 },\n { x: 0.984375, y: 0.640625 },\n { x: 0.015625, y: 0.671875 },\n { x: 0.015625, y: 0.671875 },\n { x: 0.046875, y: 0.671875 },\n { x: 0.046875, y: 0.671875 },\n { x: 0.078125, y: 0.671875 },\n { x: 0.078125, y: 0.671875 },\n { x: 0.109375, y: 0.671875 },\n { x: 0.109375, y: 0.671875 },\n { x: 0.140625, y: 0.671875 },\n { x: 0.140625, y: 0.671875 },\n { x: 0.171875, y: 0.671875 },\n { x: 0.171875, y: 0.671875 },\n { x: 0.203125, y: 0.671875 },\n { x: 0.203125, y: 0.671875 },\n { x: 0.234375, y: 0.671875 },\n { x: 0.234375, y: 0.671875 },\n { x: 0.265625, y: 0.671875 },\n { x: 0.265625, y: 0.671875 },\n { x: 0.296875, y: 0.671875 },\n { x: 0.296875, y: 0.671875 },\n { x: 0.328125, y: 0.671875 },\n { x: 0.328125, y: 0.671875 },\n { x: 0.359375, y: 0.671875 },\n { x: 0.359375, y: 0.671875 },\n { x: 0.390625, y: 0.671875 },\n { x: 0.390625, y: 0.671875 },\n { x: 0.421875, y: 0.671875 },\n { x: 0.421875, y: 0.671875 },\n { x: 0.453125, y: 0.671875 },\n { x: 0.453125, y: 0.671875 },\n { x: 0.484375, y: 0.671875 },\n { x: 0.484375, y: 0.671875 },\n { x: 0.515625, y: 0.671875 },\n { x: 0.515625, y: 0.671875 },\n { x: 0.546875, y: 0.671875 },\n { x: 0.546875, y: 0.671875 },\n { x: 0.578125, y: 0.671875 },\n { x: 0.578125, y: 0.671875 },\n { x: 0.609375, y: 0.671875 },\n { x: 0.609375, y: 0.671875 },\n { x: 0.640625, y: 0.671875 },\n { x: 0.640625, y: 0.671875 },\n { x: 0.671875, y: 0.671875 },\n { x: 0.671875, y: 0.671875 },\n { x: 0.703125, y: 0.671875 },\n { x: 0.703125, y: 0.671875 },\n { x: 0.734375, y: 0.671875 },\n { x: 0.734375, y: 0.671875 },\n { x: 0.765625, y: 0.671875 },\n { x: 0.765625, y: 0.671875 },\n { x: 0.796875, y: 0.671875 },\n { x: 0.796875, y: 0.671875 },\n { x: 0.828125, y: 0.671875 },\n { x: 0.828125, y: 0.671875 },\n { x: 0.859375, y: 0.671875 },\n { x: 0.859375, y: 0.671875 },\n { x: 0.890625, y: 0.671875 },\n { x: 0.890625, y: 0.671875 },\n { x: 0.921875, y: 0.671875 },\n { x: 0.921875, y: 0.671875 },\n { x: 0.953125, y: 0.671875 },\n { x: 0.953125, y: 0.671875 },\n { x: 0.984375, y: 0.671875 },\n { x: 0.984375, y: 0.671875 },\n { x: 0.015625, y: 0.703125 },\n { x: 0.015625, y: 0.703125 },\n { x: 0.046875, y: 0.703125 },\n { x: 0.046875, y: 0.703125 },\n { x: 0.078125, y: 0.703125 },\n { x: 0.078125, y: 0.703125 },\n { x: 0.109375, y: 0.703125 },\n { x: 0.109375, y: 0.703125 },\n { x: 0.140625, y: 0.703125 },\n { x: 0.140625, y: 0.703125 },\n { x: 0.171875, y: 0.703125 },\n { x: 0.171875, y: 0.703125 },\n { x: 0.203125, y: 0.703125 },\n { x: 0.203125, y: 0.703125 },\n { x: 0.234375, y: 0.703125 },\n { x: 0.234375, y: 0.703125 },\n { x: 0.265625, y: 0.703125 },\n { x: 0.265625, y: 0.703125 },\n { x: 0.296875, y: 0.703125 },\n { x: 0.296875, y: 0.703125 },\n { x: 0.328125, y: 0.703125 },\n { x: 0.328125, y: 0.703125 },\n { x: 0.359375, y: 0.703125 },\n { x: 0.359375, y: 0.703125 },\n { x: 0.390625, y: 0.703125 },\n { x: 0.390625, y: 0.703125 },\n { x: 0.421875, y: 0.703125 },\n { x: 0.421875, y: 0.703125 },\n { x: 0.453125, y: 0.703125 },\n { x: 0.453125, y: 0.703125 },\n { x: 0.484375, y: 0.703125 },\n { x: 0.484375, y: 0.703125 },\n { x: 0.515625, y: 0.703125 },\n { x: 0.515625, y: 0.703125 },\n { x: 0.546875, y: 0.703125 },\n { x: 0.546875, y: 0.703125 },\n { x: 0.578125, y: 0.703125 },\n { x: 0.578125, y: 0.703125 },\n { x: 0.609375, y: 0.703125 },\n { x: 0.609375, y: 0.703125 },\n { x: 0.640625, y: 0.703125 },\n { x: 0.640625, y: 0.703125 },\n { x: 0.671875, y: 0.703125 },\n { x: 0.671875, y: 0.703125 },\n { x: 0.703125, y: 0.703125 },\n { x: 0.703125, y: 0.703125 },\n { x: 0.734375, y: 0.703125 },\n { x: 0.734375, y: 0.703125 },\n { x: 0.765625, y: 0.703125 },\n { x: 0.765625, y: 0.703125 },\n { x: 0.796875, y: 0.703125 },\n { x: 0.796875, y: 0.703125 },\n { x: 0.828125, y: 0.703125 },\n { x: 0.828125, y: 0.703125 },\n { x: 0.859375, y: 0.703125 },\n { x: 0.859375, y: 0.703125 },\n { x: 0.890625, y: 0.703125 },\n { x: 0.890625, y: 0.703125 },\n { x: 0.921875, y: 0.703125 },\n { x: 0.921875, y: 0.703125 },\n { x: 0.953125, y: 0.703125 },\n { x: 0.953125, y: 0.703125 },\n { x: 0.984375, y: 0.703125 },\n { x: 0.984375, y: 0.703125 },\n { x: 0.015625, y: 0.734375 },\n { x: 0.015625, y: 0.734375 },\n { x: 0.046875, y: 0.734375 },\n { x: 0.046875, y: 0.734375 },\n { x: 0.078125, y: 0.734375 },\n { x: 0.078125, y: 0.734375 },\n { x: 0.109375, y: 0.734375 },\n { x: 0.109375, y: 0.734375 },\n { x: 0.140625, y: 0.734375 },\n { x: 0.140625, y: 0.734375 },\n { x: 0.171875, y: 0.734375 },\n { x: 0.171875, y: 0.734375 },\n { x: 0.203125, y: 0.734375 },\n { x: 0.203125, y: 0.734375 },\n { x: 0.234375, y: 0.734375 },\n { x: 0.234375, y: 0.734375 },\n { x: 0.265625, y: 0.734375 },\n { x: 0.265625, y: 0.734375 },\n { x: 0.296875, y: 0.734375 },\n { x: 0.296875, y: 0.734375 },\n { x: 0.328125, y: 0.734375 },\n { x: 0.328125, y: 0.734375 },\n { x: 0.359375, y: 0.734375 },\n { x: 0.359375, y: 0.734375 },\n { x: 0.390625, y: 0.734375 },\n { x: 0.390625, y: 0.734375 },\n { x: 0.421875, y: 0.734375 },\n { x: 0.421875, y: 0.734375 },\n { x: 0.453125, y: 0.734375 },\n { x: 0.453125, y: 0.734375 },\n { x: 0.484375, y: 0.734375 },\n { x: 0.484375, y: 0.734375 },\n { x: 0.515625, y: 0.734375 },\n { x: 0.515625, y: 0.734375 },\n { x: 0.546875, y: 0.734375 },\n { x: 0.546875, y: 0.734375 },\n { x: 0.578125, y: 0.734375 },\n { x: 0.578125, y: 0.734375 },\n { x: 0.609375, y: 0.734375 },\n { x: 0.609375, y: 0.734375 },\n { x: 0.640625, y: 0.734375 },\n { x: 0.640625, y: 0.734375 },\n { x: 0.671875, y: 0.734375 },\n { x: 0.671875, y: 0.734375 },\n { x: 0.703125, y: 0.734375 },\n { x: 0.703125, y: 0.734375 },\n { x: 0.734375, y: 0.734375 },\n { x: 0.734375, y: 0.734375 },\n { x: 0.765625, y: 0.734375 },\n { x: 0.765625, y: 0.734375 },\n { x: 0.796875, y: 0.734375 },\n { x: 0.796875, y: 0.734375 },\n { x: 0.828125, y: 0.734375 },\n { x: 0.828125, y: 0.734375 },\n { x: 0.859375, y: 0.734375 },\n { x: 0.859375, y: 0.734375 },\n { x: 0.890625, y: 0.734375 },\n { x: 0.890625, y: 0.734375 },\n { x: 0.921875, y: 0.734375 },\n { x: 0.921875, y: 0.734375 },\n { x: 0.953125, y: 0.734375 },\n { x: 0.953125, y: 0.734375 },\n { x: 0.984375, y: 0.734375 },\n { x: 0.984375, y: 0.734375 },\n { x: 0.015625, y: 0.765625 },\n { x: 0.015625, y: 0.765625 },\n { x: 0.046875, y: 0.765625 },\n { x: 0.046875, y: 0.765625 },\n { x: 0.078125, y: 0.765625 },\n { x: 0.078125, y: 0.765625 },\n { x: 0.109375, y: 0.765625 },\n { x: 0.109375, y: 0.765625 },\n { x: 0.140625, y: 0.765625 },\n { x: 0.140625, y: 0.765625 },\n { x: 0.171875, y: 0.765625 },\n { x: 0.171875, y: 0.765625 },\n { x: 0.203125, y: 0.765625 },\n { x: 0.203125, y: 0.765625 },\n { x: 0.234375, y: 0.765625 },\n { x: 0.234375, y: 0.765625 },\n { x: 0.265625, y: 0.765625 },\n { x: 0.265625, y: 0.765625 },\n { x: 0.296875, y: 0.765625 },\n { x: 0.296875, y: 0.765625 },\n { x: 0.328125, y: 0.765625 },\n { x: 0.328125, y: 0.765625 },\n { x: 0.359375, y: 0.765625 },\n { x: 0.359375, y: 0.765625 },\n { x: 0.390625, y: 0.765625 },\n { x: 0.390625, y: 0.765625 },\n { x: 0.421875, y: 0.765625 },\n { x: 0.421875, y: 0.765625 },\n { x: 0.453125, y: 0.765625 },\n { x: 0.453125, y: 0.765625 },\n { x: 0.484375, y: 0.765625 },\n { x: 0.484375, y: 0.765625 },\n { x: 0.515625, y: 0.765625 },\n { x: 0.515625, y: 0.765625 },\n { x: 0.546875, y: 0.765625 },\n { x: 0.546875, y: 0.765625 },\n { x: 0.578125, y: 0.765625 },\n { x: 0.578125, y: 0.765625 },\n { x: 0.609375, y: 0.765625 },\n { x: 0.609375, y: 0.765625 },\n { x: 0.640625, y: 0.765625 },\n { x: 0.640625, y: 0.765625 },\n { x: 0.671875, y: 0.765625 },\n { x: 0.671875, y: 0.765625 },\n { x: 0.703125, y: 0.765625 },\n { x: 0.703125, y: 0.765625 },\n { x: 0.734375, y: 0.765625 },\n { x: 0.734375, y: 0.765625 },\n { x: 0.765625, y: 0.765625 },\n { x: 0.765625, y: 0.765625 },\n { x: 0.796875, y: 0.765625 },\n { x: 0.796875, y: 0.765625 },\n { x: 0.828125, y: 0.765625 },\n { x: 0.828125, y: 0.765625 },\n { x: 0.859375, y: 0.765625 },\n { x: 0.859375, y: 0.765625 },\n { x: 0.890625, y: 0.765625 },\n { x: 0.890625, y: 0.765625 },\n { x: 0.921875, y: 0.765625 },\n { x: 0.921875, y: 0.765625 },\n { x: 0.953125, y: 0.765625 },\n { x: 0.953125, y: 0.765625 },\n { x: 0.984375, y: 0.765625 },\n { x: 0.984375, y: 0.765625 },\n { x: 0.015625, y: 0.796875 },\n { x: 0.015625, y: 0.796875 },\n { x: 0.046875, y: 0.796875 },\n { x: 0.046875, y: 0.796875 },\n { x: 0.078125, y: 0.796875 },\n { x: 0.078125, y: 0.796875 },\n { x: 0.109375, y: 0.796875 },\n { x: 0.109375, y: 0.796875 },\n { x: 0.140625, y: 0.796875 },\n { x: 0.140625, y: 0.796875 },\n { x: 0.171875, y: 0.796875 },\n { x: 0.171875, y: 0.796875 },\n { x: 0.203125, y: 0.796875 },\n { x: 0.203125, y: 0.796875 },\n { x: 0.234375, y: 0.796875 },\n { x: 0.234375, y: 0.796875 },\n { x: 0.265625, y: 0.796875 },\n { x: 0.265625, y: 0.796875 },\n { x: 0.296875, y: 0.796875 },\n { x: 0.296875, y: 0.796875 },\n { x: 0.328125, y: 0.796875 },\n { x: 0.328125, y: 0.796875 },\n { x: 0.359375, y: 0.796875 },\n { x: 0.359375, y: 0.796875 },\n { x: 0.390625, y: 0.796875 },\n { x: 0.390625, y: 0.796875 },\n { x: 0.421875, y: 0.796875 },\n { x: 0.421875, y: 0.796875 },\n { x: 0.453125, y: 0.796875 },\n { x: 0.453125, y: 0.796875 },\n { x: 0.484375, y: 0.796875 },\n { x: 0.484375, y: 0.796875 },\n { x: 0.515625, y: 0.796875 },\n { x: 0.515625, y: 0.796875 },\n { x: 0.546875, y: 0.796875 },\n { x: 0.546875, y: 0.796875 },\n { x: 0.578125, y: 0.796875 },\n { x: 0.578125, y: 0.796875 },\n { x: 0.609375, y: 0.796875 },\n { x: 0.609375, y: 0.796875 },\n { x: 0.640625, y: 0.796875 },\n { x: 0.640625, y: 0.796875 },\n { x: 0.671875, y: 0.796875 },\n { x: 0.671875, y: 0.796875 },\n { x: 0.703125, y: 0.796875 },\n { x: 0.703125, y: 0.796875 },\n { x: 0.734375, y: 0.796875 },\n { x: 0.734375, y: 0.796875 },\n { x: 0.765625, y: 0.796875 },\n { x: 0.765625, y: 0.796875 },\n { x: 0.796875, y: 0.796875 },\n { x: 0.796875, y: 0.796875 },\n { x: 0.828125, y: 0.796875 },\n { x: 0.828125, y: 0.796875 },\n { x: 0.859375, y: 0.796875 },\n { x: 0.859375, y: 0.796875 },\n { x: 0.890625, y: 0.796875 },\n { x: 0.890625, y: 0.796875 },\n { x: 0.921875, y: 0.796875 },\n { x: 0.921875, y: 0.796875 },\n { x: 0.953125, y: 0.796875 },\n { x: 0.953125, y: 0.796875 },\n { x: 0.984375, y: 0.796875 },\n { x: 0.984375, y: 0.796875 },\n { x: 0.015625, y: 0.828125 },\n { x: 0.015625, y: 0.828125 },\n { x: 0.046875, y: 0.828125 },\n { x: 0.046875, y: 0.828125 },\n { x: 0.078125, y: 0.828125 },\n { x: 0.078125, y: 0.828125 },\n { x: 0.109375, y: 0.828125 },\n { x: 0.109375, y: 0.828125 },\n { x: 0.140625, y: 0.828125 },\n { x: 0.140625, y: 0.828125 },\n { x: 0.171875, y: 0.828125 },\n { x: 0.171875, y: 0.828125 },\n { x: 0.203125, y: 0.828125 },\n { x: 0.203125, y: 0.828125 },\n { x: 0.234375, y: 0.828125 },\n { x: 0.234375, y: 0.828125 },\n { x: 0.265625, y: 0.828125 },\n { x: 0.265625, y: 0.828125 },\n { x: 0.296875, y: 0.828125 },\n { x: 0.296875, y: 0.828125 },\n { x: 0.328125, y: 0.828125 },\n { x: 0.328125, y: 0.828125 },\n { x: 0.359375, y: 0.828125 },\n { x: 0.359375, y: 0.828125 },\n { x: 0.390625, y: 0.828125 },\n { x: 0.390625, y: 0.828125 },\n { x: 0.421875, y: 0.828125 },\n { x: 0.421875, y: 0.828125 },\n { x: 0.453125, y: 0.828125 },\n { x: 0.453125, y: 0.828125 },\n { x: 0.484375, y: 0.828125 },\n { x: 0.484375, y: 0.828125 },\n { x: 0.515625, y: 0.828125 },\n { x: 0.515625, y: 0.828125 },\n { x: 0.546875, y: 0.828125 },\n { x: 0.546875, y: 0.828125 },\n { x: 0.578125, y: 0.828125 },\n { x: 0.578125, y: 0.828125 },\n { x: 0.609375, y: 0.828125 },\n { x: 0.609375, y: 0.828125 },\n { x: 0.640625, y: 0.828125 },\n { x: 0.640625, y: 0.828125 },\n { x: 0.671875, y: 0.828125 },\n { x: 0.671875, y: 0.828125 },\n { x: 0.703125, y: 0.828125 },\n { x: 0.703125, y: 0.828125 },\n { x: 0.734375, y: 0.828125 },\n { x: 0.734375, y: 0.828125 },\n { x: 0.765625, y: 0.828125 },\n { x: 0.765625, y: 0.828125 },\n { x: 0.796875, y: 0.828125 },\n { x: 0.796875, y: 0.828125 },\n { x: 0.828125, y: 0.828125 },\n { x: 0.828125, y: 0.828125 },\n { x: 0.859375, y: 0.828125 },\n { x: 0.859375, y: 0.828125 },\n { x: 0.890625, y: 0.828125 },\n { x: 0.890625, y: 0.828125 },\n { x: 0.921875, y: 0.828125 },\n { x: 0.921875, y: 0.828125 },\n { x: 0.953125, y: 0.828125 },\n { x: 0.953125, y: 0.828125 },\n { x: 0.984375, y: 0.828125 },\n { x: 0.984375, y: 0.828125 },\n { x: 0.015625, y: 0.859375 },\n { x: 0.015625, y: 0.859375 },\n { x: 0.046875, y: 0.859375 },\n { x: 0.046875, y: 0.859375 },\n { x: 0.078125, y: 0.859375 },\n { x: 0.078125, y: 0.859375 },\n { x: 0.109375, y: 0.859375 },\n { x: 0.109375, y: 0.859375 },\n { x: 0.140625, y: 0.859375 },\n { x: 0.140625, y: 0.859375 },\n { x: 0.171875, y: 0.859375 },\n { x: 0.171875, y: 0.859375 },\n { x: 0.203125, y: 0.859375 },\n { x: 0.203125, y: 0.859375 },\n { x: 0.234375, y: 0.859375 },\n { x: 0.234375, y: 0.859375 },\n { x: 0.265625, y: 0.859375 },\n { x: 0.265625, y: 0.859375 },\n { x: 0.296875, y: 0.859375 },\n { x: 0.296875, y: 0.859375 },\n { x: 0.328125, y: 0.859375 },\n { x: 0.328125, y: 0.859375 },\n { x: 0.359375, y: 0.859375 },\n { x: 0.359375, y: 0.859375 },\n { x: 0.390625, y: 0.859375 },\n { x: 0.390625, y: 0.859375 },\n { x: 0.421875, y: 0.859375 },\n { x: 0.421875, y: 0.859375 },\n { x: 0.453125, y: 0.859375 },\n { x: 0.453125, y: 0.859375 },\n { x: 0.484375, y: 0.859375 },\n { x: 0.484375, y: 0.859375 },\n { x: 0.515625, y: 0.859375 },\n { x: 0.515625, y: 0.859375 },\n { x: 0.546875, y: 0.859375 },\n { x: 0.546875, y: 0.859375 },\n { x: 0.578125, y: 0.859375 },\n { x: 0.578125, y: 0.859375 },\n { x: 0.609375, y: 0.859375 },\n { x: 0.609375, y: 0.859375 },\n { x: 0.640625, y: 0.859375 },\n { x: 0.640625, y: 0.859375 },\n { x: 0.671875, y: 0.859375 },\n { x: 0.671875, y: 0.859375 },\n { x: 0.703125, y: 0.859375 },\n { x: 0.703125, y: 0.859375 },\n { x: 0.734375, y: 0.859375 },\n { x: 0.734375, y: 0.859375 },\n { x: 0.765625, y: 0.859375 },\n { x: 0.765625, y: 0.859375 },\n { x: 0.796875, y: 0.859375 },\n { x: 0.796875, y: 0.859375 },\n { x: 0.828125, y: 0.859375 },\n { x: 0.828125, y: 0.859375 },\n { x: 0.859375, y: 0.859375 },\n { x: 0.859375, y: 0.859375 },\n { x: 0.890625, y: 0.859375 },\n { x: 0.890625, y: 0.859375 },\n { x: 0.921875, y: 0.859375 },\n { x: 0.921875, y: 0.859375 },\n { x: 0.953125, y: 0.859375 },\n { x: 0.953125, y: 0.859375 },\n { x: 0.984375, y: 0.859375 },\n { x: 0.984375, y: 0.859375 },\n { x: 0.015625, y: 0.890625 },\n { x: 0.015625, y: 0.890625 },\n { x: 0.046875, y: 0.890625 },\n { x: 0.046875, y: 0.890625 },\n { x: 0.078125, y: 0.890625 },\n { x: 0.078125, y: 0.890625 },\n { x: 0.109375, y: 0.890625 },\n { x: 0.109375, y: 0.890625 },\n { x: 0.140625, y: 0.890625 },\n { x: 0.140625, y: 0.890625 },\n { x: 0.171875, y: 0.890625 },\n { x: 0.171875, y: 0.890625 },\n { x: 0.203125, y: 0.890625 },\n { x: 0.203125, y: 0.890625 },\n { x: 0.234375, y: 0.890625 },\n { x: 0.234375, y: 0.890625 },\n { x: 0.265625, y: 0.890625 },\n { x: 0.265625, y: 0.890625 },\n { x: 0.296875, y: 0.890625 },\n { x: 0.296875, y: 0.890625 },\n { x: 0.328125, y: 0.890625 },\n { x: 0.328125, y: 0.890625 },\n { x: 0.359375, y: 0.890625 },\n { x: 0.359375, y: 0.890625 },\n { x: 0.390625, y: 0.890625 },\n { x: 0.390625, y: 0.890625 },\n { x: 0.421875, y: 0.890625 },\n { x: 0.421875, y: 0.890625 },\n { x: 0.453125, y: 0.890625 },\n { x: 0.453125, y: 0.890625 },\n { x: 0.484375, y: 0.890625 },\n { x: 0.484375, y: 0.890625 },\n { x: 0.515625, y: 0.890625 },\n { x: 0.515625, y: 0.890625 },\n { x: 0.546875, y: 0.890625 },\n { x: 0.546875, y: 0.890625 },\n { x: 0.578125, y: 0.890625 },\n { x: 0.578125, y: 0.890625 },\n { x: 0.609375, y: 0.890625 },\n { x: 0.609375, y: 0.890625 },\n { x: 0.640625, y: 0.890625 },\n { x: 0.640625, y: 0.890625 },\n { x: 0.671875, y: 0.890625 },\n { x: 0.671875, y: 0.890625 },\n { x: 0.703125, y: 0.890625 },\n { x: 0.703125, y: 0.890625 },\n { x: 0.734375, y: 0.890625 },\n { x: 0.734375, y: 0.890625 },\n { x: 0.765625, y: 0.890625 },\n { x: 0.765625, y: 0.890625 },\n { x: 0.796875, y: 0.890625 },\n { x: 0.796875, y: 0.890625 },\n { x: 0.828125, y: 0.890625 },\n { x: 0.828125, y: 0.890625 },\n { x: 0.859375, y: 0.890625 },\n { x: 0.859375, y: 0.890625 },\n { x: 0.890625, y: 0.890625 },\n { x: 0.890625, y: 0.890625 },\n { x: 0.921875, y: 0.890625 },\n { x: 0.921875, y: 0.890625 },\n { x: 0.953125, y: 0.890625 },\n { x: 0.953125, y: 0.890625 },\n { x: 0.984375, y: 0.890625 },\n { x: 0.984375, y: 0.890625 },\n { x: 0.015625, y: 0.921875 },\n { x: 0.015625, y: 0.921875 },\n { x: 0.046875, y: 0.921875 },\n { x: 0.046875, y: 0.921875 },\n { x: 0.078125, y: 0.921875 },\n { x: 0.078125, y: 0.921875 },\n { x: 0.109375, y: 0.921875 },\n { x: 0.109375, y: 0.921875 },\n { x: 0.140625, y: 0.921875 },\n { x: 0.140625, y: 0.921875 },\n { x: 0.171875, y: 0.921875 },\n { x: 0.171875, y: 0.921875 },\n { x: 0.203125, y: 0.921875 },\n { x: 0.203125, y: 0.921875 },\n { x: 0.234375, y: 0.921875 },\n { x: 0.234375, y: 0.921875 },\n { x: 0.265625, y: 0.921875 },\n { x: 0.265625, y: 0.921875 },\n { x: 0.296875, y: 0.921875 },\n { x: 0.296875, y: 0.921875 },\n { x: 0.328125, y: 0.921875 },\n { x: 0.328125, y: 0.921875 },\n { x: 0.359375, y: 0.921875 },\n { x: 0.359375, y: 0.921875 },\n { x: 0.390625, y: 0.921875 },\n { x: 0.390625, y: 0.921875 },\n { x: 0.421875, y: 0.921875 },\n { x: 0.421875, y: 0.921875 },\n { x: 0.453125, y: 0.921875 },\n { x: 0.453125, y: 0.921875 },\n { x: 0.484375, y: 0.921875 },\n { x: 0.484375, y: 0.921875 },\n { x: 0.515625, y: 0.921875 },\n { x: 0.515625, y: 0.921875 },\n { x: 0.546875, y: 0.921875 },\n { x: 0.546875, y: 0.921875 },\n { x: 0.578125, y: 0.921875 },\n { x: 0.578125, y: 0.921875 },\n { x: 0.609375, y: 0.921875 },\n { x: 0.609375, y: 0.921875 },\n { x: 0.640625, y: 0.921875 },\n { x: 0.640625, y: 0.921875 },\n { x: 0.671875, y: 0.921875 },\n { x: 0.671875, y: 0.921875 },\n { x: 0.703125, y: 0.921875 },\n { x: 0.703125, y: 0.921875 },\n { x: 0.734375, y: 0.921875 },\n { x: 0.734375, y: 0.921875 },\n { x: 0.765625, y: 0.921875 },\n { x: 0.765625, y: 0.921875 },\n { x: 0.796875, y: 0.921875 },\n { x: 0.796875, y: 0.921875 },\n { x: 0.828125, y: 0.921875 },\n { x: 0.828125, y: 0.921875 },\n { x: 0.859375, y: 0.921875 },\n { x: 0.859375, y: 0.921875 },\n { x: 0.890625, y: 0.921875 },\n { x: 0.890625, y: 0.921875 },\n { x: 0.921875, y: 0.921875 },\n { x: 0.921875, y: 0.921875 },\n { x: 0.953125, y: 0.921875 },\n { x: 0.953125, y: 0.921875 },\n { x: 0.984375, y: 0.921875 },\n { x: 0.984375, y: 0.921875 },\n { x: 0.015625, y: 0.953125 },\n { x: 0.015625, y: 0.953125 },\n { x: 0.046875, y: 0.953125 },\n { x: 0.046875, y: 0.953125 },\n { x: 0.078125, y: 0.953125 },\n { x: 0.078125, y: 0.953125 },\n { x: 0.109375, y: 0.953125 },\n { x: 0.109375, y: 0.953125 },\n { x: 0.140625, y: 0.953125 },\n { x: 0.140625, y: 0.953125 },\n { x: 0.171875, y: 0.953125 },\n { x: 0.171875, y: 0.953125 },\n { x: 0.203125, y: 0.953125 },\n { x: 0.203125, y: 0.953125 },\n { x: 0.234375, y: 0.953125 },\n { x: 0.234375, y: 0.953125 },\n { x: 0.265625, y: 0.953125 },\n { x: 0.265625, y: 0.953125 },\n { x: 0.296875, y: 0.953125 },\n { x: 0.296875, y: 0.953125 },\n { x: 0.328125, y: 0.953125 },\n { x: 0.328125, y: 0.953125 },\n { x: 0.359375, y: 0.953125 },\n { x: 0.359375, y: 0.953125 },\n { x: 0.390625, y: 0.953125 },\n { x: 0.390625, y: 0.953125 },\n { x: 0.421875, y: 0.953125 },\n { x: 0.421875, y: 0.953125 },\n { x: 0.453125, y: 0.953125 },\n { x: 0.453125, y: 0.953125 },\n { x: 0.484375, y: 0.953125 },\n { x: 0.484375, y: 0.953125 },\n { x: 0.515625, y: 0.953125 },\n { x: 0.515625, y: 0.953125 },\n { x: 0.546875, y: 0.953125 },\n { x: 0.546875, y: 0.953125 },\n { x: 0.578125, y: 0.953125 },\n { x: 0.578125, y: 0.953125 },\n { x: 0.609375, y: 0.953125 },\n { x: 0.609375, y: 0.953125 },\n { x: 0.640625, y: 0.953125 },\n { x: 0.640625, y: 0.953125 },\n { x: 0.671875, y: 0.953125 },\n { x: 0.671875, y: 0.953125 },\n { x: 0.703125, y: 0.953125 },\n { x: 0.703125, y: 0.953125 },\n { x: 0.734375, y: 0.953125 },\n { x: 0.734375, y: 0.953125 },\n { x: 0.765625, y: 0.953125 },\n { x: 0.765625, y: 0.953125 },\n { x: 0.796875, y: 0.953125 },\n { x: 0.796875, y: 0.953125 },\n { x: 0.828125, y: 0.953125 },\n { x: 0.828125, y: 0.953125 },\n { x: 0.859375, y: 0.953125 },\n { x: 0.859375, y: 0.953125 },\n { x: 0.890625, y: 0.953125 },\n { x: 0.890625, y: 0.953125 },\n { x: 0.921875, y: 0.953125 },\n { x: 0.921875, y: 0.953125 },\n { x: 0.953125, y: 0.953125 },\n { x: 0.953125, y: 0.953125 },\n { x: 0.984375, y: 0.953125 },\n { x: 0.984375, y: 0.953125 },\n { x: 0.015625, y: 0.984375 },\n { x: 0.015625, y: 0.984375 },\n { x: 0.046875, y: 0.984375 },\n { x: 0.046875, y: 0.984375 },\n { x: 0.078125, y: 0.984375 },\n { x: 0.078125, y: 0.984375 },\n { x: 0.109375, y: 0.984375 },\n { x: 0.109375, y: 0.984375 },\n { x: 0.140625, y: 0.984375 },\n { x: 0.140625, y: 0.984375 },\n { x: 0.171875, y: 0.984375 },\n { x: 0.171875, y: 0.984375 },\n { x: 0.203125, y: 0.984375 },\n { x: 0.203125, y: 0.984375 },\n { x: 0.234375, y: 0.984375 },\n { x: 0.234375, y: 0.984375 },\n { x: 0.265625, y: 0.984375 },\n { x: 0.265625, y: 0.984375 },\n { x: 0.296875, y: 0.984375 },\n { x: 0.296875, y: 0.984375 },\n { x: 0.328125, y: 0.984375 },\n { x: 0.328125, y: 0.984375 },\n { x: 0.359375, y: 0.984375 },\n { x: 0.359375, y: 0.984375 },\n { x: 0.390625, y: 0.984375 },\n { x: 0.390625, y: 0.984375 },\n { x: 0.421875, y: 0.984375 },\n { x: 0.421875, y: 0.984375 },\n { x: 0.453125, y: 0.984375 },\n { x: 0.453125, y: 0.984375 },\n { x: 0.484375, y: 0.984375 },\n { x: 0.484375, y: 0.984375 },\n { x: 0.515625, y: 0.984375 },\n { x: 0.515625, y: 0.984375 },\n { x: 0.546875, y: 0.984375 },\n { x: 0.546875, y: 0.984375 },\n { x: 0.578125, y: 0.984375 },\n { x: 0.578125, y: 0.984375 },\n { x: 0.609375, y: 0.984375 },\n { x: 0.609375, y: 0.984375 },\n { x: 0.640625, y: 0.984375 },\n { x: 0.640625, y: 0.984375 },\n { x: 0.671875, y: 0.984375 },\n { x: 0.671875, y: 0.984375 },\n { x: 0.703125, y: 0.984375 },\n { x: 0.703125, y: 0.984375 },\n { x: 0.734375, y: 0.984375 },\n { x: 0.734375, y: 0.984375 },\n { x: 0.765625, y: 0.984375 },\n { x: 0.765625, y: 0.984375 },\n { x: 0.796875, y: 0.984375 },\n { x: 0.796875, y: 0.984375 },\n { x: 0.828125, y: 0.984375 },\n { x: 0.828125, y: 0.984375 },\n { x: 0.859375, y: 0.984375 },\n { x: 0.859375, y: 0.984375 },\n { x: 0.890625, y: 0.984375 },\n { x: 0.890625, y: 0.984375 },\n { x: 0.921875, y: 0.984375 },\n { x: 0.921875, y: 0.984375 },\n { x: 0.953125, y: 0.984375 },\n { x: 0.953125, y: 0.984375 },\n { x: 0.984375, y: 0.984375 },\n { x: 0.984375, y: 0.984375 },\n { x: 0.03125, y: 0.03125 },\n { x: 0.03125, y: 0.03125 },\n { x: 0.09375, y: 0.03125 },\n { x: 0.09375, y: 0.03125 },\n { x: 0.15625, y: 0.03125 },\n { x: 0.15625, y: 0.03125 },\n { x: 0.21875, y: 0.03125 },\n { x: 0.21875, y: 0.03125 },\n { x: 0.28125, y: 0.03125 },\n { x: 0.28125, y: 0.03125 },\n { x: 0.34375, y: 0.03125 },\n { x: 0.34375, y: 0.03125 },\n { x: 0.40625, y: 0.03125 },\n { x: 0.40625, y: 0.03125 },\n { x: 0.46875, y: 0.03125 },\n { x: 0.46875, y: 0.03125 },\n { x: 0.53125, y: 0.03125 },\n { x: 0.53125, y: 0.03125 },\n { x: 0.59375, y: 0.03125 },\n { x: 0.59375, y: 0.03125 },\n { x: 0.65625, y: 0.03125 },\n { x: 0.65625, y: 0.03125 },\n { x: 0.71875, y: 0.03125 },\n { x: 0.71875, y: 0.03125 },\n { x: 0.78125, y: 0.03125 },\n { x: 0.78125, y: 0.03125 },\n { x: 0.84375, y: 0.03125 },\n { x: 0.84375, y: 0.03125 },\n { x: 0.90625, y: 0.03125 },\n { x: 0.90625, y: 0.03125 },\n { x: 0.96875, y: 0.03125 },\n { x: 0.96875, y: 0.03125 },\n { x: 0.03125, y: 0.09375 },\n { x: 0.03125, y: 0.09375 },\n { x: 0.09375, y: 0.09375 },\n { x: 0.09375, y: 0.09375 },\n { x: 0.15625, y: 0.09375 },\n { x: 0.15625, y: 0.09375 },\n { x: 0.21875, y: 0.09375 },\n { x: 0.21875, y: 0.09375 },\n { x: 0.28125, y: 0.09375 },\n { x: 0.28125, y: 0.09375 },\n { x: 0.34375, y: 0.09375 },\n { x: 0.34375, y: 0.09375 },\n { x: 0.40625, y: 0.09375 },\n { x: 0.40625, y: 0.09375 },\n { x: 0.46875, y: 0.09375 },\n { x: 0.46875, y: 0.09375 },\n { x: 0.53125, y: 0.09375 },\n { x: 0.53125, y: 0.09375 },\n { x: 0.59375, y: 0.09375 },\n { x: 0.59375, y: 0.09375 },\n { x: 0.65625, y: 0.09375 },\n { x: 0.65625, y: 0.09375 },\n { x: 0.71875, y: 0.09375 },\n { x: 0.71875, y: 0.09375 },\n { x: 0.78125, y: 0.09375 },\n { x: 0.78125, y: 0.09375 },\n { x: 0.84375, y: 0.09375 },\n { x: 0.84375, y: 0.09375 },\n { x: 0.90625, y: 0.09375 },\n { x: 0.90625, y: 0.09375 },\n { x: 0.96875, y: 0.09375 },\n { x: 0.96875, y: 0.09375 },\n { x: 0.03125, y: 0.15625 },\n { x: 0.03125, y: 0.15625 },\n { x: 0.09375, y: 0.15625 },\n { x: 0.09375, y: 0.15625 },\n { x: 0.15625, y: 0.15625 },\n { x: 0.15625, y: 0.15625 },\n { x: 0.21875, y: 0.15625 },\n { x: 0.21875, y: 0.15625 },\n { x: 0.28125, y: 0.15625 },\n { x: 0.28125, y: 0.15625 },\n { x: 0.34375, y: 0.15625 },\n { x: 0.34375, y: 0.15625 },\n { x: 0.40625, y: 0.15625 },\n { x: 0.40625, y: 0.15625 },\n { x: 0.46875, y: 0.15625 },\n { x: 0.46875, y: 0.15625 },\n { x: 0.53125, y: 0.15625 },\n { x: 0.53125, y: 0.15625 },\n { x: 0.59375, y: 0.15625 },\n { x: 0.59375, y: 0.15625 },\n { x: 0.65625, y: 0.15625 },\n { x: 0.65625, y: 0.15625 },\n { x: 0.71875, y: 0.15625 },\n { x: 0.71875, y: 0.15625 },\n { x: 0.78125, y: 0.15625 },\n { x: 0.78125, y: 0.15625 },\n { x: 0.84375, y: 0.15625 },\n { x: 0.84375, y: 0.15625 },\n { x: 0.90625, y: 0.15625 },\n { x: 0.90625, y: 0.15625 },\n { x: 0.96875, y: 0.15625 },\n { x: 0.96875, y: 0.15625 },\n { x: 0.03125, y: 0.21875 },\n { x: 0.03125, y: 0.21875 },\n { x: 0.09375, y: 0.21875 },\n { x: 0.09375, y: 0.21875 },\n { x: 0.15625, y: 0.21875 },\n { x: 0.15625, y: 0.21875 },\n { x: 0.21875, y: 0.21875 },\n { x: 0.21875, y: 0.21875 },\n { x: 0.28125, y: 0.21875 },\n { x: 0.28125, y: 0.21875 },\n { x: 0.34375, y: 0.21875 },\n { x: 0.34375, y: 0.21875 },\n { x: 0.40625, y: 0.21875 },\n { x: 0.40625, y: 0.21875 },\n { x: 0.46875, y: 0.21875 },\n { x: 0.46875, y: 0.21875 },\n { x: 0.53125, y: 0.21875 },\n { x: 0.53125, y: 0.21875 },\n { x: 0.59375, y: 0.21875 },\n { x: 0.59375, y: 0.21875 },\n { x: 0.65625, y: 0.21875 },\n { x: 0.65625, y: 0.21875 },\n { x: 0.71875, y: 0.21875 },\n { x: 0.71875, y: 0.21875 },\n { x: 0.78125, y: 0.21875 },\n { x: 0.78125, y: 0.21875 },\n { x: 0.84375, y: 0.21875 },\n { x: 0.84375, y: 0.21875 },\n { x: 0.90625, y: 0.21875 },\n { x: 0.90625, y: 0.21875 },\n { x: 0.96875, y: 0.21875 },\n { x: 0.96875, y: 0.21875 },\n { x: 0.03125, y: 0.28125 },\n { x: 0.03125, y: 0.28125 },\n { x: 0.09375, y: 0.28125 },\n { x: 0.09375, y: 0.28125 },\n { x: 0.15625, y: 0.28125 },\n { x: 0.15625, y: 0.28125 },\n { x: 0.21875, y: 0.28125 },\n { x: 0.21875, y: 0.28125 },\n { x: 0.28125, y: 0.28125 },\n { x: 0.28125, y: 0.28125 },\n { x: 0.34375, y: 0.28125 },\n { x: 0.34375, y: 0.28125 },\n { x: 0.40625, y: 0.28125 },\n { x: 0.40625, y: 0.28125 },\n { x: 0.46875, y: 0.28125 },\n { x: 0.46875, y: 0.28125 },\n { x: 0.53125, y: 0.28125 },\n { x: 0.53125, y: 0.28125 },\n { x: 0.59375, y: 0.28125 },\n { x: 0.59375, y: 0.28125 },\n { x: 0.65625, y: 0.28125 },\n { x: 0.65625, y: 0.28125 },\n { x: 0.71875, y: 0.28125 },\n { x: 0.71875, y: 0.28125 },\n { x: 0.78125, y: 0.28125 },\n { x: 0.78125, y: 0.28125 },\n { x: 0.84375, y: 0.28125 },\n { x: 0.84375, y: 0.28125 },\n { x: 0.90625, y: 0.28125 },\n { x: 0.90625, y: 0.28125 },\n { x: 0.96875, y: 0.28125 },\n { x: 0.96875, y: 0.28125 },\n { x: 0.03125, y: 0.34375 },\n { x: 0.03125, y: 0.34375 },\n { x: 0.09375, y: 0.34375 },\n { x: 0.09375, y: 0.34375 },\n { x: 0.15625, y: 0.34375 },\n { x: 0.15625, y: 0.34375 },\n { x: 0.21875, y: 0.34375 },\n { x: 0.21875, y: 0.34375 },\n { x: 0.28125, y: 0.34375 },\n { x: 0.28125, y: 0.34375 },\n { x: 0.34375, y: 0.34375 },\n { x: 0.34375, y: 0.34375 },\n { x: 0.40625, y: 0.34375 },\n { x: 0.40625, y: 0.34375 },\n { x: 0.46875, y: 0.34375 },\n { x: 0.46875, y: 0.34375 },\n { x: 0.53125, y: 0.34375 },\n { x: 0.53125, y: 0.34375 },\n { x: 0.59375, y: 0.34375 },\n { x: 0.59375, y: 0.34375 },\n { x: 0.65625, y: 0.34375 },\n { x: 0.65625, y: 0.34375 },\n { x: 0.71875, y: 0.34375 },\n { x: 0.71875, y: 0.34375 },\n { x: 0.78125, y: 0.34375 },\n { x: 0.78125, y: 0.34375 },\n { x: 0.84375, y: 0.34375 },\n { x: 0.84375, y: 0.34375 },\n { x: 0.90625, y: 0.34375 },\n { x: 0.90625, y: 0.34375 },\n { x: 0.96875, y: 0.34375 },\n { x: 0.96875, y: 0.34375 },\n { x: 0.03125, y: 0.40625 },\n { x: 0.03125, y: 0.40625 },\n { x: 0.09375, y: 0.40625 },\n { x: 0.09375, y: 0.40625 },\n { x: 0.15625, y: 0.40625 },\n { x: 0.15625, y: 0.40625 },\n { x: 0.21875, y: 0.40625 },\n { x: 0.21875, y: 0.40625 },\n { x: 0.28125, y: 0.40625 },\n { x: 0.28125, y: 0.40625 },\n { x: 0.34375, y: 0.40625 },\n { x: 0.34375, y: 0.40625 },\n { x: 0.40625, y: 0.40625 },\n { x: 0.40625, y: 0.40625 },\n { x: 0.46875, y: 0.40625 },\n { x: 0.46875, y: 0.40625 },\n { x: 0.53125, y: 0.40625 },\n { x: 0.53125, y: 0.40625 },\n { x: 0.59375, y: 0.40625 },\n { x: 0.59375, y: 0.40625 },\n { x: 0.65625, y: 0.40625 },\n { x: 0.65625, y: 0.40625 },\n { x: 0.71875, y: 0.40625 },\n { x: 0.71875, y: 0.40625 },\n { x: 0.78125, y: 0.40625 },\n { x: 0.78125, y: 0.40625 },\n { x: 0.84375, y: 0.40625 },\n { x: 0.84375, y: 0.40625 },\n { x: 0.90625, y: 0.40625 },\n { x: 0.90625, y: 0.40625 },\n { x: 0.96875, y: 0.40625 },\n { x: 0.96875, y: 0.40625 },\n { x: 0.03125, y: 0.46875 },\n { x: 0.03125, y: 0.46875 },\n { x: 0.09375, y: 0.46875 },\n { x: 0.09375, y: 0.46875 },\n { x: 0.15625, y: 0.46875 },\n { x: 0.15625, y: 0.46875 },\n { x: 0.21875, y: 0.46875 },\n { x: 0.21875, y: 0.46875 },\n { x: 0.28125, y: 0.46875 },\n { x: 0.28125, y: 0.46875 },\n { x: 0.34375, y: 0.46875 },\n { x: 0.34375, y: 0.46875 },\n { x: 0.40625, y: 0.46875 },\n { x: 0.40625, y: 0.46875 },\n { x: 0.46875, y: 0.46875 },\n { x: 0.46875, y: 0.46875 },\n { x: 0.53125, y: 0.46875 },\n { x: 0.53125, y: 0.46875 },\n { x: 0.59375, y: 0.46875 },\n { x: 0.59375, y: 0.46875 },\n { x: 0.65625, y: 0.46875 },\n { x: 0.65625, y: 0.46875 },\n { x: 0.71875, y: 0.46875 },\n { x: 0.71875, y: 0.46875 },\n { x: 0.78125, y: 0.46875 },\n { x: 0.78125, y: 0.46875 },\n { x: 0.84375, y: 0.46875 },\n { x: 0.84375, y: 0.46875 },\n { x: 0.90625, y: 0.46875 },\n { x: 0.90625, y: 0.46875 },\n { x: 0.96875, y: 0.46875 },\n { x: 0.96875, y: 0.46875 },\n { x: 0.03125, y: 0.53125 },\n { x: 0.03125, y: 0.53125 },\n { x: 0.09375, y: 0.53125 },\n { x: 0.09375, y: 0.53125 },\n { x: 0.15625, y: 0.53125 },\n { x: 0.15625, y: 0.53125 },\n { x: 0.21875, y: 0.53125 },\n { x: 0.21875, y: 0.53125 },\n { x: 0.28125, y: 0.53125 },\n { x: 0.28125, y: 0.53125 },\n { x: 0.34375, y: 0.53125 },\n { x: 0.34375, y: 0.53125 },\n { x: 0.40625, y: 0.53125 },\n { x: 0.40625, y: 0.53125 },\n { x: 0.46875, y: 0.53125 },\n { x: 0.46875, y: 0.53125 },\n { x: 0.53125, y: 0.53125 },\n { x: 0.53125, y: 0.53125 },\n { x: 0.59375, y: 0.53125 },\n { x: 0.59375, y: 0.53125 },\n { x: 0.65625, y: 0.53125 },\n { x: 0.65625, y: 0.53125 },\n { x: 0.71875, y: 0.53125 },\n { x: 0.71875, y: 0.53125 },\n { x: 0.78125, y: 0.53125 },\n { x: 0.78125, y: 0.53125 },\n { x: 0.84375, y: 0.53125 },\n { x: 0.84375, y: 0.53125 },\n { x: 0.90625, y: 0.53125 },\n { x: 0.90625, y: 0.53125 },\n { x: 0.96875, y: 0.53125 },\n { x: 0.96875, y: 0.53125 },\n { x: 0.03125, y: 0.59375 },\n { x: 0.03125, y: 0.59375 },\n { x: 0.09375, y: 0.59375 },\n { x: 0.09375, y: 0.59375 },\n { x: 0.15625, y: 0.59375 },\n { x: 0.15625, y: 0.59375 },\n { x: 0.21875, y: 0.59375 },\n { x: 0.21875, y: 0.59375 },\n { x: 0.28125, y: 0.59375 },\n { x: 0.28125, y: 0.59375 },\n { x: 0.34375, y: 0.59375 },\n { x: 0.34375, y: 0.59375 },\n { x: 0.40625, y: 0.59375 },\n { x: 0.40625, y: 0.59375 },\n { x: 0.46875, y: 0.59375 },\n { x: 0.46875, y: 0.59375 },\n { x: 0.53125, y: 0.59375 },\n { x: 0.53125, y: 0.59375 },\n { x: 0.59375, y: 0.59375 },\n { x: 0.59375, y: 0.59375 },\n { x: 0.65625, y: 0.59375 },\n { x: 0.65625, y: 0.59375 },\n { x: 0.71875, y: 0.59375 },\n { x: 0.71875, y: 0.59375 },\n { x: 0.78125, y: 0.59375 },\n { x: 0.78125, y: 0.59375 },\n { x: 0.84375, y: 0.59375 },\n { x: 0.84375, y: 0.59375 },\n { x: 0.90625, y: 0.59375 },\n { x: 0.90625, y: 0.59375 },\n { x: 0.96875, y: 0.59375 },\n { x: 0.96875, y: 0.59375 },\n { x: 0.03125, y: 0.65625 },\n { x: 0.03125, y: 0.65625 },\n { x: 0.09375, y: 0.65625 },\n { x: 0.09375, y: 0.65625 },\n { x: 0.15625, y: 0.65625 },\n { x: 0.15625, y: 0.65625 },\n { x: 0.21875, y: 0.65625 },\n { x: 0.21875, y: 0.65625 },\n { x: 0.28125, y: 0.65625 },\n { x: 0.28125, y: 0.65625 },\n { x: 0.34375, y: 0.65625 },\n { x: 0.34375, y: 0.65625 },\n { x: 0.40625, y: 0.65625 },\n { x: 0.40625, y: 0.65625 },\n { x: 0.46875, y: 0.65625 },\n { x: 0.46875, y: 0.65625 },\n { x: 0.53125, y: 0.65625 },\n { x: 0.53125, y: 0.65625 },\n { x: 0.59375, y: 0.65625 },\n { x: 0.59375, y: 0.65625 },\n { x: 0.65625, y: 0.65625 },\n { x: 0.65625, y: 0.65625 },\n { x: 0.71875, y: 0.65625 },\n { x: 0.71875, y: 0.65625 },\n { x: 0.78125, y: 0.65625 },\n { x: 0.78125, y: 0.65625 },\n { x: 0.84375, y: 0.65625 },\n { x: 0.84375, y: 0.65625 },\n { x: 0.90625, y: 0.65625 },\n { x: 0.90625, y: 0.65625 },\n { x: 0.96875, y: 0.65625 },\n { x: 0.96875, y: 0.65625 },\n { x: 0.03125, y: 0.71875 },\n { x: 0.03125, y: 0.71875 },\n { x: 0.09375, y: 0.71875 },\n { x: 0.09375, y: 0.71875 },\n { x: 0.15625, y: 0.71875 },\n { x: 0.15625, y: 0.71875 },\n { x: 0.21875, y: 0.71875 },\n { x: 0.21875, y: 0.71875 },\n { x: 0.28125, y: 0.71875 },\n { x: 0.28125, y: 0.71875 },\n { x: 0.34375, y: 0.71875 },\n { x: 0.34375, y: 0.71875 },\n { x: 0.40625, y: 0.71875 },\n { x: 0.40625, y: 0.71875 },\n { x: 0.46875, y: 0.71875 },\n { x: 0.46875, y: 0.71875 },\n { x: 0.53125, y: 0.71875 },\n { x: 0.53125, y: 0.71875 },\n { x: 0.59375, y: 0.71875 },\n { x: 0.59375, y: 0.71875 },\n { x: 0.65625, y: 0.71875 },\n { x: 0.65625, y: 0.71875 },\n { x: 0.71875, y: 0.71875 },\n { x: 0.71875, y: 0.71875 },\n { x: 0.78125, y: 0.71875 },\n { x: 0.78125, y: 0.71875 },\n { x: 0.84375, y: 0.71875 },\n { x: 0.84375, y: 0.71875 },\n { x: 0.90625, y: 0.71875 },\n { x: 0.90625, y: 0.71875 },\n { x: 0.96875, y: 0.71875 },\n { x: 0.96875, y: 0.71875 },\n { x: 0.03125, y: 0.78125 },\n { x: 0.03125, y: 0.78125 },\n { x: 0.09375, y: 0.78125 },\n { x: 0.09375, y: 0.78125 },\n { x: 0.15625, y: 0.78125 },\n { x: 0.15625, y: 0.78125 },\n { x: 0.21875, y: 0.78125 },\n { x: 0.21875, y: 0.78125 },\n { x: 0.28125, y: 0.78125 },\n { x: 0.28125, y: 0.78125 },\n { x: 0.34375, y: 0.78125 },\n { x: 0.34375, y: 0.78125 },\n { x: 0.40625, y: 0.78125 },\n { x: 0.40625, y: 0.78125 },\n { x: 0.46875, y: 0.78125 },\n { x: 0.46875, y: 0.78125 },\n { x: 0.53125, y: 0.78125 },\n { x: 0.53125, y: 0.78125 },\n { x: 0.59375, y: 0.78125 },\n { x: 0.59375, y: 0.78125 },\n { x: 0.65625, y: 0.78125 },\n { x: 0.65625, y: 0.78125 },\n { x: 0.71875, y: 0.78125 },\n { x: 0.71875, y: 0.78125 },\n { x: 0.78125, y: 0.78125 },\n { x: 0.78125, y: 0.78125 },\n { x: 0.84375, y: 0.78125 },\n { x: 0.84375, y: 0.78125 },\n { x: 0.90625, y: 0.78125 },\n { x: 0.90625, y: 0.78125 },\n { x: 0.96875, y: 0.78125 },\n { x: 0.96875, y: 0.78125 },\n { x: 0.03125, y: 0.84375 },\n { x: 0.03125, y: 0.84375 },\n { x: 0.09375, y: 0.84375 },\n { x: 0.09375, y: 0.84375 },\n { x: 0.15625, y: 0.84375 },\n { x: 0.15625, y: 0.84375 },\n { x: 0.21875, y: 0.84375 },\n { x: 0.21875, y: 0.84375 },\n { x: 0.28125, y: 0.84375 },\n { x: 0.28125, y: 0.84375 },\n { x: 0.34375, y: 0.84375 },\n { x: 0.34375, y: 0.84375 },\n { x: 0.40625, y: 0.84375 },\n { x: 0.40625, y: 0.84375 },\n { x: 0.46875, y: 0.84375 },\n { x: 0.46875, y: 0.84375 },\n { x: 0.53125, y: 0.84375 },\n { x: 0.53125, y: 0.84375 },\n { x: 0.59375, y: 0.84375 },\n { x: 0.59375, y: 0.84375 },\n { x: 0.65625, y: 0.84375 },\n { x: 0.65625, y: 0.84375 },\n { x: 0.71875, y: 0.84375 },\n { x: 0.71875, y: 0.84375 },\n { x: 0.78125, y: 0.84375 },\n { x: 0.78125, y: 0.84375 },\n { x: 0.84375, y: 0.84375 },\n { x: 0.84375, y: 0.84375 },\n { x: 0.90625, y: 0.84375 },\n { x: 0.90625, y: 0.84375 },\n { x: 0.96875, y: 0.84375 },\n { x: 0.96875, y: 0.84375 },\n { x: 0.03125, y: 0.90625 },\n { x: 0.03125, y: 0.90625 },\n { x: 0.09375, y: 0.90625 },\n { x: 0.09375, y: 0.90625 },\n { x: 0.15625, y: 0.90625 },\n { x: 0.15625, y: 0.90625 },\n { x: 0.21875, y: 0.90625 },\n { x: 0.21875, y: 0.90625 },\n { x: 0.28125, y: 0.90625 },\n { x: 0.28125, y: 0.90625 },\n { x: 0.34375, y: 0.90625 },\n { x: 0.34375, y: 0.90625 },\n { x: 0.40625, y: 0.90625 },\n { x: 0.40625, y: 0.90625 },\n { x: 0.46875, y: 0.90625 },\n { x: 0.46875, y: 0.90625 },\n { x: 0.53125, y: 0.90625 },\n { x: 0.53125, y: 0.90625 },\n { x: 0.59375, y: 0.90625 },\n { x: 0.59375, y: 0.90625 },\n { x: 0.65625, y: 0.90625 },\n { x: 0.65625, y: 0.90625 },\n { x: 0.71875, y: 0.90625 },\n { x: 0.71875, y: 0.90625 },\n { x: 0.78125, y: 0.90625 },\n { x: 0.78125, y: 0.90625 },\n { x: 0.84375, y: 0.90625 },\n { x: 0.84375, y: 0.90625 },\n { x: 0.90625, y: 0.90625 },\n { x: 0.90625, y: 0.90625 },\n { x: 0.96875, y: 0.90625 },\n { x: 0.96875, y: 0.90625 },\n { x: 0.03125, y: 0.96875 },\n { x: 0.03125, y: 0.96875 },\n { x: 0.09375, y: 0.96875 },\n { x: 0.09375, y: 0.96875 },\n { x: 0.15625, y: 0.96875 },\n { x: 0.15625, y: 0.96875 },\n { x: 0.21875, y: 0.96875 },\n { x: 0.21875, y: 0.96875 },\n { x: 0.28125, y: 0.96875 },\n { x: 0.28125, y: 0.96875 },\n { x: 0.34375, y: 0.96875 },\n { x: 0.34375, y: 0.96875 },\n { x: 0.40625, y: 0.96875 },\n { x: 0.40625, y: 0.96875 },\n { x: 0.46875, y: 0.96875 },\n { x: 0.46875, y: 0.96875 },\n { x: 0.53125, y: 0.96875 },\n { x: 0.53125, y: 0.96875 },\n { x: 0.59375, y: 0.96875 },\n { x: 0.59375, y: 0.96875 },\n { x: 0.65625, y: 0.96875 },\n { x: 0.65625, y: 0.96875 },\n { x: 0.71875, y: 0.96875 },\n { x: 0.71875, y: 0.96875 },\n { x: 0.78125, y: 0.96875 },\n { x: 0.78125, y: 0.96875 },\n { x: 0.84375, y: 0.96875 },\n { x: 0.84375, y: 0.96875 },\n { x: 0.90625, y: 0.96875 },\n { x: 0.90625, y: 0.96875 },\n { x: 0.96875, y: 0.96875 },\n { x: 0.96875, y: 0.96875 },\n { x: 0.0625, y: 0.0625 },\n { x: 0.0625, y: 0.0625 },\n { x: 0.0625, y: 0.0625 },\n { x: 0.0625, y: 0.0625 },\n { x: 0.0625, y: 0.0625 },\n { x: 0.0625, y: 0.0625 },\n { x: 0.1875, y: 0.0625 },\n { x: 0.1875, y: 0.0625 },\n { x: 0.1875, y: 0.0625 },\n { x: 0.1875, y: 0.0625 },\n { x: 0.1875, y: 0.0625 },\n { x: 0.1875, y: 0.0625 },\n { x: 0.3125, y: 0.0625 },\n { x: 0.3125, y: 0.0625 },\n { x: 0.3125, y: 0.0625 },\n { x: 0.3125, y: 0.0625 },\n { x: 0.3125, y: 0.0625 },\n { x: 0.3125, y: 0.0625 },\n { x: 0.4375, y: 0.0625 },\n { x: 0.4375, y: 0.0625 },\n { x: 0.4375, y: 0.0625 },\n { x: 0.4375, y: 0.0625 },\n { x: 0.4375, y: 0.0625 },\n { x: 0.4375, y: 0.0625 },\n { x: 0.5625, y: 0.0625 },\n { x: 0.5625, y: 0.0625 },\n { x: 0.5625, y: 0.0625 },\n { x: 0.5625, y: 0.0625 },\n { x: 0.5625, y: 0.0625 },\n { x: 0.5625, y: 0.0625 },\n { x: 0.6875, y: 0.0625 },\n { x: 0.6875, y: 0.0625 },\n { x: 0.6875, y: 0.0625 },\n { x: 0.6875, y: 0.0625 },\n { x: 0.6875, y: 0.0625 },\n { x: 0.6875, y: 0.0625 },\n { x: 0.8125, y: 0.0625 },\n { x: 0.8125, y: 0.0625 },\n { x: 0.8125, y: 0.0625 },\n { x: 0.8125, y: 0.0625 },\n { x: 0.8125, y: 0.0625 },\n { x: 0.8125, y: 0.0625 },\n { x: 0.9375, y: 0.0625 },\n { x: 0.9375, y: 0.0625 },\n { x: 0.9375, y: 0.0625 },\n { x: 0.9375, y: 0.0625 },\n { x: 0.9375, y: 0.0625 },\n { x: 0.9375, y: 0.0625 },\n { x: 0.0625, y: 0.1875 },\n { x: 0.0625, y: 0.1875 },\n { x: 0.0625, y: 0.1875 },\n { x: 0.0625, y: 0.1875 },\n { x: 0.0625, y: 0.1875 },\n { x: 0.0625, y: 0.1875 },\n { x: 0.1875, y: 0.1875 },\n { x: 0.1875, y: 0.1875 },\n { x: 0.1875, y: 0.1875 },\n { x: 0.1875, y: 0.1875 },\n { x: 0.1875, y: 0.1875 },\n { x: 0.1875, y: 0.1875 },\n { x: 0.3125, y: 0.1875 },\n { x: 0.3125, y: 0.1875 },\n { x: 0.3125, y: 0.1875 },\n { x: 0.3125, y: 0.1875 },\n { x: 0.3125, y: 0.1875 },\n { x: 0.3125, y: 0.1875 },\n { x: 0.4375, y: 0.1875 },\n { x: 0.4375, y: 0.1875 },\n { x: 0.4375, y: 0.1875 },\n { x: 0.4375, y: 0.1875 },\n { x: 0.4375, y: 0.1875 },\n { x: 0.4375, y: 0.1875 },\n { x: 0.5625, y: 0.1875 },\n { x: 0.5625, y: 0.1875 },\n { x: 0.5625, y: 0.1875 },\n { x: 0.5625, y: 0.1875 },\n { x: 0.5625, y: 0.1875 },\n { x: 0.5625, y: 0.1875 },\n { x: 0.6875, y: 0.1875 },\n { x: 0.6875, y: 0.1875 },\n { x: 0.6875, y: 0.1875 },\n { x: 0.6875, y: 0.1875 },\n { x: 0.6875, y: 0.1875 },\n { x: 0.6875, y: 0.1875 },\n { x: 0.8125, y: 0.1875 },\n { x: 0.8125, y: 0.1875 },\n { x: 0.8125, y: 0.1875 },\n { x: 0.8125, y: 0.1875 },\n { x: 0.8125, y: 0.1875 },\n { x: 0.8125, y: 0.1875 },\n { x: 0.9375, y: 0.1875 },\n { x: 0.9375, y: 0.1875 },\n { x: 0.9375, y: 0.1875 },\n { x: 0.9375, y: 0.1875 },\n { x: 0.9375, y: 0.1875 },\n { x: 0.9375, y: 0.1875 },\n { x: 0.0625, y: 0.3125 },\n { x: 0.0625, y: 0.3125 },\n { x: 0.0625, y: 0.3125 },\n { x: 0.0625, y: 0.3125 },\n { x: 0.0625, y: 0.3125 },\n { x: 0.0625, y: 0.3125 },\n { x: 0.1875, y: 0.3125 },\n { x: 0.1875, y: 0.3125 },\n { x: 0.1875, y: 0.3125 },\n { x: 0.1875, y: 0.3125 },\n { x: 0.1875, y: 0.3125 },\n { x: 0.1875, y: 0.3125 },\n { x: 0.3125, y: 0.3125 },\n { x: 0.3125, y: 0.3125 },\n { x: 0.3125, y: 0.3125 },\n { x: 0.3125, y: 0.3125 },\n { x: 0.3125, y: 0.3125 },\n { x: 0.3125, y: 0.3125 },\n { x: 0.4375, y: 0.3125 },\n { x: 0.4375, y: 0.3125 },\n { x: 0.4375, y: 0.3125 },\n { x: 0.4375, y: 0.3125 },\n { x: 0.4375, y: 0.3125 },\n { x: 0.4375, y: 0.3125 },\n { x: 0.5625, y: 0.3125 },\n { x: 0.5625, y: 0.3125 },\n { x: 0.5625, y: 0.3125 },\n { x: 0.5625, y: 0.3125 },\n { x: 0.5625, y: 0.3125 },\n { x: 0.5625, y: 0.3125 },\n { x: 0.6875, y: 0.3125 },\n { x: 0.6875, y: 0.3125 },\n { x: 0.6875, y: 0.3125 },\n { x: 0.6875, y: 0.3125 },\n { x: 0.6875, y: 0.3125 },\n { x: 0.6875, y: 0.3125 },\n { x: 0.8125, y: 0.3125 },\n { x: 0.8125, y: 0.3125 },\n { x: 0.8125, y: 0.3125 },\n { x: 0.8125, y: 0.3125 },\n { x: 0.8125, y: 0.3125 },\n { x: 0.8125, y: 0.3125 },\n { x: 0.9375, y: 0.3125 },\n { x: 0.9375, y: 0.3125 },\n { x: 0.9375, y: 0.3125 },\n { x: 0.9375, y: 0.3125 },\n { x: 0.9375, y: 0.3125 },\n { x: 0.9375, y: 0.3125 },\n { x: 0.0625, y: 0.4375 },\n { x: 0.0625, y: 0.4375 },\n { x: 0.0625, y: 0.4375 },\n { x: 0.0625, y: 0.4375 },\n { x: 0.0625, y: 0.4375 },\n { x: 0.0625, y: 0.4375 },\n { x: 0.1875, y: 0.4375 },\n { x: 0.1875, y: 0.4375 },\n { x: 0.1875, y: 0.4375 },\n { x: 0.1875, y: 0.4375 },\n { x: 0.1875, y: 0.4375 },\n { x: 0.1875, y: 0.4375 },\n { x: 0.3125, y: 0.4375 },\n { x: 0.3125, y: 0.4375 },\n { x: 0.3125, y: 0.4375 },\n { x: 0.3125, y: 0.4375 },\n { x: 0.3125, y: 0.4375 },\n { x: 0.3125, y: 0.4375 },\n { x: 0.4375, y: 0.4375 },\n { x: 0.4375, y: 0.4375 },\n { x: 0.4375, y: 0.4375 },\n { x: 0.4375, y: 0.4375 },\n { x: 0.4375, y: 0.4375 },\n { x: 0.4375, y: 0.4375 },\n { x: 0.5625, y: 0.4375 },\n { x: 0.5625, y: 0.4375 },\n { x: 0.5625, y: 0.4375 },\n { x: 0.5625, y: 0.4375 },\n { x: 0.5625, y: 0.4375 },\n { x: 0.5625, y: 0.4375 },\n { x: 0.6875, y: 0.4375 },\n { x: 0.6875, y: 0.4375 },\n { x: 0.6875, y: 0.4375 },\n { x: 0.6875, y: 0.4375 },\n { x: 0.6875, y: 0.4375 },\n { x: 0.6875, y: 0.4375 },\n { x: 0.8125, y: 0.4375 },\n { x: 0.8125, y: 0.4375 },\n { x: 0.8125, y: 0.4375 },\n { x: 0.8125, y: 0.4375 },\n { x: 0.8125, y: 0.4375 },\n { x: 0.8125, y: 0.4375 },\n { x: 0.9375, y: 0.4375 },\n { x: 0.9375, y: 0.4375 },\n { x: 0.9375, y: 0.4375 },\n { x: 0.9375, y: 0.4375 },\n { x: 0.9375, y: 0.4375 },\n { x: 0.9375, y: 0.4375 },\n { x: 0.0625, y: 0.5625 },\n { x: 0.0625, y: 0.5625 },\n { x: 0.0625, y: 0.5625 },\n { x: 0.0625, y: 0.5625 },\n { x: 0.0625, y: 0.5625 },\n { x: 0.0625, y: 0.5625 },\n { x: 0.1875, y: 0.5625 },\n { x: 0.1875, y: 0.5625 },\n { x: 0.1875, y: 0.5625 },\n { x: 0.1875, y: 0.5625 },\n { x: 0.1875, y: 0.5625 },\n { x: 0.1875, y: 0.5625 },\n { x: 0.3125, y: 0.5625 },\n { x: 0.3125, y: 0.5625 },\n { x: 0.3125, y: 0.5625 },\n { x: 0.3125, y: 0.5625 },\n { x: 0.3125, y: 0.5625 },\n { x: 0.3125, y: 0.5625 },\n { x: 0.4375, y: 0.5625 },\n { x: 0.4375, y: 0.5625 },\n { x: 0.4375, y: 0.5625 },\n { x: 0.4375, y: 0.5625 },\n { x: 0.4375, y: 0.5625 },\n { x: 0.4375, y: 0.5625 },\n { x: 0.5625, y: 0.5625 },\n { x: 0.5625, y: 0.5625 },\n { x: 0.5625, y: 0.5625 },\n { x: 0.5625, y: 0.5625 },\n { x: 0.5625, y: 0.5625 },\n { x: 0.5625, y: 0.5625 },\n { x: 0.6875, y: 0.5625 },\n { x: 0.6875, y: 0.5625 },\n { x: 0.6875, y: 0.5625 },\n { x: 0.6875, y: 0.5625 },\n { x: 0.6875, y: 0.5625 },\n { x: 0.6875, y: 0.5625 },\n { x: 0.8125, y: 0.5625 },\n { x: 0.8125, y: 0.5625 },\n { x: 0.8125, y: 0.5625 },\n { x: 0.8125, y: 0.5625 },\n { x: 0.8125, y: 0.5625 },\n { x: 0.8125, y: 0.5625 },\n { x: 0.9375, y: 0.5625 },\n { x: 0.9375, y: 0.5625 },\n { x: 0.9375, y: 0.5625 },\n { x: 0.9375, y: 0.5625 },\n { x: 0.9375, y: 0.5625 },\n { x: 0.9375, y: 0.5625 },\n { x: 0.0625, y: 0.6875 },\n { x: 0.0625, y: 0.6875 },\n { x: 0.0625, y: 0.6875 },\n { x: 0.0625, y: 0.6875 },\n { x: 0.0625, y: 0.6875 },\n { x: 0.0625, y: 0.6875 },\n { x: 0.1875, y: 0.6875 },\n { x: 0.1875, y: 0.6875 },\n { x: 0.1875, y: 0.6875 },\n { x: 0.1875, y: 0.6875 },\n { x: 0.1875, y: 0.6875 },\n { x: 0.1875, y: 0.6875 },\n { x: 0.3125, y: 0.6875 },\n { x: 0.3125, y: 0.6875 },\n { x: 0.3125, y: 0.6875 },\n { x: 0.3125, y: 0.6875 },\n { x: 0.3125, y: 0.6875 },\n { x: 0.3125, y: 0.6875 },\n { x: 0.4375, y: 0.6875 },\n { x: 0.4375, y: 0.6875 },\n { x: 0.4375, y: 0.6875 },\n { x: 0.4375, y: 0.6875 },\n { x: 0.4375, y: 0.6875 },\n { x: 0.4375, y: 0.6875 },\n { x: 0.5625, y: 0.6875 },\n { x: 0.5625, y: 0.6875 },\n { x: 0.5625, y: 0.6875 },\n { x: 0.5625, y: 0.6875 },\n { x: 0.5625, y: 0.6875 },\n { x: 0.5625, y: 0.6875 },\n { x: 0.6875, y: 0.6875 },\n { x: 0.6875, y: 0.6875 },\n { x: 0.6875, y: 0.6875 },\n { x: 0.6875, y: 0.6875 },\n { x: 0.6875, y: 0.6875 },\n { x: 0.6875, y: 0.6875 },\n { x: 0.8125, y: 0.6875 },\n { x: 0.8125, y: 0.6875 },\n { x: 0.8125, y: 0.6875 },\n { x: 0.8125, y: 0.6875 },\n { x: 0.8125, y: 0.6875 },\n { x: 0.8125, y: 0.6875 },\n { x: 0.9375, y: 0.6875 },\n { x: 0.9375, y: 0.6875 },\n { x: 0.9375, y: 0.6875 },\n { x: 0.9375, y: 0.6875 },\n { x: 0.9375, y: 0.6875 },\n { x: 0.9375, y: 0.6875 },\n { x: 0.0625, y: 0.8125 },\n { x: 0.0625, y: 0.8125 },\n { x: 0.0625, y: 0.8125 },\n { x: 0.0625, y: 0.8125 },\n { x: 0.0625, y: 0.8125 },\n { x: 0.0625, y: 0.8125 },\n { x: 0.1875, y: 0.8125 },\n { x: 0.1875, y: 0.8125 },\n { x: 0.1875, y: 0.8125 },\n { x: 0.1875, y: 0.8125 },\n { x: 0.1875, y: 0.8125 },\n { x: 0.1875, y: 0.8125 },\n { x: 0.3125, y: 0.8125 },\n { x: 0.3125, y: 0.8125 },\n { x: 0.3125, y: 0.8125 },\n { x: 0.3125, y: 0.8125 },\n { x: 0.3125, y: 0.8125 },\n { x: 0.3125, y: 0.8125 },\n { x: 0.4375, y: 0.8125 },\n { x: 0.4375, y: 0.8125 },\n { x: 0.4375, y: 0.8125 },\n { x: 0.4375, y: 0.8125 },\n { x: 0.4375, y: 0.8125 },\n { x: 0.4375, y: 0.8125 },\n { x: 0.5625, y: 0.8125 },\n { x: 0.5625, y: 0.8125 },\n { x: 0.5625, y: 0.8125 },\n { x: 0.5625, y: 0.8125 },\n { x: 0.5625, y: 0.8125 },\n { x: 0.5625, y: 0.8125 },\n { x: 0.6875, y: 0.8125 },\n { x: 0.6875, y: 0.8125 },\n { x: 0.6875, y: 0.8125 },\n { x: 0.6875, y: 0.8125 },\n { x: 0.6875, y: 0.8125 },\n { x: 0.6875, y: 0.8125 },\n { x: 0.8125, y: 0.8125 },\n { x: 0.8125, y: 0.8125 },\n { x: 0.8125, y: 0.8125 },\n { x: 0.8125, y: 0.8125 },\n { x: 0.8125, y: 0.8125 },\n { x: 0.8125, y: 0.8125 },\n { x: 0.9375, y: 0.8125 },\n { x: 0.9375, y: 0.8125 },\n { x: 0.9375, y: 0.8125 },\n { x: 0.9375, y: 0.8125 },\n { x: 0.9375, y: 0.8125 },\n { x: 0.9375, y: 0.8125 },\n { x: 0.0625, y: 0.9375 },\n { x: 0.0625, y: 0.9375 },\n { x: 0.0625, y: 0.9375 },\n { x: 0.0625, y: 0.9375 },\n { x: 0.0625, y: 0.9375 },\n { x: 0.0625, y: 0.9375 },\n { x: 0.1875, y: 0.9375 },\n { x: 0.1875, y: 0.9375 },\n { x: 0.1875, y: 0.9375 },\n { x: 0.1875, y: 0.9375 },\n { x: 0.1875, y: 0.9375 },\n { x: 0.1875, y: 0.9375 },\n { x: 0.3125, y: 0.9375 },\n { x: 0.3125, y: 0.9375 },\n { x: 0.3125, y: 0.9375 },\n { x: 0.3125, y: 0.9375 },\n { x: 0.3125, y: 0.9375 },\n { x: 0.3125, y: 0.9375 },\n { x: 0.4375, y: 0.9375 },\n { x: 0.4375, y: 0.9375 },\n { x: 0.4375, y: 0.9375 },\n { x: 0.4375, y: 0.9375 },\n { x: 0.4375, y: 0.9375 },\n { x: 0.4375, y: 0.9375 },\n { x: 0.5625, y: 0.9375 },\n { x: 0.5625, y: 0.9375 },\n { x: 0.5625, y: 0.9375 },\n { x: 0.5625, y: 0.9375 },\n { x: 0.5625, y: 0.9375 },\n { x: 0.5625, y: 0.9375 },\n { x: 0.6875, y: 0.9375 },\n { x: 0.6875, y: 0.9375 },\n { x: 0.6875, y: 0.9375 },\n { x: 0.6875, y: 0.9375 },\n { x: 0.6875, y: 0.9375 },\n { x: 0.6875, y: 0.9375 },\n { x: 0.8125, y: 0.9375 },\n { x: 0.8125, y: 0.9375 },\n { x: 0.8125, y: 0.9375 },\n { x: 0.8125, y: 0.9375 },\n { x: 0.8125, y: 0.9375 },\n { x: 0.8125, y: 0.9375 },\n { x: 0.9375, y: 0.9375 },\n { x: 0.9375, y: 0.9375 },\n { x: 0.9375, y: 0.9375 },\n { x: 0.9375, y: 0.9375 },\n { x: 0.9375, y: 0.9375 },\n { x: 0.9375, y: 0.9375 },\n];\n", "import * as tf from '../../dist/tfjs.esm.js';\nimport * as box from './box';\nimport * as anchors from './anchors';\nimport type { Tensor, GraphModel } from '../tfjs/types';\n\nexport class HandDetector {\n model: GraphModel;\n anchors: number[][];\n anchorsTensor: Tensor;\n inputSize: number;\n inputSizeTensor: Tensor;\n doubleInputSizeTensor: Tensor;\n\n constructor(model) {\n this.model = model;\n this.anchors = anchors.anchors.map((anchor) => [anchor.x, anchor.y]);\n this.anchorsTensor = tf.tensor2d(this.anchors);\n this.inputSize = (this.model && this.model.inputs && this.model.inputs[0].shape) ? this.model.inputs[0].shape[2] : 0;\n this.inputSizeTensor = tf.tensor1d([this.inputSize, this.inputSize]);\n this.doubleInputSizeTensor = tf.tensor1d([this.inputSize * 2, this.inputSize * 2]);\n }\n\n normalizeBoxes(boxes) {\n return tf.tidy(() => {\n const boxOffsets = tf.slice(boxes, [0, 0], [-1, 2]);\n const boxSizes = tf.slice(boxes, [0, 2], [-1, 2]);\n const boxCenterPoints = tf.add(tf.div(boxOffsets, this.inputSizeTensor), this.anchorsTensor);\n const halfBoxSizes = tf.div(boxSizes, this.doubleInputSizeTensor);\n const startPoints = tf.mul(tf.sub(boxCenterPoints, halfBoxSizes), this.inputSizeTensor);\n const endPoints = tf.mul(tf.add(boxCenterPoints, halfBoxSizes), this.inputSizeTensor);\n return tf.concat2d([startPoints, endPoints], 1);\n });\n }\n\n normalizeLandmarks(rawPalmLandmarks, index) {\n return tf.tidy(() => {\n const landmarks = tf.add(tf.div(tf.reshape(rawPalmLandmarks, [-1, 7, 2]), this.inputSizeTensor), this.anchors[index]);\n return tf.mul(landmarks, this.inputSizeTensor);\n });\n }\n\n async getBoxes(input, config) {\n const t: Record = {};\n t.batched = this.model.predict(input) as Tensor;\n t.predictions = tf.squeeze(t.batched);\n t.scores = tf.tidy(() => tf.squeeze(tf.sigmoid(tf.slice(t.predictions, [0, 0], [-1, 1]))));\n const scores = await t.scores.data();\n t.boxes = tf.slice(t.predictions, [0, 1], [-1, 4]);\n t.norm = this.normalizeBoxes(t.boxes);\n // box detection is flaky so we look for 3x boxes than we need results\n t.nms = await tf.image.nonMaxSuppressionAsync(t.norm, t.scores, 3 * config.hand.maxDetected, config.hand.iouThreshold, config.hand.minConfidence);\n const nms = await t.nms.array() as Array;\n const hands: Array<{ box: Tensor, palmLandmarks: Tensor, confidence: number }> = [];\n for (const index of nms) {\n const palmBox = tf.slice(t.norm, [index, 0], [1, -1]);\n const palmLandmarks = tf.tidy(() => tf.reshape(this.normalizeLandmarks(tf.slice(t.predictions, [index, 5], [1, 14]), index), [-1, 2]));\n hands.push({ box: palmBox, palmLandmarks, confidence: scores[index] });\n // console.log('handdetector:getBoxes', nms.length, index, scores[index], config.hand.maxDetected, config.hand.iouThreshold, config.hand.minConfidence, palmBox.dataSync());\n }\n for (const tensor of Object.keys(t)) tf.dispose(t[tensor]); // dispose all\n return hands;\n }\n\n async estimateHandBounds(input, config): Promise<{ startPoint: number[]; endPoint: number[]; palmLandmarks: number[]; confidence: number }[]> {\n const inputHeight = input.shape[1];\n const inputWidth = input.shape[2];\n const image = tf.tidy(() => tf.sub(tf.div(tf.image.resizeBilinear(input, [this.inputSize, this.inputSize]), 127.5), 1));\n const predictions = await this.getBoxes(image, config);\n tf.dispose(image);\n const hands: Array<{ startPoint: number[]; endPoint: number[]; palmLandmarks: number[]; confidence: number }> = [];\n if (!predictions || predictions.length === 0) return hands;\n for (const prediction of predictions) {\n const boxes = await prediction.box.data();\n const startPoint = boxes.slice(0, 2);\n const endPoint = boxes.slice(2, 4);\n const palmLandmarks = await prediction.palmLandmarks.array();\n tf.dispose(prediction.box);\n tf.dispose(prediction.palmLandmarks);\n hands.push(box.scaleBoxCoordinates({ startPoint, endPoint, palmLandmarks, confidence: prediction.confidence }, [inputWidth / this.inputSize, inputHeight / this.inputSize]));\n }\n return hands;\n }\n}\n", "export function normalizeRadians(angle) {\n return angle - 2 * Math.PI * Math.floor((angle + Math.PI) / (2 * Math.PI));\n}\n\nexport function computeRotation(point1, point2) {\n const radians = Math.PI / 2 - Math.atan2(-(point2[1] - point1[1]), point2[0] - point1[0]);\n return normalizeRadians(radians);\n}\n\nexport const buildTranslationMatrix = (x, y) => [[1, 0, x], [0, 1, y], [0, 0, 1]];\n\nexport function dot(v1, v2) {\n let product = 0;\n for (let i = 0; i < v1.length; i++) {\n product += v1[i] * v2[i];\n }\n return product;\n}\n\nexport function getColumnFrom2DArr(arr, columnIndex) {\n const column: Array = [];\n for (let i = 0; i < arr.length; i++) {\n column.push(arr[i][columnIndex]);\n }\n return column;\n}\n\nexport function multiplyTransformMatrices(mat1, mat2) {\n const product: Array = [];\n const size = mat1.length;\n for (let row = 0; row < size; row++) {\n product.push([]);\n for (let col = 0; col < size; col++) {\n product[row].push(dot(mat1[row], getColumnFrom2DArr(mat2, col)));\n }\n }\n return product;\n}\n\nexport function buildRotationMatrix(rotation, center) {\n const cosA = Math.cos(rotation);\n const sinA = Math.sin(rotation);\n const rotationMatrix = [[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]];\n const translationMatrix = buildTranslationMatrix(center[0], center[1]);\n const translationTimesRotation = multiplyTransformMatrices(translationMatrix, rotationMatrix);\n const negativeTranslationMatrix = buildTranslationMatrix(-center[0], -center[1]);\n return multiplyTransformMatrices(translationTimesRotation, negativeTranslationMatrix);\n}\n\nexport function invertTransformMatrix(matrix) {\n const rotationComponent = [[matrix[0][0], matrix[1][0]], [matrix[0][1], matrix[1][1]]];\n const translationComponent = [matrix[0][2], matrix[1][2]];\n const invertedTranslation = [\n -dot(rotationComponent[0], translationComponent),\n -dot(rotationComponent[1], translationComponent),\n ];\n return [\n rotationComponent[0].concat(invertedTranslation[0]),\n rotationComponent[1].concat(invertedTranslation[1]),\n [0, 0, 1],\n ];\n}\n\nexport function rotatePoint(homogeneousCoordinate, rotationMatrix) {\n return [\n dot(homogeneousCoordinate, rotationMatrix[0]),\n dot(homogeneousCoordinate, rotationMatrix[1]),\n ];\n}\n", "import * as tf from '../../dist/tfjs.esm.js';\nimport * as box from './box';\nimport * as util from './util';\nimport type * as detector from './handdetector';\nimport type { Tensor, GraphModel } from '../tfjs/types';\nimport { env } from '../env';\n\nconst palmBoxEnlargeFactor = 5; // default 3\nconst handBoxEnlargeFactor = 1.65; // default 1.65\nconst palmLandmarkIds = [0, 5, 9, 13, 17, 1, 2];\nconst palmLandmarksPalmBase = 0;\nconst palmLandmarksMiddleFingerBase = 2;\n\nexport class HandPipeline {\n handDetector: detector.HandDetector;\n handPoseModel: GraphModel;\n inputSize: number;\n storedBoxes: Array<{ startPoint: number[]; endPoint: number[]; palmLandmarks: number[]; confidence: number } | null>;\n skipped: number;\n detectedHands: number;\n\n constructor(handDetector, handPoseModel) {\n this.handDetector = handDetector;\n this.handPoseModel = handPoseModel;\n this.inputSize = this.handPoseModel && this.handPoseModel.inputs[0].shape ? this.handPoseModel.inputs[0].shape[2] : 0;\n this.storedBoxes = [];\n this.skipped = 0;\n this.detectedHands = 0;\n }\n\n // eslint-disable-next-line class-methods-use-this\n calculateLandmarksBoundingBox(landmarks) {\n const xs = landmarks.map((d) => d[0]);\n const ys = landmarks.map((d) => d[1]);\n const startPoint = [Math.min(...xs), Math.min(...ys)];\n const endPoint = [Math.max(...xs), Math.max(...ys)];\n return { startPoint, endPoint };\n }\n\n getBoxForPalmLandmarks(palmLandmarks, rotationMatrix) {\n const rotatedPalmLandmarks = palmLandmarks.map((coord) => util.rotatePoint([...coord, 1], rotationMatrix));\n const boxAroundPalm = this.calculateLandmarksBoundingBox(rotatedPalmLandmarks);\n return box.enlargeBox(box.squarifyBox(boxAroundPalm), palmBoxEnlargeFactor);\n }\n\n getBoxForHandLandmarks(landmarks) {\n const boundingBox = this.calculateLandmarksBoundingBox(landmarks);\n const boxAroundHand = box.enlargeBox(box.squarifyBox(boundingBox), handBoxEnlargeFactor);\n boxAroundHand.palmLandmarks = [];\n for (let i = 0; i < palmLandmarkIds.length; i++) {\n boxAroundHand.palmLandmarks.push(landmarks[palmLandmarkIds[i]].slice(0, 2));\n }\n return boxAroundHand;\n }\n\n transformRawCoords(rawCoords, box2, angle, rotationMatrix) {\n const boxSize = box.getBoxSize(box2);\n const scaleFactor = [boxSize[0] / this.inputSize, boxSize[1] / this.inputSize, (boxSize[0] + boxSize[1]) / this.inputSize / 2];\n const coordsScaled = rawCoords.map((coord) => [\n scaleFactor[0] * (coord[0] - this.inputSize / 2),\n scaleFactor[1] * (coord[1] - this.inputSize / 2),\n scaleFactor[2] * coord[2],\n ]);\n const coordsRotationMatrix = util.buildRotationMatrix(angle, [0, 0]);\n const coordsRotated = coordsScaled.map((coord) => {\n const rotated = util.rotatePoint(coord, coordsRotationMatrix);\n return [...rotated, coord[2]];\n });\n const inverseRotationMatrix = util.invertTransformMatrix(rotationMatrix);\n const boxCenter = [...box.getBoxCenter(box2), 1];\n const originalBoxCenter = [\n util.dot(boxCenter, inverseRotationMatrix[0]),\n util.dot(boxCenter, inverseRotationMatrix[1]),\n ];\n return coordsRotated.map((coord) => [\n Math.trunc(coord[0] + originalBoxCenter[0]),\n Math.trunc(coord[1] + originalBoxCenter[1]),\n Math.trunc(coord[2]),\n ]);\n }\n\n async estimateHands(image, config) {\n let useFreshBox = false;\n\n // run new detector every skipFrames unless we only want box to start with\n let boxes;\n\n // console.log('handpipeline:estimateHands:skip criteria', this.skipped, config.hand.skipFrames, !config.hand.landmarks, !config.skipFrame); // should skip hand detector?\n if ((this.skipped === 0) || (this.skipped > config.hand.skipFrames) || !config.hand.landmarks || !config.skipFrame) {\n boxes = await this.handDetector.estimateHandBounds(image, config);\n this.skipped = 0;\n }\n if (config.skipFrame) this.skipped++;\n\n // if detector result count doesn't match current working set, use it to reset current working set\n if (boxes && (boxes.length > 0) && ((boxes.length !== this.detectedHands) && (this.detectedHands !== config.hand.maxDetected) || !config.hand.landmarks)) {\n this.detectedHands = 0;\n this.storedBoxes = [...boxes];\n // for (const possible of boxes) this.storedBoxes.push(possible);\n if (this.storedBoxes.length > 0) useFreshBox = true;\n }\n const hands: Array<{ landmarks: number[], confidence: number, boxConfidence: number, fingerConfidence: number, box: { topLeft: number[], bottomRight: number[] } }> = [];\n\n // go through working set of boxes\n for (let i = 0; i < this.storedBoxes.length; i++) {\n const currentBox = this.storedBoxes[i];\n if (!currentBox) continue;\n if (config.hand.landmarks) {\n const angle = config.hand.rotation ? util.computeRotation(currentBox.palmLandmarks[palmLandmarksPalmBase], currentBox.palmLandmarks[palmLandmarksMiddleFingerBase]) : 0;\n const palmCenter = box.getBoxCenter(currentBox);\n const palmCenterNormalized = [palmCenter[0] / image.shape[2], palmCenter[1] / image.shape[1]];\n const rotatedImage = config.hand.rotation && env.kernels.includes('rotatewithoffset') ? tf.image.rotateWithOffset(image, angle, 0, palmCenterNormalized) : image.clone();\n const rotationMatrix = util.buildRotationMatrix(-angle, palmCenter);\n const newBox = useFreshBox ? this.getBoxForPalmLandmarks(currentBox.palmLandmarks, rotationMatrix) : currentBox;\n const croppedInput = box.cutBoxFromImageAndResize(newBox, rotatedImage, [this.inputSize, this.inputSize]);\n const handImage = tf.div(croppedInput, 255);\n tf.dispose(croppedInput);\n tf.dispose(rotatedImage);\n const [confidenceT, keypoints] = await this.handPoseModel.predict(handImage) as Array;\n tf.dispose(handImage);\n const confidence = (await confidenceT.data())[0];\n tf.dispose(confidenceT);\n if (confidence >= config.hand.minConfidence / 4) {\n const keypointsReshaped = tf.reshape(keypoints, [-1, 3]);\n const rawCoords = await keypointsReshaped.array();\n tf.dispose(keypoints);\n tf.dispose(keypointsReshaped);\n const coords = this.transformRawCoords(rawCoords, newBox, angle, rotationMatrix);\n const nextBoundingBox = this.getBoxForHandLandmarks(coords);\n this.storedBoxes[i] = { ...nextBoundingBox, confidence };\n const result = {\n landmarks: coords,\n confidence,\n boxConfidence: currentBox.confidence,\n fingerConfidence: confidence,\n box: { topLeft: nextBoundingBox.startPoint, bottomRight: nextBoundingBox.endPoint },\n };\n hands.push(result);\n } else {\n // console.log('handpipeline:estimateHands low', confidence);\n this.storedBoxes[i] = null;\n }\n tf.dispose(keypoints);\n } else {\n // const enlarged = box.enlargeBox(box.squarifyBox(box.shiftBox(currentBox, HAND_BOX_SHIFT_VECTOR)), handBoxEnlargeFactor);\n const enlarged = box.enlargeBox(box.squarifyBox(currentBox), handBoxEnlargeFactor);\n const result = {\n confidence: currentBox.confidence,\n boxConfidence: currentBox.confidence,\n fingerConfidence: 0,\n box: { topLeft: enlarged.startPoint, bottomRight: enlarged.endPoint },\n landmarks: [],\n };\n hands.push(result);\n }\n }\n this.storedBoxes = this.storedBoxes.filter((a) => a !== null);\n this.detectedHands = hands.length;\n if (hands.length > config.hand.maxDetected) hands.length = config.hand.maxDetected;\n return hands;\n }\n}\n", "const Finger = {\n thumb: 0,\n index: 1,\n middle: 2,\n ring: 3,\n pinky: 4,\n all: [0, 1, 2, 3, 4], // just for convenience\n nameMapping: { 0: 'thumb', 1: 'index', 2: 'middle', 3: 'ring', 4: 'pinky' },\n // Describes mapping of joints based on the 21 points returned by handpose.\n // [0] Palm\n // [1-4] Thumb\n // [5-8] Index\n // [9-12] Middle\n // [13-16] Ring\n // [17-20] Pinky\n pointsMapping: {\n 0: [[0, 1], [1, 2], [2, 3], [3, 4]],\n 1: [[0, 5], [5, 6], [6, 7], [7, 8]],\n 2: [[0, 9], [9, 10], [10, 11], [11, 12]],\n 3: [[0, 13], [13, 14], [14, 15], [15, 16]],\n 4: [[0, 17], [17, 18], [18, 19], [19, 20]],\n },\n getName: (value) => Finger.nameMapping[value],\n getPoints: (value) => Finger.pointsMapping[value],\n};\n\nconst FingerCurl = {\n none: 0,\n half: 1,\n full: 2,\n nameMapping: { 0: 'none', 1: 'half', 2: 'full' },\n getName: (value) => FingerCurl.nameMapping[value],\n};\n\nconst FingerDirection = {\n verticalUp: 0,\n verticalDown: 1,\n horizontalLeft: 2,\n horizontalRight: 3,\n diagonalUpRight: 4,\n diagonalUpLeft: 5,\n diagonalDownRight: 6,\n diagonalDownLeft: 7,\n nameMapping: { 0: 'verticalUp', 1: 'verticalDown', 2: 'horizontalLeft', 3: 'horizontalRight', 4: 'diagonalUpRight', 5: 'diagonalUpLeft', 6: 'diagonalDownRight', 7: 'diagonalDownLeft' },\n getName: (value) => FingerDirection.nameMapping[value],\n};\n\nexport { Finger, FingerCurl, FingerDirection };\n", "import { Finger, FingerCurl, FingerDirection } from './description';\n\nconst options = {\n // curl estimation\n HALF_CURL_START_LIMIT: 60.0,\n NO_CURL_START_LIMIT: 130.0,\n // direction estimation\n DISTANCE_VOTE_POWER: 1.1,\n SINGLE_ANGLE_VOTE_POWER: 0.9,\n TOTAL_ANGLE_VOTE_POWER: 1.6,\n};\n\nfunction calculateSlope(point1x, point1y, point2x, point2y) {\n const value = (point1y - point2y) / (point1x - point2x);\n let slope = Math.atan(value) * 180 / Math.PI;\n if (slope <= 0) slope = -slope;\n else if (slope > 0) slope = 180 - slope;\n return slope;\n}\n\n// point1, point2 are 2d or 3d point arrays (xy[z])\n// returns either a single scalar (2d) or array of two slopes (3d)\nfunction getSlopes(point1, point2) {\n if (!point1 || !point2) return [0, 0];\n const slopeXY = calculateSlope(point1[0], point1[1], point2[0], point2[1]);\n if (point1.length === 2) return slopeXY;\n const slopeYZ = calculateSlope(point1[1], point1[2], point2[1], point2[2]);\n return [slopeXY, slopeYZ];\n}\n\nfunction angleOrientationAt(angle, weightageAt = 1.0) {\n let isVertical = 0;\n let isDiagonal = 0;\n let isHorizontal = 0;\n if (angle >= 75.0 && angle <= 105.0) isVertical = 1 * weightageAt;\n else if (angle >= 25.0 && angle <= 155.0) isDiagonal = 1 * weightageAt;\n else isHorizontal = 1 * weightageAt;\n return [isVertical, isDiagonal, isHorizontal];\n}\n\nfunction estimateFingerCurl(startPoint, midPoint, endPoint) {\n const start_mid_x_dist = startPoint[0] - midPoint[0];\n const start_end_x_dist = startPoint[0] - endPoint[0];\n const mid_end_x_dist = midPoint[0] - endPoint[0];\n const start_mid_y_dist = startPoint[1] - midPoint[1];\n const start_end_y_dist = startPoint[1] - endPoint[1];\n const mid_end_y_dist = midPoint[1] - endPoint[1];\n const start_mid_z_dist = startPoint[2] - midPoint[2];\n const start_end_z_dist = startPoint[2] - endPoint[2];\n const mid_end_z_dist = midPoint[2] - endPoint[2];\n const start_mid_dist = Math.sqrt(start_mid_x_dist * start_mid_x_dist + start_mid_y_dist * start_mid_y_dist + start_mid_z_dist * start_mid_z_dist);\n const start_end_dist = Math.sqrt(start_end_x_dist * start_end_x_dist + start_end_y_dist * start_end_y_dist + start_end_z_dist * start_end_z_dist);\n const mid_end_dist = Math.sqrt(mid_end_x_dist * mid_end_x_dist + mid_end_y_dist * mid_end_y_dist + mid_end_z_dist * mid_end_z_dist);\n let cos_in = (mid_end_dist * mid_end_dist + start_mid_dist * start_mid_dist - start_end_dist * start_end_dist) / (2 * mid_end_dist * start_mid_dist);\n if (cos_in > 1.0) cos_in = 1.0;\n else if (cos_in < -1.0) cos_in = -1.0;\n let angleOfCurve = Math.acos(cos_in);\n angleOfCurve = (57.2958 * angleOfCurve) % 180;\n let fingerCurl;\n if (angleOfCurve > options.NO_CURL_START_LIMIT) fingerCurl = FingerCurl.none;\n else if (angleOfCurve > options.HALF_CURL_START_LIMIT) fingerCurl = FingerCurl.half;\n else fingerCurl = FingerCurl.full;\n return fingerCurl;\n}\n\nfunction estimateHorizontalDirection(start_end_x_dist, start_mid_x_dist, mid_end_x_dist, max_dist_x) {\n let estimatedDirection;\n if (max_dist_x === Math.abs(start_end_x_dist)) {\n if (start_end_x_dist > 0) estimatedDirection = FingerDirection.horizontalLeft;\n else estimatedDirection = FingerDirection.horizontalRight;\n } else if (max_dist_x === Math.abs(start_mid_x_dist)) {\n if (start_mid_x_dist > 0) estimatedDirection = FingerDirection.horizontalLeft;\n else estimatedDirection = FingerDirection.horizontalRight;\n } else {\n if (mid_end_x_dist > 0) estimatedDirection = FingerDirection.horizontalLeft;\n else estimatedDirection = FingerDirection.horizontalRight;\n }\n return estimatedDirection;\n}\n\nfunction estimateVerticalDirection(start_end_y_dist, start_mid_y_dist, mid_end_y_dist, max_dist_y) {\n let estimatedDirection;\n if (max_dist_y === Math.abs(start_end_y_dist)) {\n if (start_end_y_dist < 0) estimatedDirection = FingerDirection.verticalDown;\n else estimatedDirection = FingerDirection.verticalUp;\n } else if (max_dist_y === Math.abs(start_mid_y_dist)) {\n if (start_mid_y_dist < 0) estimatedDirection = FingerDirection.verticalDown;\n else estimatedDirection = FingerDirection.verticalUp;\n } else {\n if (mid_end_y_dist < 0) estimatedDirection = FingerDirection.verticalDown;\n else estimatedDirection = FingerDirection.verticalUp;\n }\n return estimatedDirection;\n}\n\nfunction estimateDiagonalDirection(start_end_y_dist, start_mid_y_dist, mid_end_y_dist, max_dist_y, start_end_x_dist, start_mid_x_dist, mid_end_x_dist, max_dist_x) {\n let estimatedDirection;\n const reqd_vertical_direction = estimateVerticalDirection(start_end_y_dist, start_mid_y_dist, mid_end_y_dist, max_dist_y);\n const reqd_horizontal_direction = estimateHorizontalDirection(start_end_x_dist, start_mid_x_dist, mid_end_x_dist, max_dist_x);\n if (reqd_vertical_direction === FingerDirection.verticalUp) {\n if (reqd_horizontal_direction === FingerDirection.horizontalLeft) estimatedDirection = FingerDirection.diagonalUpLeft;\n else estimatedDirection = FingerDirection.diagonalUpRight;\n } else {\n if (reqd_horizontal_direction === FingerDirection.horizontalLeft) estimatedDirection = FingerDirection.diagonalDownLeft;\n else estimatedDirection = FingerDirection.diagonalDownRight;\n }\n return estimatedDirection;\n}\n\nfunction calculateFingerDirection(startPoint, midPoint, endPoint, fingerSlopes) {\n const start_mid_x_dist = startPoint[0] - midPoint[0];\n const start_end_x_dist = startPoint[0] - endPoint[0];\n const mid_end_x_dist = midPoint[0] - endPoint[0];\n const start_mid_y_dist = startPoint[1] - midPoint[1];\n const start_end_y_dist = startPoint[1] - endPoint[1];\n const mid_end_y_dist = midPoint[1] - endPoint[1];\n const max_dist_x = Math.max(Math.abs(start_mid_x_dist), Math.abs(start_end_x_dist), Math.abs(mid_end_x_dist));\n const max_dist_y = Math.max(Math.abs(start_mid_y_dist), Math.abs(start_end_y_dist), Math.abs(mid_end_y_dist));\n let voteVertical = 0.0;\n let voteDiagonal = 0.0;\n let voteHorizontal = 0.0;\n const start_end_x_y_dist_ratio = max_dist_y / (max_dist_x + 0.00001);\n if (start_end_x_y_dist_ratio > 1.5) voteVertical += options.DISTANCE_VOTE_POWER;\n else if (start_end_x_y_dist_ratio > 0.66) voteDiagonal += options.DISTANCE_VOTE_POWER;\n else voteHorizontal += options.DISTANCE_VOTE_POWER;\n const start_mid_dist = Math.sqrt(start_mid_x_dist * start_mid_x_dist + start_mid_y_dist * start_mid_y_dist);\n const start_end_dist = Math.sqrt(start_end_x_dist * start_end_x_dist + start_end_y_dist * start_end_y_dist);\n const mid_end_dist = Math.sqrt(mid_end_x_dist * mid_end_x_dist + mid_end_y_dist * mid_end_y_dist);\n const max_dist = Math.max(start_mid_dist, start_end_dist, mid_end_dist);\n let calc_start_point_x = startPoint[0];\n let calc_start_point_y = startPoint[1];\n let calc_end_point_x = endPoint[0];\n let calc_end_point_y = endPoint[1];\n if (max_dist === start_mid_dist) {\n calc_end_point_x = endPoint[0];\n calc_end_point_y = endPoint[1];\n } else if (max_dist === mid_end_dist) {\n calc_start_point_x = midPoint[0];\n calc_start_point_y = midPoint[1];\n }\n const calcStartPoint = [calc_start_point_x, calc_start_point_y];\n const calcEndPoint = [calc_end_point_x, calc_end_point_y];\n const totalAngle = getSlopes(calcStartPoint, calcEndPoint);\n const votes = angleOrientationAt(totalAngle, options.TOTAL_ANGLE_VOTE_POWER);\n voteVertical += votes[0];\n voteDiagonal += votes[1];\n voteHorizontal += votes[2];\n for (const fingerSlope of fingerSlopes) {\n const fingerVotes = angleOrientationAt(fingerSlope, options.SINGLE_ANGLE_VOTE_POWER);\n voteVertical += fingerVotes[0];\n voteDiagonal += fingerVotes[1];\n voteHorizontal += fingerVotes[2];\n }\n // in case of tie, highest preference goes to Vertical,\n // followed by horizontal and then diagonal\n let estimatedDirection;\n if (voteVertical === Math.max(voteVertical, voteDiagonal, voteHorizontal)) {\n estimatedDirection = estimateVerticalDirection(start_end_y_dist, start_mid_y_dist, mid_end_y_dist, max_dist_y);\n } else if (voteHorizontal === Math.max(voteDiagonal, voteHorizontal)) {\n estimatedDirection = estimateHorizontalDirection(start_end_x_dist, start_mid_x_dist, mid_end_x_dist, max_dist_x);\n } else {\n estimatedDirection = estimateDiagonalDirection(start_end_y_dist, start_mid_y_dist, mid_end_y_dist, max_dist_y, start_end_x_dist, start_mid_x_dist, mid_end_x_dist, max_dist_x);\n }\n return estimatedDirection;\n}\n\nexport function estimate(landmarks) {\n // step 1: calculate slopes\n const slopesXY: Array = [];\n const slopesYZ: Array = [];\n const fingerCurls: Array = [];\n const fingerDirections: Array = [];\n if (!landmarks) return { curls: fingerCurls, directions: fingerDirections };\n\n // step 1: calculate slopes\n for (const finger of Finger.all) {\n const points = Finger.getPoints(finger);\n const slopeAtXY: Array = [];\n const slopeAtYZ: Array = [];\n for (const point of points) {\n const point1 = landmarks[point[0]];\n const point2 = landmarks[point[1]];\n // calculate single slope\n const slopes = getSlopes(point1, point2);\n const slopeXY = slopes[0];\n const slopeYZ = slopes[1];\n slopeAtXY.push(slopeXY);\n slopeAtYZ.push(slopeYZ);\n }\n slopesXY.push(slopeAtXY);\n slopesYZ.push(slopeAtYZ);\n }\n\n // step 2: calculate orientations\n for (const finger of Finger.all) {\n // start finger predictions from palm - except for thumb\n const pointIndexAt = (finger === Finger.thumb) ? 1 : 0;\n const fingerPointsAt = Finger.getPoints(finger);\n const startPoint = landmarks[fingerPointsAt[pointIndexAt][0]];\n const midPoint = landmarks[fingerPointsAt[pointIndexAt + 1][1]];\n const endPoint = landmarks[fingerPointsAt[3][1]];\n // check if finger is curled\n const fingerCurled = estimateFingerCurl(startPoint, midPoint, endPoint);\n const fingerPosition = calculateFingerDirection(startPoint, midPoint, endPoint, slopesXY[finger].slice(pointIndexAt));\n fingerCurls[finger] = fingerCurled;\n fingerDirections[finger] = fingerPosition;\n }\n return { curls: fingerCurls, directions: fingerDirections };\n}\n", "export default class Gesture {\n name;\n curls;\n directions;\n weights;\n weightsRelative;\n\n constructor(name) {\n // name (should be unique)\n this.name = name;\n this.curls = {};\n this.directions = {};\n this.weights = [1.0, 1.0, 1.0, 1.0, 1.0];\n this.weightsRelative = [1.0, 1.0, 1.0, 1.0, 1.0];\n }\n\n addCurl(finger, curl, confidence) {\n if (typeof this.curls[finger] === 'undefined') this.curls[finger] = [];\n this.curls[finger].push([curl, confidence]);\n }\n\n addDirection(finger, position, confidence) {\n if (!this.directions[finger]) this.directions[finger] = [];\n this.directions[finger].push([position, confidence]);\n }\n\n setWeight(finger, weight) {\n this.weights[finger] = weight;\n // recalculate relative weights\n const total = this.weights.reduce((a, b) => a + b, 0);\n this.weightsRelative = this.weights.map((el) => el * 5 / total);\n }\n\n matchAgainst(detectedCurls, detectedDirections) {\n let confidence = 0.0;\n // look at the detected curl of each finger and compare with\n // the expected curl of this finger inside current gesture\n for (const fingerIdx in detectedCurls) {\n const detectedCurl = detectedCurls[fingerIdx];\n const expectedCurls = this.curls[fingerIdx];\n if (typeof expectedCurls === 'undefined') {\n // no curl description available for this finger\n // add default confidence of \"1\"\n confidence += this.weightsRelative[fingerIdx];\n continue;\n }\n // compare to each possible curl of this specific finger\n for (const [expectedCurl, score] of expectedCurls) {\n if (detectedCurl === expectedCurl) {\n confidence += score * this.weightsRelative[fingerIdx];\n break;\n }\n }\n }\n // same for detected direction of each finger\n for (const fingerIdx in detectedDirections) {\n const detectedDirection = detectedDirections[fingerIdx];\n const expectedDirections = this.directions[fingerIdx];\n if (typeof expectedDirections === 'undefined') {\n // no direction description available for this finger\n // add default confidence of \"1\"\n confidence += this.weightsRelative[fingerIdx];\n continue;\n }\n // compare to each possible direction of this specific finger\n for (const [expectedDirection, score] of expectedDirections) {\n if (detectedDirection === expectedDirection) {\n confidence += score * this.weightsRelative[fingerIdx];\n break;\n }\n }\n }\n return confidence / 10;\n }\n}\n", "import { Finger, FingerCurl, FingerDirection } from './description';\nimport Gesture from './gesture';\n\n// describe thumbs up gesture \uD83D\uDC4D\nconst ThumbsUp = new Gesture('thumbs up');\nThumbsUp.addCurl(Finger.thumb, FingerCurl.none, 1.0);\nThumbsUp.addDirection(Finger.thumb, FingerDirection.verticalUp, 1.0);\nThumbsUp.addDirection(Finger.thumb, FingerDirection.diagonalUpLeft, 0.25);\nThumbsUp.addDirection(Finger.thumb, FingerDirection.diagonalUpRight, 0.25);\nfor (const finger of [Finger.index, Finger.middle, Finger.ring, Finger.pinky]) {\n ThumbsUp.addCurl(finger, FingerCurl.full, 1.0);\n ThumbsUp.addDirection(finger, FingerDirection.horizontalLeft, 1.0);\n ThumbsUp.addDirection(finger, FingerDirection.horizontalRight, 1.0);\n}\n\n// describe Victory gesture \u270C\uFE0F\nconst Victory = new Gesture('victory');\nVictory.addCurl(Finger.thumb, FingerCurl.half, 0.5);\nVictory.addCurl(Finger.thumb, FingerCurl.none, 0.5);\nVictory.addDirection(Finger.thumb, FingerDirection.verticalUp, 1.0);\nVictory.addDirection(Finger.thumb, FingerDirection.diagonalUpLeft, 1.0);\nVictory.addCurl(Finger.index, FingerCurl.none, 1.0);\nVictory.addDirection(Finger.index, FingerDirection.verticalUp, 0.75);\nVictory.addDirection(Finger.index, FingerDirection.diagonalUpLeft, 1.0);\nVictory.addCurl(Finger.middle, FingerCurl.none, 1.0);\nVictory.addDirection(Finger.middle, FingerDirection.verticalUp, 1.0);\nVictory.addDirection(Finger.middle, FingerDirection.diagonalUpLeft, 0.75);\nVictory.addCurl(Finger.ring, FingerCurl.full, 1.0);\nVictory.addDirection(Finger.ring, FingerDirection.verticalUp, 0.2);\nVictory.addDirection(Finger.ring, FingerDirection.diagonalUpLeft, 1.0);\nVictory.addDirection(Finger.ring, FingerDirection.horizontalLeft, 0.2);\nVictory.addCurl(Finger.pinky, FingerCurl.full, 1.0);\nVictory.addDirection(Finger.pinky, FingerDirection.verticalUp, 0.2);\nVictory.addDirection(Finger.pinky, FingerDirection.diagonalUpLeft, 1.0);\nVictory.addDirection(Finger.pinky, FingerDirection.horizontalLeft, 0.2);\nVictory.setWeight(Finger.index, 2);\nVictory.setWeight(Finger.middle, 2);\n\nexport default [ThumbsUp, Victory];\n", "// based on \n\nimport * as estimator from './estimator';\nimport { Finger, FingerCurl, FingerDirection } from './description';\nimport Gestures from './gestures';\n\nconst minConfidence = 0.7;\n\nexport function analyze(keypoints) { // get estimations of curl / direction for each finger\n if (!keypoints || keypoints.length === 0) return null;\n const estimatorRes = estimator.estimate(keypoints);\n const landmarks = {};\n for (const fingerIdx of Finger.all) {\n landmarks[Finger.getName(fingerIdx)] = {\n curl: FingerCurl.getName(estimatorRes.curls[fingerIdx]),\n direction: FingerDirection.getName(estimatorRes.directions[fingerIdx]),\n };\n }\n // console.log('finger landmarks', landmarks);\n return landmarks;\n}\n\nexport function match(keypoints) { // compare gesture description to each known gesture\n const poses: Array<{ name: string, confidence: number }> = [];\n if (!keypoints || keypoints.length === 0) return poses;\n const estimatorRes = estimator.estimate(keypoints);\n for (const gesture of Gestures) {\n const confidence = gesture.matchAgainst(estimatorRes.curls, estimatorRes.directions);\n if (confidence >= minConfidence) poses.push({ name: gesture.name, confidence });\n }\n // console.log('finger poses', poses);\n return poses;\n}\n", "/**\n * HandPose module entry point\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as handdetector from './handdetector';\nimport * as handpipeline from './handpipeline';\nimport * as fingerPose from '../fingerpose/fingerpose';\nimport type { HandResult } from '../result';\nimport type { Tensor, GraphModel } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nconst meshAnnotations = {\n thumb: [1, 2, 3, 4],\n index: [5, 6, 7, 8],\n middle: [9, 10, 11, 12],\n ring: [13, 14, 15, 16],\n pinky: [17, 18, 19, 20],\n palm: [0],\n};\n\nlet handDetectorModel: GraphModel | null;\nlet handPoseModel: GraphModel | null;\nlet handPipeline: handpipeline.HandPipeline;\n\nexport async function predict(input: Tensor, config: Config): Promise {\n const predictions = await handPipeline.estimateHands(input, config);\n if (!predictions) return [];\n const hands: Array = [];\n for (let i = 0; i < predictions.length; i++) {\n const annotations = {};\n if (predictions[i].landmarks) {\n for (const key of Object.keys(meshAnnotations)) {\n annotations[key] = meshAnnotations[key].map((index) => predictions[i].landmarks[index]);\n }\n }\n\n const keypoints = predictions[i].landmarks as unknown as Array<[number, number, number]>;\n\n let box: [number, number, number, number] = [Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, 0, 0]; // maximums so conditionals work\n let boxRaw: [number, number, number, number] = [0, 0, 0, 0];\n if (keypoints && keypoints.length > 0) { // if we have landmarks, calculate box based on landmarks\n for (const pt of keypoints) {\n if (pt[0] < box[0]) box[0] = pt[0];\n if (pt[1] < box[1]) box[1] = pt[1];\n if (pt[0] > box[2]) box[2] = pt[0];\n if (pt[1] > box[3]) box[3] = pt[1];\n }\n box[2] -= box[0];\n box[3] -= box[1];\n boxRaw = [box[0] / (input.shape[2] || 0), box[1] / (input.shape[1] || 0), box[2] / (input.shape[2] || 0), box[3] / (input.shape[1] || 0)];\n } else { // otherwise use box from prediction\n box = predictions[i].box ? [\n Math.trunc(Math.max(0, predictions[i].box.topLeft[0])),\n Math.trunc(Math.max(0, predictions[i].box.topLeft[1])),\n Math.trunc(Math.min((input.shape[2] || 0), predictions[i].box.bottomRight[0]) - Math.max(0, predictions[i].box.topLeft[0])),\n Math.trunc(Math.min((input.shape[1] || 0), predictions[i].box.bottomRight[1]) - Math.max(0, predictions[i].box.topLeft[1])),\n ] : [0, 0, 0, 0];\n boxRaw = [\n (predictions[i].box.topLeft[0]) / (input.shape[2] || 0),\n (predictions[i].box.topLeft[1]) / (input.shape[1] || 0),\n (predictions[i].box.bottomRight[0] - predictions[i].box.topLeft[0]) / (input.shape[2] || 0),\n (predictions[i].box.bottomRight[1] - predictions[i].box.topLeft[1]) / (input.shape[1] || 0),\n ];\n }\n const landmarks = fingerPose.analyze(keypoints);\n hands.push({\n id: i,\n score: Math.round(100 * predictions[i].confidence) / 100,\n boxScore: Math.round(100 * predictions[i].boxConfidence) / 100,\n fingerScore: Math.round(100 * predictions[i].fingerConfidence) / 100,\n label: 'hand',\n box,\n boxRaw,\n keypoints,\n annotations: annotations as HandResult['annotations'],\n landmarks: landmarks as HandResult['landmarks'],\n });\n }\n return hands;\n}\n\nexport async function load(config: Config): Promise<[GraphModel | null, GraphModel | null]> {\n if (env.initial) {\n handDetectorModel = null;\n handPoseModel = null;\n }\n if (!handDetectorModel || !handPoseModel) {\n [handDetectorModel, handPoseModel] = await Promise.all([\n config.hand.enabled ? tf.loadGraphModel(join(config.modelBasePath, config.hand.detector?.modelPath || ''), { fromTFHub: (config.hand.detector?.modelPath || '').includes('tfhub.dev') }) as unknown as GraphModel : null,\n config.hand.landmarks ? tf.loadGraphModel(join(config.modelBasePath, config.hand.skeleton?.modelPath || ''), { fromTFHub: (config.hand.skeleton?.modelPath || '').includes('tfhub.dev') }) as unknown as GraphModel : null,\n ]);\n if (config.hand.enabled) {\n if (!handDetectorModel || !handDetectorModel['modelUrl']) log('load model failed:', config.hand.detector?.modelPath || '');\n else if (config.debug) log('load model:', handDetectorModel['modelUrl']);\n if (!handPoseModel || !handPoseModel['modelUrl']) log('load model failed:', config.hand.skeleton?.modelPath || '');\n else if (config.debug) log('load model:', handPoseModel['modelUrl']);\n }\n } else {\n if (config.debug) log('cached model:', handDetectorModel['modelUrl']);\n if (config.debug) log('cached model:', handPoseModel['modelUrl']);\n }\n const handDetector = new handdetector.HandDetector(handDetectorModel);\n handPipeline = new handpipeline.HandPipeline(handDetector, handPoseModel);\n return [handDetectorModel, handPoseModel];\n}\n", "/**\n * Hand Detection and Segmentation\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport type { HandResult } from '../result';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\nimport * as fingerPose from '../fingerpose/fingerpose';\n\nconst models: [GraphModel | null, GraphModel | null] = [null, null];\nconst modelOutputNodes = ['StatefulPartitionedCall/Postprocessor/Slice', 'StatefulPartitionedCall/Postprocessor/ExpandDims_1'];\nconst inputSize = [[0, 0], [0, 0]];\n\nconst classes = [\n 'hand',\n 'fist',\n 'pinch',\n 'point',\n 'face',\n 'tip',\n 'pinchtip',\n];\n\nlet skipped = 0;\nlet outputSize;\n\ntype HandDetectResult = {\n id: number,\n score: number,\n box: [number, number, number, number],\n boxRaw: [number, number, number, number],\n label: string,\n yxBox: [number, number, number, number],\n}\n\nconst cache: {\n handBoxes: Array,\n fingerBoxes: Array\n tmpBoxes: Array\n} = {\n handBoxes: [],\n fingerBoxes: [],\n tmpBoxes: [],\n};\n\nconst fingerMap = {\n thumb: [1, 2, 3, 4],\n index: [5, 6, 7, 8],\n middle: [9, 10, 11, 12],\n ring: [13, 14, 15, 16],\n pinky: [17, 18, 19, 20],\n palm: [0],\n};\n\nexport async function load(config: Config): Promise<[GraphModel, GraphModel]> {\n if (env.initial) {\n models[0] = null;\n models[1] = null;\n }\n if (!models[0]) {\n models[0] = await tf.loadGraphModel(join(config.modelBasePath, config.hand.detector?.modelPath || '')) as unknown as GraphModel;\n const inputs = Object.values(models[0].modelSignature['inputs']);\n inputSize[0][0] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[1].size) : 0;\n inputSize[0][1] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;\n if (!models[0] || !models[0]['modelUrl']) log('load model failed:', config.object.modelPath);\n else if (config.debug) log('load model:', models[0]['modelUrl']);\n } else if (config.debug) log('cached model:', models[0]['modelUrl']);\n if (!models[1]) {\n models[1] = await tf.loadGraphModel(join(config.modelBasePath, config.hand.skeleton?.modelPath || '')) as unknown as GraphModel;\n const inputs = Object.values(models[1].modelSignature['inputs']);\n inputSize[1][0] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[1].size) : 0;\n inputSize[1][1] = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;\n if (!models[1] || !models[1]['modelUrl']) log('load model failed:', config.object.modelPath);\n else if (config.debug) log('load model:', models[1]['modelUrl']);\n } else if (config.debug) log('cached model:', models[1]['modelUrl']);\n return models as [GraphModel, GraphModel];\n}\n\nasync function detectHands(input: Tensor, config: Config): Promise {\n const hands: HandDetectResult[] = [];\n if (!input || !models[0]) return hands;\n const t: Record = {};\n const ratio = (input.shape[2] || 1) / (input.shape[1] || 1);\n const height = Math.min(Math.round((input.shape[1] || 0) / 8) * 8, 512); // use dynamic input size but cap at 1024\n const width = Math.round(height * ratio / 8) * 8;\n t.resize = tf.image.resizeBilinear(input, [height, width]); // todo: resize with padding\n t.cast = tf.cast(t.resize, 'int32');\n [t.rawScores, t.rawBoxes] = await models[0].executeAsync(t.cast, modelOutputNodes) as Tensor[];\n t.boxes = tf.squeeze(t.rawBoxes, [0, 2]);\n t.scores = tf.squeeze(t.rawScores, [0]);\n const classScores = tf.unstack(t.scores, 1);\n let id = 0;\n for (let i = 0; i < classScores.length; i++) {\n if (i !== 0 && i !== 1) continue;\n t.nms = await tf.image.nonMaxSuppressionAsync(t.boxes, classScores[i], config.hand.maxDetected, config.hand.iouThreshold, config.hand.minConfidence);\n const nms = await t.nms.data();\n tf.dispose(t.nms);\n for (const res of Array.from(nms)) { // generates results for each class\n const boxSlice = tf.slice(t.boxes, res, 1);\n const yxBox = await boxSlice.data();\n const boxRaw: [number, number, number, number] = [yxBox[1], yxBox[0], yxBox[3] - yxBox[1], yxBox[2] - yxBox[0]];\n const box: [number, number, number, number] = [Math.trunc(boxRaw[0] * outputSize[0]), Math.trunc(boxRaw[1] * outputSize[1]), Math.trunc(boxRaw[2] * outputSize[0]), Math.trunc(boxRaw[3] * outputSize[1])];\n tf.dispose(boxSlice);\n const scoreSlice = tf.slice(classScores[i], res, 1);\n const score = (await scoreSlice.data())[0];\n tf.dispose(scoreSlice);\n const hand: HandDetectResult = { id: id++, score, box, boxRaw, label: classes[i], yxBox };\n hands.push(hand);\n }\n }\n classScores.forEach((tensor) => tf.dispose(tensor));\n Object.keys(t).forEach((tensor) => tf.dispose(t[tensor]));\n hands.sort((a, b) => b.score - a.score);\n if (hands.length > (config.hand.maxDetected || 1)) hands.length = (config.hand.maxDetected || 1);\n return hands;\n}\n\nconst boxScaleFact = 1.5; // hand finger model prefers slighly larger box\nfunction updateBoxes(h, keypoints) {\n const finger = [keypoints.map((pt) => pt[0]), keypoints.map((pt) => pt[1])]; // all fingers coords\n const minmax = [Math.min(...finger[0]), Math.max(...finger[0]), Math.min(...finger[1]), Math.max(...finger[1])]; // find min and max coordinates for x and y of all fingers\n const center = [(minmax[0] + minmax[1]) / 2, (minmax[2] + minmax[3]) / 2]; // find center x and y coord of all fingers\n const diff = Math.max(center[0] - minmax[0], center[1] - minmax[2], -center[0] + minmax[1], -center[1] + minmax[3]) * boxScaleFact; // largest distance from center in any direction\n h.box = [\n Math.trunc(center[0] - diff),\n Math.trunc(center[1] - diff),\n Math.trunc(2 * diff),\n Math.trunc(2 * diff),\n ] as [number, number, number, number];\n h.boxRaw = [ // work backwards\n h.box[0] / outputSize[0],\n h.box[1] / outputSize[1],\n h.box[2] / outputSize[0],\n h.box[3] / outputSize[1],\n ] as [number, number, number, number];\n h.yxBox = [ // work backwards\n h.boxRaw[1],\n h.boxRaw[0],\n h.boxRaw[3] + h.boxRaw[1],\n h.boxRaw[2] + h.boxRaw[0],\n ] as [number, number, number, number];\n}\n\nasync function detectFingers(input: Tensor, h: HandDetectResult, config: Config): Promise {\n const hand: HandResult = {\n id: h.id,\n score: Math.round(100 * h.score) / 100,\n boxScore: Math.round(100 * h.score) / 100,\n fingerScore: 0,\n box: h.box,\n boxRaw: h.boxRaw,\n label: h.label,\n keypoints: [],\n landmarks: {} as HandResult['landmarks'],\n annotations: {} as HandResult['annotations'],\n };\n if (!input || !models[1]) return hand; // something is wrong\n if (config.hand.landmarks) {\n const t: Record = {};\n if (!h.yxBox) return hand;\n t.crop = tf.image.cropAndResize(input, [h.yxBox], [0], [inputSize[1][0], inputSize[1][1]], 'bilinear');\n t.cast = tf.cast(t.crop, 'float32');\n t.div = tf.div(t.cast, 255);\n [t.score, t.keypoints] = models[1].execute(t.div) as Tensor[];\n const score = Math.round(100 * (await t.score.data())[0] / 100);\n if (score > (config.hand.minConfidence || 0)) {\n hand.fingerScore = score;\n t.reshaped = tf.reshape(t.keypoints, [-1, 3]);\n const rawCoords = await t.reshaped.array() as number[];\n hand.keypoints = (rawCoords as number[]).map((coord) => [\n (h.box[2] * coord[0] / inputSize[1][0]) + h.box[0],\n (h.box[3] * coord[1] / inputSize[1][1]) + h.box[1],\n (h.box[2] + h.box[3]) / 2 / inputSize[1][0] * coord[2],\n ]);\n updateBoxes(h, hand.keypoints); // replace detected box with box calculated around keypoints\n hand.box = h.box;\n hand.landmarks = fingerPose.analyze(hand.keypoints) as HandResult['landmarks']; // calculate finger landmarks\n for (const key of Object.keys(fingerMap)) { // map keypoints to per-finger annotations\n hand.annotations[key] = fingerMap[key].map((index) => (hand.landmarks && hand.keypoints[index] ? hand.keypoints[index] : null));\n }\n cache.tmpBoxes.push(h); // if finger detection is enabled, only update cache if fingers are detected\n }\n Object.keys(t).forEach((tensor) => tf.dispose(t[tensor]));\n }\n return hand;\n}\n\nexport async function predict(input: Tensor, config: Config): Promise {\n outputSize = [input.shape[2] || 0, input.shape[1] || 0];\n let hands: Array = [];\n cache.tmpBoxes = []; // clear temp cache\n if (!config.hand.landmarks) cache.fingerBoxes = cache.handBoxes; // if hand detection only reset finger boxes cache\n if ((skipped < (config.hand.skipFrames || 0)) && config.skipFrame) { // just run finger detection while reusing cached boxes\n skipped++;\n hands = await Promise.all(cache.fingerBoxes.map((hand) => detectFingers(input, hand, config))); // run from finger box cache\n // console.log('SKIP', skipped, hands.length, cache.handBoxes.length, cache.fingerBoxes.length, cache.tmpBoxes.length);\n } else { // calculate new boxes and run finger detection\n skipped = 0;\n hands = await Promise.all(cache.fingerBoxes.map((hand) => detectFingers(input, hand, config))); // run from finger box cache\n // console.log('CACHE', skipped, hands.length, cache.handBoxes.length, cache.fingerBoxes.length, cache.tmpBoxes.length);\n if (hands.length !== config.hand.maxDetected) { // run hand detection only if we dont have enough hands in cache\n cache.handBoxes = await detectHands(input, config);\n const newHands = await Promise.all(cache.handBoxes.map((hand) => detectFingers(input, hand, config)));\n hands = hands.concat(newHands);\n // console.log('DETECT', skipped, hands.length, cache.handBoxes.length, cache.fingerBoxes.length, cache.tmpBoxes.length);\n }\n }\n cache.fingerBoxes = [...cache.tmpBoxes]; // repopulate cache with validated hands\n return hands as HandResult[];\n}\n\n/*\n- Live Site: \n- TFJS Port: \n- Original: \n- Writeup: \n*/\n", "export const full = [\n 'nose',\n 'leftEyeInside',\n 'leftEye',\n 'leftEyeOutside',\n 'rightEyeInside',\n 'rightEye',\n 'rightEyeOutside',\n 'leftEar',\n 'rightEar',\n 'leftMouth',\n 'rightMouth',\n 'leftShoulder',\n 'rightShoulder',\n 'leftElbow',\n 'rightElbow',\n 'leftWrist',\n 'rightWrist',\n 'leftPalm',\n 'rightPalm',\n 'leftIndex',\n 'rightIndex',\n 'leftPinky',\n 'rightPinky',\n 'leftHip',\n 'rightHip',\n 'leftKnee',\n 'rightKnee',\n 'leftAnkle',\n 'rightAnkle',\n 'leftHeel',\n 'rightHeel',\n 'leftFoot',\n 'rightFoot',\n 'midHip',\n 'forehead',\n 'leftThumb',\n 'leftHand',\n 'rightThumb',\n 'rightHand',\n];\n\nexport const upper = [\n 'nose',\n 'leftEyeInside',\n 'leftEye',\n 'leftEyeOutside',\n 'rightEyeInside',\n 'rightEye',\n 'rightEyeOutside',\n 'leftEar',\n 'rightEar',\n 'leftMouth',\n 'rightMouth',\n 'leftShoulder',\n 'rightShoulder',\n 'leftElbow',\n 'rightElbow',\n 'left:15',\n 'right:16',\n 'left:17',\n 'right:18',\n 'left:19',\n 'right:20',\n 'left:21',\n 'right:22',\n 'leftChest',\n 'rightChest',\n 'neck',\n 'forehead',\n 'left:27',\n 'right:28',\n 'left:29',\n 'right:30',\n];\n", "/**\n * BlazePose Module\n */\n\n// paper: https://ai.googleblog.com/2020/08/on-device-real-time-body-pose-tracking.html\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as annotations from './annotations';\nimport type { Tensor, GraphModel } from '../tfjs/types';\nimport type { BodyResult } from '../result';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model: GraphModel | null;\n\nexport async function load(config: Config): Promise {\n if (env.initial) model = null;\n if (!model) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath || '')) as unknown as GraphModel;\n model['width'] = parseInt(model['signature'].inputs['input_1:0'].tensorShape.dim[2].size);\n model['height'] = parseInt(model['signature'].inputs['input_1:0'].tensorShape.dim[1].size);\n if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n\nexport async function predict(image: Tensor, config: Config): Promise {\n if (!model) return [];\n if (!config.body.enabled) return [];\n const imgSize = { width: (image.shape[2] || 0), height: (image.shape[1] || 0) };\n const resize = tf.image.resizeBilinear(image, [model['width'], model['height']], false);\n const normalize = tf.div(resize, [255.0]);\n tf.dispose(resize);\n const resT = await model.predict(normalize) as Array;\n const findT = resT.find((t) => (t.size === 195 || t.size === 155));\n const points = await findT?.data() || []; // order of output tensors may change between models, full has 195 and upper has 155 items\n resT.forEach((t) => tf.dispose(t));\n tf.dispose(normalize);\n const keypoints: Array<{ id, part, position: [number, number, number], positionRaw: [number, number, number], score, presence }> = [];\n const labels = points?.length === 195 ? annotations.full : annotations.upper; // full model has 39 keypoints, upper has 31 keypoints\n const depth = 5; // each points has x,y,z,visibility,presence\n for (let i = 0; i < points.length / depth; i++) {\n keypoints.push({\n id: i,\n part: labels[i],\n position: [\n Math.trunc(imgSize.width * points[depth * i + 0] / 255), // return normalized x value istead of 0..255\n Math.trunc(imgSize.height * points[depth * i + 1] / 255), // return normalized y value istead of 0..255\n Math.trunc(points[depth * i + 2]) + 0, // fix negative zero\n ],\n positionRaw: [\n points[depth * i + 0] / 255, // return x value normalized to 0..1\n points[depth * i + 1] / 255, // return y value normalized to 0..1\n points[depth * i + 2] + 0, // fix negative zero\n ],\n score: (100 - Math.trunc(100 / (1 + Math.exp(points[depth * i + 3])))) / 100, // reverse sigmoid value\n presence: (100 - Math.trunc(100 / (1 + Math.exp(points[depth * i + 4])))) / 100, // reverse sigmoid value\n });\n }\n const x = keypoints.map((a) => a.position[0]);\n const y = keypoints.map((a) => a.position[1]);\n const box: [number, number, number, number] = [\n Math.min(...x),\n Math.min(...y),\n Math.max(...x) - Math.min(...x),\n Math.max(...y) - Math.min(...x),\n ];\n const boxRaw: [number, number, number, number] = [0, 0, 0, 0]; // not yet implemented\n const score = keypoints.reduce((prev, curr) => (curr.score > prev ? curr.score : prev), 0);\n return [{ id: 0, score, box, boxRaw, keypoints }];\n}\n", "/**\n * EfficientPose Module\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport type { BodyResult } from '../result';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model: GraphModel | null;\n\ntype Keypoints = { score: number, part: string, position: [number, number], positionRaw: [number, number] };\n\nconst keypoints: Array = [];\nlet box: [number, number, number, number] = [0, 0, 0, 0];\nlet boxRaw: [number, number, number, number] = [0, 0, 0, 0];\nlet score = 0;\nlet skipped = Number.MAX_SAFE_INTEGER;\n\nconst bodyParts = ['head', 'neck', 'rightShoulder', 'rightElbow', 'rightWrist', 'chest', 'leftShoulder', 'leftElbow', 'leftWrist', 'pelvis', 'rightHip', 'rightKnee', 'rightAnkle', 'leftHip', 'leftKnee', 'leftAnkle'];\n\nexport async function load(config: Config): Promise {\n if (env.initial) model = null;\n if (!model) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath || '')) as unknown as GraphModel;\n if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n\n// performs argmax and max functions on a 2d tensor\nfunction max2d(inputs, minScore) {\n const [width, height] = inputs.shape;\n return tf.tidy(() => {\n const mod = (a, b) => tf.sub(a, tf.mul(tf.div(a, tf.scalar(b, 'int32')), tf.scalar(b, 'int32'))); // modulus op implemented in tf\n const reshaped = tf.reshape(inputs, [height * width]); // combine all data\n const newScore = tf.max(reshaped, 0).dataSync()[0]; // get highest score // inside tf.tidy\n if (newScore > minScore) { // skip coordinate calculation is score is too low\n const coords = tf.argMax(reshaped, 0);\n const x = mod(coords, width).dataSync()[0]; // inside tf.tidy\n const y = tf.div(coords, tf.scalar(width, 'int32')).dataSync()[0]; // inside tf.tidy\n return [x, y, newScore];\n }\n return [0, 0, newScore];\n });\n}\n\nexport async function predict(image: Tensor, config: Config): Promise {\n if ((skipped < (config.body?.skipFrames || 0)) && config.skipFrame && Object.keys(keypoints).length > 0) {\n skipped++;\n return [{ id: 0, score, box, boxRaw, keypoints }];\n }\n skipped = 0;\n return new Promise(async (resolve) => {\n const tensor = tf.tidy(() => {\n if (!model?.inputs[0].shape) return null;\n const resize = tf.image.resizeBilinear(image, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false);\n const enhance = tf.mul(resize, 2);\n const norm = enhance.sub(1);\n return norm;\n });\n\n let resT;\n if (config.body.enabled) resT = await model?.predict(tensor);\n tf.dispose(tensor);\n\n if (resT) {\n keypoints.length = 0;\n const squeeze = resT.squeeze();\n tf.dispose(resT);\n // body parts are basically just a stack of 2d tensors\n const stack = squeeze.unstack(2);\n tf.dispose(squeeze);\n // process each unstacked tensor as a separate body part\n for (let id = 0; id < stack.length; id++) {\n // actual processing to get coordinates and score\n const [x, y, partScore] = max2d(stack[id], config.body.minConfidence);\n if (score > (config.body?.minConfidence || 0)) {\n keypoints.push({\n score: Math.round(100 * partScore) / 100,\n part: bodyParts[id],\n positionRaw: [ // normalized to 0..1\n // @ts-ignore model is not undefined here\n x / model.inputs[0].shape[2], y / model.inputs[0].shape[1],\n ],\n position: [ // normalized to input image size\n // @ts-ignore model is not undefined here\n Math.round(image.shape[2] * x / model.inputs[0].shape[2]), Math.round(image.shape[1] * y / model.inputs[0].shape[1]),\n ],\n });\n }\n }\n stack.forEach((s) => tf.dispose(s));\n }\n score = keypoints.reduce((prev, curr) => (curr.score > prev ? curr.score : prev), 0);\n const x = keypoints.map((a) => a.position[0]);\n const y = keypoints.map((a) => a.position[1]);\n box = [\n Math.min(...x),\n Math.min(...y),\n Math.max(...x) - Math.min(...x),\n Math.max(...y) - Math.min(...y),\n ];\n const xRaw = keypoints.map((a) => a.positionRaw[0]);\n const yRaw = keypoints.map((a) => a.positionRaw[1]);\n boxRaw = [\n Math.min(...xRaw),\n Math.min(...yRaw),\n Math.max(...xRaw) - Math.min(...xRaw),\n Math.max(...yRaw) - Math.min(...yRaw),\n ];\n resolve([{ id: 0, score, box, boxRaw, keypoints }]);\n });\n}\n", "/**\n * EfficientPose Module\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport type { BodyResult } from '../result';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model: GraphModel | null;\n\ntype Keypoints = { score: number, part: string, position: [number, number], positionRaw: [number, number] };\nconst keypoints: Array = [];\ntype Person = { id: number, score: number, box: [number, number, number, number], boxRaw: [number, number, number, number], keypoints: Array }\n\nlet box: [number, number, number, number] = [0, 0, 0, 0];\nlet boxRaw: [number, number, number, number] = [0, 0, 0, 0];\nlet score = 0;\nlet skipped = Number.MAX_SAFE_INTEGER;\n\nconst bodyParts = ['nose', 'leftEye', 'rightEye', 'leftEar', 'rightEar', 'leftShoulder', 'rightShoulder', 'leftElbow', 'rightElbow', 'leftWrist', 'rightWrist', 'leftHip', 'rightHip', 'leftKnee', 'rightKnee', 'leftAnkle', 'rightAnkle'];\n\nexport async function load(config: Config): Promise {\n if (env.initial) model = null;\n if (!model) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath || '')) as unknown as GraphModel;\n if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n\nasync function parseSinglePose(res, config, image) {\n keypoints.length = 0;\n const kpt = res[0][0];\n for (let id = 0; id < kpt.length; id++) {\n score = kpt[id][2];\n if (score > config.body.minConfidence) {\n keypoints.push({\n score: Math.round(100 * score) / 100,\n part: bodyParts[id],\n positionRaw: [ // normalized to 0..1\n kpt[id][1],\n kpt[id][0],\n ],\n position: [ // normalized to input image size\n Math.round((image.shape[2] || 0) * kpt[id][1]),\n Math.round((image.shape[1] || 0) * kpt[id][0]),\n ],\n });\n }\n }\n score = keypoints.reduce((prev, curr) => (curr.score > prev ? curr.score : prev), 0);\n const x = keypoints.map((a) => a.position[0]);\n const y = keypoints.map((a) => a.position[1]);\n box = [\n Math.min(...x),\n Math.min(...y),\n Math.max(...x) - Math.min(...x),\n Math.max(...y) - Math.min(...y),\n ];\n const xRaw = keypoints.map((a) => a.positionRaw[0]);\n const yRaw = keypoints.map((a) => a.positionRaw[1]);\n boxRaw = [\n Math.min(...xRaw),\n Math.min(...yRaw),\n Math.max(...xRaw) - Math.min(...xRaw),\n Math.max(...yRaw) - Math.min(...yRaw),\n ];\n const persons: Array = [];\n persons.push({ id: 0, score, box, boxRaw, keypoints });\n return persons;\n}\n\nasync function parseMultiPose(res, config, image) {\n const persons: Array = [];\n for (let p = 0; p < res[0].length; p++) {\n const kpt = res[0][p];\n score = Math.round(100 * kpt[51 + 4]) / 100;\n // eslint-disable-next-line no-continue\n if (score < config.body.minConfidence) continue;\n keypoints.length = 0;\n for (let i = 0; i < 17; i++) {\n const partScore = Math.round(100 * kpt[3 * i + 2]) / 100;\n if (partScore > config.body.minConfidence) {\n keypoints.push({\n part: bodyParts[i],\n score: partScore,\n positionRaw: [\n kpt[3 * i + 1],\n kpt[3 * i + 0],\n ],\n position: [\n Math.trunc(kpt[3 * i + 1] * (image.shape[2] || 0)),\n Math.trunc(kpt[3 * i + 0] * (image.shape[1] || 0)),\n ],\n });\n }\n }\n boxRaw = [kpt[51 + 1], kpt[51 + 0], kpt[51 + 3] - kpt[51 + 1], kpt[51 + 2] - kpt[51 + 0]];\n persons.push({\n id: p,\n score,\n boxRaw,\n box: [\n Math.trunc(boxRaw[0] * (image.shape[2] || 0)),\n Math.trunc(boxRaw[1] * (image.shape[1] || 0)),\n Math.trunc(boxRaw[2] * (image.shape[2] || 0)),\n Math.trunc(boxRaw[3] * (image.shape[1] || 0)),\n ],\n keypoints,\n });\n }\n return persons;\n}\n\nexport async function predict(image: Tensor, config: Config): Promise {\n if ((skipped < (config.body.skipFrames || 0)) && config.skipFrame && Object.keys(keypoints).length > 0) {\n skipped++;\n return [{ id: 0, score, box, boxRaw, keypoints }];\n }\n skipped = 0;\n return new Promise(async (resolve) => {\n const tensor = tf.tidy(() => {\n if (!model?.inputs[0].shape) return null;\n let inputSize = model.inputs[0].shape[2];\n if (inputSize === -1) inputSize = 256;\n const resize = tf.image.resizeBilinear(image, [inputSize, inputSize], false);\n const cast = tf.cast(resize, 'int32');\n return cast;\n });\n\n let resT;\n if (config.body.enabled) resT = await model?.predict(tensor);\n tf.dispose(tensor);\n\n if (!resT) resolve([]);\n const res = await resT.array();\n let persons;\n if (resT.shape[2] === 17) persons = await parseSinglePose(res, config, image);\n else if (resT.shape[2] === 56) persons = await parseMultiPose(res, config, image);\n tf.dispose(resT);\n\n resolve(persons);\n });\n}\n", "/**\n * CoCo Labels used by object detection modules\n */\nexport const labels = [\n { class: 1, label: 'person' },\n { class: 2, label: 'bicycle' },\n { class: 3, label: 'car' },\n { class: 4, label: 'motorcycle' },\n { class: 5, label: 'airplane' },\n { class: 6, label: 'bus' },\n { class: 7, label: 'train' },\n { class: 8, label: 'truck' },\n { class: 9, label: 'boat' },\n { class: 10, label: 'traffic light' },\n { class: 11, label: 'fire hydrant' },\n { class: 12, label: 'stop sign' },\n { class: 13, label: 'parking meter' },\n { class: 14, label: 'bench' },\n { class: 15, label: 'bird' },\n { class: 16, label: 'cat' },\n { class: 17, label: 'dog' },\n { class: 18, label: 'horse' },\n { class: 19, label: 'sheep' },\n { class: 20, label: 'cow' },\n { class: 21, label: 'elephant' },\n { class: 22, label: 'bear' },\n { class: 23, label: 'zebra' },\n { class: 24, label: 'giraffe' },\n { class: 25, label: 'backpack' },\n { class: 26, label: 'umbrella' },\n { class: 27, label: 'handbag' },\n { class: 28, label: 'tie' },\n { class: 29, label: 'suitcase' },\n { class: 30, label: 'frisbee' },\n { class: 31, label: 'skis' },\n { class: 32, label: 'snowboard' },\n { class: 33, label: 'sports ball' },\n { class: 34, label: 'kite' },\n { class: 35, label: 'baseball bat' },\n { class: 36, label: 'baseball glove' },\n { class: 37, label: 'skateboard' },\n { class: 38, label: 'surfboard' },\n { class: 39, label: 'tennis racket' },\n { class: 40, label: 'bottle' },\n { class: 41, label: 'wine glass' },\n { class: 42, label: 'cup' },\n { class: 43, label: 'fork' },\n { class: 44, label: 'knife' },\n { class: 45, label: 'spoon' },\n { class: 46, label: 'bowl' },\n { class: 47, label: 'banana' },\n { class: 48, label: 'apple' },\n { class: 49, label: 'sandwich' },\n { class: 50, label: 'orange' },\n { class: 51, label: 'broccoli' },\n { class: 52, label: 'carrot' },\n { class: 53, label: 'hot dog' },\n { class: 54, label: 'pizza' },\n { class: 55, label: 'donut' },\n { class: 56, label: 'cake' },\n { class: 57, label: 'chair' },\n { class: 58, label: 'couch' },\n { class: 59, label: 'potted plant' },\n { class: 60, label: 'bed' },\n { class: 61, label: 'dining table' },\n { class: 62, label: 'toilet' },\n { class: 63, label: 'tv' },\n { class: 64, label: 'laptop' },\n { class: 65, label: 'mouse' },\n { class: 66, label: 'remote' },\n { class: 67, label: 'keyboard' },\n { class: 68, label: 'cell phone' },\n { class: 69, label: 'microwave' },\n { class: 70, label: 'oven' },\n { class: 71, label: 'toaster' },\n { class: 72, label: 'sink' },\n { class: 73, label: 'refrigerator' },\n { class: 74, label: 'book' },\n { class: 75, label: 'clock' },\n { class: 76, label: 'vase' },\n { class: 77, label: 'scissors' },\n { class: 78, label: 'teddy bear' },\n { class: 79, label: 'hair drier' },\n { class: 80, label: 'toothbrush' },\n];\n", "/**\n * NanoDet object detection module\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport { labels } from './labels';\nimport type { ObjectResult } from '../result';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model;\nlet last: Array = [];\nlet skipped = Number.MAX_SAFE_INTEGER;\n\nconst scaleBox = 2.5; // increase box size\n\nexport async function load(config: Config): Promise {\n if (!model || env.initial) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.object.modelPath || ''));\n const inputs = Object.values(model.modelSignature['inputs']);\n model.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;\n if (!model.inputSize) throw new Error(`cannot determine model inputSize: ${config.object.modelPath}`);\n if (!model || !model.modelUrl) log('load model failed:', config.object.modelPath);\n else if (config.debug) log('load model:', model.modelUrl);\n } else if (config.debug) log('cached model:', model.modelUrl);\n return model;\n}\n\nasync function process(res, inputSize, outputShape, config) {\n let id = 0;\n let results: Array = [];\n for (const strideSize of [1, 2, 4]) { // try each stride size as it detects large/medium/small objects\n // find scores, boxes, classes\n tf.tidy(async () => { // wrap in tidy to automatically deallocate temp tensors\n const baseSize = strideSize * 13; // 13x13=169, 26x26=676, 52x52=2704\n // find boxes and scores output depending on stride\n const scoresT = res.find((a) => (a.shape[1] === (baseSize ** 2) && a.shape[2] === labels.length))?.squeeze();\n const featuresT = res.find((a) => (a.shape[1] === (baseSize ** 2) && a.shape[2] < labels.length))?.squeeze();\n const boxesMax = featuresT.reshape([-1, 4, featuresT.shape[1] / 4]); // reshape [output] to [4, output / 4] where number is number of different features inside each stride\n const boxIdx = await boxesMax.argMax(2).array(); // what we need is indexes of features with highest scores, not values itself\n const scores = await scoresT.array(); // optionally use exponential scores or just as-is\n for (let i = 0; i < scoresT.shape[0]; i++) { // total strides (x * y matrix)\n for (let j = 0; j < scoresT.shape[1]; j++) { // one score for each class\n const score = scores[i][j]; // get score for current position\n if (score > config.object.minConfidence && j !== 61) {\n const cx = (0.5 + Math.trunc(i % baseSize)) / baseSize; // center.x normalized to range 0..1\n const cy = (0.5 + Math.trunc(i / baseSize)) / baseSize; // center.y normalized to range 0..1\n const boxOffset = boxIdx[i].map((a) => a * (baseSize / strideSize / inputSize)); // just grab indexes of features with highest scores\n const [x, y] = [\n cx - (scaleBox / strideSize * boxOffset[0]),\n cy - (scaleBox / strideSize * boxOffset[1]),\n ];\n const [w, h] = [\n cx + (scaleBox / strideSize * boxOffset[2]) - x,\n cy + (scaleBox / strideSize * boxOffset[3]) - y,\n ];\n let boxRaw = [x, y, w, h]; // results normalized to range 0..1\n boxRaw = boxRaw.map((a) => Math.max(0, Math.min(a, 1))); // fix out-of-bounds coords\n const box = [ // results normalized to input image pixels\n boxRaw[0] * outputShape[0],\n boxRaw[1] * outputShape[1],\n boxRaw[2] * outputShape[0],\n boxRaw[3] * outputShape[1],\n ];\n const result = {\n id: id++,\n // strideSize,\n score: Math.round(100 * score) / 100,\n class: j + 1,\n label: labels[j].label,\n // center: [Math.trunc(outputShape[0] * cx), Math.trunc(outputShape[1] * cy)],\n // centerRaw: [cx, cy],\n box: (box.map((a) => Math.trunc(a))) as [number, number, number, number],\n boxRaw: boxRaw as [number, number, number, number],\n };\n results.push(result);\n }\n }\n }\n });\n }\n // deallocate tensors\n res.forEach((t) => tf.dispose(t));\n\n // normally nms is run on raw results, but since boxes need to be calculated this way we skip calulcation of\n // unnecessary boxes and run nms only on good candidates (basically it just does IOU analysis as scores are already filtered)\n const nmsBoxes = results.map((a) => [a.boxRaw[1], a.boxRaw[0], a.boxRaw[3], a.boxRaw[2]]); // switches coordinates from x,y to y,x as expected by tf.nms\n const nmsScores = results.map((a) => a.score);\n let nmsIdx: Array = [];\n if (nmsBoxes && nmsBoxes.length > 0) {\n const nms = await tf.image.nonMaxSuppressionAsync(nmsBoxes, nmsScores, config.object.maxDetected, config.object.iouThreshold, config.object.minConfidence);\n nmsIdx = await nms.data();\n tf.dispose(nms);\n }\n\n // filter & sort results\n results = results\n .filter((_val, idx) => nmsIdx.includes(idx))\n .sort((a, b) => (b.score - a.score));\n\n return results;\n}\n\nexport async function predict(image: Tensor, config: Config): Promise {\n if ((skipped < (config.object.skipFrames || 0)) && config.skipFrame && (last.length > 0)) {\n skipped++;\n return last;\n }\n skipped = 0;\n if (!env.kernels.includes('mod') || !env.kernels.includes('sparsetodense')) return last;\n return new Promise(async (resolve) => {\n const outputSize = [image.shape[2], image.shape[1]];\n const resize = tf.image.resizeBilinear(image, [model.inputSize, model.inputSize], false);\n const norm = tf.div(resize, 255);\n const transpose = norm.transpose([0, 3, 1, 2]);\n tf.dispose(norm);\n tf.dispose(resize);\n\n let objectT;\n if (config.object.enabled) objectT = await model.predict(transpose);\n tf.dispose(transpose);\n\n const obj = await process(objectT, model.inputSize, outputSize, config);\n last = obj;\n resolve(obj);\n });\n}\n", "/**\n * CenterNet object detection module\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport { labels } from './labels';\nimport type { ObjectResult } from '../result';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\nlet model: GraphModel | null;\nlet inputSize = 0;\nlet last: ObjectResult[] = [];\nlet skipped = Number.MAX_SAFE_INTEGER;\n\nexport async function load(config: Config): Promise {\n if (env.initial) model = null;\n if (!model) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.object.modelPath || '')) as unknown as GraphModel;\n const inputs = Object.values(model.modelSignature['inputs']);\n inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;\n if (!model || !model['modelUrl']) log('load model failed:', config.object.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n\nasync function process(res: Tensor | null, outputShape, config: Config) {\n if (!res) return [];\n const results: Array = [];\n const detections = await res.array();\n const squeezeT = tf.squeeze(res);\n tf.dispose(res);\n const arr = tf.split(squeezeT, 6, 1); // x1, y1, x2, y2, score, class\n tf.dispose(squeezeT);\n const stackT = tf.stack([arr[1], arr[0], arr[3], arr[2]], 1); // reorder dims as tf.nms expects y, x\n const boxesT = tf.squeeze(stackT);\n tf.dispose(stackT);\n const scoresT = tf.squeeze(arr[4]);\n const classesT = tf.squeeze(arr[5]);\n arr.forEach((t) => tf.dispose(t));\n const nmsT = await tf.image.nonMaxSuppressionAsync(boxesT, scoresT, config.object.maxDetected, config.object.iouThreshold, config.object.minConfidence);\n tf.dispose(boxesT);\n tf.dispose(scoresT);\n tf.dispose(classesT);\n const nms = await nmsT.data();\n tf.dispose(nmsT);\n let i = 0;\n for (const id of nms) {\n const score = Math.trunc(100 * detections[0][id][4]) / 100;\n const classVal = detections[0][id][5];\n const label = labels[classVal].label;\n const [x, y] = [\n detections[0][id][0] / inputSize,\n detections[0][id][1] / inputSize,\n ];\n const boxRaw = [\n x,\n y,\n detections[0][id][2] / inputSize - x,\n detections[0][id][3] / inputSize - y,\n ] as [number, number, number, number];\n const box = [\n Math.trunc(boxRaw[0] * outputShape[0]),\n Math.trunc(boxRaw[1] * outputShape[1]),\n Math.trunc(boxRaw[2] * outputShape[0]),\n Math.trunc(boxRaw[3] * outputShape[1]),\n ] as [number, number, number, number];\n results.push({ id: i++, score, class: classVal, label, box, boxRaw });\n }\n return results;\n}\n\nexport async function predict(input: Tensor, config: Config): Promise {\n if ((skipped < (config.object.skipFrames || 0)) && config.skipFrame && (last.length > 0)) {\n skipped++;\n return last;\n }\n skipped = 0;\n if (!env.kernels.includes('mod') || !env.kernels.includes('sparsetodense')) return last;\n return new Promise(async (resolve) => {\n const outputSize = [input.shape[2], input.shape[1]];\n const resize = tf.image.resizeBilinear(input, [inputSize, inputSize]);\n const objectT = config.object.enabled ? model?.execute(resize, ['tower_0/detections']) as Tensor : null;\n tf.dispose(resize);\n\n const obj = await process(objectT, outputSize, config);\n last = obj;\n\n resolve(obj);\n });\n}\n", "/**\n * EfficientPose Module\n */\n\nimport { log, join } from '../helpers';\nimport * as tf from '../../dist/tfjs.esm.js';\nimport * as image from '../image/image';\nimport type { GraphModel, Tensor } from '../tfjs/types';\nimport type { Config } from '../config';\nimport { env } from '../env';\n\ntype Input = Tensor | typeof Image | ImageData | ImageBitmap | HTMLImageElement | HTMLMediaElement | HTMLVideoElement | HTMLCanvasElement | OffscreenCanvas;\n\nlet model: GraphModel;\nlet busy = false;\n\nexport async function load(config: Config): Promise {\n if (!model || env.initial) {\n model = await tf.loadGraphModel(join(config.modelBasePath, config.segmentation.modelPath || '')) as unknown as GraphModel;\n if (!model || !model['modelUrl']) log('load model failed:', config.segmentation.modelPath);\n else if (config.debug) log('load model:', model['modelUrl']);\n } else if (config.debug) log('cached model:', model['modelUrl']);\n return model;\n}\n\nexport async function predict(input: { tensor: Tensor | null, canvas: OffscreenCanvas | HTMLCanvasElement | null }, config: Config)\n: Promise<{ data: Uint8ClampedArray | null, canvas: HTMLCanvasElement | OffscreenCanvas | null, alpha: HTMLCanvasElement | OffscreenCanvas | null }> {\n const width = input.tensor?.shape[2] || 0;\n const height = input.tensor?.shape[1] || 0;\n if (!input.tensor || !model || !model.inputs[0].shape) return { data: null, canvas: null, alpha: null };\n const resizeInput = tf.image.resizeBilinear(input.tensor, [model.inputs[0].shape[1], model.inputs[0].shape[2]], false);\n const norm = tf.div(resizeInput, 255);\n const res = model.predict(norm) as Tensor;\n // meet output: 1,256,256,1\n // selfie output: 1,144,256,2\n tf.dispose(resizeInput);\n tf.dispose(norm);\n\n const squeeze = tf.squeeze(res, 0);\n tf.dispose(res);\n let dataT;\n if (squeeze.shape[2] === 2) {\n // model meet has two channels for fg and bg\n const softmax = squeeze.softmax();\n const [bg, fg] = tf.unstack(softmax, 2);\n const expand = tf.expandDims(fg, 2);\n const pad = tf.expandDims(expand, 0);\n tf.dispose(softmax);\n tf.dispose(bg);\n tf.dispose(fg);\n // running sofmax before unstack creates 2x2 matrix so we only take upper-left quadrant\n const crop = tf.image.cropAndResize(pad, [[0, 0, 0.5, 0.5]], [0], [width, height]);\n // otherwise run softmax after unstack and use standard resize\n // resizeOutput = tf.image.resizeBilinear(expand, [input.tensor?.shape[1], input.tensor?.shape[2]]);\n dataT = tf.squeeze(crop, 0);\n tf.dispose(crop);\n tf.dispose(expand);\n tf.dispose(pad);\n } else { // model selfie has a single channel that we can use directly\n dataT = tf.image.resizeBilinear(squeeze, [height, width]);\n }\n tf.dispose(squeeze);\n const data = await dataT.dataSync();\n\n if (env.node) {\n tf.dispose(dataT);\n return { data, canvas: null, alpha: null }; // running in nodejs so return alpha array as-is\n }\n\n const alphaCanvas = image.canvas(width, height);\n await tf.browser.toPixels(dataT, alphaCanvas);\n tf.dispose(dataT);\n const alphaCtx = alphaCanvas.getContext('2d') as CanvasRenderingContext2D;\n if (config.segmentation.blur && config.segmentation.blur > 0) alphaCtx.filter = `blur(${config.segmentation.blur}px)`; // use css filter for bluring, can be done with gaussian blur manually instead\n const alphaData = alphaCtx.getImageData(0, 0, width, height);\n\n // original canvas where only alpha shows\n const compositeCanvas = image.canvas(width, height);\n const compositeCtx = compositeCanvas.getContext('2d') as CanvasRenderingContext2D;\n if (input.canvas) compositeCtx.drawImage(input.canvas, 0, 0);\n compositeCtx.globalCompositeOperation = 'darken'; // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation // best options are: darken, color-burn, multiply\n if (config.segmentation.blur && config.segmentation.blur > 0) compositeCtx.filter = `blur(${config.segmentation.blur}px)`; // use css filter for bluring, can be done with gaussian blur manually instead\n compositeCtx.drawImage(alphaCanvas, 0, 0);\n compositeCtx.globalCompositeOperation = 'source-over'; // reset composite operation\n compositeCtx.filter = 'none'; // reset css filter\n const compositeData = compositeCtx.getImageData(0, 0, width, height);\n for (let i = 0; i < width * height; i++) compositeData.data[4 * i + 3] = alphaData.data[4 * i + 0]; // copy original alpha value to new composite canvas\n compositeCtx.putImageData(compositeData, 0, 0);\n\n return { data, canvas: compositeCanvas, alpha: alphaCanvas };\n}\n\nexport async function process(input: Input, background: Input | undefined, config: Config)\n: Promise<{ data: Uint8ClampedArray | null, canvas: HTMLCanvasElement | OffscreenCanvas | null, alpha: HTMLCanvasElement | OffscreenCanvas | null }> {\n if (busy) return { data: null, canvas: null, alpha: null };\n busy = true;\n if (!model) await load(config);\n const inputImage = image.process(input, config);\n const segmentation = await predict(inputImage, config);\n tf.dispose(inputImage.tensor);\n let mergedCanvas: HTMLCanvasElement | OffscreenCanvas | null = null;\n\n if (background && segmentation.canvas) { // draw background with segmentation as overlay if background is present\n mergedCanvas = image.canvas(inputImage.canvas?.width || 0, inputImage.canvas?.height || 0);\n const bgImage = image.process(background, config);\n tf.dispose(bgImage.tensor);\n const ctxMerge = mergedCanvas.getContext('2d') as CanvasRenderingContext2D;\n // ctxMerge.globalCompositeOperation = 'source-over';\n ctxMerge.drawImage(bgImage.canvas as HTMLCanvasElement, 0, 0, mergedCanvas.width, mergedCanvas.height);\n // ctxMerge.globalCompositeOperation = 'source-atop';\n ctxMerge.drawImage(segmentation.canvas as HTMLCanvasElement, 0, 0);\n // ctxMerge.globalCompositeOperation = 'source-over';\n }\n\n busy = false;\n return { data: segmentation.data, canvas: mergedCanvas || segmentation.canvas, alpha: segmentation.alpha };\n}\n", "import { log } from './helpers';\nimport type { GraphModel } from './tfjs/types';\nimport * as facemesh from './blazeface/facemesh';\nimport * as faceres from './faceres/faceres';\nimport * as emotion from './emotion/emotion';\nimport * as posenet from './posenet/posenet';\nimport * as handpose from './handpose/handpose';\nimport * as handtrack from './handtrack/handtrack';\nimport * as blazepose from './blazepose/blazepose';\nimport * as efficientpose from './efficientpose/efficientpose';\nimport * as movenet from './movenet/movenet';\nimport * as nanodet from './object/nanodet';\nimport * as centernet from './object/centernet';\nimport * as segmentation from './segmentation/segmentation';\nimport { env } from './env';\n// import * as agegenderrace from './gear/agegenderrace';\n\nexport function reset(instance) {\n // if (instance.config.debug) log('resetting loaded models');\n instance.models = {\n face: null, // array of models\n handpose: null, // array of models\n handtrack: null, // array of models\n posenet: null,\n blazepose: null,\n efficientpose: null,\n movenet: null,\n age: null,\n gender: null,\n emotion: null,\n embedding: null,\n nanodet: null,\n centernet: null,\n faceres: null,\n segmentation: null,\n };\n}\n\n/** Load method preloads all instance.configured models on-demand */\nexport async function load(instance) {\n if (env.initial) reset(instance);\n if (instance.config.async) { // load models concurrently\n [\n instance.models.face,\n instance.models.emotion,\n instance.models.handpose,\n instance.models.handtrack,\n instance.models.posenet,\n instance.models.blazepose,\n instance.models.efficientpose,\n instance.models.movenet,\n instance.models.nanodet,\n instance.models.centernet,\n instance.models.faceres,\n instance.models.segmentation,\n // instance.models.agegenderrace,\n ] = await Promise.all([\n instance.models.face || (instance.config.face.enabled ? facemesh.load(instance.config) : null),\n instance.models.emotion || ((instance.config.face.enabled && instance.config.face.emotion.enabled) ? emotion.load(instance.config) : null),\n instance.models.handpose || (instance.config.hand.enabled && instance.config.hand.detector.modelPath.includes('handdetect') ? handpose.load(instance.config) : null),\n instance.models.handtrack || (instance.config.hand.enabled && instance.config.hand.detector.modelPath.includes('handtrack') ? handtrack.load(instance.config) : null),\n instance.models.posenet || (instance.config.body.enabled && instance.config.body.modelPath.includes('posenet') ? posenet.load(instance.config) : null),\n instance.models.blazepose || (instance.config.body.enabled && instance.config.body.modelPath.includes('blazepose') ? blazepose.load(instance.config) : null),\n instance.models.efficientpose || (instance.config.body.enabled && instance.config.body.modelPath.includes('efficientpose') ? efficientpose.load(instance.config) : null),\n instance.models.movenet || (instance.config.body.enabled && instance.config.body.modelPath.includes('movenet') ? movenet.load(instance.config) : null),\n instance.models.nanodet || (instance.config.object.enabled && instance.config.object.modelPath.includes('nanodet') ? nanodet.load(instance.config) : null),\n instance.models.centernet || (instance.config.object.enabled && instance.config.object.modelPath.includes('centernet') ? centernet.load(instance.config) : null),\n instance.models.faceres || ((instance.config.face.enabled && instance.config.face.description.enabled) ? faceres.load(instance.config) : null),\n instance.models.segmentation || (instance.config.segmentation.enabled ? segmentation.load(instance.config) : null),\n // instance.models.agegenderrace || ((instance.config.face.enabled && instance.config.face.agegenderrace.enabled) ? agegenderrace.load(instance.config) : null),\n ]);\n } else { // load models sequentially\n if (instance.config.face.enabled && !instance.models.face) instance.models.face = await facemesh.load(instance.config);\n if (instance.config.face.enabled && instance.config.face.emotion.enabled && !instance.models.emotion) instance.models.emotion = await emotion.load(instance.config);\n if (instance.config.hand.enabled && !instance.models.handpose && instance.config.hand.detector.modelPath.includes('handdetect')) instance.models.handpose = await handpose.load(instance.config);\n if (instance.config.hand.enabled && !instance.models.handtrack && instance.config.hand.detector.modelPath.includes('handtrack')) instance.models.handtrack = await handtrack.load(instance.config);\n if (instance.config.body.enabled && !instance.models.posenet && instance.config.body.modelPath.includes('posenet')) instance.models.posenet = await posenet.load(instance.config);\n if (instance.config.body.enabled && !instance.models.blazepose && instance.config.body.modelPath.includes('blazepose')) instance.models.blazepose = await blazepose.load(instance.config);\n if (instance.config.body.enabled && !instance.models.efficientpose && instance.config.body.modelPath.includes('efficientpose')) instance.models.efficientpose = await blazepose.load(instance.config);\n if (instance.config.body.enabled && !instance.models.movenet && instance.config.body.modelPath.includes('movenet')) instance.models.movenet = await movenet.load(instance.config);\n if (instance.config.object.enabled && !instance.models.nanodet && instance.config.object.modelPath.includes('nanodet')) instance.models.nanodet = await nanodet.load(instance.config);\n if (instance.config.object.enabled && !instance.models.centernet && instance.config.object.modelPath.includes('centernet')) instance.models.centernet = await centernet.load(instance.config);\n if (instance.config.face.enabled && instance.config.face.description.enabled && !instance.models.faceres) instance.models.faceres = await faceres.load(instance.config);\n if (instance.config.segmentation.enabled && !instance.models.segmentation) instance.models.segmentation = await segmentation.load(instance.config);\n // if (instance.config.face.enabled && instance.config.face.agegenderrace.enabled && !instance.models.agegenderrace) instance.models.agegenderrace = await agegenderrace.load(instance.config);\n }\n}\n\nexport async function validate(instance) {\n interface Op { name: string, category: string, op: string }\n const simpleOps = ['const', 'placeholder', 'noop', 'pad', 'squeeze', 'add', 'sub', 'mul', 'div'];\n for (const defined of Object.keys(instance.models)) {\n if (instance.models[defined]) { // check if model is loaded\n let models: GraphModel[] = [];\n if (Array.isArray(instance.models[defined])) {\n models = instance.models[defined]\n .filter((model) => (model !== null))\n .map((model) => ((model && model.executor) ? model : model.model));\n } else {\n models = [instance.models[defined]];\n }\n for (const model of models) {\n if (!model) {\n if (instance.config.debug) log('model marked as loaded but not defined:', defined);\n continue;\n }\n const ops: string[] = [];\n // @ts-ignore // executor is a private method\n const executor = model?.executor;\n if (executor && executor.graph.nodes) {\n for (const kernel of Object.values(executor.graph.nodes)) {\n const op = (kernel as Op).op.toLowerCase();\n if (!ops.includes(op)) ops.push(op);\n }\n } else {\n if (!executor && instance.config.debug) log('model signature not determined:', defined);\n }\n const missing: string[] = [];\n for (const op of ops) {\n if (!simpleOps.includes(op) // exclude simple ops\n && !instance.env.kernels.includes(op) // check actual kernel ops\n && !instance.env.kernels.includes(op.replace('_', '')) // check variation without _\n && !instance.env.kernels.includes(op.replace('native', '')) // check standard variation\n && !instance.env.kernels.includes(op.replace('v2', ''))) { // check non-versioned variation\n missing.push(op);\n }\n }\n // log('model validation ops:', defined, ops);\n if (missing.length > 0 && instance.config.debug) log('model validation:', defined, missing);\n }\n }\n }\n}\n", "/**\n * Module that analyzes person age\n * Obsolete\n */\n\nimport { log, now } from './helpers';\nimport * as tf from '../dist/tfjs.esm.js';\nimport * as facemesh from './blazeface/facemesh';\nimport * as emotion from './emotion/emotion';\nimport * as faceres from './faceres/faceres';\nimport type { FaceResult } from './result';\nimport type { Tensor } from './tfjs/types';\n\n// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\nconst rad2deg = (theta) => Math.round((theta * 180) / Math.PI);\n\nconst calculateGaze = (face): { bearing: number, strength: number } => {\n const radians = (pt1, pt2) => Math.atan2(pt1[1] - pt2[1], pt1[0] - pt2[0]); // function to calculate angle between any two points\n if (!face.annotations['rightEyeIris'] || !face.annotations['leftEyeIris']) return { bearing: 0, strength: 0 };\n\n const offsetIris = [0, -0.1]; // iris center may not align with average of eye extremes\n const eyeRatio = 1; // factor to normalize changes x vs y\n\n const left = face.mesh[33][2] > face.mesh[263][2]; // pick left or right eye depending which one is closer bazed on outsize point z axis\n const irisCenter = left ? face.mesh[473] : face.mesh[468];\n const eyeCenter = left // eye center is average of extreme points on x axis for both x and y, ignoring y extreme points as eyelids naturally open/close more when gazing up/down so relative point is less precise\n ? [(face.mesh[133][0] + face.mesh[33][0]) / 2, (face.mesh[133][1] + face.mesh[33][1]) / 2]\n : [(face.mesh[263][0] + face.mesh[362][0]) / 2, (face.mesh[263][1] + face.mesh[362][1]) / 2];\n const eyeSize = left // eye size is difference between extreme points for both x and y, used to normalize & squarify eye dimensions\n ? [face.mesh[133][0] - face.mesh[33][0], face.mesh[23][1] - face.mesh[27][1]]\n : [face.mesh[263][0] - face.mesh[362][0], face.mesh[253][1] - face.mesh[257][1]];\n\n const eyeDiff = [ // x distance between extreme point and center point normalized with eye size\n (eyeCenter[0] - irisCenter[0]) / eyeSize[0] - offsetIris[0],\n eyeRatio * (irisCenter[1] - eyeCenter[1]) / eyeSize[1] - offsetIris[1],\n ];\n let strength = Math.sqrt((eyeDiff[0] ** 2) + (eyeDiff[1] ** 2)); // vector length is a diagonal between two differences\n strength = Math.min(strength, face.boxRaw[2] / 2, face.boxRaw[3] / 2); // limit strength to half of box size to avoid clipping due to low precision\n const bearing = (radians([0, 0], eyeDiff) + (Math.PI / 2)) % Math.PI; // using eyeDiff instead eyeCenter/irisCenter combo due to manual adjustments and rotate clockwise 90degrees\n\n return { bearing, strength };\n};\n\nconst calculateFaceAngle = (face, imageSize): {\n angle: { pitch: number, yaw: number, roll: number },\n matrix: [number, number, number, number, number, number, number, number, number],\n gaze: { bearing: number, strength: number },\n} => {\n // const degrees = (theta) => Math.abs(((theta * 180) / Math.PI) % 360);\n const normalize = (v) => { // normalize vector\n const length = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);\n v[0] /= length;\n v[1] /= length;\n v[2] /= length;\n return v;\n };\n const subVectors = (a, b) => { // vector subtraction (a - b)\n const x = a[0] - b[0];\n const y = a[1] - b[1];\n const z = a[2] - b[2];\n return [x, y, z];\n };\n const crossVectors = (a, b) => { // vector cross product (a x b)\n const x = a[1] * b[2] - a[2] * b[1];\n const y = a[2] * b[0] - a[0] * b[2];\n const z = a[0] * b[1] - a[1] * b[0];\n return [x, y, z];\n };\n // 3x3 rotation matrix to Euler angles based on https://www.geometrictools.com/Documentation/EulerAngles.pdf\n const rotationMatrixToEulerAngle = (r) => {\n // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\n const [r00, r01, r02, r10, r11, r12, r20, r21, r22] = r;\n let thetaX: number;\n let thetaY: number;\n let thetaZ: number;\n if (r10 < 1) { // YZX calculation\n if (r10 > -1) {\n thetaZ = Math.asin(r10);\n thetaY = Math.atan2(-r20, r00);\n thetaX = Math.atan2(-r12, r11);\n } else {\n thetaZ = -Math.PI / 2;\n thetaY = -Math.atan2(r21, r22);\n thetaX = 0;\n }\n } else {\n thetaZ = Math.PI / 2;\n thetaY = Math.atan2(r21, r22);\n thetaX = 0;\n }\n if (isNaN(thetaX)) thetaX = 0;\n if (isNaN(thetaY)) thetaY = 0;\n if (isNaN(thetaZ)) thetaZ = 0;\n return { pitch: 2 * -thetaX, yaw: 2 * -thetaY, roll: 2 * -thetaZ };\n };\n // simple Euler angle calculation based existing 3D mesh\n // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\n const meshToEulerAngle = (mesh) => {\n const radians = (a1, a2, b1, b2) => Math.atan2(b2 - a2, b1 - a1);\n // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\n const angle = {\n // values are in radians in range of -pi/2 to pi/2 which is -90 to +90 degrees, value of 0 means center\n // pitch is face move up/down\n pitch: radians(mesh[10][1], mesh[10][2], mesh[152][1], mesh[152][2]), // looking at y,z of top and bottom points of the face\n // yaw is face turn left/right\n yaw: radians(mesh[33][0], mesh[33][2], mesh[263][0], mesh[263][2]), // looking at x,z of outside corners of leftEye and rightEye\n // roll is face lean left/right\n roll: radians(mesh[33][0], mesh[33][1], mesh[263][0], mesh[263][1]), // looking at x,y of outside corners of leftEye and rightEye\n };\n return angle;\n };\n\n // initialize gaze and mesh\n const mesh = face.meshRaw;\n if (!mesh || mesh.length < 300) return { angle: { pitch: 0, yaw: 0, roll: 0 }, matrix: [1, 0, 0, 0, 1, 0, 0, 0, 1], gaze: { bearing: 0, strength: 0 } };\n\n const size = Math.max(face.boxRaw[2] * imageSize[0], face.boxRaw[3] * imageSize[1]) / 1.5;\n // top, bottom, left, right\n const pts = [mesh[10], mesh[152], mesh[234], mesh[454]].map((pt) => [\n // make the xyz coordinates proportional, independent of the image/box size\n pt[0] * imageSize[0] / size,\n pt[1] * imageSize[1] / size,\n pt[2],\n ]);\n\n const y_axis = normalize(subVectors(pts[1], pts[0]));\n let x_axis = normalize(subVectors(pts[3], pts[2]));\n const z_axis = normalize(crossVectors(x_axis, y_axis));\n // adjust x_axis to make sure that all axes are perpendicular to each other\n x_axis = crossVectors(y_axis, z_axis);\n\n // Rotation Matrix from Axis Vectors - http://renderdan.blogspot.com/2006/05/rotation-matrix-from-axis-vectors.html\n // 3x3 rotation matrix is flatten to array in row-major order. Note that the rotation represented by this matrix is inverted.\n const matrix: [number, number, number, number, number, number, number, number, number] = [\n x_axis[0], x_axis[1], x_axis[2],\n y_axis[0], y_axis[1], y_axis[2],\n z_axis[0], z_axis[1], z_axis[2],\n ];\n const angle = rotationMatrixToEulerAngle(matrix);\n // const angle = meshToEulerAngle(mesh);\n\n // we have iris keypoints so we can calculate gaze direction\n const gaze = mesh.length === 478 ? calculateGaze(face) : { bearing: 0, strength: 0 };\n\n return { angle, matrix, gaze };\n};\n\nexport const detectFace = async (parent /* instance of human */, input: Tensor): Promise => {\n // run facemesh, includes blazeface and iris\n // eslint-disable-next-line no-async-promise-executor\n let timeStamp;\n let ageRes;\n let gearRes;\n let genderRes;\n let emotionRes;\n let embeddingRes;\n let descRes;\n const faceRes: Array = [];\n parent.state = 'run:face';\n timeStamp = now();\n const faces = await facemesh.predict(input, parent.config);\n parent.performance.face = Math.trunc(now() - timeStamp);\n if (!input.shape || input.shape.length !== 4) return [];\n if (!faces) return [];\n // for (const face of faces) {\n for (let i = 0; i < faces.length; i++) {\n parent.analyze('Get Face');\n\n // is something went wrong, skip the face\n // @ts-ignore possibly undefied\n if (!faces[i].tensor || faces[i].tensor['isDisposedInternal']) {\n log('Face object is disposed:', faces[i].tensor);\n continue;\n }\n\n const rotation = calculateFaceAngle(faces[i], [input.shape[2], input.shape[1]]);\n\n // run emotion, inherits face from blazeface\n parent.analyze('Start Emotion:');\n if (parent.config.async) {\n emotionRes = parent.config.face.emotion.enabled ? emotion.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : {};\n } else {\n parent.state = 'run:emotion';\n timeStamp = now();\n emotionRes = parent.config.face.emotion.enabled ? await emotion.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : {};\n parent.performance.emotion = Math.trunc(now() - timeStamp);\n }\n parent.analyze('End Emotion:');\n\n // run gear, inherits face from blazeface\n /*\n parent.analyze('Start GEAR:');\n if (parent.config.async) {\n gearRes = parent.config.face.agegenderrace.enabled ? agegenderrace.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : {};\n } else {\n parent.state = 'run:gear';\n timeStamp = now();\n gearRes = parent.config.face.agegenderrace.enabled ? await agegenderrace.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : {};\n parent.performance.emotion = Math.trunc(now() - timeStamp);\n }\n parent.analyze('End GEAR:');\n */\n\n // run emotion, inherits face from blazeface\n parent.analyze('Start Description:');\n if (parent.config.async) {\n descRes = parent.config.face.description.enabled ? faceres.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : [];\n } else {\n parent.state = 'run:description';\n timeStamp = now();\n descRes = parent.config.face.description.enabled ? await faceres.predict(faces[i].tensor || tf.tensor([]), parent.config, i, faces.length) : [];\n parent.performance.embedding = Math.trunc(now() - timeStamp);\n }\n parent.analyze('End Description:');\n\n // if async wait for results\n if (parent.config.async) {\n [ageRes, genderRes, emotionRes, embeddingRes, descRes, gearRes] = await Promise.all([ageRes, genderRes, emotionRes, embeddingRes, descRes, gearRes]);\n }\n\n parent.analyze('Finish Face:');\n\n // calculate iris distance\n // iris: array[ center, left, top, right, bottom]\n if (!parent.config.face.iris.enabled && faces[i]?.annotations?.leftEyeIris && faces[i]?.annotations?.rightEyeIris) {\n delete faces[i].annotations.leftEyeIris;\n delete faces[i].annotations.rightEyeIris;\n }\n const irisSize = (faces[i].annotations?.leftEyeIris && faces[i].annotations?.rightEyeIris)\n /* note: average human iris size is 11.7mm */\n ? Math.max(Math.abs(faces[i].annotations.leftEyeIris[3][0] - faces[i].annotations.leftEyeIris[1][0]), Math.abs(faces[i].annotations.rightEyeIris[4][1] - faces[i].annotations.rightEyeIris[2][1])) / input.shape[2]\n : 0;\n\n // optionally return tensor\n const tensor = parent.config.face.detector.return ? tf.squeeze(faces[i].tensor) : null;\n // dispose original face tensor\n tf.dispose(faces[i].tensor);\n // delete temp face image\n if (faces[i].tensor) delete faces[i].tensor;\n // combine results\n faceRes.push({\n ...faces[i],\n id: i,\n age: descRes.age,\n gender: descRes.gender,\n genderScore: descRes.genderScore,\n embedding: descRes.descriptor,\n emotion: emotionRes,\n iris: irisSize !== 0 ? Math.trunc(500 / irisSize / 11.7) / 100 : 0,\n rotation,\n tensor,\n });\n parent.analyze('End Face');\n }\n parent.analyze('End FaceMesh:');\n if (parent.config.async) {\n if (parent.performance.face) delete parent.performance.face;\n if (parent.performance.age) delete parent.performance.age;\n if (parent.performance.gender) delete parent.performance.gender;\n if (parent.performance.emotion) delete parent.performance.emotion;\n }\n return faceRes;\n};\n", "/**\n * Gesture detection module\n */\n\nimport type { GestureResult } from '../result';\nimport * as fingerPose from '../fingerpose/fingerpose';\n\n/**\n * @typedef FaceGesture\n */\nexport type FaceGesture =\n `facing ${'left' | 'center' | 'right'}`\n | `blink ${'left' | 'right'} eye`\n | `mouth ${number}% open`\n | `head ${'up' | 'down'}`;\n\n/**\n * @typedef IrisGesture\n */\nexport type IrisGesture =\n 'facing center'\n | `looking ${'left' | 'right' | 'up' | 'down'}`\n | 'looking center';\n\n/**\n * @typedef BodyGesture\n */\nexport type BodyGesture =\n `leaning ${'left' | 'right'}`\n | `raise ${'left' | 'right'} hand`\n | 'i give up';\n\n/**\n * @typedef BodyGesture\n */\nexport type HandGesture =\n `${'thumb' | 'index' | 'middle' | 'ring' | 'pinky'} forward`\n | `${'thumb' | 'index' | 'middle' | 'ring' | 'pinky'} up`\n | 'victory'\n | 'thumbs up';\n\nexport const body = (res): GestureResult[] => {\n if (!res) return [];\n const gestures: Array<{ body: number, gesture: BodyGesture }> = [];\n for (let i = 0; i < res.length; i++) {\n // raising hands\n const leftWrist = res[i].keypoints.find((a) => (a.part === 'leftWrist'));\n const rightWrist = res[i].keypoints.find((a) => (a.part === 'rightWrist'));\n const nose = res[i].keypoints.find((a) => (a.part === 'nose'));\n if (nose && leftWrist && rightWrist && (leftWrist.position.y < nose.position.y) && (rightWrist.position.y < nose.position.y)) gestures.push({ body: i, gesture: 'i give up' });\n else if (nose && leftWrist && (leftWrist.position.y < nose.position.y)) gestures.push({ body: i, gesture: 'raise left hand' });\n else if (nose && rightWrist && (rightWrist.position.y < nose.position.y)) gestures.push({ body: i, gesture: 'raise right hand' });\n\n // leaning\n const leftShoulder = res[i].keypoints.find((a) => (a.part === 'leftShoulder'));\n const rightShoulder = res[i].keypoints.find((a) => (a.part === 'rightShoulder'));\n if (leftShoulder && rightShoulder) gestures.push({ body: i, gesture: `leaning ${(leftShoulder.position.y > rightShoulder.position.y) ? 'left' : 'right'}` });\n }\n return gestures;\n};\n\nexport const face = (res): GestureResult[] => {\n if (!res) return [];\n const gestures: Array<{ face: number, gesture: FaceGesture }> = [];\n for (let i = 0; i < res.length; i++) {\n if (res[i].mesh && res[i].mesh.length > 0) {\n const eyeFacing = res[i].mesh[33][2] - res[i].mesh[263][2];\n if (Math.abs(eyeFacing) < 10) gestures.push({ face: i, gesture: 'facing center' });\n else gestures.push({ face: i, gesture: `facing ${eyeFacing < 0 ? 'left' : 'right'}` });\n const openLeft = Math.abs(res[i].mesh[374][1] - res[i].mesh[386][1]) / Math.abs(res[i].mesh[443][1] - res[i].mesh[450][1]); // center of eye inner lid y coord div center of wider eye border y coord\n if (openLeft < 0.2) gestures.push({ face: i, gesture: 'blink left eye' });\n const openRight = Math.abs(res[i].mesh[145][1] - res[i].mesh[159][1]) / Math.abs(res[i].mesh[223][1] - res[i].mesh[230][1]); // center of eye inner lid y coord div center of wider eye border y coord\n if (openRight < 0.2) gestures.push({ face: i, gesture: 'blink right eye' });\n const mouthOpen = Math.min(100, 500 * Math.abs(res[i].mesh[13][1] - res[i].mesh[14][1]) / Math.abs(res[i].mesh[10][1] - res[i].mesh[152][1]));\n if (mouthOpen > 10) gestures.push({ face: i, gesture: `mouth ${Math.trunc(mouthOpen)}% open` });\n const chinDepth = res[i].mesh[152][2];\n if (Math.abs(chinDepth) > 10) gestures.push({ face: i, gesture: `head ${chinDepth < 0 ? 'up' : 'down'}` });\n }\n }\n return gestures;\n};\n\nexport const iris = (res): GestureResult[] => {\n if (!res) return [];\n const gestures: Array<{ iris: number, gesture: IrisGesture }> = [];\n for (let i = 0; i < res.length; i++) {\n if (!res[i].annotations || !res[i].annotations.leftEyeIris || !res[i].annotations.rightEyeIris) continue;\n const sizeXLeft = res[i].annotations.leftEyeIris[3][0] - res[i].annotations.leftEyeIris[1][0];\n const sizeYLeft = res[i].annotations.leftEyeIris[4][1] - res[i].annotations.leftEyeIris[2][1];\n const areaLeft = Math.abs(sizeXLeft * sizeYLeft);\n\n const sizeXRight = res[i].annotations.rightEyeIris[3][0] - res[i].annotations.rightEyeIris[1][0];\n const sizeYRight = res[i].annotations.rightEyeIris[4][1] - res[i].annotations.rightEyeIris[2][1];\n const areaRight = Math.abs(sizeXRight * sizeYRight);\n\n let center = false;\n const difference = Math.abs(areaLeft - areaRight) / Math.max(areaLeft, areaRight);\n if (difference < 0.25) {\n center = true;\n gestures.push({ iris: i, gesture: 'facing center' });\n }\n\n const rightIrisCenterX = Math.abs(res[i].mesh[33][0] - res[i].annotations.rightEyeIris[0][0]) / res[i].box[2];\n const leftIrisCenterX = Math.abs(res[i].mesh[263][0] - res[i].annotations.leftEyeIris[0][0]) / res[i].box[2];\n if (leftIrisCenterX > 0.06 || rightIrisCenterX > 0.06) center = false;\n if (leftIrisCenterX > 0.06) gestures.push({ iris: i, gesture: 'looking right' });\n if (rightIrisCenterX > 0.06) gestures.push({ iris: i, gesture: 'looking left' });\n\n const rightIrisCenterY = Math.abs(res[i].mesh[145][1] - res[i].annotations.rightEyeIris[0][1]) / res[i].box[3];\n const leftIrisCenterY = Math.abs(res[i].mesh[374][1] - res[i].annotations.leftEyeIris[0][1]) / res[i].box[3];\n if (leftIrisCenterY < 0.01 || rightIrisCenterY < 0.01 || leftIrisCenterY > 0.022 || rightIrisCenterY > 0.022) center = false;\n if (leftIrisCenterY < 0.01 || rightIrisCenterY < 0.01) gestures.push({ iris: i, gesture: 'looking down' });\n if (leftIrisCenterY > 0.022 || rightIrisCenterY > 0.022) gestures.push({ iris: i, gesture: 'looking up' });\n\n // still center;\n if (center) gestures.push({ iris: i, gesture: 'looking center' });\n }\n return gestures;\n};\n\nexport const hand = (res): GestureResult[] => {\n if (!res) return [];\n const gestures: Array<{ hand: number, gesture: HandGesture }> = [];\n for (let i = 0; i < res.length; i++) {\n const fingers: Array<{ name: string, position: number }> = [];\n if (res[i]['annotations']) {\n for (const [finger, pos] of Object.entries(res[i]['annotations'])) {\n if (finger !== 'palmBase' && Array.isArray(pos) && pos[0]) fingers.push({ name: finger.toLowerCase(), position: pos[0] }); // get tip of each finger\n }\n }\n if (fingers && fingers.length > 0) {\n const closest = fingers.reduce((best, a) => (best.position[2] < a.position[2] ? best : a));\n gestures.push({ hand: i, gesture: `${closest.name} forward` as HandGesture });\n const highest = fingers.reduce((best, a) => (best.position[1] < a.position[1] ? best : a));\n gestures.push({ hand: i, gesture: `${highest.name} up` as HandGesture });\n }\n if (res[i]['keypoints']) {\n const poses = fingerPose.match(res[i]['keypoints']);\n for (const pose of poses) gestures.push({ hand: i, gesture: pose.name as HandGesture });\n }\n }\n return gestures;\n};\n", "/**\n * Module that implements helper draw functions, exposed as human.draw\n */\n\nimport { TRI468 as triangulation } from './blazeface/coords';\nimport { mergeDeep, now } from './helpers';\nimport type { Result, FaceResult, BodyResult, HandResult, ObjectResult, GestureResult, PersonResult } from './result';\n\n/**\n * Draw Options\n * Accessed via `human.draw.options` or provided per each draw method as the drawOptions optional parameter\n * -color: draw color\n * -labelColor: color for labels\n * -shadowColor: optional shadow color for labels\n * -font: font for labels\n * -lineHeight: line height for labels, used for multi-line labels,\n * -lineWidth: width of any lines,\n * -pointSize: size of any point,\n * -roundRect: for boxes, round corners by this many pixels,\n * -drawPoints: should points be drawn,\n * -drawLabels: should labels be drawn,\n * -drawBoxes: should boxes be drawn,\n * -drawPolygons: should polygons be drawn,\n * -fillPolygons: should drawn polygons be filled,\n * -useDepth: use z-axis coordinate as color shade,\n * -useCurves: draw polygons as cures or as lines,\n * -bufferedOutput: experimental: allows to call draw methods multiple times for each detection and interpolate results between results thus achieving smoother animations\n */\nexport interface DrawOptions {\n color: string,\n labelColor: string,\n shadowColor: string,\n font: string,\n lineHeight: number,\n lineWidth: number,\n pointSize: number,\n roundRect: number,\n drawPoints: boolean,\n drawLabels: boolean,\n drawBoxes: boolean,\n drawPolygons: boolean,\n drawGaze: boolean,\n fillPolygons: boolean,\n useDepth: boolean,\n useCurves: boolean,\n bufferedOutput: boolean,\n}\n\nexport const options: DrawOptions = {\n color: 'rgba(173, 216, 230, 0.6)', // 'lightblue' with light alpha channel\n labelColor: 'rgba(173, 216, 230, 1)', // 'lightblue' with dark alpha channel\n shadowColor: 'black',\n font: 'small-caps 14px \"Segoe UI\"',\n lineHeight: 18,\n lineWidth: