From fa7875ddb1b1db247adfb994170e42a69290b55b Mon Sep 17 00:00:00 2001 From: ivmartel Date: Wed, 27 Nov 2024 11:03:44 +0100 Subject: [PATCH] Beta v0.35.0-beta.3 --- dist/dwv.d.ts | 13 ------------- dist/dwv.min.js | 2 +- dist/dwv.min.js.map | 2 +- package.json | 2 +- resources/api/dwv.api.md | 2 -- resources/doc/jsdoc.conf.json | 4 ++-- src/dicom/dicomParser.js | 2 +- 7 files changed, 6 insertions(+), 21 deletions(-) diff --git a/dist/dwv.d.ts b/dist/dwv.d.ts index d16c984be0..a56c5f9f4d 100644 --- a/dist/dwv.d.ts +++ b/dist/dwv.d.ts @@ -1918,19 +1918,6 @@ export declare class DrawLayer { * @returns {boolean} True if the position was updated. */ setCurrentPosition(position: Point, index?: Index): boolean; - /** - * Get the current position group. - * - * @returns {Konva.Group|undefined} The Konva.Group. - */ - getCurrentPosGroup(): Konva.Group | undefined; - /** - * Get a Konva group using its id. - * - * @param {string} id The group id. - * @returns {object|undefined} The Konva group. - */ - getGroup(id: string): object | undefined; /** * Add an event listener to this class. * diff --git a/dist/dwv.min.js b/dist/dwv.min.js index fa58a7ec72..1c11b791c5 100644 --- a/dist/dwv.min.js +++ b/dist/dwv.min.js @@ -1,2 +1,2 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("konva"),require("magic-wand-tool"),require("jszip")):"function"==typeof define&&define.amd?define(["konva","konmagic-wand-tool","jszip"],t):"object"==typeof exports?exports.dwv=t(require("konva"),require("magic-wand-tool"),require("jszip")):e.dwv=t(e.Konva,e.MagicWand,e.JSZip)}(this,(function(e,t,n){return function(){"use strict";var i={654:function(e){e.exports=n},944:function(t){t.exports=e},324:function(e){e.exports=t}},r={};function o(e){var t=r[e];if(void 0!==t)return t.exports;var n=r[e]={exports:{}};return i[e](n,n.exports,o),n.exports}o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,{a:t}),t},o.d=function(e,t){for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var a={};o.r(a),o.d(a,{Annotation:function(){return Bi},AnnotationGroup:function(){return Jn},AnnotationGroupFactory:function(){return to},App:function(){return Io},AppOptions:function(){return vo},ChangeSegmentColourCommand:function(){return Po},Circle:function(){return pi},ColourMap:function(){return f},DataElement:function(){return ve},DeleteSegmentCommand:function(){return Lo},DicomCode:function(){return kt},DicomData:function(){return no},DicomParser:function(){return Ge},DicomSRContent:function(){return Kr},DicomWriter:function(){return Qt},DrawController:function(){return $n},DrawLayer:function(){return Ci},DrawShapeHandler:function(){return Di},Ellipse:function(){return Si},Geometry:function(){return nt},Image:function(){return Un},Index:function(){return s},LayerGroup:function(){return Ki},MaskFactory:function(){return Fn},MaskSegment:function(){return pn},MaskSegmentHelper:function(){return To},MaskSegmentViewHelper:function(){return wo},Matrix33:function(){return A},NumberRange:function(){return et},Orientation:function(){return St},OverlayData:function(){return Do},PlaneHelper:function(){return Bn},Point:function(){return E},Point2D:function(){return R},Point3D:function(){return F},Protractor:function(){return hi},RGB:function(){return C},ROI:function(){return di},Rectangle:function(){return ci},RescaleSlopeAndIntercept:function(){return Xe},Scalar2D:function(){return Oo},Scalar3D:function(){return Ao},ScrollWheel:function(){return Hn},Size:function(){return je},Spacing:function(){return tt},Tag:function(){return de},TagValueExtractor:function(){return Lt},ToolConfig:function(){return yo},ToolboxController:function(){return lr},Vector3D:function(){return P},View:function(){return Nn},ViewConfig:function(){return Co},ViewController:function(){return Gn},ViewLayer:function(){return Xi},WindowLevel:function(){return u},WriterRule:function(){return At},addTagsToDictionary:function(){return Z},buildMultipart:function(){return X},createImage:function(){return En},createMaskImage:function(){return qn},createView:function(){return Vn},customUI:function(){return ki},decoderScripts:function(){return fr},defaultPresets:function(){return d},defaults:function(){return xi},getDefaultDicomSegJson:function(){return Rn},getDicomSRContentItem:function(){return $r},getDwvVersion:function(){return Le},getElementsFromJSONTags:function(){return Bt},getEllipseIndices:function(){return gi},getLayerDetailsFromEvent:function(){return Zi},getMousePoint:function(){return Wi},getOrientationName:function(){return ft},getPixelDataTag:function(){return De},getRectangleIndices:function(){return ui},getReverseOrientation:function(){return Ae},getSRContent:function(){return Jr},getTagFromKey:function(){return Se},getTouchPoints:function(){return zi},getTypedArray:function(){return Ue},getUID:function(){return xt},hasDicomPrefix:function(){return Pe},i18n:function(){return q},isEqualRgb:function(){return y},labToUintLab:function(){return v},logger:function(){return c},luts:function(){return D},precisionRound:function(){return B},srgbToCielab:function(){return T},toolList:function(){return Mi},toolOptions:function(){return Qi}});class s{#e;constructor(e){if(!e||void 0===e)throw new Error("Cannot create index with no values.");if(0===e.length)throw new Error("Cannot create index with empty values.");if(!e.every((function(e){return!isNaN(e)})))throw new Error("Cannot create index with non number values.");this.#e=e}get(e){return this.#e[e]}length(){return this.#e.length}toString(){return"("+this.#e.toString()+")"}getValues(){return this.#e.slice()}canCompare(e){return!!e&&this.length()===e.length()}equals(e){if(!this.canCompare(e))return!1;for(let t=0,n=this.length();tthis.#u?this.#l:e*this.#d+this.#h}}class S{#g;#p;#r;#m=0;#f=!0;constructor(e,t,n){if(this.#g=e,t){const e=this.#g.getLength();this.#m=e/2}else this.#m=0;this.#f=n}getVoiLut(){return this.#p}getModalityLut(){return this.#g}setVoiLut(e){if(this.#p=e,this.#p.setSignedOffset(this.#g.getRSI().getSlope()*this.#m),this.#f){const e=this.#g.getLength();this.#r=new Uint8ClampedArray(e);for(let t=0;t255?255:t})),green:g((function(e){const t=256/3;let n=0;return e>=t&&(n=3*(e-t),n>255)?255:n})),blue:g((function(e){const t=256/3;let n=0;return e>=2*t&&(n=3*(e-2*t),n>255)?255:n}))},hot_iron:{red:[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],green:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,255],blue:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,255]},pet:{red:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205,207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],green:[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,128,126,124,122,120,118,116,114,112,110,108,106,104,102,100,98,96,94,92,90,88,86,84,82,80,78,76,74,72,70,68,66,64,63,61,59,57,55,53,51,49,47,45,43,41,39,37,35,33,31,29,27,25,23,21,19,17,15,13,11,9,7,5,3,1,0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,255],blue:[0,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205,207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,252,248,244,240,236,232,228,224,220,216,212,208,204,200,196,192,188,184,180,176,172,168,164,160,156,152,148,144,140,136,132,128,124,120,116,112,108,104,100,96,92,88,84,80,76,72,68,64,60,56,52,48,44,40,36,32,28,24,20,16,12,8,4,0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,85,89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157,161,165,170,174,178,182,186,190,194,198,202,206,210,214,218,222,226,230,234,238,242,246,250,255]},hot_metal_blue:{red:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,9,12,15,18,21,24,26,29,32,35,38,41,44,47,50,52,55,57,59,62,64,66,69,71,74,76,78,81,83,85,88,90,93,96,99,102,105,108,111,114,116,119,122,125,128,131,134,137,140,143,146,149,152,155,158,161,164,166,169,172,175,178,181,184,187,190,194,198,201,205,209,213,217,221,224,228,232,236,240,244,247,251,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],green:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,8,9,11,13,15,17,19,21,23,24,26,28,30,32,34,36,38,40,41,43,45,47,49,51,53,55,56,58,60,62,64,66,68,70,72,73,75,77,79,81,83,85,87,88,90,92,94,96,98,100,102,104,105,107,109,111,113,115,117,119,120,122,124,126,128,130,132,134,136,137,139,141,143,145,147,149,151,152,154,156,158,160,162,164,166,168,169,171,173,175,177,179,181,183,184,186,188,190,192,194,196,198,200,201,203,205,207,209,211,213,215,216,218,220,222,224,226,228,229,231,233,235,237,239,240,242,244,246,248,250,251,253,255],blue:[0,2,4,6,8,10,12,14,16,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,184,186,188,190,192,194,196,198,200,197,194,191,188,185,182,179,176,174,171,168,165,162,159,156,153,150,144,138,132,126,121,115,109,103,97,91,85,79,74,68,62,56,50,47,44,41,38,35,32,29,26,24,21,18,15,12,9,6,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,9,12,15,18,21,24,26,29,32,35,38,41,44,47,50,53,56,59,62,65,68,71,74,76,79,82,85,88,91,94,97,100,103,106,109,112,115,118,121,124,126,129,132,135,138,141,144,147,150,153,156,159,162,165,168,171,174,176,179,182,185,188,191,194,197,200,203,206,210,213,216,219,223,226,229,232,236,239,242,245,249,252,255]},pet_20step:{red:[0,0,0,0,0,0,0,0,0,0,0,0,0,96,96,96,96,96,96,96,96,96,96,96,96,96,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,80,80,80,80,80,80,80,80,80,80,80,80,80,96,96,96,96,96,96,96,96,96,96,96,96,96,112,112,112,112,112,112,112,112,112,112,112,112,112,128,128,128,128,128,128,128,128,128,128,128,128,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,80,80,80,80,80,80,80,80,80,80,80,80,80,64,64,64,64,64,64,64,64,64,64,64,64,224,224,224,224,224,224,224,224,224,224,224,224,224,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,192,192,192,192,192,192,192,192,192,192,192,192,192,176,176,176,176,176,176,176,176,176,176,176,176,176,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],green:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,80,80,80,80,80,80,80,80,80,80,80,80,80,96,96,96,96,96,96,96,96,96,96,96,96,96,112,112,112,112,112,112,112,112,112,112,112,112,112,128,128,128,128,128,128,128,128,128,128,128,128,96,96,96,96,96,96,96,96,96,96,96,96,96,144,144,144,144,144,144,144,144,144,144,144,144,144,192,192,192,192,192,192,192,192,192,192,192,192,192,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,208,208,208,208,208,208,208,208,208,208,208,208,208,176,176,176,176,176,176,176,176,176,176,176,176,176,144,144,144,144,144,144,144,144,144,144,144,144,96,96,96,96,96,96,96,96,96,96,96,96,96,48,48,48,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255],blue:[0,0,0,0,0,0,0,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,112,112,112,112,112,112,112,112,112,112,112,112,128,128,128,128,128,128,128,128,128,128,128,128,128,176,176,176,176,176,176,176,176,176,176,176,176,176,192,192,192,192,192,192,192,192,192,192,192,192,192,224,224,224,224,224,224,224,224,224,224,224,224,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,80,80,80,80,80,80,80,80,80,80,80,80,80,64,64,64,64,64,64,64,64,64,64,64,64,80,80,80,80,80,80,80,80,80,80,80,80,80,96,96,96,96,96,96,96,96,96,96,96,96,96,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255]}};class C{r;g;b;constructor(e,t,n){this.r=e,this.g=t,this.b=n}}function y(e,t){return null!==e&&null!==t&&void 0!==e&&void 0!==t&&e.r===t.r&&e.g===t.g&&e.b===t.b}function v(e){return{l:655.35*e.l,a:257*e.a+32896,b:257*e.b+32896}}const I={x:95.0489,y:100,z:108.884};function T(e){return function(e){function t(e){let t=null;return t=e>.008856452?Math.pow(e,.333333333):7.787037037*e+.137931034,t}const n=I,i=t(e.y/n.y);return{l:116*i-16,a:500*(t(e.x/n.x)-i),b:200*(i-t(e.z/n.z))}}(function(e){function t(e){let t=null;return t=e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4),t}const n=t(e.r/255),i=t(e.g/255),r=t(e.b/255);return{x:100*(.4124*n+.3576*i+.1805*r),y:100*(.2126*n+.7152*i+.0722*r),z:100*(.0193*n+.1192*i+.9505*r)}}(e))}function L(e){const t={Yellow:"#ffff00",Red:"#ff0000",White:"#ffffff",Green:"#008000",Blue:"#0000ff",Lime:"#00ff00",Fuchsia:"#ff00ff",Black:"#000000"};let n="#ffff00";return void 0!==t[e]&&(n=t[e]),n}class P{#D;#C;#y;constructor(e,t,n){this.#D=e,this.#C=t,this.#y=n}getX(){return this.#D}getY(){return this.#C}getZ(){return this.#y}equals(e){return null!==e&&this.#D===e.getX()&&this.#C===e.getY()&&this.#y===e.getZ()}toString(){return"("+this.#D+", "+this.#C+", "+this.#y+")"}norm(){return Math.sqrt(this.#D*this.#D+this.#C*this.#C+this.#y*this.#y)}crossProduct(e){return new P(this.#C*e.getZ()-e.getY()*this.#y,this.#y*e.getX()-e.getZ()*this.#D,this.#D*e.getY()-e.getX()*this.#C)}dotProduct(e){return this.#D*e.getX()+this.#C*e.getY()+this.#y*e.getZ()}isCodirectional(e){return this.dotProduct(e)>0}}Number.EPSILON;const w=1e-4;function O(e,t,n){return void 0===n&&(n=Number.EPSILON),Math.abs(e-t)0?1:-1;for(let t=0;t<3;++t)t===n.index?e.push(1*i):e.push(0)}return new A(e)}getThirdColMajorDirection(){return this.getColAbsMax(2).index}}function b(){return new A([1,0,0,0,1,0,0,0,1])}function x(e){return e.equals(b())}class R{#D;#C;constructor(e,t){this.#D=e,this.#C=t}getX(){return this.#D}getY(){return this.#C}getValues(){return[this.#D,this.#C]}getCentroid(){return this}equals(e){return null!=e&&this.#D===e.getX()&&this.#C===e.getY()}toString(){return"("+this.#D+", "+this.#C+")"}getDistance(e){const t=this.#D-e.getX(),n=this.#C-e.getY();return Math.sqrt(t*t+n*n)}}class F{#D;#C;#y;constructor(e,t,n){this.#D=e,this.#C=t,this.#y=n}getX(){return this.#D}getY(){return this.#C}getZ(){return this.#y}getValues(){return[this.#D,this.#C,this.#y]}equals(e){return null!==e&&this.#D===e.getX()&&this.#C===e.getY()&&this.#y===e.getZ()}isSimilar(e,t){return null!==e&&O(this.#D,e.getX(),t)&&O(this.#C,e.getY(),t)&&O(this.#y,e.getZ(),t)}toString(){return"("+this.#D+", "+this.#C+", "+this.#y+")"}getDistance(e){return Math.sqrt(this.#I(e))}#I(e){const t=this.#D-e.getX(),n=this.#C-e.getY(),i=this.#y-e.getZ();return t*t+n*n+i*i}getClosest(e){let t=0,n=this.#I(e[t]);for(let i=0;i0?0|n:0;return e.substring(i,i+t.length)===t}function M(e,t){return null!=e&&null!=t&&e.substring(e.length-t.length)===t}function Q(e){const t=[];if(null==e)return t;const n=/{(\w+)}/g;let i=n.exec(e);for(;i;)t.push(i[1]),i=n.exec(e);return t}function V(e){let t=null;if(null!=e&&"."!==e[0]){const n=e.toLowerCase().split(".");1!==n.length&&(t=n.pop(),/[a-z]/.test(t)&&!t.includes("/")||(t=null))}return t}function N(e){const t=new Uint8Array(e.length);for(let n=0,i=e.length;n=e.length)throw new Error("Non valid dimension for toStringId");let n="";for(let i=0;i=e.length)&&(n=0),(void 0===i||i<=n||i>e.length)&&(i=e.length);for(let r=n;ro;t--,o++)r=n[o],n[o]=n[t],n[t]=r}class Te{#w;#O=!0;#A=function(){return new Int8Array(new Int16Array([1]).buffer)[0]>0}();#b;#x;constructor(e,t){this.#w=e,void 0!==t&&(this.#O=t),this.#b=this.#O!==this.#A,this.#x=new DataView(e)}readUint16(e){return this.#x.getUint16(e,this.#O)}readInt16(e){return this.#x.getInt16(e,this.#O)}readUint32(e){return this.#x.getUint32(e,this.#O)}readBigUint64(e){return this.#x.getBigUint64(e,this.#O)}readInt32(e){return this.#x.getInt32(e,this.#O)}readBigInt64(e){return this.#x.getBigInt64(e,this.#O)}readFloat32(e){return this.#x.getFloat32(e,this.#O)}readFloat64(e){return this.#x.getFloat64(e,this.#O)}readBinaryArray(e,t){const n=new Uint8Array(this.#w,e,t),i=8*n.length,r=new Uint8Array(i);let o=0,a=0;for(let e=0;e2^"+e+").")}}return i}function Me(e,t){return t?8:J(e)?12:8}const Qe="00280008",Ve="00280100",Ne="00280103",Be="7FE00010";class Ge{#R={};#F;#E=new Oe;#q=this.#E;#U(e){return this.#E.decode(e)}#M(e){return this.#q.decode(e)}getDefaultCharacterSet(){return this.#F}setDefaultCharacterSet(e){this.#F=e}setDecoderCharacterSet(e){this.#q=new TextDecoder(e)}getDicomElements(){return this.#R}#Q(e,t){const n=e.readHex(t);t+=Uint16Array.BYTES_PER_ELEMENT;const i=e.readHex(t);return t+=Uint16Array.BYTES_PER_ELEMENT,{tag:new de(n,i),endOffset:t}}#V(e,t,n){const i={};let r=this.#N(e,t,n);if(t=r.endOffset,fe(r.tag))return{data:i,endOffset:r.endOffset,isSeqDelim:!0};if(i[r.tag.getKey()]={tag:r.tag,vr:"NONE",vl:r.vl,undefinedLength:r.undefinedLength},r.undefinedLength){let o=!1;for(;!o;)r=this.#N(e,t,n),t=r.endOffset,o=me(r.tag),o||(i[r.tag.getKey()]=r)}else{const o=t;for(t-=r.vl;t8&&"OB"===a&&(c.warn("Reading DICOM pixel data with bitsAllocated>8 and OB VR, treating as OW"),e.vr="OW"),l=[],1===i)l.push(t.readBinaryArray(s,o));else if(8===i)0===n?l.push(t.readUint8Array(s,o)):l.push(t.readInt8Array(s,o));else{if(16!==i)throw new Error("Unsupported bits allocated: "+i);0===n?l.push(t.readUint16Array(s,o)):l.push(t.readInt16Array(s,o))}else if(void 0!==u)if("Uint8"===u)l=t.readUint8Array(s,o);else if("Uint16"===u)l=t.readUint16Array(s,o),"O"!==a[0]&&(l=Array.from(l));else if("Uint32"===u)l=t.readUint32Array(s,o),"O"!==a[0]&&(l=Array.from(l));else if("Uint64"===u)l=t.readUint64Array(s,o);else if("Int16"===u)l=Array.from(t.readInt16Array(s,o));else if("Int32"===u)l=Array.from(t.readInt32Array(s,o));else if("Int64"===u)l=t.readInt64Array(s,o);else if("Float32"===u)l=Array.from(t.readFloat32Array(s,o));else if("Float64"===u)l=Array.from(t.readFloat64Array(s,o));else{if("string"!==u)throw new Error("Unknown VR type: "+u);{const e=t.readUint8Array(s,o);l=ee(a)?this.#M(e):this.#U(e),l=function(e){let t=e;const n=e.length-1;return e[n]===we&&(t=e.substring(0,n)),t=t.trim(),t}(l).split("\\")}}else if("xx"===a)l=Array.from(t.readUint16Array(s,o));else if("ox"===a)l=8===i?0===n?Array.from(t.readUint8Array(s,o)):Array.from(t.readInt8Array(s,o)):0===n?Array.from(t.readUint16Array(s,o)):Array.from(t.readInt16Array(s,o));else if("xs"===a)l=0===n?Array.from(t.readUint16Array(s,o)):Array.from(t.readInt16Array(s,o));else if("AT"===a){const e=t.readUint16Array(s,o);l=[];for(let t=0,n=e.length;t=65&&r<=90&&o>=65&&o<=90);let s=null;if(n===t)s=a?ie:re;else{if(a)throw new Error("Not a valid DICOM file (no magic DICM word foundand implicit VR big endian detected)");s=oe}const l=new ve("UI");return l.tag=new de("0002","0010"),l.value=[s],l.vl=l.value[0].length,l.startOffset=e.startOffset,l.endOffset=l.startOffset+l.vl,l}(i);this.#R[e.tag.getKey()]=e,n=e.value[0],t=0}if(!function(e){return e===ie||e===re||e===oe||Re(e)||Fe(e)||Ee(e)||qe(e)}(n))throw new Error("Unsupported DICOM transfer syntax: '"+n+"' ("+function(e){let t="Unknown";return void 0!==ne[e]&&(t=ne[e]),t}(n)+")");let s=!1;for(be(n)&&(s=!0),xe(n)&&(o=new Te(e,!1));t1&&t.length>e){const n=t.length/e,r=[];let o=0;for(let i=0;i{if(void 0===this.#H[e.type])return;const t=this.#H[e.type].slice();for(let n=0;n2?e:0})));let c=r.indexToOffset(l);void 0===n&&(n=!1);let u=null;u=n?function(t){return e.getRescaledValueAtOffset(t)}:function(t){return e.getValueAtOffset(t)};const d=r.get(0),h=r.get(1),S=r.get(2);let g=r.getDimSize(2);const p=e.getNumberOfComponents(),m=1===e.getPlanarConfiguration(),f=function(e,t,n,i,r,o,a,s){return 1===p?He(e,t,n,i,r,o,a,s):3===p?function(e,t,n,i,r,o,a,s,l){const c=[];return l?(c.push(He(e,t,n,i,r,o,a,s)),c.push(He(e,t+n*i,n,i,r,o,a,s)),c.push(He(e,t+2*n*i,n,i,r,o,a,s))):(i*=3,o*=3,c.push(He(e,t,n,i,r,o,a,s)),c.push(He(e,t+1,n,i,r,o,a,s)),c.push(He(e,t+2,n,i,r,o,a,s))),{next:function(){const e=c[0].next(),t=c[1].next(),n=c[2].next();return e.done?{done:!0,index:n.index}:{value:[e.value,t.value,n.value],done:!1,index:[e.index,t.index,n.index]}}}}(e,3*t,n,i,r,o,a,s,m):void 0};let D=null;if(i&&void 0!==i){const e=i.getColAbsMax(0),t=i.getColAbsMax(2),n=!1,r=!1;let o=null;if(2===t.index)o=d*h,D=0===e.index?f(u,c,o,1,d,d,n,r):f(u,c,o,d,h,1,n,r);else if(0===t.index)o=S*h,D=1===e.index?f(u,c,o,d,h,g,n,r):f(u,c,o,g,S,d,n,r);else{if(1!==t.index)throw new Error("Unknown direction: "+t.index);o=S*d,D=0===e.index?f(u,c,o,1,d,g,n,r):f(u,c,o,g,S,1,n,r)}}else if(1===e.getNumberOfComponents())D=function(e,t,n,i){void 0===i&&(i=1);let r=t;return{next:function(){if(r=e[i+1].index&&++i;const t={value:e[i].value,done:!1,index:n};return++n,t}return{done:!0,index:t}}}}class Xe{#d;#z;constructor(e,t){this.#d=e,this.#z=t}getSlope(){return this.#d}getIntercept(){return this.#z}apply(e){return e*this.#d+this.#z}equals(e){return null!=e&&this.getSlope()===e.getSlope()&&this.getIntercept()===e.getIntercept()}isID(){return 1===this.getSlope()&&0===this.getIntercept()}}class je{#e;constructor(e){if(!e||void 0===e)throw new Error("Cannot create size with no values.");if(0===e.length)throw new Error("Cannot create size with empty values.");if(!e.every((function(e){return!isNaN(e)&&0!==e})))throw new Error("Cannot create size with non number or zero values.");this.#e=e}get(e){return this.#e[e]}length(){return this.#e.length}toString(){return"("+this.#e.toString()+")"}getValues(){return this.#e.slice()}moreThanOne(e){return this.length()>=e+1&&1!==this.get(e)}canScroll3D(e){let t=2;return void 0!==e&&(t=e.getThirdColMajorDirection()),this.moreThanOne(t)}canScroll(e){let t=this.canScroll3D(e);for(let e=3;ethis.length())return null;if(void 0===t)t=0;else if(t<0||t>e)throw new Error("Invalid start value for getDimSize");let n=1;for(let i=t;in-1)throw new Error("Wrong input dir value: "+t[e]);for(let n=0;n=0&&ithis.length()-1)throw new Error("Invalid start value for indexToOffset");let n=0;for(let i=t;i0;--e)i=this.getDimSize(e),t[e]=Math.floor(n/i),n-=t[e]*i;return t[0]=n,new s(t)}get2D(){return{x:this.get(0),y:this.get(1)}}}class Ze{min;max;mean;stdDev;median;p25;p75;constructor(e,t,n,i){this.min=e,this.max=t,this.mean=n,this.stdDev=i}}function _e(e,t){return function(e){return null!=e&&(e.includes("median")||e.includes("p25")||e.includes("p75"))}(t)?function(e){const t=Ke(e);return e.sort((function(e,t){return e-t})),t.median=Je(e,.5),t.p25=Je(e,.25),t.p75=Je(e,.75),t}(e):Ke(e)}function Ke(e){let t=e[0],n=t,i=0,r=0,o=0;const a=e.length;for(let s=0;sn&&(n=o),i+=o,r+=o*o;const s=i/a;let l=r/a-s*s;l<0&&(l=0);const c=Math.sqrt(l);return new Ze(t,n,s,c)}function Je(e,t){if(0===e.length)throw new Error("Empty array provided for percentile calculation.");if(t<0||t>1)throw new Error("Invalid ratio provided for percentile calculation: "+t);if(0===t)return e[0];if(1===t)return e[e.length-1];const n=(e.length-1)*t,i=Math.floor(n),r=e[i];return r+(e[i+1]-r)*(n-i)}function $e(){return Math.random().toString(36).substring(2,15)}class et{min;max;constructor(e,t){this.min=e,this.max=t}}class tt{#e;constructor(e){if(!e||void 0===e)throw new Error("Cannot create spacing with no values.");if(0===e.length)throw new Error("Cannot create spacing with empty values.");if(!e.every((function(e){return!isNaN(e)&&0!==e})))throw new Error("Cannot create spacing with non number or zero values.");this.#e=e}get(e){return this.#e[e]}length(){return this.#e.length}toString(){return"("+this.#e.toString()+")"}getValues(){return this.#e.slice()}equals(e){if(!e)return!1;const t=this.length();if(t!==e.length())return!1;for(let n=0;nw&&c.warn("Varying slice spacing, value: "+i+" (mean: "+n.mean+", min: "+n.min+", max: "+n.max+", stdDev: "+n.stdDev+")"),i}(this.#W);if(void 0!==e&&this.#X.get(2)!==e){c.trace("Using geometric spacing "+e+" instead of tag spacing "+this.#X.get(2));const t=this.#X.getValues();t[2]=e,this.#X=new tt(t)}}getSpacing(e){this.#K&&(this.#J(),this.#K=!1);let t=this.#X;if(e&&void 0!==e){let n=it([this.#X.get(0),this.#X.get(1),this.#X.get(2)],e);n=n.map(Math.abs),t=new tt(n)}return t}getRealSpacing(){return this.getSpacing(this.#_.getInverse().asOneAndZeros())}getOrientation(){return this.#_}getSliceIndex(e,t){let n=this.#W;void 0!==t&&(n=this.#j[t]);const i=e.getClosest(n),r=n[i],o=e.minus(r);return new P(this.#_.get(0,2),this.#_.get(1,2),this.#_.get(2,2)).isCodirectional(o)?i+1:i}appendOrigin(e,t,n){const i=function(t){return t.equals(e)};if(void 0!==n){if(void 0!==this.#j[n].find(i))throw new Error("Cannot append same time origin twice");this.#j[n].splice(t,0,e)}if(void 0===n||n===this.#Z){if(void 0!==this.#W.find(i))throw new Error("Cannot append same origin twice");this.#K=!0,this.#W.splice(t,0,e);const n=this.#Y.getValues();n[2]+=1,this.#Y=new je(n)}}appendFrame(e,t){this.#j[t]=[e];const n=this.#Y.getValues(),i=this.#X.getValues();4===n.length?n[3]+=1:(n.push(2),i.push(1)),this.#Y=new je(n),this.#X=new tt(i)}toString(){return"Origin: "+this.getOrigin()+", Size: "+this.getSize()+", Spacing: "+this.getSpacing()+", Orientation: "+this.getOrientation()}equals(e){return null!==e&&this.getOrigin().equals(e.getOrigin())&&this.getSize().equals(e.getSize())&&this.getSpacing().equals(e.getSpacing())}isInBounds(e){return this.isIndexInBounds(this.worldToIndex(e))}isIndexInBounds(e,t){return this.getSize().isInBounds(e,t)}indexToWorld(e){const t=this.getSpacing(),n=new F(e.get(0)*t.get(0),e.get(1)*t.get(1),e.get(2)*t.get(2)),i=this.getOrientation().multiplyPoint3D(n),r=e.getValues(),o=this.getOrigin();return r[0]=o.getX()+i.getX(),r[1]=o.getY()+i.getY(),r[2]=o.getZ()+i.getZ(),new E(r)}pointToWorld(e){const t=this.getSpacing(),n=new F(e.getX()*t.get(0),e.getY()*t.get(1),e.getZ()*t.get(2)),i=this.getOrientation().multiplyPoint3D(n),r=this.getOrigin();return new F(r.getX()+i.getX(),r.getY()+i.getY(),r.getZ()+i.getZ())}worldToIndex(e){const t=this.getOrigin(),n=new F(e.get(0)-t.getX(),e.get(1)-t.getY(),e.get(2)-t.getZ()),i=this.getOrientation().getInverse().multiplyPoint3D(n),r=e.getValues(),o=this.getSpacing();return r[0]=Math.round(i.getX()/o.get(0)),r[1]=Math.round(i.getY()/o.get(1)),r[2]=Math.round(i.getZ()/o.get(2)),new s(r)}worldToPoint(e){const t=this.getOrigin(),n=new F(e.get(0)-t.getX(),e.get(1)-t.getY(),e.get(2)-t.getZ()),i=this.getOrientation().getInverse().multiplyPoint3D(n),r=e.getValues(),o=this.getSpacing();return r[0]=i.getX()/o.get(0),r[1]=i.getY()/o.get(1),r[2]=i.getZ()/o.get(2),new F(r[0],r[1],r[2])}}function it(e,t){return t.getInverse().multiplyArray3D(e)}function rt(e,t){return t.multiplyArray3D(e)}function ot(e){return("0"+e).slice(-2)}function at(e){if(void 0===e)return;if(1!==e.value.length)return;const t=e.value[0];let n=4,i=6;return 10===t.length&&(n=5,i=8),{year:parseInt(t.substring(0,4),10),monthIndex:t.length>=n+2?parseInt(t.substring(n,n+2),10)-1:0,day:t.length===i+2?parseInt(t.substring(i,i+2),10):0}}function st(e){if(void 0===e)return;if(1!==e.value.length)return;const t=e.value[0],n=parseInt(t.substring(0,2),10),i=t.length>=4?parseInt(t.substring(2,4),10):0,r=t.length>=6?parseInt(t.substring(4,6),10):0,o=t.length>=8?t.substring(7,10):0;return{hours:n,minutes:i,seconds:r,milliseconds:0===o?0:parseInt(o,10)*Math.pow(10,3-o.length)}}function lt(e){return{year:e.getFullYear().toString(),monthIndex:ot((e.getMonth()+1).toString()),day:ot(e.getDate().toString())}}function ct(e){return{hours:ot(e.getHours().toString()),minutes:ot(e.getMinutes().toString()),seconds:ot(e.getSeconds().toString())}}function ut(e){return e.year+e.monthIndex+e.day}function dt(e){return e.hours+e.minutes+e.seconds}function ht(){return new A([1,0,0,0,0,1,0,-1,0])}const St={Axial:"axial",Coronal:"coronal",Sagittal:"sagittal"};function gt(e){let t;return e===St.Axial?t=b():e===St.Coronal?t=ht():e===St.Sagittal&&(t=new A([0,0,-1,1,0,0,0,-1,0])),t}function pt(e){const t=new P(e.get(0,0),e.get(1,0),e.get(2,0)),n=new P(e.get(0,1),e.get(1,1),e.get(2,1)),i=new P(e.get(0,2),e.get(1,2),e.get(2,2));return mt(t)+mt(n)+mt(i)}function mt(e){let t=new P(Math.abs(e.getX()),Math.abs(e.getY()),Math.abs(e.getZ())),n="";const i=e.getX()<0?"R":"L",r=e.getY()<0?"A":"P",o=e.getZ()<0?"I":"S",a=1e-4;for(let e=0;e<3;e++)if(t.getX()>a&&t.getX()>t.getY()&&t.getX()>t.getZ())n+=i,t=new P(0,t.getY(),t.getZ());else if(t.getY()>a&&t.getY()>t.getX()&&t.getY()>t.getZ())n+=r,t=new P(t.getX(),0,t.getZ());else{if(!(t.getZ()>a&&t.getZ()>t.getX()&&t.getZ()>t.getY()))break;n+=o,t=new P(t.getX(),t.getY(),0)}return n}function ft(e){let t;const n=Dt(e);return void 0!==n&&(t=function(e){let t;return["LPS","LAI","RPI","RAS","ALS","ARI","PLI","PRS"].includes(e)?t=St.Axial:["LSA","LIP","RSP","RIA","ILA","IRP","SLP","SRA"].includes(e)?t=St.Coronal:["PSL","PIR","ASR","AIL","IAR","IPL","SAL","SPR"].includes(e)&&(t=St.Sagittal),t}(pt(n.asOneAndZeros()))),t}function Dt(e){let t;if(void 0!==e&&6===e.length){const n=new P(e[0],e[1],e[2]),i=new P(e[3],e[4],e[5]),r=n.crossProduct(i);t=new A([n.getX(),i.getX(),r.getX(),n.getY(),i.getY(),r.getY(),n.getZ(),i.getZ(),r.getZ()])}return t}function Ct(e,t){let n=b();return void 0!==t&&(n=e.asOneAndZeros().getInverse().multiply(t)),n.getAbs()}function yt(e){const t=e["00280010"];if(void 0===t)throw new Error("Missing DICOM image number of rows");if(0===t.value.length)throw new Error("Empty DICOM image number of rows");const n=e["00280011"];if(void 0===n)throw new Error("Missing DICOM image number of columns");if(0===n.value.length)throw new Error("Empty DICOM image number of columns");return[n.value[0],t.value[0]]}function vt(e){if(void 0===e["00280030"])return null;const t=e["00280030"],n=[parseFloat(t.value[1]),parseFloat(t.value[0])];return void 0!==e["00180088"]&&n.push(parseFloat(e["00180088"].value[0])),new tt(n)}function It(e){return!e&&null!==e.match(/MONOCHROME/)}function Tt(e,t,n){let i="";if(void 0===e)i+=" "+t+" is undefined,";else if(0===e.value.length)i+=" "+t+" is empty,";else if(void 0!==n)for(let r=0;r=9?st(r):void 0}}(h);S=e.date,g=e.time}void 0===g&&(g={hours:0,minutes:0,seconds:0,milliseconds:0}),a=new Date(S.year,S.monthIndex,S.day,g.hours,g.minutes,g.seconds,g.milliseconds)}const l=st(e["00080031"]);let u=new Date(i.year,i.monthIndex,i.day,l.hours,l.minutes,l.seconds,l.milliseconds);const d=e["00080022"],h=e["00080032"];if(void 0!==d&&void 0!==h){const t=at(d),i=st(h),r=new Date(t.year,t.monthIndex,t.day,i.hours,i.minutes,i.seconds,i.milliseconds);if(u>r){const a="Series date/time is after Aquisition date/time (diff="+(u.getTime()-r.getTime()).toString()+"ms) ";c.debug(a);let s=0;const l="FrameReferenceTime (00541300)",d=e["00541300"];n+=Tt(d,l),void 0!==d&&(s=d.value[0]);let h=0;const S="ActualFrameDuration (0018,1242)",g=e["00181242"];if(n+=Tt(g,S),void 0!==g&&(h=g.value[0]),s>0&&h>0){h/=1e3,s/=1e3;const e=Math.log(2)/o,n=e*h,r=1/e*Math.log(n/(1-Math.exp(-n)))-s;u=new Date(t.year,t.monthIndex,t.day,i.hours,i.minutes,i.seconds+r,i.milliseconds)}}}let S;if(void 0!==u&&void 0!==a&&void 0!==r&&void 0!==o){const e=(u.getTime()-a.getTime())/1e3;S=r*Math.pow(2,-e/o)}return{value:S,warning:n}}(e);return t+=a.warning,0!==t.length?n.warning="Cannot calculate PET SUV:"+t:n.value=1e3*i/a.value,n}(e);this.#ee=i.value,this.#$=i.warning}return this.#$}create(e,t,n){const i=yt(e),r=[i[0],i[1],1],o=e["00280008"];if(void 0!==o){const e=parseInt(o.value[0],10);e>1&&r.push(e)}const a=new je(r),s=function(e){let t=1,n=1;const i=["00280030","00181164","00182010","00280034"];for(let r=0;rparseFloat(e))))),n}(e),D=new F(p[0],p[1],p[2]),C=(new Lt).getTime(e),y=new nt(D,a,s,m,C);let v;const I=e["00080018"];void 0!==I&&(v=I.value[0]);let T=1;const L=e["00280002"];void 0!==L&&(T=L.value[0]);const P=a.getTotalSize()*T;if(P!==t.length){if(c.warn("Badly sized pixel buffer: "+t.length+" != "+P),!(P>8};r=t.value.map(e),o=n.value.map(e),a=i.value.map(e)}}else if(8===s.value[2]){c.info("Scaling 16bits color lut since the lut descriptor is 8.");let e=t.value.slice(0);r=Array.from(new Uint8Array(e.buffer)),e=n.value.slice(0),o=Array.from(new Uint8Array(e.buffer)),e=i.value.slice(0),a=Array.from(new Uint8Array(e.buffer))}w.setPaletteColourMap(new f(r,o,a))}const z=e["00082144"];return void 0!==z&&(q.RecommendedDisplayFrameRate=parseInt(z.value[0],10)),w.setMeta(q),w}}class wt{#O=!0;#x;constructor(e,t){void 0!==t&&(this.#O=t),this.#x=new DataView(e)}writeUint8(e,t){return this.#x.setUint8(e,t),e+Uint8Array.BYTES_PER_ELEMENT}writeInt8(e,t){return this.#x.setInt8(e,t),e+Int8Array.BYTES_PER_ELEMENT}writeUint16(e,t){return this.#x.setUint16(e,t,this.#O),e+Uint16Array.BYTES_PER_ELEMENT}writeInt16(e,t){return this.#x.setInt16(e,t,this.#O),e+Int16Array.BYTES_PER_ELEMENT}writeUint32(e,t){return this.#x.setUint32(e,t,this.#O),e+Uint32Array.BYTES_PER_ELEMENT}writeUint64(e,t){return this.#x.setBigUint64(e,t,this.#O),e+BigUint64Array.BYTES_PER_ELEMENT}writeInt32(e,t){return this.#x.setInt32(e,t,this.#O),e+Int32Array.BYTES_PER_ELEMENT}writeInt64(e,t){return this.#x.setBigInt64(e,t,this.#O),e+BigInt64Array.BYTES_PER_ELEMENT}writeFloat32(e,t){return this.#x.setFloat32(e,t,this.#O),e+Float32Array.BYTES_PER_ELEMENT}writeFloat64(e,t){return this.#x.setFloat64(e,t,this.#O),e+Float64Array.BYTES_PER_ELEMENT}writeHex(e,t){const n=parseInt(t,16);return this.#x.setUint16(e,n,this.#O),e+Uint16Array.BYTES_PER_ELEMENT}writeBinaryArray(e,t){if(t.length%8!=0)throw new Error("Cannot write boolean array as binary.");let n=null,i=null;for(let r=0,o=t.length;r1){let t="";for(let n=0;npe(e.tag)));void 0!==s&&void 0!==s.undefinedLength&&(a=s.undefinedLength);const l=new ve("NONE");l.vl=a?4294967295:s.vl,l.tag=ge(),l.value=[],t=this.#de(e,l,t,i);for(const n of r)pe(n.tag)||me(n.tag)||(t=this.#de(e,n,t,i));if(a){const n=new ve("NONE");n.vl=0,n.tag=new de("FFFE","E00D"),n.value=[],t=this.#de(e,n,t,i)}}return t}#he(e,t,n,i,r){const o=n;if("NONE"===t.vr);else if(i instanceof Uint8Array)n=i.length===8*t.vl?e.writeBinaryArray(n,i):e.writeUint8Array(n,i);else if(i instanceof Int8Array)n=e.writeInt8Array(n,i);else if(i instanceof Uint16Array)n=e.writeUint16Array(n,i);else if(i instanceof Int16Array)n=e.writeInt16Array(n,i);else if(i instanceof Uint32Array)n=e.writeUint32Array(n,i);else if(i instanceof Int32Array)n=e.writeInt32Array(n,i);else if(i instanceof BigUint64Array)n=e.writeUint64Array(n,i);else if(i instanceof BigInt64Array)n=e.writeInt64Array(n,i);else{const o=te[t.vr];if(void 0!==o)if("Uint8"===o)n=e.writeUint8Array(n,i);else if("Uint16"===o)n=e.writeUint16Array(n,i);else if("Int16"===o)n=e.writeInt16Array(n,i);else if("Uint32"===o)n=e.writeUint32Array(n,i);else if("Int32"===o)n=e.writeInt32Array(n,i);else if("Uint64"===o)n=e.writeUint64Array(n,i);else if("Int64"===o)n=e.writeInt64Array(n,i);else if("Float32"===o)n=e.writeFloat32Array(n,i);else if("Float64"===o)n=e.writeFloat64Array(n,i);else{if("string"!==o)throw new Error("Unknown VR type: "+o);n=e.writeUint8Array(n,i)}else if("SQ"===t.vr)n=this.#ue(e,n,i,r);else if("AT"===t.vr)for(let t=0;t1&&(o=function(e){const t=e.length,n=e[0].length;if(void 0===n)return e;const i=t*n,r=new e[0].constructor(i);for(let i=0;iObject.prototype.hasOwnProperty.call(t,n)&&e[n]===t[n]))}function zt(e){const t=new kt(e[Gt.CodeMeaning].value[0]);if(void 0!==e[Gt.CodeValue])t.value=e[Gt.CodeValue].value[0];else if(void 0!==e[Gt.LongCodeValue])t.longValue=e[Gt.LongCodeValue].value[0];else{if(void 0===e[Gt.URNCodeValue])throw new Error("Invalid code with no value, no long value and no urn value.");t.urnValue=e[Gt.URNCodeValue].value[0]}if(void 0!==t.value||void 0!==t.longValue){if(void 0===e[Gt.CodingSchemeDesignator])throw new Error("No coding sheme designator when code value or long value is present");t.schemeDesignator=e[Gt.CodingSchemeDesignator].value[0]}return t}function Wt(e){const t={};return void 0!==e.value?t.CodeValue=e.value:void 0!==e.longValue?t.LongCodeValue=e.longValue:void 0!==e.urnValue&&(t.URNCodeValue=e.urnValue),void 0!==e.schemeDesignator&&(t.CodingSchemeDesignator=e.schemeDesignator),t.CodeMeaning=e.meaning,t}const Yt={111030:"Image Region",112039:"Tracking Identifier",112040:"Tracking Unique Identifier",113048:"Pixel by pixel Maximum",113049:"Pixel by pixel mean",113051:"Pixel by pixel Minimum",113061:"Standard Deviation",113076:"Segmentation",121055:"Path",121207:"Height",121322:"Source image for image processing operation",121324:"Source Image",122438:"Reference Points",125007:"Measurement Group",125309:"Short label",128773:"Reference Geometry"},Xt={1483009:"Angle",42798e3:"Area",103355008:"Width",103339001:"Long axis",103340004:"Short axis",131190003:"Radius",261665006:"Unknown",410668003:"Length",718499004:"Color"},jt={1:"No units",mm:"Millimeter",deg:"Degree - plane angle",cm2:"Square centimeter","cm2/ml":"Square centimeter per milliliter","/cm":"Per centimeter","g/ml":"Gram per milliliter","g/ml{SUVbw}":"Standardized Uptake Value body weight","mg/ml":"Milligram per milliliter","umol/ml":"Micromole per milliliter","Bq/ml":"Becquerels per milliliter","mg/min/ml":"Milligrams per minute per milliliter","umol/min/ml":"Micromole per minute per milliliter","ml/min/g":"Milliliter per minute per gram","ml/g":"Milliliter per gram","ml/min/ml":"Milliliter per minute per milliliter","ml/ml":"Milliliter per milliliter","%":"Percentage","[hnsf'U]":"Hounsfield unit","10*23/ml":"Electron density","{counts}":"Counts","{counts}/s":"Counts per second","{propcounts}":"Proportional to counts","{propcounts}/s":"Proportional to counts per second"};function Zt(e,t){let n,i;return"DCM"===t?n=Yt[e]:"SCT"===t?n=Xt[e]:"UCUM"===t&&(n=jt[e]),void 0!==n&&(i=new kt(n),i.schemeDesignator=t,i.value=e),i}function _t(){return Zt("125007","DCM")}function Kt(){return Zt("128773","DCM")}function Jt(){return Zt("121324","DCM")}function $t(){return Zt("112039","DCM")}function en(){return Zt("125309","DCM")}function tn(){return Zt("122438","DCM")}function nn(){return Zt("718499004","SCT")}const rn={angle:{key:"1483009",scheme:"SCT"},length:{key:"410668003",scheme:"SCT"},surface:{key:"42798000",scheme:"SCT"},height:{key:"121207",scheme:"DCM"},width:{key:"103355008",scheme:"SCT"},radius:{key:"131190003",scheme:"SCT"},a:{key:"103339001",scheme:"SCT"},b:{key:"103340004",scheme:"SCT"},min:{key:"113051",scheme:"DCM"},max:{key:"113048",scheme:"DCM"},mean:{key:"113049",scheme:"DCM"},stddev:{key:"113061",scheme:"DCM"}};function on(e){let t;for(const n in rn){const i=rn[n];if(i.scheme===e.schemeDesignator&&i.key===e.value){t=n;break}}return t}const an={"unit.mm":"mm","unit.cm2":"cm2","unit.degree":"deg",HU:"[hnsf'U]",MGML:"mg/ml",ED:"10*23/ml",PCT:"%",CNTS:"{counts}",NONE:"1",CM2:"cm2",CM2ML:"cm2/ml",PCNT:"%",CPS:"{counts}/s",BQML:"Bq/ml",MGMINML:"mg/min/ml",UMOLMINML:"umol/min/ml",MLMING:"ml/min/g",MLG:"ml/g","1CM":"/cm",UMOLML:"umol/ml",PROPCNTS:"{propcounts}",PROPCPS:"{propcounts}/s",MLMINML:"ml/min/ml",MLML:"ml/ml",GML:"g/ml",SUV:"g/ml{SUVbw}"};function sn(e){let t;for(const n in an){const i=an[n];if("UCUM"===e.schemeDesignator&&i===e.value){t=n;break}}return t}const ln="00620005",cn="00620009",un="0062000C",dn="0062000D",hn="00620003",Sn="0062000F",gn="00620020";class pn{number;label;algorithmType;algorithmName;displayValue;displayRGBValue;propertyTypeCode;propertyCategoryCode;trackingUid;trackingId;constructor(e,t,n){this.number=e,this.label=t,this.algorithmType=n}}function mn(e){const t=new pn(e["00620004"].value[0],e[ln]?e[ln].value[0]:"n/a",e["00620008"].value[0]);if(void 0!==e[cn]&&(t.algorithmName=e[cn].value[0]),void 0!==e[un])t.displayValue=e[un].value[0];else if(void 0!==e[dn]){const i=e[dn].value,r=function(e){return function(e){function t(e){let t=null;return t=e<=.0031308?12.92*e:1.055*Math.pow(e,.416666667)-.055,Math.min(1,Math.max(0,t))}const n=e.x/100,i=e.y/100,r=e.z/100;return{r:Math.round(255*t(3.2406*n-1.5372*i-.4986*r)),g:Math.round(255*t(-.9689*n+1.8758*i+.0415*r)),b:Math.round(255*t(.0557*n-.204*i+1.057*r))}}(function(e){function t(e){let t=null;return t=e>.206896552?Math.pow(e,3):.128418549*e-.017712903,t}const n=I,i=(e.l+16)/116;return{x:n.x*t(i+e.a/500),y:n.y*t(i),z:n.z*t(i-e.b/200)}}(e))}({l:.001525902*(n={l:i[0],a:i[1],b:i[2]}).l,a:.003891051*n.a-128,b:.003891051*n.b-128});t.displayRGBValue=r}var n;if(void 0===e[hn])throw new Error("Missing Segmented Property Category Code Sequence.");if(t.propertyCategoryCode=zt(e[hn].value[0]),void 0===e[Sn])throw new Error("Missing Segmented Property Type Code Sequence.");return t.propertyTypeCode=zt(e[Sn].value[0]),void 0!==e[gn]&&(t.trackingId=e[gn].value[0],t.trackingUid=e["00620021"].value[0]),t}function fn(e){let t=e.algorithmType;void 0===t&&(t="MANUAL");const n={SegmentNumber:e.number,SegmentLabel:e.label,SegmentAlgorithmType:t};if("MANUAL"!==t&&void 0!==e.algorithmName&&(n.SegmentAlgorithmName=e.algorithmName),e.displayRGBValue){const t=v(T(e.displayRGBValue));n.RecommendedDisplayCIELabValue=[Math.round(t.l),Math.round(t.a),Math.round(t.b)]}else n.RecommendedDisplayGrayscaleValue=e.displayValue;return e.propertyCategoryCode&&(n.SegmentedPropertyCategoryCodeSequence={value:[Wt(e.propertyCategoryCode)]}),e.propertyTypeCode&&(n.SegmentedPropertyTypeCodeSequence={value:[Wt(e.propertyTypeCode)]}),e.trackingId&&(n.TrackingID=e.trackingId,n.TrackingUID=e.trackingUid),n}const Dn="00089124",Cn="00082112",yn="00081150",vn="00081155",In="00209116",Tn="00289110";class Ln{dimIndex;imagePosPat;derivationImages;refSegmentNumber;imageOrientationPatient;spacing;constructor(e,t,n,i){this.dimIndex=e,this.imagePosPat=t,this.derivationImages=n,this.refSegmentNumber=i}}function Pn(e){const t=[];if(void 0!==e[Dn]){const n=e[Dn].value;for(let e=0;e1&&(C=!0,p=new f(h,S,g));const y=e[52009229];if(void 0!==y){const e=y.value[0];if(void 0!==e["00209116"]){const t=e["00209116"];0!==t.value.length?D=t.value[0]["00200037"].value:c.warn("No shared functional group plane orientation sequence items.")}if(void 0!==e["00289110"]){const t=e["00289110"];0!==t.value.length?m=vt(t.value[0]):c.warn("No shared functional group pixel measure sequence items.")}}const v=function(e,t){return e.some((function(e){return On(t,e)}))},I=function(e,t){return e.findIndex((function(e){return On(t,e)}))},T=e[52009230];if(void 0===T)throw new Error("Missing or empty per frame functional sequence");if(o!==T.value.length)throw new Error("perFrameFuncGroupSequence meta and numberOfFrames are not equal.");const L=[];for(let e=0;ew;return t&&(t=e>10*w,t?(t=e>100*w,t||c.warn("Using larger+ real world epsilon in SEG pos pat adding")):c.warn("Using larger real world epsilon in SEG pos pat adding")),t},V=[];V.push(O[0]);let N=0;for(let e=1;eo)throw new Error("Test distance is increasing when adding intermediate pos pats");V.push(O[e])}const B=V.length,G=new nt(U[0],i,m,E),H=["0"];for(let e=1;e=0;--i){const a=Number.parseInt(o[i],10);g.push(h[r][a]);const s=e.getGeometry().getOrigins()[a],l=[s.getX(),s.getY(),s.getZ()],c={dimIndex:[t,o.length-i],imagePosPat:l,refSegmentNumber:t};if(void 0!==n){const e=n.getGeometry().worldToIndex(new E([s.getX(),s.getY(),s.getZ()]));c.derivationImages=[{sourceImages:[{referencedSOPInstanceUID:n.getImageUid(e),referencedSOPClassUID:n.getMeta().SOPClassUID}]}],p.push({ReferencedSOPInstanceUID:n.getImageUid(e),ReferencedSOPClassUID:n.getMeta().SOPClassUID})}S.push(c)}}r.NumberOfFrames=g.length.toString();const m=[];for(const e of S)m.push(wn(e));if(r.PerFrameFunctionalGroupsSequence={value:m},void 0!==n){const e=[];e.push({ReferencedInstanceSequence:{value:p},SeriesInstanceUID:n.getMeta().SeriesInstanceUID}),r.ReferencedSeriesSequence={value:e}}void 0!==i&&function(e,t){const n=Object.keys(t);for(const i of n)void 0!==e[i]&&c.trace("Overwritting tag: "+i),e[i]=t[i]}(r,i);const f=Bt(r),D=a.getDimSize(2),C=g.length*D/8,y=new ve("OB");return y.tag=new de("7FE0","0010"),y.vl=C,y.value=g,f["7FE00010"]=y,f}}function En(e){return(new Pt).create(e,e["7FE00010"].value[0],1)}function qn(e){return(new Fn).create(e,e["7FE00010"].value[0])}class Un{#pe;#w;#me;#t=new Xe(1,0);#fe=null;#De=!0;#Ce=!0;#ye="MONOCHROME2";#ve;#Ie=0;#Te;#Le={};#Pe=null;#we=null;#Oe=null;#Ae=new ke;constructor(e,t,n){this.#pe=e,this.#w=t,this.#me=n,this.#Te=this.#w.length/this.#pe.getSize().getTotalSize()}getImageUid(e){let t=this.#me[0];return 1!==this.#me.length&&void 0!==e&&(t=this.#me[this.getSecondaryOffset(e)]),t}getOriginForImageUid(e){let t;const n=this.#me.indexOf(e);return-1!==n&&(t=this.getGeometry().getOrigins()[n]),t}includesImageUid(e){return this.#me.includes(e)}containsImageUids(e){return function(e,t){if(null===e||null===t||void 0===e||void 0===t)return!1;if(0===e.length||0===t.length||t.length>e.length)return!1;for(const n of t)if(!e.includes(n))return!1;return!0}(this.#me,e)}getGeometry(){return this.#pe}getBuffer(){return this.#w}canQuantify(){return 1===this.getNumberOfComponents()}canWindowLevel(){return this.isMonochrome()}isMonochrome(){return It(this.getPhotometricInterpretation())}canScroll(e){const t=this.getGeometry().getSize();let n=1;return void 0!==this.#Le.numberOfFiles&&(n=this.#Le.numberOfFiles),t.canScroll(e)||1!==n}#be(){return this.#pe.getSize().getTotalSize(2)}getSecondaryOffset(e){return this.#pe.getSize().indexToOffset(e,2)}getRescaleSlopeAndIntercept(e){let t=this.#t;if(!this.isConstantRSI()){if(void 0===e)throw new Error("Cannot get non constant RSI with empty slice index.");const n=this.getSecondaryOffset(e);void 0!==this.#fe[n]?t=this.#fe[n]:c.warn("undefined non constant rsi at "+n)}return t}#xe(e){return this.#fe[e]}setRescaleSlopeAndIntercept(e,t){if(this.#De=this.#De&&e.isID(),this.#Ce){if(!this.#t.equals(e))if(void 0===t)this.#t=e;else{this.#Ce=!1,this.#fe=[];for(let e=0,t=this.#be();e=this.#Le.numberOfFiles?c.warn("Ignoring frame at index "+t+" (size: "+this.#Le.numberOfFiles+")"):(this.#w.set(e,i*t),this.appendFrame(t,new F(0,0,0)))}appendFrame(e,t){this.#pe.appendFrame(t,e),this.#Re({type:"appendframe"})}getDataRange(){return this.#Pe||(this.#Pe=this.calculateDataRange()),this.#Pe}getRescaledDataRange(){return this.#we||(this.#we=this.calculateRescaledDataRange()),this.#we}getHistogram(){if(!this.#Oe){const e=this.calculateHistogram();this.#Pe=e.dataRange,this.#we=e.rescaledDataRange,this.#Oe=e.histogram}return this.#Oe}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{this.#Ae.fireEvent(e)};setAtOffsets(e,t){let n,i;if("number"==typeof t){if(1!==this.#Te)throw new Error("Number of components is not 1 for setting single value.");n=[t]}else if(void 0!==t.r&&void 0!==t.g&&void 0!==t.b){if(3!==this.#Te)throw new Error("Number of components is not 3 for setting RGB value.");n=[t.r,t.g,t.b]}for(let t=0,r=e.length;t=3&&(r=i.getDimSize(3));for(let i=0;it&&(t=n),nn?t:n}}{let e=this.getRescaledValueAtOffset(0),t=e,n=0;const i=this.getGeometry().getSize();let r=i.getTotalSize();3===i.length()&&(r=i.getDimSize(3));for(let i=0;it&&(t=n),ni&&(i=r),ra&&(a=s),s{const e=this.getCurrentIndex();if(3===e.length()){const t=e.getValues();t.push(0),this.setCurrentIndex(new s(t))}}))}getImage(){return this.#Ee}setImage(e){this.#Ee=e}getOrientation(){return this.#_}setOrientation(e){this.#_=e}init(){this.setInitialIndex()}setInitialIndex(){const e=this.#Ee.getGeometry().getSize(),t=new Array(e.length());t.fill(0),t[0]=Math.floor(e.get(0)/2),t[1]=Math.floor(e.get(1)/2),t[2]=Math.floor(e.get(2)/2),this.setCurrentIndex(new s(t),!0)}getPlaybackMilliseconds(e){return e||(e=10),Math.round(1e3/e)}#Be=function(e,t){return 255};getAlphaFunction(){return this.#Be}setAlphaFunction(e){this.#Be=e,this.#Re({type:"alphafuncchange"})}#Ge(){if(this.#Me&&void 0!==this.#Ue[this.#Me]&&void 0!==this.#Ue[this.#Me].perslice&&!0===this.#Ue[this.#Me].perslice){this.getCurrentIndex()||this.setInitialIndex();const e=this.getCurrentIndex(),t=this.#Ee.getSecondaryOffset(e),n=this.#Ue[this.#Me].wl[t];this.setWindowLevel(n,this.#Me,!0)}if(void 0===this.#Qe&&this.setWindowLevelPresetById(0,!0),void 0===this.#Ce||this.#Ee.isConstantRSI()!==this.#Ce){let e,t;this.#Ce=this.#Ee.isConstantRSI(),this.#Ce?(e=this.#Ee.getRescaleSlopeAndIntercept(),t=!0):(e=new Xe(1,0),t=!1);const n=new l(e,this.#Ee.getMeta().BitsStored);this.#qe=new S(n,this.#Ee.getMeta().IsSigned,t)}const e=this.#qe.getVoiLut();let t;if(void 0!==e&&(t=e.getWindowLevel()),void 0===e||!this.#Qe.equals(t)){const e=new h(this.#Qe);this.#qe.setVoiLut(e)}return this.#qe}getWindowPresets(){return this.#Ue}getWindowPresetsNames(){return Object.keys(this.#Ue)}setWindowPresets(e){this.#Ue=e}addWindowPresets(e){const t=Object.keys(e);let n=null;for(let i=0;i{this.#Ae.fireEvent(e)};getWindowLevelMinMax(){const e=this.getImage().getRescaledDataRange(),t=e.min;let n=e.max-t;return n<1&&(c.warn("Zero or negative window width, defaulting to one."),n=1),new u(t+n/2,n)}setWindowLevelMinMax(){const e=this.getWindowLevelMinMax();this.setWindowLevel(e,"minmax")}generateImageData(e,t){void 0===t&&(this.getCurrentIndex()||this.setInitialIndex(),t=this.getCurrentIndex());const n=this.getImage(),i=!n.isConstantRSI(),r=We(n,t,i,this.getOrientation()),o=n.getPhotometricInterpretation();switch(o){case"MONOCHROME1":case"MONOCHROME2":!function(e,t,n,i,r){let o=0,a=0,s=t.next();for(;!s.done;)a=i.getValue(s.value),e.data[o]=r.red[a],e.data[o+1]=r.green[a],e.data[o+2]=r.blue[a],e.data[o+3]=n(s.value,s.index),o+=4,s=t.next()}(e,r,this.getAlphaFunction(),this.#Ge(),this.#ke());break;case"PALETTE COLOR":!function(e,t,n,i,r){const o=function(e){return e>>8};r&&c.info("Scaling 16bits data to 8bits.");let a=0,s=0,l=t.next();for(;!l.done;)s=l.value,r?(e.data[a]=o(i.red[s]),e.data[a+1]=o(i.green[s]),e.data[a+2]=o(i.blue[s])):(e.data[a]=i.red[s],e.data[a+1]=i.green[s],e.data[a+2]=i.blue[s]),e.data[a+3]=n(s,l.index),a+=4,l=t.next()}(e,r,this.getAlphaFunction(),n.getPaletteColourMap(),16===n.getMeta().BitsStored);break;case"RGB":!function(e,t,n){let i=0,r=t.next();for(;!r.done;)e.data[i]=r.value[0],e.data[i+1]=r.value[1],e.data[i+2]=r.value[2],e.data[i+3]=n(r.value,r.index),i+=4,r=t.next()}(e,r,this.getAlphaFunction());break;case"YBR_FULL":!function(e,t,n){let i=0,r=null,o=t.next();for(;!o.done;)a=o.value[0],s=o.value[1],r={r:a+1.402*((l=o.value[2])-128),g:a-.34414*(s-128)-.71414*(l-128),b:a+1.772*(s-128)},e.data[i]=r.r,e.data[i+1]=r.g,e.data[i+2]=r.b,e.data[i+3]=n(o.value,o.index),i+=4,o=t.next();var a,s,l}(e,r,this.getAlphaFunction());break;default:throw new Error("Unsupported photometric interpretation: "+o)}}getScrollIndex(){let e=null;const t=this.getOrientation();return e=void 0!==t?t.getThirdColMajorDirection():2,e}isAquisitionOrientation(){return x(this.#_)}}class Bn{#He;#X;#ze;#We;#Ye;constructor(e,t){this.#He=e,this.#X=e.getRealSpacing(),this.#ze=e.getOrientation(),this.#We=t,this.#Ye=function(e,t){let n=e.asOneAndZeros().multiply(t);return e.asOneAndZeros().getAbs().equals(ht().getAbs())&&(n=n.getAbs()),n}(this.#ze,t)}getViewOrientation(){return this.#We}getTargetOrientation(){return this.#Ye}getOffset3DFromPlaneOffset(e){const t=new P(e.x,e.y,0),n=this.getTargetDeOrientedVector3D(t);return new P(n.getX()*this.#X.get(0),n.getY()*this.#X.get(1),n.getZ()*this.#X.get(2))}getPlaneOffsetFromOffset3D(e){const t=new P(e.x/this.#X.get(0),e.y/this.#X.get(1),e.z/this.#X.get(2)),n=this.getTargetOrientedVector3D(t);return{x:n.getX(),y:n.getY()}}getTargetOrientedVector3D(e){let t=e;return void 0!==this.#Ye&&(t=this.#Ye.getInverse().multiplyVector3D(e)),t}getTargetDeOrientedVector3D(e){let t=e;return void 0!==this.#Ye&&(t=this.#Ye.multiplyVector3D(e)),t}getTargetDeOrientedPoint3D(e){let t=e;return void 0!==this.#Ye&&(t=this.#Ye.multiplyPoint3D(e)),t}getImageOrientedVector3D(e){let t=e;if(void 0!==this.#We){const n=rt([e.getX(),e.getY(),e.getZ()],this.#We);t=new P(n[0],n[1],n[2])}return t}getImageOrientedPoint3D(e){let t=e;if(void 0!==this.#We){const n=rt([e.getX(),e.getY(),e.getZ()],this.#We);t=new F(n[0],n[1],n[2])}return t}getImageDeOrientedVector3D(e){let t=e;if(void 0!==this.#We){const n=it([e.getX(),e.getY(),e.getZ()],this.#We);t=new P(n[0],n[1],n[2])}return t}getImageDeOrientedPoint3D(e){let t=e;if(void 0!==this.#We){const n=it([e.getX(),e.getY(),e.getZ()],this.#We);t=new F(n[0],n[1],n[2])}return t}getPositionFromPlanePoint(e,t){const n=new F(e.getX(),e.getY(),t),i=this.getImageOrientedPoint3D(n);return this.#He.pointToWorld(i)}getPlanePointFromPosition(e){const t=this.#He.worldToPoint(e);return this.getImageDeOrientedPoint3D(t)}getCosines(){return[(e=this.#Ye).get(0,0),e.get(1,0),e.get(2,0),e.get(0,1),e.get(1,1),e.get(2,1)];var e}getPlanePoints(e){const t=this.getPlanePointFromPosition(e),n=this.getPositionFromPlanePoint(new R(0,0),t.getZ()),i=this.getCosines();return[n,new F(i[0],i[1],i[2]),new F(i[3],i[4],i[5])]}worldToIndex(e){return this.#He.worldToIndex(e)}isAquisitionOrientation(){return x(this.#We)}getTargetOrientedPositiveXYZ(e){const t=it([e.x,e.y,e.z],this.#Ye);return{x:t[0],y:t[1],z:t[2]}}getScrollIndex(){let e=null;return e=void 0!==this.#We?this.#We.getThirdColMajorDirection():2,e}getNativeScrollIndex(){let e=null;return e=void 0!==this.#ze?this.#ze.getThirdColMajorDirection():2,e}}class Gn{#x;#Xe;#je;#Ze=!1;constructor(e){if(void 0===e.getImage())throw new Error("View does not have an image, cannot setup controller");this.#x=e,this.#Xe=new Bn(e.getImage().getGeometry(),e.getOrientation()),"SEG"===e.getImage().getMeta().Modality&&(this.#Ze=!0)}getPlaneHelper(){return this.#Xe}isMask(){return this.#Ze}initialise(){this.setWindowLevelPresetById(0),this.setCurrentPosition(this.getPositionFromPlanePoint(new R(0,0)))}getModality(){return this.#x.getImage().getMeta().Modality}getWindowLevelPresetsNames(){return this.#x.getWindowPresetsNames()}addWindowLevelPresets(e){return this.#x.addWindowPresets(e)}setWindowLevelPreset(e){this.#x.setWindowLevelPreset(e)}setWindowLevelPresetById(e){this.#x.setWindowLevelPresetById(e)}isPlaying(){return void 0!==this.#je}getCurrentPosition(){return this.#x.getCurrentPosition()}getCurrentIndex(){return this.#x.getCurrentIndex()}getCurrentImageUid(){return this.#x.getCurrentImageUid()}getOriginForImageUid(e){return this.#x.getOriginForImageUid(e)}includesImageUid(e){return this.#x.includesImageUid(e)}getCurrentOrientedIndex(){let e=this.#x.getCurrentIndex();if(void 0!==this.#x.getOrientation()){const t=this.#Xe.getImageDeOrientedVector3D(new P(e.get(0),e.get(1),e.get(2)));e=new s([t.getX(),t.getY(),t.getZ()])}return e}getScrollIndex(){return this.#x.getScrollIndex()}getCurrentScrollIndexValue(){return this.#x.getCurrentIndex().get(this.#x.getScrollIndex())}getOrigin(e){return this.#x.getOrigin(e)}isAquisitionOrientation(){return this.#x.isAquisitionOrientation()}getPlanePoints(e){return this.#Xe.getPlanePoints(e)}getCurrentScrollPosition(){const e=this.#x.getScrollIndex();return this.#x.getCurrentPosition().get(e)}generateImageData(e,t){this.#x.generateImageData(e,t)}setImage(e){this.#x.setImage(e)}get2DSpacing(){return this.#x.getImage().getGeometry().getSpacing(this.#x.getOrientation()).get2D()}getRescaledImageValue(e){const t=this.#x.getImage();if(!t.canQuantify())return;const n=t.getGeometry(),i=n.worldToIndex(e);let r;return n.isIndexInBounds(i)&&(r=t.getRescaledValueAtIndex(i)),r}getPixelUnit(){return this.#x.getImage().getMeta().pixelUnit}#_e(e,t,n,i){const r=ze(We(e,t,n,i)),o=e.getGeometry().getSize(i).getValues();o[2]=1;const a=new je(o),s=e.getGeometry().getSpacing(i).getValues();s[2]=1;const l=new tt(s),c=new F(0,0,0),u=new nt(c,a,l);return new Un(u,r)}getImageRegionValues(e,t){let n=this.#x.getImage();const i=this.#x.getOrientation();let r=this.getCurrentIndex(),o=!0;x(i)||(n=this.#_e(n,r,o,i),r=new s([0,0,0]),o=!1);const a=function(e,t,n,i,r){if(1!==e.getNumberOfComponents())throw new Error("Unsupported number of components for region iterator: "+e.getNumberOfComponents());void 0===n&&(n=!1);let o=null;o=n?function(t){return e.getRescaledValueAtOffset(t)}:function(t){return e.getValueAtOffset(t)};const a=e.getGeometry().getSize();void 0===i&&(i=new R(0,0)),void 0===r&&(r=new R(a.get(0)-1,a.get(1)));const s=a.indexToOffset(t.getWithNew2D(i.getX(),i.getY())),l=a.indexToOffset(t.getWithNew2D(r.getX(),r.getY()-1)),c=Math.max(1,r.getX()-i.getX());return function(e,t,n,i,r,o){let a=t,s=0;return{next:function(){if(a{let e=!1;if(e=i?this.incrementScrollIndex():this.incrementIndex(3),!e){const e=this.getCurrentIndex().getValues(),t=this.#x.getOrientation();i?e[t.getThirdColMajorDirection()]=0:e[3]=0;const n=new s(e),r=this.#x.getImage().getGeometry();this.setCurrentPosition(r.indexToWorld(n))}}),n)}else this.stop()}stop(){void 0!==this.#je&&(clearInterval(this.#je),this.#je=void 0)}getWindowLevel(){return this.#x.getWindowLevel()}getCurrentWindowPresetName(){return this.#x.getCurrentWindowPresetName()}setWindowLevel(e){this.#x.setWindowLevel(e)}getColourMap(){return this.#x.getColourMap()}setColourMap(e){this.#x.setColourMap(e)}setViewAlphaFunction(e){this.#x.setAlphaFunction(e)}bindImageAndLayer(e){const t=this.#x.getImage();t.addEventListener("imagecontentchange",e.onimagecontentchange),t.addEventListener("imagegeometrychange",e.onimagegeometrychange)}unbindImageAndLayer(e){const t=this.#x.getImage();t.removeEventListener("imagecontentchange",e.onimagecontentchange),t.removeEventListener("imagegeometrychange",e.onimagegeometrychange)}}class kn{#tt=0;getSum(){return this.#tt}add(e){this.#tt+=function(e){if(void 0===e.wheelDeltaY)return-e.deltaY;{const t=45;return e.wheelDeltaY>t?1:e.wheelDeltaY<-t?-1:-e.deltaY/60}}(e)}clear(){this.#tt=0}isTick(){return Math.abs(this.#tt)>=1}}class Hn{#nt;#it=new kn;constructor(e){this.#nt=e}wheel(e){this.#it.add(e);const t=this.#it.getSum()>=0;if(!this.#it.isTick())return;this.#it.clear(),e.preventDefault();const n=Zi(e),i=this.#nt.getLayerGroupByDivId(n.groupDivId),r=i.getActiveViewLayer().getViewController();let o;i.canScroll()?o=t?r.getIncrementScrollPosition():r.getDecrementScrollPosition():i.moreThanOne(3)&&(o=t?r.getIncrementPosition(3):r.getDecrementPosition(3)),void 0!==o&&i.isPositionInBounds(o)&&r.setCurrentPosition(o)}}class zn{#rt;#ot;constructor(e,t){this.#rt=e,this.#ot=t}getBegin(){return this.#rt}getEnd(){return this.#ot}equals(e){return null!==e&&this.getBegin().equals(e.getBegin())&&this.getEnd().equals(e.getEnd())}getDeltaX(){return this.getEnd().getX()-this.getBegin().getX()}getDeltaY(){return this.getEnd().getY()-this.getBegin().getY()}getLength(){return Math.sqrt(this.getDeltaX()*this.getDeltaX()+this.getDeltaY()*this.getDeltaY())}getWorldLength(e){let t=null;if(null!==e){const n=this.getDeltaX()*e.x,i=this.getDeltaY()*e.y;t=Math.sqrt(n*n+i*i)}return t}getMidpoint(){return new R((this.getBegin().getX()+this.getEnd().getX())/2,(this.getBegin().getY()+this.getEnd().getY())/2)}getCentroid(){return this.getMidpoint()}getSlope(){return this.getDeltaY()/this.getDeltaX()}getIntercept(){return(this.getEnd().getX()*this.getBegin().getY()-this.getBegin().getX()*this.getEnd().getY())/this.getDeltaX()}getInclination(){return 180-180*Math.atan2(this.getDeltaY(),this.getDeltaX())/Math.PI}quantify(e){const t={},n=e.get2DSpacing(),i=this.getWorldLength(n);return null!==i&&(t.length={value:i,unit:"unit.mm"}),t}}function Wn(e,t){const n=e.getDeltaX(),i=e.getDeltaY(),r=t.getDeltaX(),o=t.getDeltaY(),a=n*r+i*o,s=n*o-i*r;return 360-(180-180*Math.atan2(s,a)/Math.PI)}function Yn(e,t){const n=e.getDeltaX(),i=e.getDeltaY();return n*t.getDeltaX()+i*t.getDeltaY()==0}function Xn(e,t,n,i){void 0===i&&(i={x:1,y:1});const r=-i.x*i.x/(i.y*i.y*e.getSlope());return Zn(r,t.getY()-r*t.getX(),t,n,i)}function jn(e,t,n,i){const r=Zn(e.getSlope(),e.getIntercept(),e.getBegin(),t,i);let o;return o=function(e,t){const n=Math.min(t.getBegin().getX(),t.getEnd().getX()),i=Math.max(t.getBegin().getX(),t.getEnd().getX()),r=Math.min(t.getBegin().getY(),t.getEnd().getY()),o=Math.max(t.getBegin().getY(),t.getEnd().getY());return e.getX()>=n&&e.getX()<=i&&e.getY()>=r&&e.getY()<=o}(r.getBegin(),e)?r.getBegin():r.getEnd(),Xn(e,o,n,i)}function Zn(e,t,n,i,r){void 0===r&&(r={x:1,y:1});let o=0,a=0,s=0,l=0;if(O(e,0,w))o=n.getX()-i/(2*r.x),a=n.getY(),s=n.getX()+i/(2*r.x),l=n.getY();else if(Math.abs(e)>1e6)o=n.getX(),a=n.getY()-i/(2*r.y),s=n.getX(),l=n.getY()+i/(2*r.y);else{const c=r.x*r.x,u=r.y*r.y,d=i/(2*Math.sqrt(c+u*e*e));o=n.getX()-d,a=e*o+t,s=n.getX()+d,l=e*s+t}return new zn(new R(o,a),new R(s,l))}var _n=o(944),Kn=o.n(_n);class Jn{#at;#Le={};#Ae=new ke;#st;#lt;constructor(e){this.#at=void 0!==e?e:[],this.#st=!0}getList(){return this.#at}getLength(){return this.#at.length}isEditable(){return this.#st}setEditable(e){this.#st=e,this.#Re({type:"annotationgroupeditablechange",data:e})}getColour(){return this.#lt}setColour(e){this.#lt=e}add(e){this.#at.push(e),this.#Re({type:"annotationadd",data:e})}update(e,t){const n=this.#at.findIndex((t=>t.id===e.id));-1!==n?(this.#at[n]=e,this.#Re({type:"annotationupdate",data:e,keys:t})):c.warn("Cannot find annotation to update")}remove(e){const t=this.#at.findIndex((t=>t.id===e));if(-1!==t){const e=this.#at.splice(t,1)[0];this.#Re({type:"annotationremove",data:e})}else c.warn("Cannot find annotation to remove")}setViewController(e){for(const t of this.#at)t.setViewController(e),t.updateQuantification()}find(e){return this.#at.find((t=>t.id===e))}getMeta(){return this.#Le}hasMeta(e){return void 0!==this.#Le[e]}getMetaValue(e){return this.#Le[e]}setMetaValue(e,t){this.#Le[e]=t}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{this.#Ae.fireEvent(e)}}class $n{#ct;getAnnotation(e){return this.#ct.find(e)}getAnnotationGroup(){return this.#ct}isAnnotationGroupEditable(){return this.#ct.isEditable()}setAnnotationGroupEditable(e){this.#ct.setEditable(e)}addAnnotation(e){this.#ct.add(e)}updateAnnotation(e,t){this.#ct.update(e,t)}removeAnnotation(e){this.#ct.remove(e)}removeAnnotationWithCommand(e,t){const n=this.getAnnotation(e);if(void 0===n)return void c.warn("Cannot create remove command for undefined annotation: "+e);const i=new vi(n,this);t(i),i.execute()}updateAnnotationWithCommand(e,t,n,i){const r=this.getAnnotation(e);if(void 0===r)return void c.warn("Cannot create update command for undefined annotation: "+e);const o=new Ii(r,t,n,this);i(o),o.execute()}removeAllAnnotationsWithCommand(e){for(const t of this.#ct.getList())this.removeAnnotationWithCommand(t.id,e)}constructor(e){this.#ct=void 0!==e?e:new Jn}hasAnnotationMeta(e){return this.#ct.hasMeta(e)}setAnnotationMeta(e,t){this.#ct.setMetaValue(e,t)}}class ei{#ut=10;#dt="Verdana";#ht="#fff";#St="#ffff80";#gt={x:1,y:1};#pt={x:1,y:1};#mt=2;#ft={x:.25,y:.25};#Dt=.2;#Ct=3;getFontFamily(){return this.#dt}getFontSize(){return this.#ut}getStrokeWidth(){return this.#mt}getTextColour(){return this.#ht}getLineColour(){return this.#St}setLineColour(e){this.#St=e}setBaseScale(e){this.#gt=e}setZoomScale(e){this.#pt=e}getBaseScale(){return this.#gt}getZoomScale(){return this.#pt}scale(e){return e/this.#gt.x}applyZoomScale(e){return{x:e/this.#pt.x,y:e/this.#pt.y}}applyZoomRatio(e){return e*this.#pt.x/this.#pt.y}getShadowOffset(){return this.#ft}getTagOpacity(){return this.#Dt}getTextPadding(){return this.#Ct}getFontStr(){return"normal "+this.getFontSize()+"px sans-serif"}getLineHeight(){return this.getFontSize()+this.getFontSize()/5}getScaledFontSize(){return this.scale(this.getFontSize())}getScaledStrokeWidth(){return this.scale(this.getStrokeWidth())}getShadowLineColour(){return e=this.getLineColour(),n=e,.001172549*(t={r:parseInt(n.substring(1,3),16),g:parseInt(n.substring(3,5),16),b:parseInt(n.substring(5,7),16)}).r+.002301961*t.g+447059e-9*t.b<.5?"#fff":"#000";var e,t,n}}function ti(e){return"label"===e.name()}function ni(e){return"shape"===e.name()}function ii(e){return"position-group"===e.name()}function ri(e){const t=e.getChildren(ni)[0];if(t instanceof Kn().Line)return t}function oi(e,t){const n=e.getChildren((function(e){return e.id()==="anchor"+t}))[0];if(n instanceof Kn().Ellipse)return n}function ai(e){return function(t){return t.id()===e}}function si(e,t,n,i){const r=i.applyZoomScale(6),o={x:Math.abs(r.x),y:Math.abs(r.y)};return new(Kn().Ellipse)({x:e,y:t,stroke:"#999",fill:"rgba(100,100,100,0.7",strokeWidth:i.getStrokeWidth(),strokeScaleEnabled:!1,radius:o,radiusX:o.x,radiusY:o.y,name:"anchor",id:n.toString(),dragOnTop:!1,draggable:!0,visible:!1})}function li(e){return parseInt(e.substring(6),10)}class ci{#rt;#ot;constructor(e,t){this.#rt=new R(Math.min(e.getX(),t.getX()),Math.min(e.getY(),t.getY())),this.#ot=new R(Math.max(e.getX(),t.getX()),Math.max(e.getY(),t.getY()))}getBegin(){return this.#rt}getEnd(){return this.#ot}equals(e){return null!==e&&this.getBegin().equals(e.getBegin())&&this.getEnd().equals(e.getEnd())}getSurface(){const e=this.getBegin(),t=this.getEnd();return Math.abs(t.getX()-e.getX())*Math.abs(t.getY()-e.getY())}getWorldSurface(e){return function(e,t,n){let i=null;return null!==t&&null!==n&&(i=e*t*n),i}(this.getSurface(),e.x,e.y)}getRealWidth(){return this.getEnd().getX()-this.getBegin().getX()}getRealHeight(){return this.getEnd().getY()-this.getBegin().getY()}getWidth(){return Math.abs(this.getRealWidth())}getHeight(){return Math.abs(this.getRealHeight())}getRound(){return{min:new R(Math.round(this.getBegin().getX()),Math.round(this.getBegin().getY())),max:new R(Math.round(this.getEnd().getX()),Math.round(this.getEnd().getY()))}}getCentroid(){return new R(this.getBegin().getX()+this.getWidth()/2,this.getBegin().getY()+this.getHeight()/2)}quantify(e,t){const n={},i=e.get2DSpacing();n.width={value:this.getWidth()*i.x,unit:"unit.mm"},n.height={value:this.getHeight()*i.y,unit:"unit.mm"};const r=this.getWorldSurface(i);if(null!==r&&(n.surface={value:r/100,unit:"unit.cm2"}),e.canQuantifyImage()){const i=this.getRound(),r=e.getImageRegionValues(i.min,i.max),o=e.getPixelUnit(),a=_e(r,t);n.min={value:a.min,unit:o},n.max={value:a.max,unit:o},n.mean={value:a.mean,unit:o},n.stdDev={value:a.stdDev,unit:o},void 0!==a.median&&(n.median={value:a.median,unit:o}),void 0!==a.p25&&(n.p25={value:a.p25,unit:o}),void 0!==a.p75&&(n.p75={value:a.p75,unit:o})}return n}}function ui(e,t,n){const i=e.getValues(),r=i.slice(),o=[],a=t[0],l=Math.floor(a/2),c=t[1],u=Math.floor(c/2),d=n[0],h=n[1];for(let e=0;e3)throw new Error("Too many points for a protractor");this.#yt=e.slice(0,3)}getPoint(e){return this.#yt[e]}getLength(){return this.#yt.length}getCentroid(){return this.#yt[1]}quantify(e,t){const n={};if(3===this.#yt.length){let e=Wn(new zn(this.#yt[0],this.#yt[1]),new zn(this.#yt[1],this.#yt[2]));e>180&&(e=360-e),n.angle={value:e,unit:"unit.degree"}}return n}}class Si{#vt;#It;#Tt;constructor(e,t,n){this.#vt=e,this.#It=t,this.#Tt=n}getCenter(){return this.#vt}getCentroid(){return this.#vt}getA(){return this.#It}getB(){return this.#Tt}equals(e){return null!==e&&this.getCenter().equals(e.getCenter())&&this.getA()===e.getA()&&this.getB()===e.getB()}getSurface(){return Math.PI*this.getA()*this.getB()}getWorldSurface(e){return function(e,t,n){let i=null;return null!==t&&null!==n&&(i=e*t*n),i}(this.getSurface(),e.x,e.y)}getRound(){const e=this.getCenter().getX(),t=this.getCenter().getY(),n=this.getA(),i=this.getB(),r=n/i,o=Math.pow(i,2),a=t+i,s=[];for(let n=t-i;n{this.#Ut(e)}:e=>{this.#Mt(e)},this.#qt(t)}#Rt(){this.#qt((function(e){e.remove()}))}#Ft(){if(!this.#Ot||!this.#Ot.getLayer())return;const e=this.#Ot.getParent(),t=this.#wt.getAnchors(this.#Ot,this.#nt.getStyle());for(let n=0;n{e.cancelBubble=!0,t={mathShape:this.#bt.mathShape,referencePoints:this.#bt.referencePoints}})),e.on("dragmove.edit",(e=>{const t=e.target;t instanceof Kn().Shape&&(function(e,t){const n=t.getParent();!function(e,t,n){let i=!1;e.x()n.getX()&&(e.x(n.getX()),i=!0),e.y()n.getY()&&(e.y(n.getY()),i=!0)}(t,new R(-n.x(),-n.y()),new R(e.x-n.x(),e.y-n.y()))}(this.#At.getBaseSize(),t),void 0!==this.#wt.constrainAnchorMove&&this.#wt.constrainAnchorMove(t),this.#wt.updateAnnotationOnAnchorMove(this.#bt,t),this.#wt.updateShapeGroupOnAnchorMove(this.#bt,t,this.#nt.getStyle()),t.getLayer()?t.getLayer().draw():c.warn("No layer to draw the anchor!"),e.cancelBubble=!0)})),e.on("dragend.edit",(e=>{const n={mathShape:this.#bt.mathShape,referencePoints:this.#bt.referencePoints},i=new Ii(this.#bt,t,n,this.#At.getDrawController());this.#nt.addToUndoStack(i),this.#Pt({type:"annotationupdate",data:this.#bt,dataid:this.#At.getDataId(),keys:Object.keys(n)}),t={mathShape:n.mathShape,referencePoints:n.referencePoints},e.cancelBubble=!0})),e.on("mousedown touchstart",(e=>{e.target.moveToTop()})),e.on("mouseover.edit",(e=>{const t=e.target;t instanceof Kn().Shape&&(t.stroke("#ddd"),t.getLayer()?t.getLayer().draw():c.warn("No layer to draw the anchor!"))})),e.on("mouseout.edit",(e=>{const t=e.target;t instanceof Kn().Shape&&(t.stroke("#999"),t.getLayer()?t.getLayer().draw():c.warn("No layer to draw the anchor!"))}))}#Mt(e){e.off("dragstart.edit"),e.off("dragmove.edit"),e.off("dragend.edit"),e.off("mousedown touchstart"),e.off("mouseover.edit"),e.off("mouseout.edit")}}class fi{#Qt;constructor(){this.createTrashIcon()}createTrashIcon(){this.#Qt=new(Kn().Group);const e=new(Kn().Line)({points:[-10,-10,10,10],stroke:"red"}),t=new(Kn().Line)({points:[10,-10,-10,10],stroke:"red"});this.#Qt.width(20),this.#Qt.height(20),this.#Qt.add(e),this.#Qt.add(t)}activate(e){const t=e.getKonvaStage(),n=t.scale(),i=e.getKonvaLayer(),r={x:1/n.x,y:1/n.y};this.#Qt.x(t.offset().x+t.width()/(2*n.x)),this.#Qt.y(t.offset().y+t.height()/(15*n.y)),this.#Qt.scale(r),i.add(this.#Qt),i.draw()}changeChildrenColourOnTrashHover(e,t,n){if(this.isOverTrash(e))return this.changeGroupChildrenColour(this.#Qt,"orange"),void this.changeGroupChildrenColour(t,"red");this.changeGroupChildrenColour(this.#Qt,"red"),this.changeGroupChildrenColour(t,n)}changeGroupChildrenColour(e,t){e.getChildren().forEach((function(e){e instanceof Kn().Shape&&void 0!==e.stroke&&e.stroke(t)}))}remove(){this.#Qt.remove()}isOverTrash(e){const t=this.#Qt.width()*Math.abs(this.#Qt.scaleX())/2,n=this.#Qt.height()*Math.abs(this.#Qt.scaleY())/2;return Math.abs(e.x-this.#Qt.x()){this.#Gt=e,this.#Ht()})),e.on("mouseout",(()=>{this.onMouseOutShapeGroup(),this.#Gt=void 0}))}#Wt(e){e.off("mouseover"),e.off("mouseout")}addShapeGroupListeners(e,t,n){this.#zt(e),this.#Yt(e,t,n),this.#Xt(e,t,n),e.on("dblclick",(()=>{const e=t.textExpr;ki.openRoiDialog(t,(t=>{const i=t.textExpr,r=new Ii(t,{textExpr:e},{textExpr:i},n.getDrawController());this.#nt.addToUndoStack(r),r.execute()}))}))}#Yt(e,t,n){const i=n.getKonvaLayer(),r=e.getChildren(ni)[0];if(!(r instanceof Kn().Shape))return;let o,a,s,l;r.draggable(!0),r.on("dragstart.draw",(e=>{l=r.stroke(),o={x:r.x(),y:r.y()},a={x:e.target.x(),y:e.target.y()},s={mathShape:t.mathShape,referencePoints:t.referencePoints},this.#Qt.activate(n),this.#Vt.setAnchorsActive(!1),i.draw()})),r.on("dragmove.draw",(o=>{const s=function(e,t){return{min:new R(0,0),max:new R(e.x-Math.abs(t.width()),e.y-Math.abs(t.height()))}}(n.getBaseSize(),r);if(s&&!function(e,t,n){const i=e.getClientRect({relativeTo:e.getParent()});return i.x>t.getX()&&i.xt.getY()&&i.y{if(this.#Qt.remove(),void 0===a||void 0===a.evt)return;const c=r.x(),u=r.y(),d=Wi(a.evt),h={x:d.getX(),y:d.getY()},S=this.#kt(h,n);if(this.#Qt.isOverTrash(S)){e.x(o.x),e.y(o.y),this.#Vt.disable(),this.#Vt.reset(),this.#Qt.changeGroupChildrenColour(e,l),t.mathShape=s.mathShape,t.referencePoints=s.referencePoints;const i=new vi(t,n.getDrawController());this.#nt.addToUndoStack(i),i.execute(),this.onMouseOutShapeGroup()}else{const e={x:c-o.x,y:u-o.y};if(0!==e.x||0!==e.y){const e={mathShape:t.mathShape,referencePoints:t.referencePoints},i=new Ii(t,s,e,n.getDrawController());this.#nt.addToUndoStack(i),this.#Pt({type:"annotationupdate",data:t,dataid:n.getDataId(),keys:Object.keys(e)}),s={mathShape:e.mathShape,referencePoints:e.referencePoints}}this.#Vt.setAnchorsActive(!0),this.#Vt.resetAnchors()}i.draw(),o={x:r.x(),y:r.y()}}))}#Xt(e,t,n){const i=e.getChildren(ti)[0];if(!(i instanceof Kn().Label))return;let r,o;i.draggable(!0),i.on("dragstart.draw",(()=>{r={x:i.x(),y:i.y()},o=t.labelPosition})),i.on("dragmove.draw",(()=>{t.getFactory().updateConnector(e)})),i.on("dragend.draw",(()=>{const e=i.x()-r.x,a=i.y()-r.y;if(0!==e||0!==a){const e=new R(i.x(),i.y());t.labelPosition=e;const r=new Ii(t,{labelPosition:o},{labelPosition:e},n.getDrawController());this.#nt.addToUndoStack(r),this.#Pt({type:"annotationupdate",data:t,dataid:n.getDataId(),keys:["labelPosition"]}),o=e}r={x:i.x(),y:i.y()}}))}removeShapeListeners(e){this.#Wt(e),e.off("dblclick");const t=e.getChildren(ni)[0];t instanceof Kn().Shape&&(t.draggable(!1),t.off("dragstart.draw"),t.off("dragmove.draw"),t.off("dragend.draw"));const n=e.getChildren(ti)[0];n instanceof Kn().Label&&(n.draggable(!1),n.off("dragstart.draw"),n.off("dragend.draw"))}}class Ci{#jt;#Zt=null;#_t;#Kt;#Jt={x:1,y:1};#$t={x:1,y:1,z:1};#en={x:0,y:0};#tn={x:0,y:0};#nn={x:0,y:0};#in={x:0,y:0};#rn;#Xe;#on;#an;#sn;#ln;#cn=!0;constructor(e){this.#jt=e,this.#jt.className+=" drawLayer"}setShapeHandler(e){this.#ln=e}getDataId(){return this.#on}getReferenceLayerId(){return this.#an}#Ae=new ke;getKonvaStage(){return this.#Zt}getKonvaLayer(){return this.#Zt.getLayers()[0]}getDrawController(){return this.#rn}setPlaneHelper(e){this.#Xe=e}getId(){return this.#jt.id}removeFromDOM(){this.#jt.remove()}getBaseSize(){return this.#_t}getOpacity(){return this.#Zt.opacity()}setOpacity(e){this.#Zt.opacity(Math.min(Math.max(e,0),1))}addFlipOffsetX(){const e=this.#Zt.scale(),t=this.#Zt.size();this.#in.x+=t.width/e.x;const n=this.#Zt.offset();n.x+=this.#in.x,this.#Zt.offset(n)}addFlipOffsetY(){const e=this.#Zt.scale(),t=this.#Zt.size();this.#in.y+=t.height/e.y;const n=this.#Zt.offset();n.y+=this.#in.y,this.#Zt.offset(n)}flipScaleX(){this.#$t.x*=-1}flipScaleY(){this.#$t.y*=-1}flipScaleZ(){this.#$t.z*=-1}setScale(e,t){const n=this.#Xe.getTargetOrientedPositiveXYZ({x:e.x*this.#$t.x,y:e.y*this.#$t.y,z:e.z*this.#$t.z}),i={x:this.#Jt.x*n.x,y:this.#Jt.y*n.y},r=this.#Zt.offset();if(1===Math.abs(e.x)&&1===Math.abs(e.y)&&1===Math.abs(e.z)){const e={x:r.x-this.#nn.x,y:r.y-this.#nn.y};this.#nn={x:0,y:0},this.#Zt.offset(e)}else if(void 0!==t){let e=this.#Xe.getPlaneOffsetFromOffset3D({x:t.getX(),y:t.getY(),z:t.getZ()});e={x:e.x+this.#en.x,y:e.y+this.#en.y};const n=_i(r,this.#Zt.scale(),i,e),o={x:this.#nn.x+n.x-r.x,y:this.#nn.y+n.y-r.y};this.#nn=o,this.#Zt.offset(n)}this.#Zt.scale(i),this.#un(i)}initScale(e,t){const n=this.#Xe.getTargetOrientedPositiveXYZ({x:e.x*this.#$t.x,y:e.y*this.#$t.y,z:e.z*this.#$t.z}),i={x:this.#Jt.x*n.x,y:this.#Jt.y*n.y};this.#Zt.scale(i),this.#nn={x:t.x/this.#Jt.x,y:t.y/this.#Jt.y};const r=this.#Zt.offset();this.#Zt.offset({x:r.x+this.#nn.x,y:r.y+this.#nn.y})}setOffset(e){const t=this.#Xe.getPlaneOffsetFromOffset3D(e);this.#Zt.offset({x:t.x+this.#tn.x+this.#en.x+this.#nn.x+this.#in.x,y:t.y+this.#tn.y+this.#en.y+this.#nn.y+this.#in.y})}setBaseOffset(e,t){const n=this.#Xe.getNativeScrollIndex(),i=this.#Xe.getPlaneOffsetFromOffset3D({x:0===n?e.getX():t.getX(),y:1===n?e.getY():t.getY(),z:2===n?e.getZ():t.getZ()}),r=this.#en.x!==i.x||this.#en.y!==i.y;if(r){const e=this.#Zt.offset();this.#Zt.offset({x:e.x-this.#en.x+i.x,y:e.y-this.#en.y+i.y}),this.#en=i}return r}display(e){this.#jt.style.display=e?"":"none"}isVisible(){return""===this.#jt.style.display}draw(){this.#Zt.draw()}initialise(e,t,n){this.#_t=e,this.#Kt=t,this.#an=n,this.#Zt=new(Kn().Stage)({container:this.#jt,width:this.#_t.x,height:this.#_t.y,listening:!1}),this.#Zt.getContent().setAttribute("style","");const i=new(Kn().Layer)({listening:!1,visible:!0});this.#Zt.add(i)}setAnnotationGroup(e,t,n){if(this.#on=t,e.addEventListener("annotationadd",(e=>{this.#dn(e.data,!0),this.getKonvaLayer().draw()})),e.addEventListener("annotationupdate",(e=>{this.#hn(e.data),this.getKonvaLayer().draw()})),e.addEventListener("annotationremove",(e=>{this.#Sn(e.data),this.getKonvaLayer().draw()})),e.addEventListener("annotationgroupeditablechange",(e=>{this.activateCurrentPositionShapes(e.data)})),this.#rn=new $n(e),0!==e.getLength())for(const t of e.getList())this.#dn(t,!1),n(new yi(t,this.getDrawController()))}activateCurrentPositionShapes(e){const t=this.getKonvaLayer();if(this.#Zt.listening(!1),void 0!==this.#ln){this.#ln.disableAndResetEditor();const e=t.getChildren();for(const t of e)t instanceof Kn().Group&&t.getChildren().forEach((e=>{e instanceof Kn().Group&&this.#ln.removeShapeListeners(e)}))}const n=this.getDrawController();if(e&&n.getAnnotationGroup().isEditable()){const e=this.getCurrentPosGroup().getChildren();0!==e.length&&(this.#Zt.listening(!0),t.listening(!0)),void 0!==this.#ln&&e.forEach((e=>{if(e instanceof Kn().Group){const t=n.getAnnotation(e.id());this.#ln.addShapeGroupListeners(e,t,this)}}))}t.draw()}#gn(e){let t;return t=void 0!==e.planePoints?e.planePoints:[e.planeOrigin],this.#pn(t)}#pn(e){let t="";for(const n of e)0!==t.length&&(t+="-"),t+=G([B(n.getX(),2),B(n.getY(),2),B(n.getZ(),2)]);return t}#mn(e){let t;const n=this.#gn(e),i=this.getKonvaLayer().getChildren(ai(n));if(0!==i.length){const n=i[0];if(!(n instanceof Kn().Group))return;const r=n.getChildren(ai(e.id));0!==r.length&&r[0]instanceof Kn().Group&&(t=r[0])}return t}#dn(e,t){if(!e.isCompatibleView(this.#Xe))return;const n=this.#gn(e);let i=this.getKonvaLayer().getChildren(ai(n))[0];if(void 0===i&&(i=new(Kn().Group)({id:n,name:"position-group",visible:t}),this.getKonvaLayer().add(i)),!(i instanceof Kn().Group))return;const r=new ei,o=this.getKonvaStage();r.setZoomScale(o.scale());const a=e.getFactory().createShapeGroup(e,r);i.add(a),t&&void 0!==this.#ln&&this.#ln.addShapeGroupListeners(a,e,this),this.setLabelVisibility(a)}#Sn(e){const t=this.#mn(e);return t instanceof Kn().Group?(t.remove(),!0):(c.debug("No shape group to remove"),!1)}#hn(e){e.updateQuantification(),this.#Sn(e)&&this.#dn(e,!0)}fitToContainer(e,t,n){this.#Zt.width(e.x),this.#Zt.height(e.y);const i={x:t*this.#Kt.x,y:t*this.#Kt.y},r={x:this.#Zt.scale().x*i.x/this.#Jt.x,y:this.#Zt.scale().y*i.y/this.#Jt.y};this.#Zt.scale().x===r.x&&this.#Zt.scale().y===r.y||(this.#Jt=i,this.#Zt.scale(r));const o={x:n.x/i.x,y:n.y/i.y},a={x:e.x/i.x,y:e.y/i.y},s={x:0!==this.#in.x?a.x:0,y:0!==this.#in.y?a.y:0};this.#tn.x===o.x&&this.#tn.y===o.y&&this.#in.x===s.x&&this.#in.y===s.y||(this.#Zt.offset({x:this.#Zt.offset().x+o.x-this.#tn.x+s.x-this.#in.x,y:this.#Zt.offset().y+o.y-this.#tn.y+s.y-this.#in.y}),this.#in=s,this.#tn=o)}isAnnotationVisible(e){const t=this.getGroup(e);return void 0!==t&&t.isVisible()}setAnnotationVisibility(e,t){const n=this.getGroup(e);return void 0!==n&&(void 0===t&&(t=!n.isVisible()),n.visible(t),this.draw(),!0)}setLabelsVisibility(e){this.#cn=e;const t=this.getKonvaLayer().getChildren();for(const n of t)if(n instanceof Kn().Group){const t=n.getChildren();for(const n of t)n instanceof Kn().Group&&this.#fn(n,e)}}#fn(e,t){const n=e.getChildren(ti)[0];if(n instanceof Kn().Label&&(void 0===t&&(t=!n.isVisible()),void 0!==n.getText()&&0!==n.getText().text().length)){n.visible(t);const i=e.getChildren((e=>"Line"===e.className&&"connector"===e.name()))[0];i&&i.visible(t)}}setLabelVisibility(e){this.#fn(e,this.#cn)}deleteDraw(e,t){}deleteDraws(e){}getNumberOfDraws(){const e=this.getKonvaLayer().getChildren();let t=0;for(const n of e)n instanceof Kn().Group&&(t+=n.getChildren().length);return t}bindInteraction(){this.#Zt.listening(!0),this.#jt.style.pointerEvents="auto";const e=Gi;for(let t=0;te.id()===this.#sn));let t;return 1===e.length?e[0]instanceof Kn().Group&&(t=e[0]):0===e.length?(t=new(Kn().Group),t.name("position-group"),t.id(this.#sn),t.visible(!0),this.getKonvaLayer().add(t)):c.warn("Unexpected number of draw position groups"),t}getGroup(e){const t=this.getKonvaLayer().findOne("#"+e);return void 0===t&&c.warn("Cannot find node with id: "+e),t}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{e.srclayerid=this.getId(),e.dataid=this.#on,this.#Ae.fireEvent(e)};#un(e){const t=2/e.x,n=2/e.y,i=this.#Zt.find("Label");for(let e=0;e.33?0:1;t[n][e.data[n].length-2]=1,t[n][e.data[n].length-1]=1}t[e.data.length-2]=[],t[e.data.length-1]=[];for(let n=1;nMath.round(this.searchGran*this.cost[e.y][e.x]);setPoint(e){this.setWorking(!0),this.curPoint=e;let t=0,n=0;for(this.visited=[],n=0;nethis.getMax()?t:e))}}class Ei{getName(){return"Sharpen"}#Pn=null;setOriginalImage(e){this.#Pn=e}getOriginalImage(){return this.#Pn}update(){return this.getOriginalImage().convolute2D([0,-1,0,-1,5,-1,0,-1,0])}}class qi{getName(){return"Sobel"}#Pn=null;setOriginalImage(e){this.#Pn=e}getOriginalImage(){return this.#Pn}update(){const e=this.getOriginalImage(),t=e.convolute2D([1,0,-1,2,0,-2,1,0,-1]),n=e.convolute2D([1,2,1,0,0,0,-1,-2,-1]);return t.compose(n,(function(e,t){return Math.sqrt(e*e+t*t)}))}}class Ui{#wn;#on;#nt;constructor(e,t,n){this.#wn=e,this.#on=t,this.#nt=n}getName(){return"Filter-"+this.#wn.getName()}execute(){this.#nt.setImage(this.#on,this.#wn.update()),this.#nt.render(this.#on);const e={type:"filterrun",id:this.getName(),dataId:this.#on};this.onExecute(e)}undo(){this.#nt.setImage(this.#on,this.#wn.getOriginalImage()),this.#nt.render(this.#on);const e={type:"filterundo",id:this.getName(),dataid:this.#on};this.onUndo(e)}onExecute(e){}onUndo(e){}}const Mi={},Qi={},Vi={WindowLevel:class{#nt;#On=!1;#An;#bn;constructor(e){this.#nt=e,this.#bn=new Hn(e)}#xn(e,t){this.#nt.getLayerGroupByDivId(t).getActiveViewLayer().getViewController().isMonochrome()&&(this.#On=!0,this.#An=e)}#Rn(e,t){if(!this.#On)return;const n=this.#nt.getLayerGroupByDivId(t).getActiveViewLayer().getViewController(),i=e.getX()-this.#An.getX(),r=this.#An.getY()-e.getY(),o=n.getImageRescaledDataRange(),a=.01*(o.max-o.min),s=n.getWindowLevel().center,l=n.getWindowLevel().width,c=s+Math.round(r*a);let d=l+Math.round(i*a);var h;d=(h=d)<1?1:h;const S=new u(c,d);n.setWindowLevel(S),this.#An=e}#Fn(){this.#On&&(this.#On=!1)}mousedown=e=>{const t=Wi(e),n=Zi(e);this.#xn(t,n.groupDivId)};mousemove=e=>{const t=Wi(e),n=Zi(e);this.#Rn(t,n.groupDivId)};mouseup=e=>{this.#Fn()};mouseout=e=>{this.#Fn()};touchstart=e=>{const t=zi(e),n=Zi(e);this.#xn(t[0],n.groupDivId)};touchmove=e=>{const t=zi(e),n=Zi(e);this.#Rn(t[0],n.groupDivId)};touchend=e=>{this.#Fn()};dblclick=e=>{const t=Zi(e),n=Wi(e),i=this.#nt.getLayerGroupByDivId(t.groupDivId).getActiveViewLayer(),r=i.displayToPlaneIndex(n),o=i.getViewController();if(!o.isMonochrome())return;const a=this.#nt.getData(i.getDataId()).image,s=new u(a.getRescaledValueAtIndex(o.getCurrentIndex().getWithNew2D(r.get(0),r.get(1))),o.getWindowLevel().width);o.setWindowLevel(s)};wheel=e=>{this.#bn.wheel(e)};keydown=e=>{e.context="WindowLevel",this.#nt.onKeydown(e)};activate(e){}init(){}setFeatures(e){}},Scroll:class{#nt;#On=!1;#An;#bn;#En;#qn=!1;#Un;constructor(e){this.#nt=e,this.#bn=new Hn(e)}#xn(e,t){this.#Mn();const n=this.#nt.getLayerGroupByDivId(t).getActiveViewLayer(),i=n.getViewController();i.isPlaying()&&i.stop(),this.#On=!0,this.#An=e;const r=n.displayToPlanePos(e),o=i.getPositionFromPlanePoint(r);i.setCurrentPosition(o)}#Rn(e,t){if(!this.#On)return void(this.#qn&&this.#Qn(e,t));const n=this.#nt.getLayerGroupByDivId(t),i=n.getActiveViewLayer().getViewController();let r;const o=e.getY()-this.#An.getY(),a=Math.abs(o)>15;a&&n.canScroll()&&(r=o>0?i.getDecrementScrollPosition():i.getIncrementScrollPosition());const s=e.getX()-this.#An.getX(),l=Math.abs(s)>15;l&&n.moreThanOne(3)&&(r=s>0?i.getIncrementPosition(3):i.getDecrementPosition(3)),void 0!==r&&n.isPositionInBounds(r)&&i.setCurrentPosition(r),(l||a)&&(this.#An=e)}#Fn(){this.#On&&(this.#On=!1)}mousedown=e=>{const t=Wi(e),n=Zi(e);this.#xn(t,n.groupDivId)};mousemove=e=>{const t=Wi(e),n=Zi(e);this.#Rn(t,n.groupDivId)};mouseup=e=>{this.#Fn()};mouseout=e=>{this.#Fn(),this.#Mn()};touchstart=e=>{this.#En=setTimeout((()=>{this.dblclick(e)}),500);const t=zi(e),n=Zi(e);this.#xn(t[0],n.groupDivId)};touchmove=e=>{null!==this.#En&&(clearTimeout(this.#En),this.#En=null);const t=zi(e),n=Zi(e);this.#Rn(t[0],n.groupDivId)};touchend=e=>{null!==this.#En&&(clearTimeout(this.#En),this.#En=null),this.#Fn()};wheel=e=>{this.#bn.wheel(e)};keydown=e=>{e.context="Scroll",this.#nt.onKeydown(e)};dblclick=e=>{const t=Zi(e);this.#nt.getLayerGroupByDivId(t.groupDivId).getActiveViewLayer().getViewController().play()};#Qn(e,t){const n=this.#nt.getLayerGroupByDivId(t);this.#Un=t,n.showTooltip(e)}#Mn(){void 0!==this.#Un&&(this.#nt.getLayerGroupByDivId(this.#Un).removeTooltipDiv(),this.#Un=void 0)}activate(e){e||this.#Mn()}setFeatures(e){void 0!==e.displayTooltip&&(this.#qn=e.displayTooltip)}init(){}},ZoomAndPan:class{#nt;#On=!1;#An;#Vn;#Nn;#Bn;constructor(e){this.#nt=e}#xn(e){this.#On=!0,this.#An=e,this.#Vn=!1}#Gn=e=>{this.#On=!0,this.#An=e[0],this.#Vn=!1,this.#Nn=new zn(e[0],e[1]),this.#Bn=this.#Nn.getMidpoint()};#Rn(e,t){if(!this.#On)return;this.#Vn=!0;const n=e.getX()-this.#An.getX(),i=e.getY()-this.#An.getY(),r=this.#nt.getLayerGroupByDivId(t),o=r.getActiveViewLayer(),a=o.getViewController(),s=o.displayToPlaneScale(new R(n,i)),l=a.getOffset3DFromPlaneOffset({x:s.getX(),y:s.getY()});r.addTranslation({x:l.getX(),y:l.getY(),z:l.getZ()}),r.draw(),this.#An=e}#kn=(e,t)=>{if(!this.#On)return;this.#Vn=!0;const n=new zn(e[0],e[1]).getLength()/this.#Nn.getLength(),i=this.#nt.getLayerGroupByDivId(t),r=i.getActiveViewLayer(),o=r.getViewController();if(1===n){const t=e[0].getY()-this.#An.getY();if(Math.abs(t)<15)return;if(i.canScroll()){let e;e=t>0?o.getIncrementScrollPosition():o.getDecrementScrollPosition(),void 0!==e&&i.isPositionInBounds(e)&&o.setCurrentPosition(e)}}else{const e=(n-1)/10;if(Math.abs(e)%.1<=.05&&void 0!==this.#Bn){const t=r.displayToMainPlanePos(this.#Bn),n=o.getPlanePositionFromPlanePoint(t);i.addScale(e,n),i.draw()}}};#Hn(e,t){const n=this.#nt.getLayerGroupByDivId(t).getActiveViewLayer(),i=n.getViewController(),r=n.displayToPlanePos(e),o=i.getPositionFromPlanePoint(r);i.setCurrentPosition(o)}#Fn(){this.#On&&(this.#On=!1)}mousedown=e=>{const t=Wi(e);this.#xn(t)};mousemove=e=>{const t=Wi(e),n=Zi(e);this.#Rn(t,n.groupDivId)};mouseup=e=>{if(!this.#Vn){const t=Wi(e),n=Zi(e);this.#Hn(t,n.groupDivId)}this.#Fn()};mouseout=e=>{this.#Fn()};touchstart=e=>{const t=zi(e);1===t.length?this.#xn(t[0]):2===t.length&&this.#Gn(t)};touchmove=e=>{const t=zi(e),n=Zi(e);1===t.length?this.#Rn(t[0],n.groupDivId):2===t.length&&this.#kn(t,n.groupDivId)};touchend=e=>{if(!this.#Vn){const t=Wi(e),n=Zi(e);this.#Hn(t,n.groupDivId)}this.#Fn()};wheel=e=>{e.preventDefault();const t=-e.deltaY/500,n=Zi(e),i=Wi(e),r=this.#nt.getLayerGroupByDivId(n.groupDivId),o=r.getActiveViewLayer(),a=o.getViewController(),s=o.displayToMainPlanePos(i),l=a.getPlanePositionFromPlanePoint(s);r.addScale(t,l),r.draw()};keydown=e=>{e.context="ZoomAndPan",this.#nt.onKeydown(e)};activate(e){}init(){}setFeatures(e){}},Opacity:class{#nt;#On=!1;#An;#bn;constructor(e){this.#nt=e,this.#bn=new Hn(e)}#xn(e){this.#On=!0,this.#An=e}#Rn(e,t){if(!this.#On)return;const n=e.getX()-this.#An.getX();if(Math.abs(n)>15){const i=this.#nt.getLayerGroupByDivId(t).getActiveViewLayer(),r=i.getOpacity();i.setOpacity(r+n/200),i.draw(),this.#An=e}}#Fn(){this.#On&&(this.#On=!1)}mousedown=e=>{const t=Wi(e);this.#xn(t)};mousemove=e=>{const t=Wi(e),n=Zi(e);this.#Rn(t,n.groupDivId)};mouseup=e=>{this.#Fn()};mouseout=e=>{this.#Fn()};touchstart=e=>{const t=zi(e);this.#xn(t[0])};touchmove=e=>{const t=zi(e),n=Zi(e);this.#Rn(t[0],n.groupDivId)};touchend=e=>{this.#Fn()};wheel=e=>{this.#bn.wheel(e)};keydown=e=>{e.context="Opacity",this.#nt.onKeydown(e)};activate(e){}init(){}setFeatures(e){}},Draw:class{#nt;#bn;#zn;#Wn=!1;#Yn=null;#wt=null;#Xn=null;#jn;#yt=[];#Zn=null;#_n=!0;#Kn=[];#ln;#Jn=!1;#H={};#$n=!1;#ei=[];constructor(e){this.#nt=e,this.#bn=new Hn(e),this.#ln=new Di(e,this.#Re),this.#zn=e.getStyle()}#ti(e,t){const n=this.#nt.getLayerGroupByDivId(t);let i=n.getActiveDrawLayer();if(void 0===i){const e=n.getActiveViewLayer().getDataId(),r=this.#nt.getData(e).image.getMeta().SeriesInstanceUID;if(this.#Kn.includes(r))return void this.#Re({type:"warn",message:"Cannot create draw layer, data is in black list"});const o=this.#nt.createAnnotationData(e);this.#nt.addAndRenderAnnotationData(o,t,e),i=n.getActiveDrawLayer(),i.setShapeHandler(this.#ln),n.setActiveDrawLayerByDataId(i.getDataId())}const r=i.getDrawController().getAnnotationGroup(),o=i.getKonvaStage();if(this.#zn.setZoomScale(o.scale()),r.isEditable()){const t=o.getIntersection({x:e.getX(),y:e.getY()});t?this.#ni(i,t):this.#ii(n,e)}}#ii(e,t){this.#ln.disableAndResetEditor(),this.#ri();const n=e.getActiveViewLayer();this.#Zn=n.displayToPlanePos(t),this.#yt.push(this.#Zn)}#ri(){this.#Wn=!0,this.#wt=new this.#Yn[this.#jn],this.#yt=[]}#oi(){this.#Wn=!1,this.#yt=[]}#ni(e,t){let n=t.getParent();t instanceof Kn().Tag&&(n=n.getParent());const i=n.find(".shape")[0];i instanceof Kn().Shape&&(this.#Re({type:"annotationselect",annotationid:n.id(),dataid:e.getDataId()}),this.#ln.setEditorShape(i,e))}#ai(e,t){const n=this.#nt.getLayerGroupByDivId(t),i=n.getActiveViewLayer().displayToPlanePos(e);(Math.abs(i.getX()-this.#Zn.getX())>0||Math.abs(i.getY()-this.#Zn.getY())>0)&&(this.#$n&&this.#yt.pop(),this.#Zn=i,this.#$n=!0,this.#yt.push(this.#Zn),this.#si(this.#yt,n))}#li(e){if(0!==this.#yt.length){if(this.#yt.length===this.#wt.getNPoints()){const t=this.#nt.getLayerGroupByDivId(e);this.#ci(this.#yt,t),this.#oi()}this.#$n=!1}else c.warn("Draw mouseup but no points...")}mousedown=e=>{if(this.#Wn)return;const t=Wi(e),n=Zi(e);this.#ti(t,n.groupDivId)};mousemove=e=>{if(!this.#Wn)return;const t=Wi(e),n=Zi(e);this.#ai(t,n.groupDivId)};mouseup=e=>{if(!this.#Wn)return;const t=Zi(e);this.#li(t.groupDivId)};dblclick=e=>{if(this.#wt&&void 0!==this.#wt.getNPoints())return;if(!this.#Wn)return;if(0===this.#yt.length)return void c.warn("Draw dblclick but no points...");const t=Zi(e),n=this.#nt.getLayerGroupByDivId(t.groupDivId);this.#ci(this.#yt,n),this.#oi()};mouseout=e=>{if(!this.#Wn)return;const t=Zi(e);this.#li(t.groupDivId)};touchstart=e=>{if(this.#Wn)return;const t=zi(e),n=Zi(e);this.#ti(t[0],n.groupDivId)};touchmove=e=>{if(!this.#Wn)return;const t=Zi(e),n=zi(e),i=this.#nt.getLayerGroupByDivId(t.groupDivId),r=i.getActiveViewLayer().displayToPlanePos(n[0]);(Math.abs(r.getX()-this.#Zn.getX())>0||Math.abs(r.getY()-this.#Zn.getY())>0)&&(1!==this.#yt.length&&this.#yt.pop(),this.#Zn=r,this.#yt.push(this.#Zn),this.#yt.length{this.#yt.push(this.#Zn)}),this.#wt.getTimeout())),this.#si(this.#yt,i))};touchend=e=>{this.dblclick(e)};wheel=e=>{this.#_n&&this.#bn.wheel(e)};keydown=e=>{this.#Wn||(e.context="Draw",this.#nt.onKeydown(e));const t=this.#ln.getEditorAnnotation();if(("Delete"===e.key||"Backspace"===e.key)&&void 0!==t){const e=this.#nt.getActiveLayerGroup().getActiveDrawLayer().getDrawController(),n=new vi(t,e);this.#nt.addToUndoStack(n),n.execute(),this.#ln.onMouseOutShapeGroup()}if("Escape"===e.key&&null!==this.#Xn){const e=this.#Xn.getLayer();this.#Xn.destroy(),this.#Xn=null,this.#oi(),e.draw()}};#si(e,t){this.#Xn&&(this.#Xn.destroy(),this.#Xn=null);const n=t.getActiveDrawLayer(),i=n.getDrawController(),r=n.getKonvaLayer(),o=t.getActiveViewLayer().getViewController();if(this.#Jn){const e=["#ffff80","#ff80ff","#80ffff","#80ff80","8080ff","ff8080"],t=n.getId(),i=t.substring(t.length-1),r=e[parseInt(i,10)-1];void 0!==r&&this.#zn.setLineColour(r)}const a=new Bi,s=i.getAnnotationGroup().getColour();a.colour=void 0!==s?s:this.#zn.getLineColour(),a.init(o),this.#wt.setAnnotationMathShape(a,e),this.#Xn=this.#wt.createShapeGroup(a,this.#zn),n.setLabelVisibility(this.#Xn),this.#Xn.getChildren(ni)[0].listening(!1),r.listening(!1),r.add(this.#Xn),r.draw()}#ci(e,t){this.#Xn&&(this.#Xn.destroy(),this.#Xn=null);const n=t.getActiveDrawLayer(),i=n.getKonvaLayer(),r=n.getDrawController(),o=t.getActiveViewLayer().getViewController(),a=new Bi,s=r.getAnnotationGroup().getColour();a.colour=void 0!==s?s:this.#zn.getLineColour(),a.id=$e(),a.init(o),this.#wt.setAnnotationMathShape(a,e);const l=new yi(a,r);this.#nt.addToUndoStack(l),l.execute(),i.listening(!0)}#ui(e){const t=e.getId();return void 0===this.#ei[t]&&(this.#ei[t]=()=>{e.activateCurrentPositionShapes(!0)}),this.#ei[t]}#di(e,t){e.setShapeHandler(this.#ln),e.activateCurrentPositionShapes(t),t?this.#nt.addEventListener("positionchange",this.#ui(e)):this.#nt.removeEventListener("positionchange",this.#ui(e))}activate(e){e||this.#ln.onMouseOutShapeGroup();const t=this.#nt.getDrawLayers();for(const n of t)void 0!==n&&this.#di(n,e);this.#nt.addEventListener("drawlayeradd",(t=>{const n=this.#nt.getDrawLayers((function(e){return e.getId()===t.layerid}));1===n.length&&this.#di(n[0],e)}))}setOptions(e){this.#Yn=e}getOptionsType(){return"factory"}setFeatures(e){if(void 0!==e.autoShapeColour&&(this.#Jn=e.autoShapeColour),void 0!==e.shapeColour&&(this.#zn.setLineColour(e.shapeColour),this.#Jn=!1),void 0!==e.shapeName){if(!this.hasShape(e.shapeName))throw new Error("Unknown shape: '"+e.shapeName+"'");this.#jn=e.shapeName}void 0!==e.mouseOverCursor&&this.#ln.storeMouseOverCursor(e.mouseOverCursor),void 0!==e.withScroll&&(this.#_n=e.withScroll),void 0!==e.blacklist&&(this.#Kn=e.blacklist)}init(){}getEventNames(){return["annotationupdate","annotationselect","warn"]}addEventListener(e,t){void 0===this.#H[e]&&(this.#H[e]=[]),this.#H[e].push(t)}removeEventListener(e,t){if(void 0!==this.#H[e])for(let n=0;n{if(void 0!==this.#H[e.type])for(let t=0;t{e.context="Filter",this.#nt.onKeydown(e)};getEventNames(){return["filterrun","filterundo"]}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{this.#Ae.fireEvent(e)};getSelectedFilter(){return this.#Si}setFeatures(e){if(void 0!==e.filterName){if(!this.hasFilter(e.filterName))throw new Error("Unknown filter: '"+e.filterName+"'");this.#Si&&this.#Si.activate(!1),this.#Si=this.#hi[e.filterName],this.#Si.activate(!0)}if(void 0!==e.run&&e.run){let t={};void 0!==e.runArgs&&(t=e.runArgs),this.getSelectedFilter().run(t)}}getFilterList(){return this.#hi}hasFilter(e){return this.#hi[e]}},Floodfill:class{#nt;constructor(e){this.#nt=e}#gi=5;#pi=0;#mi=2e3;#fi=null;#Di=null;#Ci=10;#yi=null;#On=!1;#bt;#vi;#Ii=null;#Ti=[];#Li=!1;#zn=new ei;#Ae=new ke;setExtend(e){this.#Li=e}getExtend(){return this.#Li}#Pi=(e,t)=>{const n=this.#nt.getLayerGroupByDivId(t).getActiveViewLayer().displayToPlaneIndex(e);return{x:n.get(0),y:n.get(1)}};#wi(e,t,n){this.#Ti=[];const i={data:this.#fi.data,width:this.#fi.width,height:this.#fi.height,bytes:4};this.#Di=Li().floodFill(i,e.x,e.y,t),this.#Di=Li().gaussBlurOnlyBorder(this.#Di,this.#gi);let r=Li().traceContours(this.#Di);if(r=Li().simplifyContours(r,this.#pi,this.#mi),r.length>0&&r[0].points[0].x){if(n)return r[0].points;for(let e=0,t=r[0].points.length;eo&&this.#Oi(this.#vi,a,n);t--)i.decrementIndex(2);i.setCurrentPosition(r)}onThresholdChange(e){}#xn(e,t){const n=this.#nt.getLayerGroupByDivId(t),i=n.getActiveViewLayer();let r=n.getActiveDrawLayer();if(void 0===r){const e=n.getActiveViewLayer().getDataId(),i=this.#nt.createAnnotationData(e);this.#nt.addAndRenderAnnotationData(i,t,e),r=n.getActiveDrawLayer(),n.setActiveDrawLayerByDataId(r.getDataId())}this.#fi=i.getImageData(),this.#fi?(this.#zn.setZoomScale(r.getKonvaLayer().getAbsoluteScale()),this.#On=!0,this.#vi=this.#Pi(e,t),this.#Oi(this.#vi,this.#Ci,n),this.onThresholdChange(this.#Ci)):c.error("No image found")}#Rn(e,t){if(!this.#On)return;const n=this.#Pi(e,t);this.#yi=Math.round(Math.sqrt(Math.pow(this.#vi.x-n.x,2)+Math.pow(this.#vi.y-n.y,2))/2),this.#yi=this.#yi{const t=Wi(e),n=Zi(e);this.#xn(t,n.groupDivId)};mousemove=e=>{const t=Wi(e),n=Zi(e);this.#Rn(t,n.groupDivId)};mouseup=e=>{this.#Fn()};mouseout=e=>{this.#Fn()};touchstart=e=>{const t=zi(e),n=Zi(e);this.#xn(t[0],n.groupDivId)};touchmove=e=>{const t=zi(e),n=Zi(e);this.#Rn(t[0],n.groupDivId)};touchend=e=>{this.#Fn()};keydown=e=>{e.context="Floodfill",this.#nt.onKeydown(e)};activate(e){e&&(this.#zn.setBaseScale(this.#nt.getBaseScale()),this.setFeatures({shapeColour:this.#zn.getLineColour()}))}init(){}getEventNames(){return["drawcreate","drawchange","drawmove","drawdelete"]}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}setFeatures(e){void 0!==e.shapeColour&&this.#zn.setLineColour(e.shapeColour)}},Livewire:class{#nt;constructor(e){this.#nt=e}#On=!1;#An;#bt;#zn=new ei;#Ai=new Pi;#bi=new Pi;#Ti=[];#xi=5;#Ae=new ke;#Ri(e){const t=e.get(1);for(let e=0;e{const t=Wi(e),n=Zi(e);this.#xn(t,n.groupDivId)};mousemove=e=>{const t=Wi(e),n=Zi(e);this.#Rn(t,n.groupDivId)};mouseup(e){}mouseout=e=>{};dblclick=e=>{this.#qi()};touchstart=e=>{const t=zi(e),n=Zi(e);this.#xn(t[0],n.groupDivId)};touchmove=e=>{const t=zi(e),n=Zi(e);this.#Rn(t[0],n.groupDivId)};touchend=e=>{};keydown=e=>{e.context="Livewire",this.#nt.onKeydown(e)};activate(e){if(e){const e=this.#nt.getActiveLayerGroup().getActiveViewLayer(),t=e.getViewController().getImageSize();this.#Ei.setDimensions(t.get(0),t.get(1)),this.#Ei.setData(e.getImageData().data),this.#zn.setBaseScale(this.#nt.getBaseScale()),this.setFeatures({shapeColour:this.#zn.getLineColour()})}}init(){}getEventNames(){return["drawcreate","drawchange","drawmove","drawdelete"]}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}setFeatures(e){void 0!==e.shapeColour&&this.#zn.setLineColour(e.shapeColour)}}},Ni={draw:{ArrowFactory:class{#Ui="arrow";#Mi=new Ri(this.#Qi);static supports(e){return e instanceof R}getName(){return this.#Ui}getGroupName(){return this.#Ui+"-group"}getNPoints(){return 2}getTimeout(){return 0}setAnnotationMathShape(e,t){e.mathShape=this.#Vi(t),e.referencePoints=[t[1]],e.setTextExpr(this.#Ni()),e.updateQuantification()}createShapeGroup(e,t){const n=new(Kn().Group);n.name(this.getGroupName()),n.visible(!0),n.id(e.id);const i=this.#Bi(e,t);n.add(i);const r=this.#Gi(e,t);for(const e of r)n.add(e);const o=this.#Mi.create(e,t);n.add(o);const a=this.#ki(i);return n.add(this.#Mi.getConnector(a,o,t)),n}#ki(e){const t=e.points(),n=e.x(),i=e.y(),r=(t[0]+t[2])/2+n,o=(t[1]+t[3])/2+i;return[new R(r,o)]}#Hi(e){const t=e.points(),n=e.x(),i=e.y();return[new R(t[0]+n,t[1]+i),new R(t[2]+n,t[3]+i)]}getAnchors(e,t){const n=this.#Hi(e),i=[];for(let e=0;e180&&(o=360-o,a+=o);const s=33*Math.min(i.getLength(),r.getLength())/100;return[new(Kn().Arc)({innerRadius:s,outerRadius:s,stroke:e.colour,strokeWidth:t.getStrokeWidth(),strokeScaleEnabled:!1,angle:o,rotation:-a,x:n.getPoint(1).getX(),y:n.getPoint(1).getY(),name:"shape-arc"})]}#Qi(e){const t=e.mathShape,n=new zn(t.getPoint(0),t.getPoint(1)),i=new zn(t.getPoint(1),t.getPoint(2)),r=(n.getMidpoint().getX()+i.getMidpoint().getX())/2,o=(n.getMidpoint().getY()+i.getMidpoint().getY())/2;return new R(r,o)}#zi(e,t,n){const i=e.mathShape,r=new zn(i.getPoint(0),i.getPoint(1)),o=new zn(i.getPoint(1),i.getPoint(2)),a=t.getParent();if(!(a instanceof Kn().Group))return;const s=this.#Wi(a);s.position({x:0,y:0}),s.points([i.getPoint(0).getX(),i.getPoint(0).getY(),i.getPoint(1).getX(),i.getPoint(1).getY(),i.getPoint(2).getX(),i.getPoint(2).getY()]);const l=a.getChildren((function(e){return"shape-arc"===e.name()}))[0];if(!(l instanceof Kn().Arc))return;const c=oi(a,0),u=oi(a,1),d=oi(a,2);switch(t.id()){case"anchor0":c.x(t.x()),c.y(t.y());break;case"anchor1":u.x(t.x()),u.y(t.y());break;case"anchor2":d.x(t.x()),d.y(t.y())}let h=Wn(r,o),S=r.getInclination();h>180&&(h=360-h,S+=h);const g=33*Math.min(r.getLength(),o.getLength())/100;l.innerRadius(g),l.outerRadius(g),l.angle(h),l.rotation(-S);const p={x:u.x(),y:u.y()};l.position(p),s.hitFunc((function(e){e.beginPath(),e.moveTo(i.getPoint(0).getX(),i.getPoint(0).getY()),e.lineTo(i.getPoint(1).getX(),i.getPoint(1).getY()),e.lineTo(i.getPoint(2).getX(),i.getPoint(2).getY()),e.closePath(),e.fillStrokeShape(s)}))}#Yi(e,t){}#Xi(e,t){}},RectangleFactory:class{#Ui="rectangle";#Mi=new Ri(this.#Qi);static supports(e){return e instanceof ci}getName(){return this.#Ui}getGroupName(){return this.#Ui+"-group"}getNPoints(){return 2}getTimeout(){return 0}setAnnotationMathShape(e,t){e.mathShape=this.#Vi(t),e.setTextExpr(this.#Ni()),e.updateQuantification()}createShapeGroup(e,t){const n=new(Kn().Group);n.name(this.getGroupName()),n.visible(!0),n.id(e.id);const i=this.#Bi(e,t);n.add(i);const r=this.#Mi.create(e,t);n.add(r);const o=this.#ki(i);return n.add(this.#Mi.getConnector(o,r,t)),n}#ki(e){const t=e.x(),n=e.y(),i=e.width(),r=e.height();return[new R(t+i/2,n),new R(t,n+r/2),new R(t+i/2,n+r),new R(t+i,n+r/2)]}#Hi(e){const t=e.x(),n=e.y(),i=e.width(),r=e.height();return[new R(t,n),new R(t+i,n),new R(t+i,n+r),new R(t,n+r)]}getAnchors(e,t){const n=this.#Hi(e),i=[];for(let e=0;e{this.#Ae.fireEvent(e)}},Sobel:class{#nt;constructor(e){this.#nt=e}#Ae=new ke;activate(e){}init(){}run(e){if(void 0===e.dataId)throw new Error("No dataId to run sobel filter on.");const t=new qi,n=this.#nt.getData(e.dataId).image;t.setOriginalImage(n);const i=new Ui(t,e.dataId,this.#nt);i.onExecute=this.#Re,i.onUndo=this.#Re,i.execute(),this.#nt.addToUndoStack(i)}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{this.#Ae.fireEvent(e)}},Sharpen:class{#nt;constructor(e){this.#nt=e}#Ae=new ke;activate(e){}init(){}run(e){if(void 0===e.dataId)throw new Error("No dataId to run sharpen filter on.");const t=new Ei,n=this.#nt.getData(e.dataId).image;t.setOriginalImage(n);const i=new Ui(t,e.dataId,this.#nt);i.onExecute=this.#Re,i.onUndo=this.#Re,i.execute(),this.#nt.addToUndoStack(i)}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{this.#Ae.fireEvent(e)}}}};class Bi{id;referenceSopUID;mathShape;referencePoints;colour;quantification;textExpr;labelPosition;planeOrigin;planePoints;#Zi;getOrientationName(){let e;return void 0!==this.planePoints&&(e=ft(this.planePoints[1].getValues().concat(this.planePoints[2].getValues()))),e}init(e){void 0===this.referenceSopUID?(this.#Zi=e,this.referenceSopUID=e.getCurrentImageUid(),this.planeOrigin=e.getOriginForImageUid(this.referenceSopUID),e.isAquisitionOrientation()||(this.planePoints=e.getPlanePoints(e.getCurrentPosition()))):c.debug("Cannot initialise annotation twice")}isCompatibleView(e){let t=!1;if(void 0===this.planePoints)e.isAquisitionOrientation()&&(t=!0);else{const n=e.getCosines(),i=new F(n[0],n[1],n[2]),r=new F(n[3],n[4],n[5]);i.equals(this.planePoints[1])&&r.equals(this.planePoints[2])&&(t=!0)}return t}setViewController(e){e.includesImageUid(this.referenceSopUID)&&this.isCompatibleView(e.getPlaneHelper())&&(this.#Zi=e,this.planeOrigin=e.getOriginForImageUid(this.referenceSopUID))}getCentroid(){let e;if(void 0!==this.#Zi&&void 0!==this.mathShape.getCentroid){let t=this.planeOrigin;void 0!==this.planePoints&&(t=this.planePoints[0]);const n=new E([t.getX(),t.getY(),t.getZ()]),i=this.#Zi.getIndexFromPosition(n),r=this.#Zi.getScrollIndex(),o=i.getValues()[r],a=this.mathShape.getCentroid();e=this.#Zi.getPositionFromPlanePoint(a,o)}return e}setTextExpr(e){if(void 0!==this.#Zi){const t=this.#Zi.getModality();void 0!==e[t]?this.textExpr=e[t]:this.textExpr=e["*"]}else c.warn("Cannot set text expr without a view controller")}getText(){return function(e,t){let n="";if(null==e)return n;if(n=e,null==t)return n;const i=Q(e);for(let e=0;e{this.#on===e.dataid&&(this.#Zi.setImage(e.value[0]),this.#hr(this.#Zi.getImageSize().get2D()),this.#rr=!0)};bindImage(){this.#Zi&&this.#Zi.bindImageAndLayer(this)}unbindImage(){this.#Zi&&this.#Zi.unbindImageAndLayer(this)}onimagecontentchange=e=>{this.#on===e.dataid&&(this.#$i=this.#Zi.isPositionInBounds(),this.#rr=!0,this.draw())};onimagegeometrychange=e=>{if(this.#on===e.dataid){const e=this.#Zi.getImageSize().get2D();if(this.#_t.x!==e.x||this.#_t.y!==e.y){if(void 0!==this.#ar&&void 0!==this.#sr){const e=this.#Zi.getOrigin(),t=this.#sr.minus(e),n=this.#Zi.getOrigin(this.#Zi.getCurrentPosition()),i=this.#ar.minus(n);this.setBaseOffset(t,i)}this.#hr(e),this.#rr=!0,this.draw()}}};getId(){return this.#jt.id}removeFromDOM(){this.#jt.remove()}getBaseSize(){return this.#_t}getImageWorldSize(){return this.#Zi.getImageWorldSize()}getOpacity(){return this.#tr}setOpacity(e){if(e===this.#tr)return;this.#tr=Math.min(Math.max(e,0),1);const t={type:"opacitychange",value:[this.#tr]};this.#Re(t)}addFlipOffsetX(){this.#in.x+=this.#_i.width/this.#nr.x,this.#ir.x+=this.#in.x}addFlipOffsetY(){this.#in.y+=this.#_i.height/this.#nr.y,this.#ir.y+=this.#in.y}flipScaleX(){this.#$t.x*=-1}flipScaleY(){this.#$t.y*=-1}flipScaleZ(){this.#$t.z*=-1}setScale(e,t){const n=this.#Zi.getPlaneHelper(),i=n.getTargetOrientedPositiveXYZ({x:e.x*this.#$t.x,y:e.y*this.#$t.y,z:e.z*this.#$t.z}),r={x:this.#Jt.x*i.x,y:this.#Jt.y*i.y};if(1===Math.abs(e.x)&&1===Math.abs(e.y)&&1===Math.abs(e.z)){const e={x:this.#ir.x-this.#nn.x,y:this.#ir.y-this.#nn.y};this.#nn={x:0,y:0},this.#ir=e}else if(void 0!==t){let e=n.getPlaneOffsetFromOffset3D({x:t.getX(),y:t.getY(),z:t.getZ()});e={x:e.x+this.#en.x,y:e.y+this.#en.y};const i=_i(this.#ir,this.#nr,r,e),o={x:this.#nn.x+i.x-this.#ir.x,y:this.#nn.y+i.y-this.#ir.y};this.#nn=o,this.#ir=i}this.#nr=r}initScale(e,t){const n=this.#Zi.getPlaneHelper().getTargetOrientedPositiveXYZ({x:e.x*this.#$t.x,y:e.y*this.#$t.y,z:e.z*this.#$t.z}),i={x:this.#Jt.x*n.x,y:this.#Jt.y*n.y};this.#nr=i,this.#nn={x:t.x/this.#Jt.x,y:t.y/this.#Jt.y},this.#ir={x:this.#ir.x+this.#nn.x,y:this.#ir.y+this.#nn.y}}setBaseOffset(e,t,n,i){const r=this.#Zi.getPlaneHelper(),o=r.getNativeScrollIndex(),a=r.getPlaneOffsetFromOffset3D({x:0===o?e.getX():t.getX(),y:1===o?e.getY():t.getY(),z:2===o?e.getZ():t.getZ()}),s=this.#en.x!==a.x||this.#en.y!==a.y;return void 0!==n&&void 0!==i&&(this.#ar=n,this.#sr=i),s&&(this.#ir={x:this.#ir.x-this.#en.x+a.x,y:this.#ir.y-this.#en.y+a.y},this.#en=a),s}setOffset(e){const t=this.#Zi.getPlaneHelper().getPlaneOffsetFromOffset3D(e);this.#ir={x:t.x+this.#tn.x+this.#en.x+this.#nn.x+this.#in.x,y:t.y+this.#tn.y+this.#en.y+this.#nn.y+this.#in.y}}displayToPlaneIndex(e){const t=this.displayToPlanePos(e);return new s([Math.floor(t.getX()),Math.floor(t.getY())])}displayToPlaneScale(e){return new R(e.getX()/this.#nr.x,e.getY()/this.#nr.y)}displayToPlanePos(e){const t=this.displayToPlaneScale(e);return new R(t.getX()+this.#ir.x,t.getY()+this.#ir.y)}planePosToDisplay(e){let t=(e.getX()-this.#ir.x+this.#en.x)*this.#nr.x,n=(e.getY()-this.#ir.y+this.#en.y)*this.#nr.y;return(t<0||t>=this.#_i.width)&&(t=void 0),(n<0||n>=this.#_i.height)&&(n=void 0),new R(t,n)}displayToMainPlanePos(e){const t=this.displayToPlanePos(e);return new R(t.getX()-this.#en.x,t.getY()-this.#en.y)}display(e){this.#jt.style.display=e?"":"none"}isVisible(){return""===this.#jt.style.display}draw(){if(!this.#$i)return;let e={type:"renderstart",layerid:this.getId(),dataid:this.getDataId()};this.#Re(e),this.#rr&&this.#Sr(),this.#Ji.globalAlpha=this.#tr,this.clear(),this.#Ji.setTransform(this.#nr.x,0,0,this.#nr.y,-1*this.#ir.x*this.#nr.x,-1*this.#ir.y*this.#nr.y),this.#Ji.imageSmoothingEnabled=this.#or,this.#Ji.drawImage(this.#Ki,0,0),e={type:"renderend",layerid:this.getId(),dataid:this.getDataId()},this.#Re(e)}initialise(e,t,n){this.#Kt=t,this.#tr=Math.min(Math.max(n,0),1),this.#_i=document.createElement("canvas"),this.#jt.appendChild(this.#_i),this.#_i.getContext?(this.#Ji=this.#_i.getContext("2d"),this.#Ji?(this.#Ki=document.createElement("canvas"),this.#hr(e),this.#rr=!0):alert("Error: failed to get the 2D context.")):alert("Error: no canvas.getContext method.")}#hr(e){if(!Yi(e.x,e.y))throw new Error("Cannot create canvas with size "+e.x+", "+e.y);this.#_t=e,this.#Ki.width=this.#_t.x,this.#Ki.height=this.#_t.y,this.#Ji.clearRect(0,0,this.#_t.x,this.#_t.y),this.#er=this.#Ji.createImageData(this.#_t.x,this.#_t.y)}fitToContainer(e,t,n){let i=!1;if(this.#_i.width!==e.x||this.#_i.height!==e.y){if(!Yi(e.x,e.y))throw new Error("Cannot resize canvas "+e.x+", "+e.y);this.#_i.width=e.x,this.#_i.height=e.y,i=!0}const r={x:t*this.#Kt.x,y:t*this.#Kt.y},o={x:this.#nr.x*r.x/this.#Jt.x,y:this.#nr.y*r.y/this.#Jt.y};this.#nr.x===o.x&&this.#nr.y===o.y||(this.#Jt=r,this.#nr=o,i=!0);const a={x:n.x/r.x,y:n.y/r.y},s={x:e.x/r.x,y:e.y/r.y},l={x:0!==this.#in.x?s.x:0,y:0!==this.#in.y?s.y:0};this.#tn.x===a.x&&this.#tn.y===a.y&&this.#in.x===l.x&&this.#in.y===l.y||(this.#ir={x:this.#ir.x+a.x-this.#tn.x+l.x-this.#in.x,y:this.#ir.y+a.y-this.#tn.y+l.y-this.#in.y},this.#in=l,this.#tn=a,i=!0),i&&this.draw()}bindInteraction(){this.#jt.style.pointerEvents="auto";const e=Gi;for(let t=0;t{e.srclayerid=this.getId(),e.dataid=this.#on,this.#Ae.fireEvent(e)};#Sr(){this.#Zi.generateImageData(this.#er),this.#Ki.getContext("2d").putImageData(this.#er,0,0),this.#rr=!1}#lr=e=>{void 0!==e.skipGenerate&&!0===e.skipGenerate||(this.#rr=!0,this.draw())};#cr=e=>{void 0!==e.skipGenerate&&!0===e.skipGenerate||(this.#rr=!0,this.draw())};#ur=e=>{if(void 0===e.skipGenerate||!0!==e.skipGenerate){let t=!0;if(void 0!==e.valid&&(t=e.valid),t){const t=[0,1,2],n=t.indexOf(this.#Zi.getScrollIndex());t.splice(n,1),0===e.diffDims.filter((function(e){return-1===t.indexOf(e)})).length&&this.#$i||(this.#$i=!0,this.#rr=!0,this.draw())}else this.#$i&&(this.#$i=!1,this.clear())}};#dr=e=>{void 0!==e.skipGenerate&&!0===e.skipGenerate||(this.#rr=!0,this.draw())};setCurrentPosition(e,t){return this.#Zi.setCurrentPosition(e)}clear(){this.#Ji.save(),this.#Ji.setTransform(1,0,0,1,0,0),this.#Ji.clearRect(0,0,this.#_i.width,this.#_i.height),this.#Ji.restore()}}function ji(e){const t=e.split("-layer-");return 2!==t.length&&c.warn("Not the expected layer div id format..."),{groupDivId:t[0],layerIndex:t[1],layerId:e}}function Zi(e){let t=null;const n=e.target.closest(".layer");return n&&void 0!==n.id&&(t=ji(n.id)),t}function _i(e,t,n,i){const r=(i.x-e.x)*t.x,o=(i.y-e.y)*t.y;return{x:i.x-r/n.x,y:i.y-o/n.y}}class Ki{#jt;#gr=[];#nr={x:1,y:1,z:1};#gt={x:1,y:1,z:1};#ir={x:0,y:0,z:0};#pr=void 0;#mr=void 0;#Ae=new ke;#fr=!1;#Dr=[];#Cr;#Ne;#or=!1;constructor(e){this.#jt=e}getShowCrosshair(){return this.#fr}setShowCrosshair(e){this.#fr=e,e?(this.addEventListener("offsetchange",this.#yr),this.addEventListener("zoomchange",this.#yr),this.#vr()):(this.removeEventListener("offsetchange",this.#yr),this.removeEventListener("zoomchange",this.#yr),this.#Ir())}setImageSmoothing(e){this.#or=e;for(const t of this.#gr)t instanceof Xi&&t.setImageSmoothing(e)}#yr=e=>{this.#vr()};getDivId(){return this.#jt.id}getScale(){return this.#nr}getBaseScale(){return this.#gt}getAddedScale(){return{x:this.#nr.x/this.#gt.x,y:this.#nr.y/this.#gt.y,z:this.#nr.z/this.#gt.z}}getOffset(){return this.#ir}getNumberOfLayers(){let e=0;return this.#gr.forEach((t=>{void 0!==t&&e++})),e}includes(e){if(void 0===e)return!1;for(const t of this.#gr)if(void 0!==t&&t.getId()===e)return!0;return!1}getViewLayers(e){void 0===e&&(e=function(){return!0});const t=[];for(const n of this.#gr)n instanceof Xi&&e(n)&&t.push(n);return t}someViewLayer(e){let t=!1;for(const n of this.#gr)if(n instanceof Xi&&e(n)){t=!0;break}return t}getDrawLayers(e){void 0===e&&(e=function(){return!0});const t=[];for(const n of this.#gr)n instanceof Ci&&e(n)&&t.push(n);return t}getNumberOfViewLayers(){let e=0;return this.#gr.forEach((t=>{void 0!==t&&t instanceof Xi&&e++})),e}getActiveViewLayer(){let e;if(void 0!==this.#pr){const t=this.#gr[this.#pr];t instanceof Xi&&(e=t)}return e}getBaseViewLayer(){let e;for(const t of this.#gr)if(t instanceof Xi){e=t;break}if(void 0!==e)return e;c.warn("No layer found")}getViewLayersByDataId(e){return this.getViewLayers((function(t){return t.getDataId()===e}))}searchViewLayers(e){const t=[];for(const n of this.#gr)n instanceof Xi&&n.getViewController().equalImageMeta(e)&&t.push(n);return t}getViewDataIndices(){const e=[];for(const t of this.#gr)t instanceof Xi&&e.push(t.getDataId());return e}getActiveDrawLayer(){let e;if(void 0!==this.#mr){const t=this.#gr[this.#mr];t instanceof Ci&&(e=t)}return e}getDrawLayersByDataId(e){return this.getDrawLayers((function(t){return t.getDataId()===e}))}setActiveViewLayer(e){this.#gr[e]instanceof Xi?(this.#pr=e,this.#Re({type:"activelayerchange",value:[this.#gr[e]]})):c.warn("No view layer to set as active with index: "+e)}setActiveViewLayerByDataId(e){let t;for(let n=0;n0;)e[0].remove()}removeLayersByDataId(e){for(const t of this.#gr)void 0!==t&&t.getDataId()===e&&this.removeLayer(t)}removeLayer(e){const t=this.#gr.findIndex((t=>t===e));if(-1===t)throw new Error("Cannot find layer to remove");e instanceof Xi?(this.#wr(e),this.#pr===t&&(this.#pr=void 0)):(this.#Or(e),this.#mr===t&&(this.#mr=void 0)),this.#gr[t]=void 0,e.removeFromDOM()}#vr(e){let t;void 0===e&&(e=this.#Ne),this.#Ir();for(const e of this.#gr)if(e instanceof Xi){t=e;break}if(void 0===t)return void c.warn("No layer to show crosshair");const n=t.getViewController().getPlanePositionFromPosition(e),i=t.planePosToDisplay(n);if(void 0!==i.getY()){const e=document.createElement("hr");e.id=this.getDivId()+"-scroll-crosshair-horizontal",e.className="horizontal",e.style.width=this.#jt.offsetWidth+"px",e.style.left="0px",e.style.top=i.getY()+"px",this.#Dr.push(e),this.#jt.appendChild(e)}if(void 0!==i.getX()){const e=document.createElement("hr");e.id=this.getDivId()+"-scroll-crosshair-vertical",e.className="vertical",e.style.width=this.#jt.offsetHeight+"px",e.style.left=i.getX()+"px",e.style.top="0px",this.#Dr.push(e),this.#jt.appendChild(e)}}#Ir(){for(const e of this.#Dr)e.remove();this.#Dr=[]}showTooltip(e){this.removeTooltipDiv();const t=this.getActiveViewLayer(),n=t.getViewController(),i=t.displayToPlanePos(e),r=n.getPositionFromPlanePoint(i),o=n.getRescaledImageValue(r);if(void 0!==o){const t=document.createElement("span");t.id="scroll-tooltip",t.style.left=e.getX()+10+"px",t.style.top=e.getY()+10+"px";let i=B(o,3).toString();void 0!==n.getPixelUnit()&&(i+=" "+n.getPixelUnit()),t.appendChild(document.createTextNode(i)),this.#Cr=t,this.#jt.appendChild(t)}}removeTooltipDiv(){void 0!==this.#Cr&&(this.#Cr.remove(),this.#Cr=void 0)}isPositionInBounds(e){return this.someViewLayer((function(t){return t.getViewController().isPositionInBounds(e)}))}canScroll(){return this.someViewLayer((function(e){return e.getViewController().canScroll()}))}moreThanOne(e){return this.someViewLayer((function(t){return t.getViewController().moreThanOne(e)}))}updateLayersToPositionChange=e=>{for(const e of this.#gr)void 0!==e&&(e.removeEventListener("positionchange",this.updateLayersToPositionChange),e.removeEventListener("positionchange",this.#Re));const t=new s(e.value[0]),n=new E(e.value[1]);this.#Ne=n,this.#fr&&this.#vr(n);const i={};let r,o;for(const a of this.#gr){if(void 0===a)continue;let s=!1;if(a instanceof Xi){const e=a.getViewController(),t=e.getOrigin(),l=e.getOrigin(n);let c,u;if(void 0===o)r=t,o=l,c=new P(0,0,0),u=new P(0,0,0);else if(e.isPositionInBounds(n)&&void 0!==l){const e=r.minus(t);c=new P(e.getX(),e.getY(),e.getZ());const n=o.minus(l);u=new P(n.getX(),n.getY(),n.getZ())}void 0!==c&&void 0!==u&&(s=a.setBaseOffset(c,u,o,r),i[a.getId()]={scroll:c,plane:u})}if(a instanceof Ci){const e=i[a.getReferenceLayerId()];void 0!==e&&(s=a.setBaseOffset(e.scroll,e.plane))}let l=!1;a.getId()!==e.srclayerid&&(l=a.setCurrentPosition(n,t)),!l&&s&&a.draw()}for(const e of this.#gr)void 0!==e&&(e.addEventListener("positionchange",this.updateLayersToPositionChange),e.addEventListener("positionchange",this.#Re))};getDivToWorldSizeRatio(){if(0===this.#jt.offsetWidth&&0===this.#jt.offsetHeight)throw new Error("Cannot fit to zero sized container.");const e=this.getMaxWorldSize();if(void 0!==e){if(0===this.#jt.offsetHeight){const t=this.#jt.offsetWidth/e.x,n=e.y*t;this.#jt.style.height=n+"px"}return Math.min(this.#jt.offsetWidth/e.x,this.#jt.offsetHeight/e.y)}}fitToContainer(e){const t=this.getMaxWorldSize();if(void 0===t)return;const n={x:this.#jt.offsetWidth,y:this.#jt.offsetHeight},i={x:-.5*(n.x-Math.floor(t.x*e)),y:-.5*(n.y-Math.floor(t.y*e))};for(const t of this.#gr)void 0!==t&&t.fitToContainer(n,e,i);this.#fr&&this.#vr()}getMaxWorldSize(){let e={x:0,y:0};for(const t of this.#gr)if(t instanceof Xi){const n=t.getImageWorldSize();n.x>e.x&&(e.x=n.x),n.y>e.y&&(e.y=n.y)}return 0===e.x&&0===e.y&&(e=void 0),e}flipScaleZ(){this.#gt.z*=-1,this.setScale(this.#gt)}addScale(e,t){const n={x:this.#nr.x*(1+e),y:this.#nr.y*(1+e),z:this.#nr.z*(1+e)};this.setScale(n,t)}setScale(e,t){this.#nr=e;for(const e of this.#gr)void 0!==e&&e.setScale(this.#nr,t);const n=[e.x,e.y,e.z];void 0!==t&&(n.push(t.getX()),n.push(t.getY()),n.push(t.getZ())),this.#Re({type:"zoomchange",value:n})}addTranslation(e){this.setOffset({x:this.#ir.x-e.x,y:this.#ir.y-e.y,z:this.#ir.z-e.z})}setOffset(e){this.#ir=e;for(const e of this.#gr)void 0!==e&&e.setOffset(this.#ir);this.#Re({type:"offsetchange",value:[this.#ir.x,this.#ir.y,this.#ir.z]})}reset(){this.setScale(this.#gt),this.setOffset({x:0,y:0,z:0})}draw(){for(const e of this.#gr)void 0!==e&&e.draw()}display(e){for(const t of this.#gr)void 0!==t&&t.display(e)}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{this.#Ae.fireEvent(e)}}const Ji={WindowLevelBinder:class{getEventType=function(){return"wlchange"};getCallback=function(e){return function(t){const n=e.getViewLayersByDataId(t.dataid);if(0!==n.length){const e=n[0].getViewController();if(2===t.value.length){const n=new u(t.value[0],t.value[1]);e.setWindowLevel(n)}3===t.value.length&&e.setWindowLevelPreset(t.value[2])}}}},PositionBinder:class{getEventType=function(){return"positionchange"};getCallback=function(e){return function(t){const n=t.value[1],i=e.getActiveViewLayer().getViewController(),r=i.getCurrentPosition(),o=r.length(),a=n.length;a!==o&&(a===o-1?n.push(r.get(o-1)):a===o+1&&n.pop()),i.setCurrentPosition(new E(n))}}},ZoomBinder:class{getEventType=function(){return"zoomchange"};getCallback=function(e){return function(t){const n={x:t.value[0],y:t.value[1],z:t.value[2]};let i;6===t.value.length&&(i=new F(t.value[3],t.value[4],t.value[5])),e.setScale(n,i),e.draw()}}},OffsetBinder:class{getEventType=function(){return"offsetchange"};getCallback=function(e){return function(t){e.setOffset({x:t.value[0],y:t.value[1],z:t.value[2]}),e.draw()}}},OpacityBinder:class{getEventType=function(){return"opacitychange"};getCallback=function(e){return function(t){if(void 0===t.dataid)return;const n=e.getViewLayersByDataId(t.dataid),i=e.getBaseViewLayer();0!==n.length&&i!==n[0]&&(n[0].setOpacity(t.value),n[0].draw())}}},ColourMapBinder:class{getEventType=function(){return"colourmapchange"};getCallback=function(e){return function(t){const n=e.getViewLayersByDataId(t.dataid);0!==n.length&&n[0].getViewController().setColourMap(t.value[0])}}}};class $i{#Ar=[];#br;#or=!1;#xr=[];#ei=null;getLayerGroup(e){return this.#Ar[e]}getNumberOfLayerGroups(){return this.#Ar.length}getActiveLayerGroup(){return this.getLayerGroup(this.#br)}setActiveLayerGroup(e){void 0!==this.getLayerGroup(e)?this.#br=e:c.warn("No layer group to set as active with index: "+e)}getViewLayersByDataId(e){let t=[];for(let n=0;nt===e));if(-1===t)throw new Error("Cannot find layerGroup to remove");this.unbindLayerGroups(),e.empty(),this.#Ar.splice(t,1),this.#br===t&&(this.#br=void 0),this.bindLayerGroups()}reset(){for(let e=0;e{this.#Fr(t,e),e.getCallback(this.#Ar[t])(n),this.#Rr(t,e)}},this.#ei[t].push(n)),n.callback}#Rr(e,t){for(let n=0;n0&&(--this.#Br,this.#Nr[this.#Br].undo(),this.#Re({type:"undo",command:this.#Nr[this.#Br].getName()}))}redo(){this.#Br{this.#Ae.fireEvent(e)}}class lr{#Gr;#kr=null;#ei=[];#Hr={};constructor(e){this.#Gr=e}init(){for(const e in this.#Gr)this.#Gr[e].init();this.enableShortcuts(!0)}enableShortcuts(e){e?window.addEventListener("keydown",this.#zr("window","keydown"),!0):window.removeEventListener("keydown",this.#zr("window","keydown"),!0)}getToolList(){return this.#Gr}hasTool(e){return void 0!==this.getToolList()[e]}getSelectedTool(){return this.#kr}getSelectedToolEventHandler(e){return this.getSelectedTool()[e]}setSelectedTool(e){if(!this.hasTool(e))throw new Error("Unknown tool: '"+e+"'");this.#kr&&this.#kr.activate(!1),this.#kr=this.#Gr[e],this.#kr.activate(!0)}setToolFeatures(e){this.getSelectedTool()&&this.getSelectedTool().setFeatures(e)}bindLayerGroup(e,t){const n=e.getDivId();e.addEventListener("activelayerchange",this.#Wr(n)),this.#Yr(n,t)}#Yr(e,t){void 0!==this.#Hr[e]&&this.#Xr(this.#Hr[e]),this.#Hr[e]=t,this.#jr(t)}#Wr(e){return t=>{const n=t.value[0];void 0!==n&&this.#Yr(e,n)}}#jr(e){e.bindInteraction();const t=Gi;for(let n=0;n{if(this.#kr){const t=this.#kr[e.type];t&&t(e)}};this.#ei[e][t]=n}return this.#ei[e][t]}}class cr{#Zr=[];#_r=2;#Kr;constructor(e){this.#Kr=e}setNumberOfDimensions(e){this.#_r=e}setNToLoad(e){for(let t=0;t{if(!e.lengthComputable)return;if(void 0===e.subindex)return;if(void 0===e.index)return;const t=100*e.loaded/e.total;this.#Zr[e.index][e.subindex]=t;let n=null;n=void 0!==e.item?e.item:{loaded:this.#Jr(e.index),total:100,source:e.source},this.#Kr({lengthComputable:!0,loaded:this.#$r(),total:100,item:n})};#Jr(e){let t=0;for(let n=0;n{n.index=e,n.subindex=t,this.onprogress(n)}}getUndefinedMonoProgressHandler(e){return t=>{t.subindex=e,this.onprogress(t)}}}class ur{#eo=null;#to=[];#no=null;#io=0;#ro=0;#oo;#F;getDefaultCharacterSet(){return this.#F}setDefaultCharacterSet(e){this.#F=e}#ao(e){this.#eo=e,this.#io=0,this.#ro=0,this.#oo=!1,this.#so(),this.#lo()}#co(e){this.#to.push(e)}#so(){this.#to=[]}#uo(e){this.#no=e}#lo(){this.#no=null}#do=e=>{this.#io++,this.#io===this.#eo.length&&this.onload({source:this.#eo})};#ho=e=>{this.#ro++,this.#ro===this.#eo.length&&this.onloadend({source:this.#eo})};#So(e,t){return n=>{n.source=t,e(n)}}load(e,t){this.onloadstart({source:e}),1===e.length&&(M(e[0],"DICOMDIR")||M(e[0],".dcmdir"))?this.#go(e[0],t):this.#po(e,t)}#mo(e,t,n){return i=>{const r=i.target.status;200!==r&&0!==r?(this.onerror({source:t,error:"GET "+i.target.responseURL+" "+i.target.status+" ("+i.target.statusText+")",target:i.target}),this.#ho()):e.load(i.target.response,t,n)}}#po(e,t){if(void 0===e||0===e.length)return;this.#ao(e);const n=new cr(this.onprogress);n.setNToLoad(e.length);const i=[];for(let e=0;e{s{this.#ho(),s(e)};const c=this.#So(this.onabort,r);a.onabort=e=>{this.#ho(),c(e)},1===o.loadUrlAs()&&(a.responseType="arraybuffer"),this.#co(a)}let c=this.#to.length;void 0!==t&&void 0!==t.batchSize&&0!==c&&(c=Math.min(t.batchSize,this.#to.length));for(let e=0;e{const i=n.target.status;if(200!==i&&0!==i)this.onerror({source:e,error:"GET "+n.target.responseURL+" "+n.target.status+" ("+n.target.statusText+")",target:n.target}),this.onloadend({});else{const i=function(e){const t=new Ge;t.parse(e);const n=t.getDicomElements();if(void 0===n["00041220"]||void 0===n["00041220"].value)return void c.warn("No Directory Record Sequence found in DICOMDIR.");const i=n["00041220"].value;if(0===i.length)return void c.warn("The Directory Record Sequence of the DICOMDIR is empty.");const r=[];let o=null,a=null;for(let e=0;e{this.#So(this.onerror,e)(t),this.onloadend({})},n.onabort=t=>{this.#So(this.onabort,e)(t),this.onloadend({})},n.send(null)}abort(){this.#oo=!0;for(let e=0;e0){const t=this.freeThreads.shift();this.runningThreads.push(t),t.run(e)}else this.taskQueue.push(e)}abort(){this.#fo(),this.onabort({type:"work-abort"}),this.onworkend({type:"work-end"})}onTaskEnd(e){if(this.taskQueue.length>0){const t=this.taskQueue.shift();e.run(t)}else{e.stop(),this.freeThreads.push(e);for(let t=0;t{this.#fo(),this.onerror({error:e}),this.onworkend({type:"work-end"})};#fo(){this.taskQueue=[];for(let e=0;e{e.itemNumber=this.runningTask.info.itemNumber,e.numberOfItems=this.runningTask.info.numberOfItems,e.index=this.runningTask.info.index,this.parentPool.onworkitem(e),this.parentPool.onTaskEnd(this)};onerror=e=>{e.itemNumber=this.runningTask.info.itemNumber,e.numberOfItems=this.runningTask.info.numberOfItems,e.index=this.runningTask.info.index,this.parentPool.handleWorkerError(e),this.stop()}}class Sr{constructor(e,t,n){this.script=e,this.startMessage=t,this.info=n}}const gr="undefined"!=typeof JpegImage,pr="undefined"!=typeof jpeg&&void 0!==jpeg.lossless,mr="undefined"!=typeof JpxImage,fr={jpeg2000:"","jpeg-lossless":"","jpeg-baseline":"",rle:""};class Dr{#Do;#Co=new dr(10);#yo=!1;constructor(e,t){this.#Do=e}decode(e,t,n){this.#yo||(this.#yo=!0,this.#Co.onworkstart=this.ondecodestart,this.#Co.onworkitem=this.ondecodeditem,this.#Co.onwork=this.ondecoded,this.#Co.onworkend=this.ondecodeend,this.#Co.onerror=this.onerror,this.#Co.onabort=this.onabort);const i=new Sr(this.#Do,{buffer:e,meta:t},n);this.#Co.addWorkerTask(i)}abort(){this.#Co.abort()}ondecodestart(e){}ondecodeditem(e){}ondecoded(e){}ondecodeend(e){}onerror(e){}onabort(e){}}class Cr{#vo;#Io;constructor(e,t){this.#vo=e,this.#Io=t}#To=0;decode(e,t,n){++this.#To;let i=null,r=null;if("jpeg-lossless"===this.#vo){if(!pr)throw new Error("No JPEG Lossless decoder provided");const n=t.bitsAllocated/8,o=new Uint8Array(e);i=new jpeg.lossless.Decoder;const a=i.decode(o.buffer,0,o.buffer.byteLength,n);8===t.bitsAllocated?r=t.isSigned?new Int8Array(a.buffer):new Uint8Array(a.buffer):16===t.bitsAllocated&&(r=t.isSigned?new Int16Array(a.buffer):new Uint16Array(a.buffer))}else if("jpeg-baseline"===this.#vo){if(!gr)throw new Error("No JPEG Baseline decoder provided");i=new JpegImage,i.parse(e),r=i.getData(i.width,i.height)}else if("jpeg2000"===this.#vo){if(!mr)throw new Error("No JPEG 2000 decoder provided");i=new JpxImage,i.parse(e),r=i.tiles[0].items}else"rle"===this.#vo&&(i=new dwvdecoder.RleDecoder,r=i.decode(e,t.bitsAllocated,t.isSigned,t.sliceSize,t.samplesPerPixel,t.planarConfiguration));this.ondecodeditem({data:[r],index:n.index,numberOfItems:n.numberOfItems,itemNumber:n.itemNumber}),this.#To===this.#Io&&(this.ondecoded({}),this.ondecodeend({}))}abort(){this.onabort({}),this.ondecodeend({})}ondecodestart(e){}ondecodeditem(e){}ondecoded(e){}ondecodeend(e){}onerror(e){}onabort(e){}}class yr{#yo=!1;#Lo=null;constructor(e,t){void 0!==fr&&void 0!==fr[e]?this.#Lo=new Dr(fr[e],t):this.#Lo=new Cr(e,t)}decode(e,t,n){this.#yo||(this.#yo=!0,this.#Lo.ondecodestart=this.ondecodestart,this.#Lo.ondecodeditem=this.ondecodeditem,this.#Lo.ondecoded=this.ondecoded,this.#Lo.ondecodeend=this.ondecodeend,this.#Lo.onerror=this.onerror,this.#Lo.onabort=this.onabort),this.#Lo.decode(e,t,n)}abort(){this.#Lo.abort()}ondecodestart(e){}ondecodeditem(e){}ondecoded(e){}ondecodeend(e){}onerror(e){}onabort(e){}}const vr={NumericValue:"0040A30A",FloatingPointValue:"0040A161",RationalNumeratorValue:"0040A162",RationalDenominatorValue:"0040A163",MeasurementUnitsCodeSequence:"004008EA"};class Ir{numericValue;floatingPointValue;rationalNumeratorValue;rationalDenominatorValue;measurementUnitsCode;toString(){return this.numericValue+" "+this.measurementUnitsCode.toString()}}function Tr(e){const t={};return void 0!==e.measurementUnitsCode&&(t.MeasurementUnitsCodeSequence={value:[Wt(e.measurementUnitsCode)]}),void 0!==e.floatingPointValue&&(t.FloatingPointValue=e.floatingPointValue),void 0!==e.rationalNumeratorValue&&(t.RationalNumeratorValue=e.rationalNumeratorValue),void 0!==e.rationalDenominatorValue&&(t.RationalDenominatorValue=e.rationalDenominatorValue),void 0!==e.numericValue&&(t.NumericValue=e.numericValue),t}const Lr={MeasuredValueSequence:"0040A300",NumericValueQualifierCodeSequence:"0040A301"};class Pr{measuredValue;numericValueQualifierCode;toString(){let e=this.measuredValue.toString();return void 0!==this.numericValueQualifierCode&&(e+=" "+this.numericValueQualifierCode.toString()),e}}function wr(e){const t={};return void 0!==e.measuredValue&&(t.MeasuredValueSequence={value:[Tr(e.measuredValue)]}),void 0!==e.numericValueQualifierCode&&(t.NumericValueQualifierCodeSequence={value:[Wt(e.numericValueQualifierCode)]}),t}const Or={ReferencedSOPClassUID:"00081150",ReferencedSOPInstanceUID:"00081155"};class Ar{referencedSOPClassUID;referencedSOPInstanceUID;toString(){return this.referencedSOPInstanceUID+" (class: "+this.referencedSOPClassUID+")"}}function br(e){const t=new Ar;return void 0!==e[Or.ReferencedSOPClassUID]&&(t.referencedSOPClassUID=e[Or.ReferencedSOPClassUID].value[0]),void 0!==e[Or.ReferencedSOPInstanceUID]&&(t.referencedSOPInstanceUID=e[Or.ReferencedSOPInstanceUID].value[0]),t}function xr(e){const t={};return void 0!==e.referencedSOPClassUID&&(t.ReferencedSOPClassUID=e.referencedSOPClassUID),void 0!==e.referencedSOPInstanceUID&&(t.ReferencedSOPInstanceUID=e.referencedSOPInstanceUID),t}const Rr={ReferencedFrameNumber:"00081160",ReferencedSOPSequence:"00081199",ReferencedSegmentNumber:"0062000B"};class Fr{referencedSOPSequence;referencedFrameNumber;referencedSegmentNumber;fiducialUID;toString(){return this.referencedSOPSequence.toString()}}function Er(e){const t={};return void 0!==e.referencedFrameNumber&&(t.ReferencedFrameNumber=e.referencedFrameNumber),void 0!==e.referencedSOPSequence&&(t.ReferencedSOPSequence={value:[xr(e.referencedSOPSequence)]}),void 0!==e.referencedSegmentNumber&&(t.ReferencedSegmentNumber=e.referencedSegmentNumber),t}const qr={PixelOriginInterpretation:"00480301",GraphicData:"00700022",GraphicType:"00700023",FiducialUID:"0070031A"},Ur="POINT",Mr="MULTIPOINT",Qr="POLYLINE",Vr="CIRCLE",Nr="ELLIPSE";class Br{graphicData;graphicType;pixelOriginInterpretation;fiducialUID;toString(){return this.graphicType+" {"+this.graphicData+"}"}}function Gr(e){const t={};return void 0!==e.pixelOriginInterpretation&&(t.PixelOriginInterpretation=e.pixelOriginInterpretation),void 0!==e.graphicData&&(t.GraphicData=e.graphicData),void 0!==e.graphicType&&(t.GraphicType=e.graphicType),void 0!==e.fiducialUID&&(t.FiducialUID=e.fiducialUID),t}const kr={GraphicData:"00700022",GraphicType:"00700023",ReferencedFrameofReferenceUID:"30060024",FiducialUID:"0070031A"};class Hr{graphicData;graphicType;referencedFrameofReferenceUID;fiducialUID;toString(){return this.graphicType+"{"+this.graphicData+"}"}}function zr(e){const t={};return void 0!==e.graphicData&&(t.GraphicData=e.graphicData),void 0!==e.graphicType&&(t.GraphicType=e.graphicType),void 0!==e.referencedFrameofReferenceUID&&(t.ReferencedFrameofReferenceUID=e.referencedFrameofReferenceUID),void 0!==e.fiducialUID&&(t.FiducialUID=e.fiducialUID),t}const Wr={ReferencedSOPSequence:"00081199",RelationshipType:"0040A010",ValueType:"0040A040",ConceptNameCodeSequence:"0040A043",ConceptCodeSequence:"0040A168",ContentSequence:"0040A730",DateTime:"0040A120",Date:"0040A121",Time:"0040A122",UID:"0040A124",PersonName:"0040A123",TextValue:"0040A160",ContinuityOfContent:"0040A050"},Yr="CONTAINS",Xr="HAS PROPERTIES",jr="SELECTED FROM",Zr={text:"TEXT",num:"NUM",code:"CODE",date:"DATE",time:"TIME",datetime:"DATETIME",uidref:"UIDREF",pname:"PNAME",composite:"COMPOSITE",image:"IMAGE",waveform:"WAVEFORM",scoord:"SCOORD",scoord3d:"SCOORD3D",tcoord:"TCOORD",container:"CONTAINER",table:"TABLE"},_r={TEXT:"TextValue",DATE:"Date",TIME:"Time",DATETIME:"DateTime",UIDREF:"UID",PNAME:"PersonName",CONTAINER:"ContinuityOfContent"};class Kr{valueType;conceptNameCode;relationshipType;contentSequence;value;constructor(e){this.valueType=e}toString(e){void 0===e&&(e="");let t="";if(void 0!==this.relationshipType&&(t+="("+this.relationshipType+") "),t+=this.valueType+": ",void 0!==this.conceptNameCode&&(t+=this.conceptNameCode.toString()),t+=" = "+this.value.toString(),void 0!==this.contentSequence)for(const n of this.contentSequence)t+="\n"+e+"- "+n.toString(e+" ");return t}}function Jr(e){let t="";void 0!==e[Wr.ValueType]&&(t=e[Wr.ValueType].value[0]);const n=new Kr(t);if(void 0!==e[Wr.RelationshipType]&&(n.relationshipType=e[Wr.RelationshipType].value[0]),void 0!==e[Wr.ConceptNameCodeSequence]&&(n.conceptNameCode=zt(e[Wr.ConceptNameCodeSequence].value[0])),t===Zr.code)n.value=zt(e[Wr.ConceptCodeSequence].value[0]);else if(t===Zr.num)n.value=function(e){const t=new Pr;return void 0!==e[Lr.MeasuredValueSequence]&&(t.measuredValue=function(e){const t=new Ir;return void 0!==e[vr.NumericValue]&&(t.numericValue=e[vr.NumericValue].value[0]),void 0!==e[vr.FloatingPointValue]&&(t.floatingPointValue=e[vr.FloatingPointValue].value[0]),void 0!==e[vr.RationalNumeratorValue]&&(t.rationalNumeratorValue=e[vr.RationalNumeratorValue].value[0]),void 0!==e[vr.RationalDenominatorValue]&&(t.rationalDenominatorValue=e[vr.RationalDenominatorValue].value[0]),void 0!==e[vr.MeasurementUnitsCodeSequence]&&(t.measurementUnitsCode=zt(e[vr.MeasurementUnitsCodeSequence].value[0])),t}(e[Lr.MeasuredValueSequence].value[0])),void 0!==e[Lr.NumericValueQualifierCodeSequence]&&(t.numericValueQualifierCode=zt(e[Lr.NumericValueQualifierCodeSequence].value[0])),t}(e);else if(t===Zr.image)n.value=function(e){const t=new Fr;return void 0!==e[Rr.ReferencedFrameNumber]&&(t.referencedFrameNumber=e[Rr.ReferencedFrameNumber].value[0]),void 0!==e[Rr.ReferencedSOPSequence]&&(t.referencedSOPSequence=br(e[Rr.ReferencedSOPSequence].value[0])),void 0!==e[Rr.ReferencedSegmentNumber]&&(t.referencedSegmentNumber=e[Rr.ReferencedSegmentNumber].value[0]),t}(e);else if(t===Zr.composite)n.value=br(e[Wr.ReferencedSOPSequence].value[0]);else if(t===Zr.scoord)n.value=function(e){const t=new Br;return void 0!==e[qr.GraphicData]&&(t.graphicData=e[qr.GraphicData].value),void 0!==e[qr.GraphicType]&&(t.graphicType=e[qr.GraphicType].value[0]),void 0!==e[qr.PixelOriginInterpretation]&&(t.pixelOriginInterpretation=e[qr.PixelOriginInterpretation].value[0]),void 0!==e[qr.FiducialUID]&&(t.fiducialUID=e[qr.FiducialUID].value[0]),t}(e);else if(t===Zr.scoord3d)n.value=function(e){const t=new Hr;return void 0!==e[kr.GraphicData]&&(t.graphicData=e[kr.GraphicData].value),void 0!==e[kr.GraphicType]&&(t.graphicType=e[kr.GraphicType].value[0]),void 0!==e[kr.ReferencedFrameofReferenceUID]&&(t.referencedFrameofReferenceUID=e[kr.ReferencedFrameofReferenceUID].value[0]),void 0!==e[kr.FiducialUID]&&(t.fiducialUID=e[kr.FiducialUID].value[0]),t}(e);else{const i=_r[t];void 0!==i?n.value=e[Wr[i]].value[0]:console.warn("Unsupported input ValueType: "+t)}if(void 0!==e[Wr.ContentSequence]){n.contentSequence=[];for(const t of e[Wr.ContentSequence].value)n.contentSequence.push(Jr(t))}return n}function $r(e){let t={};if(void 0!==e.relationshipType&&(t.RelationshipType=e.relationshipType),void 0!==e.valueType&&(t.ValueType=e.valueType),void 0!==e.conceptNameCode&&(t.ConceptNameCodeSequence={value:[Wt(e.conceptNameCode)]}),"CODE"===e.valueType)t.ConceptCodeSequence={value:[Wt(e.value)]};else if(e.valueType===Zr.num)t={...t,...wr(e.value)};else if(e.valueType===Zr.image)t={...t,...Er(e.value)};else if(e.valueType===Zr.composite)t={...t,...xr(e.value)};else if(e.valueType===Zr.scoord)t={...t,...Gr(e.value)};else if(e.valueType===Zr.scoord3d)t={...t,...zr(e.value)};else{const n=_r[e.valueType];void 0!==n?t[n]=e.value:console.warn("Unsupported output ValueType: "+e.valueType)}if(void 0!==e.contentSequence){t.ContentSequence={value:[]};for(const n of e.contentSequence)t.ContentSequence.value.push($r(n))}return t}function eo(e,t,n){const i=function(e){const t=rn[e];let n;return void 0!==t&&(n=Zt(t.key,t.scheme)),n}(e);if(void 0===i)return;const r=new Kr(Zr.num);r.relationshipType=Yr,r.conceptNameCode=i;const o=new Ir;o.numericValue=t,o.measurementUnitsCode=function(e){const t=an[e];let n;return void 0!==t?n=Zt(t,"UCUM"):void 0===t&&(n=Zt("1","UCUM")),n}(n);const a=new Pr;return a.measuredValue=o,r.value=a,r}class to{#$;getWarning(){return this.#$}checkElements(e){this.#$=void 0;const t=Jr(e);return void 0!==t.conceptNameCode?t.conceptNameCode.value!==_t().value&&(this.#$="Not a measurement group"):this.#$="No root concept name code",this.#$}#Po(e){const t=new Bi;t.mathShape=function(e){const t=e.graphicData.length;if(t%2!=0)throw new Error("Expecting even number of coordinates in scroord data");const n=[];for(let i=0;i2){const e=n[0],t=n[r-1];i=e.equals(t)}let o;if(e.graphicType===Ur){if(1!==n.length)throw new Error("Expecting 1 point for point");o=n[0]}else if(e.graphicType===Vr){if(2!==n.length)throw new Error("Expecting 2 points for circles");const e=n[0],t=n[1].getDistance(e);o=new pi(e,t)}else if(e.graphicType===Nr){if(4!==n.length)throw new Error("Expecting 4 points for ellipses");const e=n[0].getDistance(n[1])/2,t=n[2].getDistance(n[3])/2,i=new R(n[0].getX()+e,n[0].getY());o=new Si(i,e,t)}else if(e.graphicType===Qr)if(i)if(5===n.length){const e=new zn(n[0],n[1]),t=new zn(n[1],n[2]),i=new zn(n[2],n[3]),r=new zn(n[3],n[4]);o=Yn(e,t)&&Yn(t,i)&&Yn(i,r)?new ci(n[0],n[2]):new di(n.slice(0,-1))}else o=new di(n.slice(0,-1));else 2===n.length?o=new zn(n[0],n[1]):3===n.length&&(o=new hi([n[0],n[1],n[2]]));return o}(e.value),t.id=$e(),t.textExpr="";for(const n of e.contentSequence){if(n.valueType===Zr.image&&n.relationshipType===jr&&Ht(n.conceptNameCode,Jt())&&(t.referenceSopUID=n.value.referencedSOPSequence.referencedSOPInstanceUID),n.valueType===Zr.uidref&&n.relationshipType===Xr&&Ht(n.conceptNameCode,$t())&&(t.id=n.value),n.valueType===Zr.text&&n.relationshipType===Xr&&Ht(n.conceptNameCode,en())&&(t.textExpr=n.value,void 0!==n.contentSequence))for(const e of n.contentSequence)e.valueType===Zr.scoord&&e.relationshipType===Xr&&Ht(e.conceptNameCode,tn())&&(t.labelPosition=new R(e.value.graphicData[0],e.value.graphicData[1]));if(n.valueType===Zr.text&&n.relationshipType===Xr&&Ht(n.conceptNameCode,nn())&&(t.colour=n.value),n.valueType===Zr.scoord&&n.relationshipType===Xr&&Ht(n.conceptNameCode,tn())&&n.value.graphicType===Mr){const e=[];for(let t=0;t{this.#Ae.fireEvent(e)};#bo(e){return t=>{t.dataid=e,this.#Re(t)}}}class ro{#xo;setOptions(e){this.#xo=e}#Lo=null;#Ro=[];#Fo=[];#Eo=[];#qo=[];#Uo(e){let t;const n=e["00080060"];if(void 0!==n){const e=n.value[0];"SEG"===e?t=new Fn:"SR"===e&&(t=new to)}return void 0===t&&void 0!==e["7FE00010"]&&(t=new Pt),t}#Mo(e,t){const n=this.#Ro[e].getDicomElements(),i=this.#qo[e];if(void 0!==i)try{const r=new no(n);i instanceof to?r.annotationGroup=i.create(n):r.image=i.create(n,this.#Fo[e],this.#xo.numberOfFiles),this.onloaditem({data:r,source:t,warn:i.getWarning()})}catch(e){this.onerror({error:e,source:t}),this.onloadend({source:t})}}#Qo(e,t){this.onprogress({lengthComputable:!0,loaded:100,total:100,index:e,source:t}),this.#Mo(e,t),this.onload({source:t}),this.onloadend({source:t})}#Vo(e,t,n){const i=this.#Ro[e],r={bitsAllocated:i.getDicomElements()["00280100"].value[0],isSigned:1===i.getDicomElements()["00280103"].value[0]},o=i.getDicomElements()["00280011"],a=i.getDicomElements()["00280010"];void 0!==o&&void 0!==a&&(r.sliceSize=o.value[0]*a.value[0]);const s=i.getDicomElements()["00280002"];void 0!==s&&(r.samplesPerPixel=s.value[0]);const l=i.getDicomElements()["00280006"];void 0!==l&&(r.planarConfiguration=l.value[0]);const c=t.length;null===this.#Lo&&(this.#Lo=new yr(n,c),this.#Lo.ondecodeditem=e=>{this.#No(e),e.itemNumber+1===e.numberOfItems&&(this.onload(e),this.onloadend(e))},this.#Lo.onerror=this.onerror,this.#Lo.onabort=this.onabort);for(let n=0;n2^"+e+") for decompressed data.")}return this.#Lo.abort(),this.onerror({error:e,source:origin}),void this.onloadend({source:origin})}}n.length!==this.#Eo[t]&&c.warn("Unsupported varying decompressed data size: "+n.length+" != "+this.#Eo[t]),this.#Fo[t].set(n,this.#Eo[t]*e.itemNumber)}else this.#Fo[t]=n;0===e.itemNumber&&this.#Mo(t,origin)}#Bo(e,t){this.#Mo(e,t),this.onload({source:t}),this.onloadend({source:t})}#Go(e,t){const n=this.#Ro[e],i=n.getDicomElements()["7FE00010"].value;n.getDicomElements()["7FE00010"].value=[],this.#Fo[e]=i[0];const r=function(e){let t;return Ee(e)?t="jpeg2000":Re(e)?t="jpeg-baseline":Fe(e)?t="jpeg-lossless":qe(e)&&(t="rle"),t}(n.getDicomElements()["00020010"].value[0]);void 0!==r?this.#Vo(e,i,r):this.#Qo(e,t)}convert(e,t,n){this.onloadstart({source:t,index:n});const i=new Ge;let r;void 0!==this.#xo.defaultCharacterSet&&i.setDefaultCharacterSet(this.#xo.defaultCharacterSet);try{i.parse(e),r=this.#Uo(i.getDicomElements()),void 0!==r&&r.checkElements(i.getDicomElements())}catch(e){return this.onerror({error:e,source:t}),void this.onloadend({source:t})}this.#Ro[n]=i,this.#qo[n]=r,r instanceof to?this.#Bo(n,t):this.#Go(n,t)}abort(){this.#Lo&&this.#Lo.abort()}onloadstart(e){}onloaditem(e){}onprogress(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}}class oo{#eo=null;#no=null;#io=0;#ro=0;#F;getDefaultCharacterSet(){return this.#F}setDefaultCharacterSet(e){this.#F=e}#ao(e){this.#eo=e,this.#io=0,this.#ro=0,this.#lo()}#uo(e){this.#no=e}#lo(){this.#no=null}#do=e=>{this.#io++,this.#io===this.#eo.length&&this.onload({source:this.#eo})};#ho=e=>{this.#ro++,this.#ro===this.#eo.length&&this.onloadend({source:this.#eo})};load(e){if(void 0===e||0===e.length)return;this.#ao(e),this.onloadstart({source:e});const t=new cr(this.onprogress);t.setNToLoad(e.length),t.setNumberOfDimensions(1);const n=[];for(let e=0;e{this.#ko=!1,this.onloadend(e)},this.#Ho.onerror=e=>{e.source=t,this.onerror(e)},this.#Ho.onabort=this.onabort),this.#ko=!0,this.#Ho.convert(e,t,n)}abort(){this.#ko=!1,this.#Ho.abort()}canLoadFile(e){const t=V(e.name);return null===t||"dcm"===t}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"dicom"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n){const e="application/dicom";return U(n.value,e)&&"+"!==n.value[e.length]}}}const n=or(e),i=V(n.pathname),r=null===i,o="dcm"===i,a=n.searchParams.get("contentType");return null!=a?"application/dicom"===a:r||o}canLoadMemory(e){const t=e["Content-Type"];if(void 0!==t&&t.startsWith("application/dicom"))return!0;if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ho.ArrayBuffer}loadUrlAs(){return 1}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}},class{#ko=!1;setOptions(e){}isLoading(){return this.#ko}load(e,t,n){this.#ko=!0,this.onloadstart({source:t});try{this.onprogress({lengthComputable:!0,loaded:100,total:100,index:n,source:t});const i={data:e,source:t};this.onloaditem(i),this.onload(i)}catch(e){this.onerror({error:e,source:t})}finally{this.#ko=!1,this.onloadend({source:t})}}abort(){this.#ko=!1,this.onabort({}),this.onloadend({})}canLoadFile(e){return"json"===V(e.name)}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"json"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n)return U(n.value,"application/json")||U(n.value,"application/dicom+json")}}return"json"===V(or(e).pathname)}canLoadMemory(e){const t=e["Content-Type"];if(void 0!==t&&t.startsWith("application/json"))return!0;if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ho.Text}loadUrlAs(){return 0}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}},class{#ko=!1;setOptions(e){}isLoading(){return this.#ko}load(e,t,n){this.onloadstart({source:t}),this.#ko=!0;const i=new oo;i.onprogress=e=>{e.loaded=50+e.loaded/2,e.index=n,this.onprogress(e)},i.onloaditem=this.onloaditem,i.onload=this.onload,i.onloadend=e=>{this.#ko=!1,this.onloadend(e)},i.onerror=this.onerror,i.onabort=this.onabort,i.load(function(e){const t=new Uint8Array(e),n=[];if(0===t.length)return n;const i=Y(new Uint8Array([13,10,13,10]));let r=W(t,i,0);if(void 0===r)throw new Error("Can't find the end of the first multipart header");const o=z(t.slice(0,r)).split("\r\n");let a;for(let e=0;e{try{if(!this.#zo){this.onprogress({lengthComputable:!0,loaded:100,total:100,index:n,source:t});const e=function(e,t,n){const i=e.width,r=e.height,o=document.createElement("canvas");o.width=i,o.height=r;const a=o.getContext("2d");a.drawImage(e,0,0);const s=a.getImageData(0,0,i,r),l={};"string"==typeof t?l.origin={value:t}:(l.fileName={value:t.name},l.fileType={value:t.type},l.fileLastModifiedDate={value:t.lastModified}),l.imageWidth={value:i},l.imageHeight={value:r};const c=n||0;return l.imageUid={value:c},{data:{image:so(i,r,c,ao(s),1,c.toString()),info:l},source:t}}(i,t,n);this.onloaditem(e),this.onload(e)}}catch(e){this.onerror({error:e,source:t})}finally{this.onloadend({source:t})}},"string"==typeof e)i.src=e;else if("string"==typeof t){const n=t.split(".").pop().toLowerCase();i.src=this.#Wo(e,n)}}abort(){this.#zo=!0,this.onabort({}),this.onloadend({})}canLoadFile(e){return void 0!==e.type&&null!==e.type.match("image.*")}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"rawimage"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n)return U(n.value,"image/")}}const n=or(e),i=V(n.pathname),r="jpeg"===i||"jpg"===i||"png"===i||"gif"===i,o=n.searchParams.get("contentType");return null!=o?"image/jpeg"===o||"image/png"===o||"image/gif"===o:r}canLoadMemory(e){if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ho.DataURL}loadUrlAs(){return 1}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}},class{setOptions(e){}isLoading(){return!0}#Wo(e,t){const n=new Uint8Array(e);let i="";for(let e=0;e{try{!function(e,t,n,i,r,o,a){const s=e.videoWidth,l=e.videoHeight,c=Math.ceil(30*e.duration),u={};"string"==typeof o?u.origin={value:o}:(u.fileName={value:o.name},u.fileType={value:o.type},u.fileLastModifiedDate={value:o.lastModified}),u.imageWidth={value:s},u.imageHeight={value:l},u.numberOfFrames={value:c},u.imageUid={value:0};const d=document.createElement("canvas");d.width=s,d.height=l;const h=d.getContext("2d");e.addEventListener("seeked",(function d(m){(function(){i({lengthComputable:!0,loaded:S,total:c,index:a,source:o}),h.drawImage(e,0,0);const n=ao(h.getImageData(0,0,s,l));0===S?(g=so(s,l,1,n,c,a.toString()),t({data:{image:g,info:u},source:o})):g.appendFrameBuffer(n,S),++S})(),p+=1/30,p<=m.target.duration?this.currentTime=p:(n({source:o}),r({source:o}),e.removeEventListener("seeked",d))}),!1);let S=0,g=null,p=0;e.currentTime=p}(e.target,this.onloaditem,this.onload,this.onprogress,this.onloadend,t,n)}catch(e){this.onerror({error:e,source:t}),this.onloadend({source:t})}}}abort(){this.onabort({}),this.onloadend({})}canLoadFile(e){return void 0!==e.type&&null!==e.type.match("video.*")}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"rawvideo"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n)return U(n.value,"video/")}}const n=V(or(e).pathname);return"mp4"===n||"ogg"===n||"webm"===n}canLoadMemory(e){if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ho.DataURL}loadUrlAs(){return 1}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}},class{#ko=!1;setOptions(e){}isLoading(){return this.#ko}#Yo="";#Xo=[];#jo=null;#Zo(e,t,n){this.#Xo.push({filename:this.#Yo,data:e});const i=100*this.#Xo.length/this.#jo.length;if(this.onprogress({lengthComputable:!0,loaded:i/2,total:100,index:n,item:{loaded:i,total:100,source:t}}),this.#Xo.length{this.#Zo(e,t,n)}))}else{const e=new oo;e.onprogress=e=>{e.loaded=50+e.loaded/2,e.index=n,this.onprogress(e)},e.onloaditem=this.onloaditem,e.onload=this.onload,e.onloadend=e=>{this.#ko=!1,this.onloadend(e)},e.onerror=this.onerror,e.onabort=this.onabort,e.load(this.#Xo)}}load(e,t,n){this.onloadstart({source:t}),this.#ko=!0,co().loadAsync(e).then((e=>{this.#Xo=[],this.#jo=e.file(/.*\.dcm/);const i=this.#Xo.length;this.#Yo=this.#jo[i].name,this.#jo[i].async("arrayBuffer").then((e=>{this.#Zo(e,t,n)}))}))}abort(){this.#ko=!1,this.onabort({}),this.onloadend({})}canLoadFile(e){return"zip"===V(e.name)}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"zip"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n)return U(n.value,"application/zip")}}return"zip"===V(or(e).pathname)}canLoadMemory(e){const t=e["Content-Type"];if(void 0!==t&&t.startsWith("application/zip"))return!0;if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ho.ArrayBuffer}loadUrlAs(){return 1}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}}],ho={Text:0,ArrayBuffer:1,DataURL:2};class So{#eo=null;#_o=[];#no=null;#io=0;#ro=0;#F;getDefaultCharacterSet(){return this.#F}setDefaultCharacterSet(e){this.#F=e}#ao(e){this.#eo=e,this.#io=0,this.#ro=0,this.#Ko(),this.#lo()}#Jo(e){this.#_o.push(e)}#Ko(){this.#_o=[]}#uo(e){this.#no=e}#lo(){this.#no=null}#do=e=>{this.#io++,this.#io===this.#eo.length&&this.onload({source:this.#eo})};#ho=e=>{this.#ro++,this.#ro===this.#eo.length&&this.onloadend({source:this.#eo})};#So(e,t){return n=>{n.source=t,e(n)}}#mo(e,t,n){return i=>{e.load(i.target.result,t,n)}}load(e){if(void 0===e||0===e.length)return;this.#ao(e),this.onloadstart({source:e});const t=new cr(this.onprogress);t.setNToLoad(e.length);const n=[];for(let e=0;e{this.#ho(),a(e)};const s=this.#So(this.onabort,i);o.onabort=e=>{this.#ho(),s(e)},r.loadFileAs()===ho.Text?o.readAsText(i):r.loadFileAs()===ho.DataURL?o.readAsDataURL(i):r.loadFileAs()===ho.ArrayBuffer&&o.readAsArrayBuffer(i)}}abort(){for(let e=0;e{this.#$o[i]={loader:t,isFirstItem:!0},this.#So(this.onloadstart,o)(e)},t.onprogress=this.#So(this.onprogress,o),t.onloaditem=e=>{const t={loadtype:n,dataid:i};void 0!==this.#$o[i]&&(t.isfirstitem=this.#$o[i].isFirstItem),this.#So(this.onloaditem,t)(e),void 0!==this.#$o[i]&&this.#$o[i].isFirstItem&&(this.#$o[i].isFirstItem=!1)},t.onload=this.#So(this.onload,o),t.onloadend=e=>{delete this.#$o[i],this.#So(this.onloadend,o)(e)},t.onerror=this.#So(this.onerror,o),t.onabort=this.#So(this.onabort,o);try{t.load(e,r)}catch(e){return this.onerror({error:e,dataid:i}),void this.onloadend({dataid:i})}}#So(e,t){return function(n){const i=Object.keys(t);for(let e=0;e{e.dataid===this.#on&&void 0!==e.data&&void 0!==e.data.imageUid&&this.#ca!==e.data.imageUid&&(this.#ca=e.data.imageUid,this.#da(e))};#da=e=>{if(e.dataid!==this.#on)return;const t=this.#la[this.#ca];if(void 0!==t){for(let n=0;n{null!==this.#ma&&this.#ma.add(e)};removeFromUndoStack=e=>{let t=!1;return null!==this.#ma&&(t=this.#ma.remove(e)),t};init(e){if(this.#xo=e,void 0===this.#xo.viewOnFirstLoadItem&&(this.#xo.viewOnFirstLoadItem=!0),void 0===this.#xo.dataViewConfigs&&(this.#xo.dataViewConfigs={}),void 0===this.#xo.rootDocument&&(this.#xo.rootDocument=document),this.#ma=new sr,this.#ma.addEventListener("undoadd",this.#Re),this.#ma.addEventListener("undo",this.#Re),this.#ma.addEventListener("redo",this.#Re),void 0!==this.#xo.tools){const e={},t=Object.keys(this.#xo.tools);for(let n=0;n{const t=this.#ha.getNextDataId();0!==e.length?this.#ga.loadFiles(e,t):c.warn("Ignoring empty input file list.")};loadURLs=(e,t)=>{const n=this.#ha.getNextDataId();0!==e.length?this.#ga.loadURLs(e,n,t):c.warn("Ignoring empty input url list.")};loadFromUri=(e,t)=>{const n=function(e){const t=ar(e);return 0===Object.keys(t).length?null:t.query}(e),i=()=>{this.removeEventListener("loadend",i),this.loadURLs([n.state])};n&&void 0!==n.input&&(void 0!==n.state&&this.addEventListener("loadend",i),function(e,t,n){e.type&&"manifest"===e.type?function(e,t){let n="";"/"===e.input[0]&&(n=window.location.protocol+"//"+window.location.host),n+=e.input;const i=new XMLHttpRequest;i.open("GET",decodeURIComponent(n),!0),i.responseType="document",i.onload=function(n){t(function(e,t){const n=[],i=e.getElementsByTagName("wado_query")[0].getAttribute("wadoURL")+"?requestType=WADO&contentType=application/dicom&",r=e.getElementsByTagName("Patient");r.length>1&&c.warn("More than one patient, loading first one.");const o=r[0].getElementsByTagName("Study");o.length>1&&c.warn("More than one study, loading first one.");const a=o[0].getAttribute("StudyInstanceUID"),s=o[0].getElementsByTagName("Series");s.length>1&&c.warn("More than one series, loading first one.");const l=s[0].getAttribute("SeriesInstanceUID"),u=s[0].getElementsByTagName("Instance");let d=u.length;t{const t=this.#ha.getNextDataId();this.#ga.loadImageObject(e,t)};abortAllLoads(){const e=this.#ga.getLoadingDataIds();for(const t of e)this.abortLoad(t)}abortLoad(e){this.#ga.abort(e),this.#ha.remove(e),this.#pa.removeLayersByDataId(e)}fitToContainer(){this.#pa.fitToContainer()}initWLDisplay(){this.#pa.getActiveLayerGroup().getActiveViewLayer().getViewController().initialise()}setImageSmoothing(e){this.#pa.setImageSmoothing(e),this.#pa.draw()}getViewConfigs(e,t){if(null===this.#xo.dataViewConfigs||void 0===this.#xo.dataViewConfigs)throw new Error("No available data view configuration");let n=[];return void 0!==this.#xo.dataViewConfigs[e]?n=this.#xo.dataViewConfigs[e]:t||void 0===this.#xo.dataViewConfigs["*"]||(n=this.#xo.dataViewConfigs["*"]),n}getViewConfig(e,t,n){return this.getViewConfigs(e,n).find((function(e){return e.divId===t}))}getDataViewConfigs(){return this.#xo.dataViewConfigs}setDataViewConfigs(e){this.#pa.empty(),this.#xo.dataViewConfigs=e,this.#Pa(e)}addDataViewConfig(e,t){const n=this.#xo.dataViewConfigs;if(void 0===n[e]&&(n[e]=[]),-1!==n[e].findIndex((function(e){return e.divId===t.divId})))throw new Error("Duplicate view config for data "+e+" and div "+t.divId);this.#xo.dataViewConfigs[e].push(t),void 0===this.#pa.getLayerGroupByDivId(t.divId)&&this.#wa(t),void 0!==this.#ha.get(e)&&this.render(e,[t])}removeDataViewConfig(e,t){const n=this.#xo.dataViewConfigs;if(void 0===n[e])return;const i=n[e].findIndex((function(e){return e.divId===t}));if(-1!==i&&(n[e].splice(i,1),0===n[e].length&&delete n[e],void 0!==this.#ha.get(e))){const n=this.#pa.getLayerGroupByDivId(t);if(void 0!==n){const t=n.getViewLayersByDataId(e);1===t.length&&n.removeLayer(t[0]);const i=n.getDrawLayersByDataId(e);if(1===i.length&&n.removeLayer(i[0]),0===t.length&&0===i.length)throw new Error("Expected one layer, got none");0===n.getNumberOfLayers()&&this.#pa.removeLayerGroup(n)}}}updateDataViewConfig(e,t,n){const i=this.#xo.dataViewConfigs;if(void 0===i[e])throw new Error("No config for dataId: "+e);const r=i[e].findIndex((function(e){return e.divId===t}));if(-1===r)throw new Error("No config for dataId: "+e+" and divId: "+t);const o=i[e][r];for(const e in n)o[e]=n[e];const a=this.#pa.getLayerGroupByDivId(o.divId);if(void 0!==a){const t=a.getViewLayersByDataId(e);1===t.length&&a.removeLayer(t[0]);const n=a.getDrawLayersByDataId(e);if(1===n.length&&a.removeLayer(n[0]),0===t.length&&0===n.length)throw new Error("Expected one layer, got none")}void 0!==this.#ha.get(e)&&this.render(e,[o])}#Pa(e){const t=Object.keys(e),n=[];for(let i=0;i{this.fitToContainer()};onKeydown=e=>{this.#Re(e)};defaultOnKeydown=e=>{if(e.ctrlKey)if(e.shiftKey){const t=this.#pa.getActiveLayerGroup(),n=t.getActiveViewLayer().getViewController();"ArrowLeft"===e.key?n.moreThanOne(3)&&n.decrementIndex(3):"ArrowUp"===e.key?t.canScroll()&&n.incrementScrollIndex():"ArrowRight"===e.key?t.moreThanOne(3)&&n.incrementIndex(3):"ArrowDown"===e.key&&t.canScroll()&&n.decrementScrollIndex()}else if("y"===e.key)this.#ma.redo();else if("z"===e.key)this.#ma.undo();else if(" "===e.key)for(let e=0;ee.divId===t));if(void 0===r)throw new Error("No reference data view config for draw");const o=new Co(t);o.orientation=r.orientation,this.addDataViewConfig(i,o),this.render(i)}#Re=e=>{this.#Ae.fireEvent(e)};#Da=e=>{void 0!==this.#xo.overlayConfig&&(this.#fa[e.dataid]=new Do(this,e.dataid,this.#xo.overlayConfig)),e.type="loadstart",this.#Re(e)};#Ca=e=>{e.type="loadprogress",this.#Re(e)};#ya=e=>{void 0===e.data&&c.error("Missing loaditem event data."),void 0===e.loadtype&&c.error("Missing loaditem event load type.");const t=e.isfirstitem;let n=null;"image"===e.loadtype?(t?this.#ha.add(e.dataid,e.data):this.#ha.update(e.dataid,e.data),n=e.data.meta):"state"===e.loadtype&&(this.applyJsonState(e.data,e.dataid),n="state"),this.#Re({type:"loaditem",data:n,source:e.source,loadtype:e.loadtype,dataid:e.dataid,isfirstitem:e.isfirstitem,warn:e.warn}),void 0!==this.#fa&&void 0!==this.#fa[e.dataid]&&this.#fa[e.dataid].addItemMeta(n),"image"===e.loadtype&&0!==this.getViewConfigs(e.dataid).length&&t&&this.#xo.viewOnFirstLoadItem&&this.render(e.dataid)};#va=e=>{e.type="load",this.#Re(e)};#Ia=e=>{e.type="loadend",this.#Re(e)};#Ta=e=>{void 0===e.type&&(e.type="error"),this.#Re(e)};#La=e=>{void 0===e.type&&(e.type="abort"),this.#Re(e)};#Oa(e){e.addEventListener("zoomchange",this.#Re),e.addEventListener("offsetchange",this.#Re),e.addEventListener("renderstart",this.#Re),e.addEventListener("renderend",this.#Re);for(let t=0;t{const t=ji(e.srclayerid).groupDivId,n=this.getViewConfig(e.dataid,t,!0);void 0!==n&&(n.windowCenter=void 0,n.windowWidth=void 0,n.wlPresetName=void 0,3===e.value.length&&(n.windowCenter=e.value[0],n.windowWidth=e.value[1],n.wlPresetName=e.value[2]))})),e.addEventListener("opacitychange",(e=>{const t=ji(e.srclayerid).groupDivId,n=this.getViewConfig(e.dataid,t,!0);void 0!==n&&(n.opacity=e.value[0])})),e.addEventListener("colourmapchange",(e=>{const t=ji(e.srclayerid).groupDivId,n=this.getViewConfig(e.dataid,t,!0);void 0!==n&&(n.colourMap=e.value[0])}))}#Aa(e,t){const n=this.#ha.get(e);if(!n)throw new Error("Cannot initialise layer with missing data, id: "+e);const i=this.#pa.getLayerGroupByDivId(t.divId);if(!i)throw new Error("Cannot initialise layer with missing group, id: "+t.divId);const r=n.image.getGeometry();this.#pa.unbindLayerGroups();const o=(new Mn).create(n.meta,n.image),a=Ct(r.getOrientation(),gt(t.orientation));o.setOrientation(a),"SEG"===n.image.getMeta().Modality&&o.setAlphaFunction((function(e){return 0===e?0:255}));const s=0===i.getNumberOfViewLayers();let l=1;void 0!==t.opacity?l=t.opacity:s||(l=.5);const c=i.addViewLayer();c.setView(o,e);const d=r.getSize(a).get2D(),h=r.getSpacing(a).get2D();c.initialise(d,h,l);const S=c.getViewController();if(void 0!==t.wlPresetName)S.setWindowLevelPreset(t.wlPresetName);else if(void 0!==t.windowCenter&&void 0!==t.windowWidth){const e=new u(t.windowCenter,t.windowWidth);S.setWindowLevel(e)}void 0!==t.colourMap?S.setColourMap(t.colourMap):s||("PT"===n.image.getMeta().Modality?S.setColourMap("hot"):S.setColourMap("rainbow")),this.#ha.addEventListener("dataimageset",c.onimageset);const g=[S.getCurrentIndex().getValues(),S.getCurrentPosition().getValues()];i.updateLayersToPositionChange({value:g,srclayerid:c.getId()}),this.#pa.fitToContainer(),c.setOffset(i.getOffset());const p=this.#ba(r.getOrientation(),t.orientation);if(this.#xa(p,c),s)c.setScale(i.getScale());else{const e=i.getBaseViewLayer();c.initScale(i.getScale(),e.getAbsoluteZoomOffset())}this.#pa.bindLayerGroups(),this.#Sa&&this.#Sa.bindLayerGroup(i,c),this.#Re({type:"viewlayeradd",layerid:c.getId(),layergroupid:i.getDivId(),dataid:e}),s&&this.#Sa&&this.#Sa.init()}addDrawLayer(e,t){const n=this.#pa.getLayerGroupByDivId(t.divId);if(!n)throw new Error("Cannot initialise layer with missing group, id: "+t.divId);const i=this.#ha.get(e);if(!i)throw new Error("Cannot initialise layer with missing data, id: "+e);const r=i.annotationGroup.getMetaValue("ReferencedSeriesSequence").value[0].SeriesInstanceUID,o=n.searchViewLayers({SeriesInstanceUID:r});if(0===o.length)return void console.warn("No loaded data that matches the measurement reference series UID");const a=o[0],s=a.getDataId();this.#pa.unbindLayerGroups();const l=a.getViewController();i.annotationGroup.setViewController(l);const c=this.#ha.get(s);if(!c)throw new Error("Cannot initialise layer without reference data, id: "+s);const u=c.image.getGeometry(),d=Ct(u.getOrientation(),gt(t.orientation)),h=u.getSize(d).get2D(),S=u.getSpacing(d).get2D(),g=n.addDrawLayer();g.initialise(h,S,a.getId());const p=new Bn(u,d);g.setPlaneHelper(p);const m=[l.getCurrentIndex().getValues(),l.getCurrentPosition().getValues()];n.updateLayersToPositionChange({value:m,srclayerid:g.getId()}),this.#pa.fitToContainer(),g.setOffset(n.getOffset());const f=this.#ba(u.getOrientation(),t.orientation);this.#xa(f,g),g.initScale(n.getScale(),a.getAbsoluteZoomOffset()),g.setAnnotationGroup(i.annotationGroup,e,this.addToUndoStack),g.setCurrentPosition(l.getCurrentPosition(),l.getCurrentIndex()),this.#pa.bindLayerGroups(),this.#Sa&&this.#Sa.bindLayerGroup(n,g),this.#Re({type:"drawlayeradd",layerid:g.getId(),layergroupid:n.getDivId(),dataid:e})}#ba(e,t){const n=pt(e.asOneAndZeros());if(void 0===n)throw new Error("Unsupported undefined orientation code");const i=void 0===t,r=!i&&t===St.Axial,o=!i&&t===St.Coronal,a=!i&&t===St.Sagittal,s={x:!1,y:!1},l={x:!1,y:!1,z:!1};return"LPS"===n?(o||a)&&(l.z=!0,s.y=!0):"LAI"===n?i||r?s.y=!0:o?l.z=!0:a&&(l.z=!0,s.x=!0):"RPI"===n?i||r?s.x=!0:o?(l.z=!0,s.x=!0):a&&(l.z=!0):"RAS"===n?(s.x=!0,s.y=!0,(o||a)&&(l.z=!0)):"LSA"===n?(s.y=!0,i||o?l.z=!0:r?l.y=!0:a&&(s.x=!0,l.y=!0,l.z=!0)):"RSP"===n?i||o?(s.x=!0,s.y=!0,l.x=!0,l.z=!0):r?(s.x=!0,l.x=!0):a&&(s.y=!0,l.z=!0):"RIA"===n?(s.x=!0,i||o?l.x=!0:r?(s.y=!0,l.x=!0,l.y=!0):a&&(l.y=!0)):"PSL"===n?(l.z=!0,(i||a||o)&&(s.y=!0)):"PIR"===n?(l.z=!0,(r||o)&&(s.x=!0)):"ASR"===n?(s.x=!0,s.y=!0,(i||a||o)&&(l.z=!0)):"AIL"===n?i||a?(s.x=!0,l.z=!0):r?s.y=!0:o&&(l.z=!0):c.warn("Unsupported orientation code: "+n+", display could be incorrect"),{scale:l,offset:s}}#xa(e,t){e.offset.x&&t.addFlipOffsetX(),e.offset.y&&t.addFlipOffsetY(),e.scale.x&&t.flipScaleX(),e.scale.y&&t.flipScaleY(),e.scale.z&&t.flipScaleZ()}}class To{#Di;#Ra;constructor(e){this.#Di=e;const t=e.getMeta();void 0===t.custom&&(t.custom={}),void 0===t.custom.segments&&(t.custom.segments=[]),this.#Ra=t.custom.segments}#Fa(e){return this.#Ra.findIndex((function(t){return t.number===e}))}hasSegment(e){return-1!==this.#Fa(e)}getNumberOfSegments(){return this.#Ra.length}maskHasSegments(e){const t=[],n=[];for(let i=0;ie.number===this.#Ea.number))}execute(){0!==this.#Ua.length&&this.#Di.setAtOffsets(this.#Ua,0),new To(this.#Di).removeSegment(this.#Ea.number),this.#qa||this.onExecute({type:"masksegmentdelete",segmentnumber:this.#Ea.number})}undo(){0!==this.#Ua.length&&(void 0!==this.#Ea.displayRGBValue?this.#Di.setAtOffsets(this.#Ua,this.#Ea.number):this.#Di.setAtOffsets(this.#Ua,this.#Ea.displayValue)),new To(this.#Di).addSegment(this.#Ea),this.onUndo({type:"masksegmentredraw",segmentnumber:this.#Ea.number})}onExecute(e){}onUndo(e){}}class Po{#Di;#Ea;#Ma;#Qa;#qa;#Ua;constructor(e,t,n,i){this.#Di=e,this.#Ea=t,this.#Ma=n,this.#qa=void 0!==i&&i,void 0!==t.displayRGBValue?this.#Qa=t.displayRGBValue:(this.#Qa=t.displayValue,this.#Ua=e.getOffsets(this.#Qa))}getName(){return"Change-segment-colour"}isValid(){let e=!0;return void 0!==this.#Ua&&(e=0!==this.#Ua.length),e}execute(){"number"==typeof this.#Ma?(this.#Di.setAtOffsets(this.#Ua,this.#Ma),this.#Ea.displayValue=this.#Ma):(this.#Di.updatePaletteColourMap(this.#Ea.number,this.#Ma),this.#Ea.displayRGBValue=this.#Ma),this.#qa||this.onExecute({type:"changemasksegmentcolour",segmentnumber:this.#Ea.number,value:[this.#Ma]})}undo(){"number"==typeof this.#Qa?(this.#Di.setAtOffsets(this.#Ua,this.#Qa),this.#Ea.displayValue=this.#Qa):(this.#Di.updatePaletteColourMap(this.#Ea.number,this.#Qa),this.#Ea.displayRGBValue=this.#Qa),this.onUndo({type:"changemasksegmentcolour",segmentnumber:this.#Ea.number,value:[this.#Qa]})}onExecute(e){}onUndo(e){}}class wo{#Va=[];#Na(e){return this.#Va.indexOf(e)}isHidden(e){return-1!==this.#Na(e)}addToHidden(e){this.isHidden(e)?c.warn("Not hidding segment, it is allready in the hidden list: "+e):this.#Va.push(e)}removeFromHidden(e){const t=this.#Na(e);-1!==t?this.#Va.splice(t,1):c.warn("Cannot remove segment, it is not in the hidden list: "+e)}getAlphaFunc(){return e=>Array.isArray(e)||0!==e&&!this.#Va.includes(e)?255:0}}class Oo{x;y}class Ao{x;y;z}return a}()})); +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("konva"),require("magic-wand-tool"),require("jszip")):"function"==typeof define&&define.amd?define(["konva","konmagic-wand-tool","jszip"],t):"object"==typeof exports?exports.dwv=t(require("konva"),require("magic-wand-tool"),require("jszip")):e.dwv=t(e.Konva,e.MagicWand,e.JSZip)}(this,(function(e,t,n){return function(){"use strict";var i={654:function(e){e.exports=n},944:function(t){t.exports=e},324:function(e){e.exports=t}},r={};function o(e){var t=r[e];if(void 0!==t)return t.exports;var n=r[e]={exports:{}};return i[e](n,n.exports,o),n.exports}o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,{a:t}),t},o.d=function(e,t){for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var a={};o.r(a),o.d(a,{Annotation:function(){return Bi},AnnotationGroup:function(){return Jn},AnnotationGroupFactory:function(){return to},App:function(){return Io},AppOptions:function(){return vo},ChangeSegmentColourCommand:function(){return Po},Circle:function(){return pi},ColourMap:function(){return f},DataElement:function(){return ve},DeleteSegmentCommand:function(){return Lo},DicomCode:function(){return kt},DicomData:function(){return no},DicomParser:function(){return Ge},DicomSRContent:function(){return Kr},DicomWriter:function(){return Qt},DrawController:function(){return $n},DrawLayer:function(){return Ci},DrawShapeHandler:function(){return Di},Ellipse:function(){return Si},Geometry:function(){return nt},Image:function(){return Un},Index:function(){return s},LayerGroup:function(){return Ki},MaskFactory:function(){return Fn},MaskSegment:function(){return pn},MaskSegmentHelper:function(){return To},MaskSegmentViewHelper:function(){return wo},Matrix33:function(){return A},NumberRange:function(){return et},Orientation:function(){return St},OverlayData:function(){return Do},PlaneHelper:function(){return Bn},Point:function(){return E},Point2D:function(){return R},Point3D:function(){return F},Protractor:function(){return hi},RGB:function(){return C},ROI:function(){return di},Rectangle:function(){return ci},RescaleSlopeAndIntercept:function(){return Xe},Scalar2D:function(){return Oo},Scalar3D:function(){return Ao},ScrollWheel:function(){return Hn},Size:function(){return je},Spacing:function(){return tt},Tag:function(){return de},TagValueExtractor:function(){return Lt},ToolConfig:function(){return yo},ToolboxController:function(){return lr},Vector3D:function(){return P},View:function(){return Nn},ViewConfig:function(){return Co},ViewController:function(){return Gn},ViewLayer:function(){return Xi},WindowLevel:function(){return u},WriterRule:function(){return At},addTagsToDictionary:function(){return Z},buildMultipart:function(){return X},createImage:function(){return En},createMaskImage:function(){return qn},createView:function(){return Vn},customUI:function(){return ki},decoderScripts:function(){return fr},defaultPresets:function(){return d},defaults:function(){return xi},getDefaultDicomSegJson:function(){return Rn},getDicomSRContentItem:function(){return $r},getDwvVersion:function(){return Le},getElementsFromJSONTags:function(){return Bt},getEllipseIndices:function(){return gi},getLayerDetailsFromEvent:function(){return Zi},getMousePoint:function(){return Wi},getOrientationName:function(){return ft},getPixelDataTag:function(){return De},getRectangleIndices:function(){return ui},getReverseOrientation:function(){return Ae},getSRContent:function(){return Jr},getTagFromKey:function(){return Se},getTouchPoints:function(){return zi},getTypedArray:function(){return Ue},getUID:function(){return xt},hasDicomPrefix:function(){return Pe},i18n:function(){return q},isEqualRgb:function(){return y},labToUintLab:function(){return v},logger:function(){return c},luts:function(){return D},precisionRound:function(){return B},srgbToCielab:function(){return T},toolList:function(){return Mi},toolOptions:function(){return Qi}});class s{#e;constructor(e){if(!e||void 0===e)throw new Error("Cannot create index with no values.");if(0===e.length)throw new Error("Cannot create index with empty values.");if(!e.every((function(e){return!isNaN(e)})))throw new Error("Cannot create index with non number values.");this.#e=e}get(e){return this.#e[e]}length(){return this.#e.length}toString(){return"("+this.#e.toString()+")"}getValues(){return this.#e.slice()}canCompare(e){return!!e&&this.length()===e.length()}equals(e){if(!this.canCompare(e))return!1;for(let t=0,n=this.length();tthis.#u?this.#l:e*this.#d+this.#h}}class S{#g;#p;#r;#m=0;#f=!0;constructor(e,t,n){if(this.#g=e,t){const e=this.#g.getLength();this.#m=e/2}else this.#m=0;this.#f=n}getVoiLut(){return this.#p}getModalityLut(){return this.#g}setVoiLut(e){if(this.#p=e,this.#p.setSignedOffset(this.#g.getRSI().getSlope()*this.#m),this.#f){const e=this.#g.getLength();this.#r=new Uint8ClampedArray(e);for(let t=0;t255?255:t})),green:g((function(e){const t=256/3;let n=0;return e>=t&&(n=3*(e-t),n>255)?255:n})),blue:g((function(e){const t=256/3;let n=0;return e>=2*t&&(n=3*(e-2*t),n>255)?255:n}))},hot_iron:{red:[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],green:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,255],blue:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,255]},pet:{red:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205,207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],green:[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,128,126,124,122,120,118,116,114,112,110,108,106,104,102,100,98,96,94,92,90,88,86,84,82,80,78,76,74,72,70,68,66,64,63,61,59,57,55,53,51,49,47,45,43,41,39,37,35,33,31,29,27,25,23,21,19,17,15,13,11,9,7,5,3,1,0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,255],blue:[0,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205,207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,252,248,244,240,236,232,228,224,220,216,212,208,204,200,196,192,188,184,180,176,172,168,164,160,156,152,148,144,140,136,132,128,124,120,116,112,108,104,100,96,92,88,84,80,76,72,68,64,60,56,52,48,44,40,36,32,28,24,20,16,12,8,4,0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,85,89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157,161,165,170,174,178,182,186,190,194,198,202,206,210,214,218,222,226,230,234,238,242,246,250,255]},hot_metal_blue:{red:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,9,12,15,18,21,24,26,29,32,35,38,41,44,47,50,52,55,57,59,62,64,66,69,71,74,76,78,81,83,85,88,90,93,96,99,102,105,108,111,114,116,119,122,125,128,131,134,137,140,143,146,149,152,155,158,161,164,166,169,172,175,178,181,184,187,190,194,198,201,205,209,213,217,221,224,228,232,236,240,244,247,251,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],green:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,8,9,11,13,15,17,19,21,23,24,26,28,30,32,34,36,38,40,41,43,45,47,49,51,53,55,56,58,60,62,64,66,68,70,72,73,75,77,79,81,83,85,87,88,90,92,94,96,98,100,102,104,105,107,109,111,113,115,117,119,120,122,124,126,128,130,132,134,136,137,139,141,143,145,147,149,151,152,154,156,158,160,162,164,166,168,169,171,173,175,177,179,181,183,184,186,188,190,192,194,196,198,200,201,203,205,207,209,211,213,215,216,218,220,222,224,226,228,229,231,233,235,237,239,240,242,244,246,248,250,251,253,255],blue:[0,2,4,6,8,10,12,14,16,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,184,186,188,190,192,194,196,198,200,197,194,191,188,185,182,179,176,174,171,168,165,162,159,156,153,150,144,138,132,126,121,115,109,103,97,91,85,79,74,68,62,56,50,47,44,41,38,35,32,29,26,24,21,18,15,12,9,6,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,9,12,15,18,21,24,26,29,32,35,38,41,44,47,50,53,56,59,62,65,68,71,74,76,79,82,85,88,91,94,97,100,103,106,109,112,115,118,121,124,126,129,132,135,138,141,144,147,150,153,156,159,162,165,168,171,174,176,179,182,185,188,191,194,197,200,203,206,210,213,216,219,223,226,229,232,236,239,242,245,249,252,255]},pet_20step:{red:[0,0,0,0,0,0,0,0,0,0,0,0,0,96,96,96,96,96,96,96,96,96,96,96,96,96,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,80,80,80,80,80,80,80,80,80,80,80,80,80,96,96,96,96,96,96,96,96,96,96,96,96,96,112,112,112,112,112,112,112,112,112,112,112,112,112,128,128,128,128,128,128,128,128,128,128,128,128,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,80,80,80,80,80,80,80,80,80,80,80,80,80,64,64,64,64,64,64,64,64,64,64,64,64,224,224,224,224,224,224,224,224,224,224,224,224,224,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,192,192,192,192,192,192,192,192,192,192,192,192,192,176,176,176,176,176,176,176,176,176,176,176,176,176,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],green:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,80,80,80,80,80,80,80,80,80,80,80,80,80,96,96,96,96,96,96,96,96,96,96,96,96,96,112,112,112,112,112,112,112,112,112,112,112,112,112,128,128,128,128,128,128,128,128,128,128,128,128,96,96,96,96,96,96,96,96,96,96,96,96,96,144,144,144,144,144,144,144,144,144,144,144,144,144,192,192,192,192,192,192,192,192,192,192,192,192,192,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,208,208,208,208,208,208,208,208,208,208,208,208,208,176,176,176,176,176,176,176,176,176,176,176,176,176,144,144,144,144,144,144,144,144,144,144,144,144,96,96,96,96,96,96,96,96,96,96,96,96,96,48,48,48,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255],blue:[0,0,0,0,0,0,0,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,112,112,112,112,112,112,112,112,112,112,112,112,128,128,128,128,128,128,128,128,128,128,128,128,128,176,176,176,176,176,176,176,176,176,176,176,176,176,192,192,192,192,192,192,192,192,192,192,192,192,192,224,224,224,224,224,224,224,224,224,224,224,224,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,80,80,80,80,80,80,80,80,80,80,80,80,80,64,64,64,64,64,64,64,64,64,64,64,64,80,80,80,80,80,80,80,80,80,80,80,80,80,96,96,96,96,96,96,96,96,96,96,96,96,96,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255]}};class C{r;g;b;constructor(e,t,n){this.r=e,this.g=t,this.b=n}}function y(e,t){return null!==e&&null!==t&&void 0!==e&&void 0!==t&&e.r===t.r&&e.g===t.g&&e.b===t.b}function v(e){return{l:655.35*e.l,a:257*e.a+32896,b:257*e.b+32896}}const I={x:95.0489,y:100,z:108.884};function T(e){return function(e){function t(e){let t=null;return t=e>.008856452?Math.pow(e,.333333333):7.787037037*e+.137931034,t}const n=I,i=t(e.y/n.y);return{l:116*i-16,a:500*(t(e.x/n.x)-i),b:200*(i-t(e.z/n.z))}}(function(e){function t(e){let t=null;return t=e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4),t}const n=t(e.r/255),i=t(e.g/255),r=t(e.b/255);return{x:100*(.4124*n+.3576*i+.1805*r),y:100*(.2126*n+.7152*i+.0722*r),z:100*(.0193*n+.1192*i+.9505*r)}}(e))}function L(e){const t={Yellow:"#ffff00",Red:"#ff0000",White:"#ffffff",Green:"#008000",Blue:"#0000ff",Lime:"#00ff00",Fuchsia:"#ff00ff",Black:"#000000"};let n="#ffff00";return void 0!==t[e]&&(n=t[e]),n}class P{#D;#C;#y;constructor(e,t,n){this.#D=e,this.#C=t,this.#y=n}getX(){return this.#D}getY(){return this.#C}getZ(){return this.#y}equals(e){return null!==e&&this.#D===e.getX()&&this.#C===e.getY()&&this.#y===e.getZ()}toString(){return"("+this.#D+", "+this.#C+", "+this.#y+")"}norm(){return Math.sqrt(this.#D*this.#D+this.#C*this.#C+this.#y*this.#y)}crossProduct(e){return new P(this.#C*e.getZ()-e.getY()*this.#y,this.#y*e.getX()-e.getZ()*this.#D,this.#D*e.getY()-e.getX()*this.#C)}dotProduct(e){return this.#D*e.getX()+this.#C*e.getY()+this.#y*e.getZ()}isCodirectional(e){return this.dotProduct(e)>0}}Number.EPSILON;const w=1e-4;function O(e,t,n){return void 0===n&&(n=Number.EPSILON),Math.abs(e-t)0?1:-1;for(let t=0;t<3;++t)t===n.index?e.push(1*i):e.push(0)}return new A(e)}getThirdColMajorDirection(){return this.getColAbsMax(2).index}}function b(){return new A([1,0,0,0,1,0,0,0,1])}function x(e){return e.equals(b())}class R{#D;#C;constructor(e,t){this.#D=e,this.#C=t}getX(){return this.#D}getY(){return this.#C}getValues(){return[this.#D,this.#C]}getCentroid(){return this}equals(e){return null!=e&&this.#D===e.getX()&&this.#C===e.getY()}toString(){return"("+this.#D+", "+this.#C+")"}getDistance(e){const t=this.#D-e.getX(),n=this.#C-e.getY();return Math.sqrt(t*t+n*n)}}class F{#D;#C;#y;constructor(e,t,n){this.#D=e,this.#C=t,this.#y=n}getX(){return this.#D}getY(){return this.#C}getZ(){return this.#y}getValues(){return[this.#D,this.#C,this.#y]}equals(e){return null!==e&&this.#D===e.getX()&&this.#C===e.getY()&&this.#y===e.getZ()}isSimilar(e,t){return null!==e&&O(this.#D,e.getX(),t)&&O(this.#C,e.getY(),t)&&O(this.#y,e.getZ(),t)}toString(){return"("+this.#D+", "+this.#C+", "+this.#y+")"}getDistance(e){return Math.sqrt(this.#I(e))}#I(e){const t=this.#D-e.getX(),n=this.#C-e.getY(),i=this.#y-e.getZ();return t*t+n*n+i*i}getClosest(e){let t=0,n=this.#I(e[t]);for(let i=0;i0?0|n:0;return e.substring(i,i+t.length)===t}function M(e,t){return null!=e&&null!=t&&e.substring(e.length-t.length)===t}function Q(e){const t=[];if(null==e)return t;const n=/{(\w+)}/g;let i=n.exec(e);for(;i;)t.push(i[1]),i=n.exec(e);return t}function V(e){let t=null;if(null!=e&&"."!==e[0]){const n=e.toLowerCase().split(".");1!==n.length&&(t=n.pop(),/[a-z]/.test(t)&&!t.includes("/")||(t=null))}return t}function N(e){const t=new Uint8Array(e.length);for(let n=0,i=e.length;n=e.length)throw new Error("Non valid dimension for toStringId");let n="";for(let i=0;i=e.length)&&(n=0),(void 0===i||i<=n||i>e.length)&&(i=e.length);for(let r=n;ro;t--,o++)r=n[o],n[o]=n[t],n[t]=r}class Te{#w;#O=!0;#A=function(){return new Int8Array(new Int16Array([1]).buffer)[0]>0}();#b;#x;constructor(e,t){this.#w=e,void 0!==t&&(this.#O=t),this.#b=this.#O!==this.#A,this.#x=new DataView(e)}readUint16(e){return this.#x.getUint16(e,this.#O)}readInt16(e){return this.#x.getInt16(e,this.#O)}readUint32(e){return this.#x.getUint32(e,this.#O)}readBigUint64(e){return this.#x.getBigUint64(e,this.#O)}readInt32(e){return this.#x.getInt32(e,this.#O)}readBigInt64(e){return this.#x.getBigInt64(e,this.#O)}readFloat32(e){return this.#x.getFloat32(e,this.#O)}readFloat64(e){return this.#x.getFloat64(e,this.#O)}readBinaryArray(e,t){const n=new Uint8Array(this.#w,e,t),i=8*n.length,r=new Uint8Array(i);let o=0,a=0;for(let e=0;e2^"+e+").")}}return i}function Me(e,t){return t?8:J(e)?12:8}const Qe="00280008",Ve="00280100",Ne="00280103",Be="7FE00010";class Ge{#R={};#F;#E=new Oe;#q=this.#E;#U(e){return this.#E.decode(e)}#M(e){return this.#q.decode(e)}getDefaultCharacterSet(){return this.#F}setDefaultCharacterSet(e){this.#F=e}setDecoderCharacterSet(e){this.#q=new TextDecoder(e)}getDicomElements(){return this.#R}#Q(e,t){const n=e.readHex(t);t+=Uint16Array.BYTES_PER_ELEMENT;const i=e.readHex(t);return t+=Uint16Array.BYTES_PER_ELEMENT,{tag:new de(n,i),endOffset:t}}#V(e,t,n){const i={};let r=this.#N(e,t,n);if(t=r.endOffset,fe(r.tag))return{data:i,endOffset:r.endOffset,isSeqDelim:!0};if(i[r.tag.getKey()]={tag:r.tag,vr:"NONE",vl:r.vl,undefinedLength:r.undefinedLength},r.undefinedLength){let o=!1;for(;!o;)r=this.#N(e,t,n),t=r.endOffset,o=me(r.tag),o||(i[r.tag.getKey()]=r)}else{const o=t;for(t-=r.vl;t8&&"OB"===a&&(c.warn("Reading DICOM pixel data with bitsAllocated>8 and OB VR, treating as OW"),e.vr="OW"),l=[],1===i)l.push(t.readBinaryArray(s,o));else if(8===i)0===n?l.push(t.readUint8Array(s,o)):l.push(t.readInt8Array(s,o));else{if(16!==i)throw new Error("Unsupported bits allocated: "+i);0===n?l.push(t.readUint16Array(s,o)):l.push(t.readInt16Array(s,o))}else if(void 0!==u)if("Uint8"===u)l=t.readUint8Array(s,o);else if("Uint16"===u)l=t.readUint16Array(s,o),"O"!==a[0]&&(l=Array.from(l));else if("Uint32"===u)l=t.readUint32Array(s,o),"O"!==a[0]&&(l=Array.from(l));else if("Uint64"===u)l=t.readUint64Array(s,o);else if("Int16"===u)l=Array.from(t.readInt16Array(s,o));else if("Int32"===u)l=Array.from(t.readInt32Array(s,o));else if("Int64"===u)l=t.readInt64Array(s,o);else if("Float32"===u)l=Array.from(t.readFloat32Array(s,o));else if("Float64"===u)l=Array.from(t.readFloat64Array(s,o));else{if("string"!==u)throw new Error("Unknown VR type: "+u);{const e=t.readUint8Array(s,o);l=ee(a)?this.#M(e):this.#U(e),l=function(e){let t=e;const n=e.length-1;return e[n]===we&&(t=e.substring(0,n)),t=t.trim(),t}(l).split("\\")}}else if("xx"===a)l=Array.from(t.readUint16Array(s,o));else if("ox"===a)l=8===i?0===n?Array.from(t.readUint8Array(s,o)):Array.from(t.readInt8Array(s,o)):0===n?Array.from(t.readUint16Array(s,o)):Array.from(t.readInt16Array(s,o));else if("xs"===a)l=0===n?Array.from(t.readUint16Array(s,o)):Array.from(t.readInt16Array(s,o));else if("AT"===a){const e=t.readUint16Array(s,o);l=[];for(let t=0,n=e.length;t=65&&r<=90&&o>=65&&o<=90);let s=null;if(n===t)s=a?ie:re;else{if(a)throw new Error("Not a valid DICOM file (no magic DICM word foundand implicit VR big endian detected)");s=oe}const l=new ve("UI");return l.tag=new de("0002","0010"),l.value=[s],l.vl=l.value[0].length,l.startOffset=e.startOffset,l.endOffset=l.startOffset+l.vl,l}(i);this.#R[e.tag.getKey()]=e,n=e.value[0],t=0}if(!function(e){return e===ie||e===re||e===oe||Re(e)||Fe(e)||Ee(e)||qe(e)}(n))throw new Error("Unsupported DICOM transfer syntax: '"+n+"' ("+function(e){let t="Unknown";return void 0!==ne[e]&&(t=ne[e]),t}(n)+")");let s=!1;for(be(n)&&(s=!0),xe(n)&&(o=new Te(e,!1));t1&&t.length>e){const n=t.length/e,r=[];let o=0;for(let i=0;i{if(void 0===this.#H[e.type])return;const t=this.#H[e.type].slice();for(let n=0;n2?e:0})));let c=r.indexToOffset(l);void 0===n&&(n=!1);let u=null;u=n?function(t){return e.getRescaledValueAtOffset(t)}:function(t){return e.getValueAtOffset(t)};const d=r.get(0),h=r.get(1),S=r.get(2);let g=r.getDimSize(2);const p=e.getNumberOfComponents(),m=1===e.getPlanarConfiguration(),f=function(e,t,n,i,r,o,a,s){return 1===p?He(e,t,n,i,r,o,a,s):3===p?function(e,t,n,i,r,o,a,s,l){const c=[];return l?(c.push(He(e,t,n,i,r,o,a,s)),c.push(He(e,t+n*i,n,i,r,o,a,s)),c.push(He(e,t+2*n*i,n,i,r,o,a,s))):(i*=3,o*=3,c.push(He(e,t,n,i,r,o,a,s)),c.push(He(e,t+1,n,i,r,o,a,s)),c.push(He(e,t+2,n,i,r,o,a,s))),{next:function(){const e=c[0].next(),t=c[1].next(),n=c[2].next();return e.done?{done:!0,index:n.index}:{value:[e.value,t.value,n.value],done:!1,index:[e.index,t.index,n.index]}}}}(e,3*t,n,i,r,o,a,s,m):void 0};let D=null;if(i&&void 0!==i){const e=i.getColAbsMax(0),t=i.getColAbsMax(2),n=!1,r=!1;let o=null;if(2===t.index)o=d*h,D=0===e.index?f(u,c,o,1,d,d,n,r):f(u,c,o,d,h,1,n,r);else if(0===t.index)o=S*h,D=1===e.index?f(u,c,o,d,h,g,n,r):f(u,c,o,g,S,d,n,r);else{if(1!==t.index)throw new Error("Unknown direction: "+t.index);o=S*d,D=0===e.index?f(u,c,o,1,d,g,n,r):f(u,c,o,g,S,1,n,r)}}else if(1===e.getNumberOfComponents())D=function(e,t,n,i){void 0===i&&(i=1);let r=t;return{next:function(){if(r=e[i+1].index&&++i;const t={value:e[i].value,done:!1,index:n};return++n,t}return{done:!0,index:t}}}}class Xe{#d;#z;constructor(e,t){this.#d=e,this.#z=t}getSlope(){return this.#d}getIntercept(){return this.#z}apply(e){return e*this.#d+this.#z}equals(e){return null!=e&&this.getSlope()===e.getSlope()&&this.getIntercept()===e.getIntercept()}isID(){return 1===this.getSlope()&&0===this.getIntercept()}}class je{#e;constructor(e){if(!e||void 0===e)throw new Error("Cannot create size with no values.");if(0===e.length)throw new Error("Cannot create size with empty values.");if(!e.every((function(e){return!isNaN(e)&&0!==e})))throw new Error("Cannot create size with non number or zero values.");this.#e=e}get(e){return this.#e[e]}length(){return this.#e.length}toString(){return"("+this.#e.toString()+")"}getValues(){return this.#e.slice()}moreThanOne(e){return this.length()>=e+1&&1!==this.get(e)}canScroll3D(e){let t=2;return void 0!==e&&(t=e.getThirdColMajorDirection()),this.moreThanOne(t)}canScroll(e){let t=this.canScroll3D(e);for(let e=3;ethis.length())return null;if(void 0===t)t=0;else if(t<0||t>e)throw new Error("Invalid start value for getDimSize");let n=1;for(let i=t;in-1)throw new Error("Wrong input dir value: "+t[e]);for(let n=0;n=0&&ithis.length()-1)throw new Error("Invalid start value for indexToOffset");let n=0;for(let i=t;i0;--e)i=this.getDimSize(e),t[e]=Math.floor(n/i),n-=t[e]*i;return t[0]=n,new s(t)}get2D(){return{x:this.get(0),y:this.get(1)}}}class Ze{min;max;mean;stdDev;median;p25;p75;constructor(e,t,n,i){this.min=e,this.max=t,this.mean=n,this.stdDev=i}}function _e(e,t){return function(e){return null!=e&&(e.includes("median")||e.includes("p25")||e.includes("p75"))}(t)?function(e){const t=Ke(e);return e.sort((function(e,t){return e-t})),t.median=Je(e,.5),t.p25=Je(e,.25),t.p75=Je(e,.75),t}(e):Ke(e)}function Ke(e){let t=e[0],n=t,i=0,r=0,o=0;const a=e.length;for(let s=0;sn&&(n=o),i+=o,r+=o*o;const s=i/a;let l=r/a-s*s;l<0&&(l=0);const c=Math.sqrt(l);return new Ze(t,n,s,c)}function Je(e,t){if(0===e.length)throw new Error("Empty array provided for percentile calculation.");if(t<0||t>1)throw new Error("Invalid ratio provided for percentile calculation: "+t);if(0===t)return e[0];if(1===t)return e[e.length-1];const n=(e.length-1)*t,i=Math.floor(n),r=e[i];return r+(e[i+1]-r)*(n-i)}function $e(){return Math.random().toString(36).substring(2,15)}class et{min;max;constructor(e,t){this.min=e,this.max=t}}class tt{#e;constructor(e){if(!e||void 0===e)throw new Error("Cannot create spacing with no values.");if(0===e.length)throw new Error("Cannot create spacing with empty values.");if(!e.every((function(e){return!isNaN(e)&&0!==e})))throw new Error("Cannot create spacing with non number or zero values.");this.#e=e}get(e){return this.#e[e]}length(){return this.#e.length}toString(){return"("+this.#e.toString()+")"}getValues(){return this.#e.slice()}equals(e){if(!e)return!1;const t=this.length();if(t!==e.length())return!1;for(let n=0;nw&&c.warn("Varying slice spacing, value: "+i+" (mean: "+n.mean+", min: "+n.min+", max: "+n.max+", stdDev: "+n.stdDev+")"),i}(this.#W);if(void 0!==e&&this.#X.get(2)!==e){c.trace("Using geometric spacing "+e+" instead of tag spacing "+this.#X.get(2));const t=this.#X.getValues();t[2]=e,this.#X=new tt(t)}}getSpacing(e){this.#K&&(this.#J(),this.#K=!1);let t=this.#X;if(e&&void 0!==e){let n=it([this.#X.get(0),this.#X.get(1),this.#X.get(2)],e);n=n.map(Math.abs),t=new tt(n)}return t}getRealSpacing(){return this.getSpacing(this.#_.getInverse().asOneAndZeros())}getOrientation(){return this.#_}getSliceIndex(e,t){let n=this.#W;void 0!==t&&(n=this.#j[t]);const i=e.getClosest(n),r=n[i],o=e.minus(r);return new P(this.#_.get(0,2),this.#_.get(1,2),this.#_.get(2,2)).isCodirectional(o)?i+1:i}appendOrigin(e,t,n){const i=function(t){return t.equals(e)};if(void 0!==n){if(void 0!==this.#j[n].find(i))throw new Error("Cannot append same time origin twice");this.#j[n].splice(t,0,e)}if(void 0===n||n===this.#Z){if(void 0!==this.#W.find(i))throw new Error("Cannot append same origin twice");this.#K=!0,this.#W.splice(t,0,e);const n=this.#Y.getValues();n[2]+=1,this.#Y=new je(n)}}appendFrame(e,t){this.#j[t]=[e];const n=this.#Y.getValues(),i=this.#X.getValues();4===n.length?n[3]+=1:(n.push(2),i.push(1)),this.#Y=new je(n),this.#X=new tt(i)}toString(){return"Origin: "+this.getOrigin()+", Size: "+this.getSize()+", Spacing: "+this.getSpacing()+", Orientation: "+this.getOrientation()}equals(e){return null!==e&&this.getOrigin().equals(e.getOrigin())&&this.getSize().equals(e.getSize())&&this.getSpacing().equals(e.getSpacing())}isInBounds(e){return this.isIndexInBounds(this.worldToIndex(e))}isIndexInBounds(e,t){return this.getSize().isInBounds(e,t)}indexToWorld(e){const t=this.getSpacing(),n=new F(e.get(0)*t.get(0),e.get(1)*t.get(1),e.get(2)*t.get(2)),i=this.getOrientation().multiplyPoint3D(n),r=e.getValues(),o=this.getOrigin();return r[0]=o.getX()+i.getX(),r[1]=o.getY()+i.getY(),r[2]=o.getZ()+i.getZ(),new E(r)}pointToWorld(e){const t=this.getSpacing(),n=new F(e.getX()*t.get(0),e.getY()*t.get(1),e.getZ()*t.get(2)),i=this.getOrientation().multiplyPoint3D(n),r=this.getOrigin();return new F(r.getX()+i.getX(),r.getY()+i.getY(),r.getZ()+i.getZ())}worldToIndex(e){const t=this.getOrigin(),n=new F(e.get(0)-t.getX(),e.get(1)-t.getY(),e.get(2)-t.getZ()),i=this.getOrientation().getInverse().multiplyPoint3D(n),r=e.getValues(),o=this.getSpacing();return r[0]=Math.round(i.getX()/o.get(0)),r[1]=Math.round(i.getY()/o.get(1)),r[2]=Math.round(i.getZ()/o.get(2)),new s(r)}worldToPoint(e){const t=this.getOrigin(),n=new F(e.get(0)-t.getX(),e.get(1)-t.getY(),e.get(2)-t.getZ()),i=this.getOrientation().getInverse().multiplyPoint3D(n),r=e.getValues(),o=this.getSpacing();return r[0]=i.getX()/o.get(0),r[1]=i.getY()/o.get(1),r[2]=i.getZ()/o.get(2),new F(r[0],r[1],r[2])}}function it(e,t){return t.getInverse().multiplyArray3D(e)}function rt(e,t){return t.multiplyArray3D(e)}function ot(e){return("0"+e).slice(-2)}function at(e){if(void 0===e)return;if(1!==e.value.length)return;const t=e.value[0];let n=4,i=6;return 10===t.length&&(n=5,i=8),{year:parseInt(t.substring(0,4),10),monthIndex:t.length>=n+2?parseInt(t.substring(n,n+2),10)-1:0,day:t.length===i+2?parseInt(t.substring(i,i+2),10):0}}function st(e){if(void 0===e)return;if(1!==e.value.length)return;const t=e.value[0],n=parseInt(t.substring(0,2),10),i=t.length>=4?parseInt(t.substring(2,4),10):0,r=t.length>=6?parseInt(t.substring(4,6),10):0,o=t.length>=8?t.substring(7,10):0;return{hours:n,minutes:i,seconds:r,milliseconds:0===o?0:parseInt(o,10)*Math.pow(10,3-o.length)}}function lt(e){return{year:e.getFullYear().toString(),monthIndex:ot((e.getMonth()+1).toString()),day:ot(e.getDate().toString())}}function ct(e){return{hours:ot(e.getHours().toString()),minutes:ot(e.getMinutes().toString()),seconds:ot(e.getSeconds().toString())}}function ut(e){return e.year+e.monthIndex+e.day}function dt(e){return e.hours+e.minutes+e.seconds}function ht(){return new A([1,0,0,0,0,1,0,-1,0])}const St={Axial:"axial",Coronal:"coronal",Sagittal:"sagittal"};function gt(e){let t;return e===St.Axial?t=b():e===St.Coronal?t=ht():e===St.Sagittal&&(t=new A([0,0,-1,1,0,0,0,-1,0])),t}function pt(e){const t=new P(e.get(0,0),e.get(1,0),e.get(2,0)),n=new P(e.get(0,1),e.get(1,1),e.get(2,1)),i=new P(e.get(0,2),e.get(1,2),e.get(2,2));return mt(t)+mt(n)+mt(i)}function mt(e){let t=new P(Math.abs(e.getX()),Math.abs(e.getY()),Math.abs(e.getZ())),n="";const i=e.getX()<0?"R":"L",r=e.getY()<0?"A":"P",o=e.getZ()<0?"I":"S",a=1e-4;for(let e=0;e<3;e++)if(t.getX()>a&&t.getX()>t.getY()&&t.getX()>t.getZ())n+=i,t=new P(0,t.getY(),t.getZ());else if(t.getY()>a&&t.getY()>t.getX()&&t.getY()>t.getZ())n+=r,t=new P(t.getX(),0,t.getZ());else{if(!(t.getZ()>a&&t.getZ()>t.getX()&&t.getZ()>t.getY()))break;n+=o,t=new P(t.getX(),t.getY(),0)}return n}function ft(e){let t;const n=Dt(e);return void 0!==n&&(t=function(e){let t;return["LPS","LAI","RPI","RAS","ALS","ARI","PLI","PRS"].includes(e)?t=St.Axial:["LSA","LIP","RSP","RIA","ILA","IRP","SLP","SRA"].includes(e)?t=St.Coronal:["PSL","PIR","ASR","AIL","IAR","IPL","SAL","SPR"].includes(e)&&(t=St.Sagittal),t}(pt(n.asOneAndZeros()))),t}function Dt(e){let t;if(void 0!==e&&6===e.length){const n=new P(e[0],e[1],e[2]),i=new P(e[3],e[4],e[5]),r=n.crossProduct(i);t=new A([n.getX(),i.getX(),r.getX(),n.getY(),i.getY(),r.getY(),n.getZ(),i.getZ(),r.getZ()])}return t}function Ct(e,t){let n=b();return void 0!==t&&(n=e.asOneAndZeros().getInverse().multiply(t)),n.getAbs()}function yt(e){const t=e["00280010"];if(void 0===t)throw new Error("Missing DICOM image number of rows");if(0===t.value.length)throw new Error("Empty DICOM image number of rows");const n=e["00280011"];if(void 0===n)throw new Error("Missing DICOM image number of columns");if(0===n.value.length)throw new Error("Empty DICOM image number of columns");return[n.value[0],t.value[0]]}function vt(e){if(void 0===e["00280030"])return null;const t=e["00280030"],n=[parseFloat(t.value[1]),parseFloat(t.value[0])];return void 0!==e["00180088"]&&n.push(parseFloat(e["00180088"].value[0])),new tt(n)}function It(e){return void 0!==e&&null!==e.match(/MONOCHROME/)}function Tt(e,t,n){let i="";if(void 0===e)i+=" "+t+" is undefined,";else if(0===e.value.length)i+=" "+t+" is empty,";else if(void 0!==n)for(let r=0;r=9?st(r):void 0}}(h);S=e.date,g=e.time}void 0===g&&(g={hours:0,minutes:0,seconds:0,milliseconds:0}),a=new Date(S.year,S.monthIndex,S.day,g.hours,g.minutes,g.seconds,g.milliseconds)}const l=st(e["00080031"]);let u=new Date(i.year,i.monthIndex,i.day,l.hours,l.minutes,l.seconds,l.milliseconds);const d=e["00080022"],h=e["00080032"];if(void 0!==d&&void 0!==h){const t=at(d),i=st(h),r=new Date(t.year,t.monthIndex,t.day,i.hours,i.minutes,i.seconds,i.milliseconds);if(u>r){const a="Series date/time is after Aquisition date/time (diff="+(u.getTime()-r.getTime()).toString()+"ms) ";c.debug(a);let s=0;const l="FrameReferenceTime (00541300)",d=e["00541300"];n+=Tt(d,l),void 0!==d&&(s=d.value[0]);let h=0;const S="ActualFrameDuration (0018,1242)",g=e["00181242"];if(n+=Tt(g,S),void 0!==g&&(h=g.value[0]),s>0&&h>0){h/=1e3,s/=1e3;const e=Math.log(2)/o,n=e*h,r=1/e*Math.log(n/(1-Math.exp(-n)))-s;u=new Date(t.year,t.monthIndex,t.day,i.hours,i.minutes,i.seconds+r,i.milliseconds)}}}let S;if(void 0!==u&&void 0!==a&&void 0!==r&&void 0!==o){const e=(u.getTime()-a.getTime())/1e3;S=r*Math.pow(2,-e/o)}return{value:S,warning:n}}(e);return t+=a.warning,0!==t.length?n.warning="Cannot calculate PET SUV:"+t:n.value=1e3*i/a.value,n}(e);this.#ee=i.value,this.#$=i.warning}return this.#$}create(e,t,n){const i=yt(e),r=[i[0],i[1],1],o=e["00280008"];if(void 0!==o){const e=parseInt(o.value[0],10);e>1&&r.push(e)}const a=new je(r),s=function(e){let t=1,n=1;const i=["00280030","00181164","00182010","00280034"];for(let r=0;rparseFloat(e))))),n}(e),D=new F(p[0],p[1],p[2]),C=(new Lt).getTime(e),y=new nt(D,a,s,m,C);let v;const I=e["00080018"];void 0!==I&&(v=I.value[0]);let T=1;const L=e["00280002"];void 0!==L&&(T=L.value[0]);const P=a.getTotalSize()*T;if(P!==t.length){if(c.warn("Badly sized pixel buffer: "+t.length+" != "+P),!(P>8};r=t.value.map(e),o=n.value.map(e),a=i.value.map(e)}}else if(8===s.value[2]){c.info("Scaling 16bits color lut since the lut descriptor is 8.");let e=t.value.slice(0);r=Array.from(new Uint8Array(e.buffer)),e=n.value.slice(0),o=Array.from(new Uint8Array(e.buffer)),e=i.value.slice(0),a=Array.from(new Uint8Array(e.buffer))}w.setPaletteColourMap(new f(r,o,a))}const z=e["00082144"];return void 0!==z&&(q.RecommendedDisplayFrameRate=parseInt(z.value[0],10)),w.setMeta(q),w}}class wt{#O=!0;#x;constructor(e,t){void 0!==t&&(this.#O=t),this.#x=new DataView(e)}writeUint8(e,t){return this.#x.setUint8(e,t),e+Uint8Array.BYTES_PER_ELEMENT}writeInt8(e,t){return this.#x.setInt8(e,t),e+Int8Array.BYTES_PER_ELEMENT}writeUint16(e,t){return this.#x.setUint16(e,t,this.#O),e+Uint16Array.BYTES_PER_ELEMENT}writeInt16(e,t){return this.#x.setInt16(e,t,this.#O),e+Int16Array.BYTES_PER_ELEMENT}writeUint32(e,t){return this.#x.setUint32(e,t,this.#O),e+Uint32Array.BYTES_PER_ELEMENT}writeUint64(e,t){return this.#x.setBigUint64(e,t,this.#O),e+BigUint64Array.BYTES_PER_ELEMENT}writeInt32(e,t){return this.#x.setInt32(e,t,this.#O),e+Int32Array.BYTES_PER_ELEMENT}writeInt64(e,t){return this.#x.setBigInt64(e,t,this.#O),e+BigInt64Array.BYTES_PER_ELEMENT}writeFloat32(e,t){return this.#x.setFloat32(e,t,this.#O),e+Float32Array.BYTES_PER_ELEMENT}writeFloat64(e,t){return this.#x.setFloat64(e,t,this.#O),e+Float64Array.BYTES_PER_ELEMENT}writeHex(e,t){const n=parseInt(t,16);return this.#x.setUint16(e,n,this.#O),e+Uint16Array.BYTES_PER_ELEMENT}writeBinaryArray(e,t){if(t.length%8!=0)throw new Error("Cannot write boolean array as binary.");let n=null,i=null;for(let r=0,o=t.length;r1){let t="";for(let n=0;npe(e.tag)));void 0!==s&&void 0!==s.undefinedLength&&(a=s.undefinedLength);const l=new ve("NONE");l.vl=a?4294967295:s.vl,l.tag=ge(),l.value=[],t=this.#de(e,l,t,i);for(const n of r)pe(n.tag)||me(n.tag)||(t=this.#de(e,n,t,i));if(a){const n=new ve("NONE");n.vl=0,n.tag=new de("FFFE","E00D"),n.value=[],t=this.#de(e,n,t,i)}}return t}#he(e,t,n,i,r){const o=n;if("NONE"===t.vr);else if(i instanceof Uint8Array)n=i.length===8*t.vl?e.writeBinaryArray(n,i):e.writeUint8Array(n,i);else if(i instanceof Int8Array)n=e.writeInt8Array(n,i);else if(i instanceof Uint16Array)n=e.writeUint16Array(n,i);else if(i instanceof Int16Array)n=e.writeInt16Array(n,i);else if(i instanceof Uint32Array)n=e.writeUint32Array(n,i);else if(i instanceof Int32Array)n=e.writeInt32Array(n,i);else if(i instanceof BigUint64Array)n=e.writeUint64Array(n,i);else if(i instanceof BigInt64Array)n=e.writeInt64Array(n,i);else{const o=te[t.vr];if(void 0!==o)if("Uint8"===o)n=e.writeUint8Array(n,i);else if("Uint16"===o)n=e.writeUint16Array(n,i);else if("Int16"===o)n=e.writeInt16Array(n,i);else if("Uint32"===o)n=e.writeUint32Array(n,i);else if("Int32"===o)n=e.writeInt32Array(n,i);else if("Uint64"===o)n=e.writeUint64Array(n,i);else if("Int64"===o)n=e.writeInt64Array(n,i);else if("Float32"===o)n=e.writeFloat32Array(n,i);else if("Float64"===o)n=e.writeFloat64Array(n,i);else{if("string"!==o)throw new Error("Unknown VR type: "+o);n=e.writeUint8Array(n,i)}else if("SQ"===t.vr)n=this.#ue(e,n,i,r);else if("AT"===t.vr)for(let t=0;t1&&(o=function(e){const t=e.length,n=e[0].length;if(void 0===n)return e;const i=t*n,r=new e[0].constructor(i);for(let i=0;iObject.prototype.hasOwnProperty.call(t,n)&&e[n]===t[n]))}function zt(e){const t=new kt(e[Gt.CodeMeaning].value[0]);if(void 0!==e[Gt.CodeValue])t.value=e[Gt.CodeValue].value[0];else if(void 0!==e[Gt.LongCodeValue])t.longValue=e[Gt.LongCodeValue].value[0];else{if(void 0===e[Gt.URNCodeValue])throw new Error("Invalid code with no value, no long value and no urn value.");t.urnValue=e[Gt.URNCodeValue].value[0]}if(void 0!==t.value||void 0!==t.longValue){if(void 0===e[Gt.CodingSchemeDesignator])throw new Error("No coding sheme designator when code value or long value is present");t.schemeDesignator=e[Gt.CodingSchemeDesignator].value[0]}return t}function Wt(e){const t={};return void 0!==e.value?t.CodeValue=e.value:void 0!==e.longValue?t.LongCodeValue=e.longValue:void 0!==e.urnValue&&(t.URNCodeValue=e.urnValue),void 0!==e.schemeDesignator&&(t.CodingSchemeDesignator=e.schemeDesignator),t.CodeMeaning=e.meaning,t}const Yt={111030:"Image Region",112039:"Tracking Identifier",112040:"Tracking Unique Identifier",113048:"Pixel by pixel Maximum",113049:"Pixel by pixel mean",113051:"Pixel by pixel Minimum",113061:"Standard Deviation",113076:"Segmentation",121055:"Path",121207:"Height",121322:"Source image for image processing operation",121324:"Source Image",122438:"Reference Points",125007:"Measurement Group",125309:"Short label",128773:"Reference Geometry"},Xt={1483009:"Angle",42798e3:"Area",103355008:"Width",103339001:"Long axis",103340004:"Short axis",131190003:"Radius",261665006:"Unknown",410668003:"Length",718499004:"Color"},jt={1:"No units",mm:"Millimeter",deg:"Degree - plane angle",cm2:"Square centimeter","cm2/ml":"Square centimeter per milliliter","/cm":"Per centimeter","g/ml":"Gram per milliliter","g/ml{SUVbw}":"Standardized Uptake Value body weight","mg/ml":"Milligram per milliliter","umol/ml":"Micromole per milliliter","Bq/ml":"Becquerels per milliliter","mg/min/ml":"Milligrams per minute per milliliter","umol/min/ml":"Micromole per minute per milliliter","ml/min/g":"Milliliter per minute per gram","ml/g":"Milliliter per gram","ml/min/ml":"Milliliter per minute per milliliter","ml/ml":"Milliliter per milliliter","%":"Percentage","[hnsf'U]":"Hounsfield unit","10*23/ml":"Electron density","{counts}":"Counts","{counts}/s":"Counts per second","{propcounts}":"Proportional to counts","{propcounts}/s":"Proportional to counts per second"};function Zt(e,t){let n,i;return"DCM"===t?n=Yt[e]:"SCT"===t?n=Xt[e]:"UCUM"===t&&(n=jt[e]),void 0!==n&&(i=new kt(n),i.schemeDesignator=t,i.value=e),i}function _t(){return Zt("125007","DCM")}function Kt(){return Zt("128773","DCM")}function Jt(){return Zt("121324","DCM")}function $t(){return Zt("112039","DCM")}function en(){return Zt("125309","DCM")}function tn(){return Zt("122438","DCM")}function nn(){return Zt("718499004","SCT")}const rn={angle:{key:"1483009",scheme:"SCT"},length:{key:"410668003",scheme:"SCT"},surface:{key:"42798000",scheme:"SCT"},height:{key:"121207",scheme:"DCM"},width:{key:"103355008",scheme:"SCT"},radius:{key:"131190003",scheme:"SCT"},a:{key:"103339001",scheme:"SCT"},b:{key:"103340004",scheme:"SCT"},min:{key:"113051",scheme:"DCM"},max:{key:"113048",scheme:"DCM"},mean:{key:"113049",scheme:"DCM"},stddev:{key:"113061",scheme:"DCM"}};function on(e){let t;for(const n in rn){const i=rn[n];if(i.scheme===e.schemeDesignator&&i.key===e.value){t=n;break}}return t}const an={"unit.mm":"mm","unit.cm2":"cm2","unit.degree":"deg",HU:"[hnsf'U]",MGML:"mg/ml",ED:"10*23/ml",PCT:"%",CNTS:"{counts}",NONE:"1",CM2:"cm2",CM2ML:"cm2/ml",PCNT:"%",CPS:"{counts}/s",BQML:"Bq/ml",MGMINML:"mg/min/ml",UMOLMINML:"umol/min/ml",MLMING:"ml/min/g",MLG:"ml/g","1CM":"/cm",UMOLML:"umol/ml",PROPCNTS:"{propcounts}",PROPCPS:"{propcounts}/s",MLMINML:"ml/min/ml",MLML:"ml/ml",GML:"g/ml",SUV:"g/ml{SUVbw}"};function sn(e){let t;for(const n in an){const i=an[n];if("UCUM"===e.schemeDesignator&&i===e.value){t=n;break}}return t}const ln="00620005",cn="00620009",un="0062000C",dn="0062000D",hn="00620003",Sn="0062000F",gn="00620020";class pn{number;label;algorithmType;algorithmName;displayValue;displayRGBValue;propertyTypeCode;propertyCategoryCode;trackingUid;trackingId;constructor(e,t,n){this.number=e,this.label=t,this.algorithmType=n}}function mn(e){const t=new pn(e["00620004"].value[0],e[ln]?e[ln].value[0]:"n/a",e["00620008"].value[0]);if(void 0!==e[cn]&&(t.algorithmName=e[cn].value[0]),void 0!==e[un])t.displayValue=e[un].value[0];else if(void 0!==e[dn]){const i=e[dn].value,r=function(e){return function(e){function t(e){let t=null;return t=e<=.0031308?12.92*e:1.055*Math.pow(e,.416666667)-.055,Math.min(1,Math.max(0,t))}const n=e.x/100,i=e.y/100,r=e.z/100;return{r:Math.round(255*t(3.2406*n-1.5372*i-.4986*r)),g:Math.round(255*t(-.9689*n+1.8758*i+.0415*r)),b:Math.round(255*t(.0557*n-.204*i+1.057*r))}}(function(e){function t(e){let t=null;return t=e>.206896552?Math.pow(e,3):.128418549*e-.017712903,t}const n=I,i=(e.l+16)/116;return{x:n.x*t(i+e.a/500),y:n.y*t(i),z:n.z*t(i-e.b/200)}}(e))}({l:.001525902*(n={l:i[0],a:i[1],b:i[2]}).l,a:.003891051*n.a-128,b:.003891051*n.b-128});t.displayRGBValue=r}var n;if(void 0===e[hn])throw new Error("Missing Segmented Property Category Code Sequence.");if(t.propertyCategoryCode=zt(e[hn].value[0]),void 0===e[Sn])throw new Error("Missing Segmented Property Type Code Sequence.");return t.propertyTypeCode=zt(e[Sn].value[0]),void 0!==e[gn]&&(t.trackingId=e[gn].value[0],t.trackingUid=e["00620021"].value[0]),t}function fn(e){let t=e.algorithmType;void 0===t&&(t="MANUAL");const n={SegmentNumber:e.number,SegmentLabel:e.label,SegmentAlgorithmType:t};if("MANUAL"!==t&&void 0!==e.algorithmName&&(n.SegmentAlgorithmName=e.algorithmName),e.displayRGBValue){const t=v(T(e.displayRGBValue));n.RecommendedDisplayCIELabValue=[Math.round(t.l),Math.round(t.a),Math.round(t.b)]}else n.RecommendedDisplayGrayscaleValue=e.displayValue;return e.propertyCategoryCode&&(n.SegmentedPropertyCategoryCodeSequence={value:[Wt(e.propertyCategoryCode)]}),e.propertyTypeCode&&(n.SegmentedPropertyTypeCodeSequence={value:[Wt(e.propertyTypeCode)]}),e.trackingId&&(n.TrackingID=e.trackingId,n.TrackingUID=e.trackingUid),n}const Dn="00089124",Cn="00082112",yn="00081150",vn="00081155",In="00209116",Tn="00289110";class Ln{dimIndex;imagePosPat;derivationImages;refSegmentNumber;imageOrientationPatient;spacing;constructor(e,t,n,i){this.dimIndex=e,this.imagePosPat=t,this.derivationImages=n,this.refSegmentNumber=i}}function Pn(e){const t=[];if(void 0!==e[Dn]){const n=e[Dn].value;for(let e=0;e1&&(C=!0,p=new f(h,S,g));const y=e[52009229];if(void 0!==y){const e=y.value[0];if(void 0!==e["00209116"]){const t=e["00209116"];0!==t.value.length?D=t.value[0]["00200037"].value:c.warn("No shared functional group plane orientation sequence items.")}if(void 0!==e["00289110"]){const t=e["00289110"];0!==t.value.length?m=vt(t.value[0]):c.warn("No shared functional group pixel measure sequence items.")}}const v=function(e,t){return e.some((function(e){return On(t,e)}))},I=function(e,t){return e.findIndex((function(e){return On(t,e)}))},T=e[52009230];if(void 0===T)throw new Error("Missing or empty per frame functional sequence");if(o!==T.value.length)throw new Error("perFrameFuncGroupSequence meta and numberOfFrames are not equal.");const L=[];for(let e=0;ew;return t&&(t=e>10*w,t?(t=e>100*w,t||c.warn("Using larger+ real world epsilon in SEG pos pat adding")):c.warn("Using larger real world epsilon in SEG pos pat adding")),t},V=[];V.push(O[0]);let N=0;for(let e=1;eo)throw new Error("Test distance is increasing when adding intermediate pos pats");V.push(O[e])}const B=V.length,G=new nt(U[0],i,m,E),H=["0"];for(let e=1;e=0;--i){const a=Number.parseInt(o[i],10);g.push(h[r][a]);const s=e.getGeometry().getOrigins()[a],l=[s.getX(),s.getY(),s.getZ()],c={dimIndex:[t,o.length-i],imagePosPat:l,refSegmentNumber:t};if(void 0!==n){const e=n.getGeometry().worldToIndex(new E([s.getX(),s.getY(),s.getZ()]));c.derivationImages=[{sourceImages:[{referencedSOPInstanceUID:n.getImageUid(e),referencedSOPClassUID:n.getMeta().SOPClassUID}]}],p.push({ReferencedSOPInstanceUID:n.getImageUid(e),ReferencedSOPClassUID:n.getMeta().SOPClassUID})}S.push(c)}}r.NumberOfFrames=g.length.toString();const m=[];for(const e of S)m.push(wn(e));if(r.PerFrameFunctionalGroupsSequence={value:m},void 0!==n){const e=[];e.push({ReferencedInstanceSequence:{value:p},SeriesInstanceUID:n.getMeta().SeriesInstanceUID}),r.ReferencedSeriesSequence={value:e}}void 0!==i&&function(e,t){const n=Object.keys(t);for(const i of n)void 0!==e[i]&&c.trace("Overwritting tag: "+i),e[i]=t[i]}(r,i);const f=Bt(r),D=a.getDimSize(2),C=g.length*D/8,y=new ve("OB");return y.tag=new de("7FE0","0010"),y.vl=C,y.value=g,f["7FE00010"]=y,f}}function En(e){return(new Pt).create(e,e["7FE00010"].value[0],1)}function qn(e){return(new Fn).create(e,e["7FE00010"].value[0])}class Un{#pe;#w;#me;#t=new Xe(1,0);#fe=null;#De=!0;#Ce=!0;#ye="MONOCHROME2";#ve;#Ie=0;#Te;#Le={};#Pe=null;#we=null;#Oe=null;#Ae=new ke;constructor(e,t,n){this.#pe=e,this.#w=t,this.#me=n,this.#Te=this.#w.length/this.#pe.getSize().getTotalSize()}getImageUid(e){let t=this.#me[0];return 1!==this.#me.length&&void 0!==e&&(t=this.#me[this.getSecondaryOffset(e)]),t}getOriginForImageUid(e){let t;const n=this.#me.indexOf(e);return-1!==n&&(t=this.getGeometry().getOrigins()[n]),t}includesImageUid(e){return this.#me.includes(e)}containsImageUids(e){return function(e,t){if(null===e||null===t||void 0===e||void 0===t)return!1;if(0===e.length||0===t.length||t.length>e.length)return!1;for(const n of t)if(!e.includes(n))return!1;return!0}(this.#me,e)}getGeometry(){return this.#pe}getBuffer(){return this.#w}canQuantify(){return 1===this.getNumberOfComponents()}canWindowLevel(){return this.isMonochrome()}isMonochrome(){return It(this.getPhotometricInterpretation())}canScroll(e){const t=this.getGeometry().getSize();let n=1;return void 0!==this.#Le.numberOfFiles&&(n=this.#Le.numberOfFiles),t.canScroll(e)||1!==n}#be(){return this.#pe.getSize().getTotalSize(2)}getSecondaryOffset(e){return this.#pe.getSize().indexToOffset(e,2)}getRescaleSlopeAndIntercept(e){let t=this.#t;if(!this.isConstantRSI()){if(void 0===e)throw new Error("Cannot get non constant RSI with empty slice index.");const n=this.getSecondaryOffset(e);void 0!==this.#fe[n]?t=this.#fe[n]:c.warn("undefined non constant rsi at "+n)}return t}#xe(e){return this.#fe[e]}setRescaleSlopeAndIntercept(e,t){if(this.#De=this.#De&&e.isID(),this.#Ce){if(!this.#t.equals(e))if(void 0===t)this.#t=e;else{this.#Ce=!1,this.#fe=[];for(let e=0,t=this.#be();e=this.#Le.numberOfFiles?c.warn("Ignoring frame at index "+t+" (size: "+this.#Le.numberOfFiles+")"):(this.#w.set(e,i*t),this.appendFrame(t,new F(0,0,0)))}appendFrame(e,t){this.#pe.appendFrame(t,e),this.#Re({type:"appendframe"})}getDataRange(){return this.#Pe||(this.#Pe=this.calculateDataRange()),this.#Pe}getRescaledDataRange(){return this.#we||(this.#we=this.calculateRescaledDataRange()),this.#we}getHistogram(){if(!this.#Oe){const e=this.calculateHistogram();this.#Pe=e.dataRange,this.#we=e.rescaledDataRange,this.#Oe=e.histogram}return this.#Oe}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{this.#Ae.fireEvent(e)};setAtOffsets(e,t){let n,i;if("number"==typeof t){if(1!==this.#Te)throw new Error("Number of components is not 1 for setting single value.");n=[t]}else if(void 0!==t.r&&void 0!==t.g&&void 0!==t.b){if(3!==this.#Te)throw new Error("Number of components is not 3 for setting RGB value.");n=[t.r,t.g,t.b]}for(let t=0,r=e.length;t=3&&(r=i.getDimSize(3));for(let i=0;it&&(t=n),nn?t:n}}{let e=this.getRescaledValueAtOffset(0),t=e,n=0;const i=this.getGeometry().getSize();let r=i.getTotalSize();3===i.length()&&(r=i.getDimSize(3));for(let i=0;it&&(t=n),ni&&(i=r),ra&&(a=s),s{const e=this.getCurrentIndex();if(3===e.length()){const t=e.getValues();t.push(0),this.setCurrentIndex(new s(t))}}))}getImage(){return this.#Ee}setImage(e){this.#Ee=e}getOrientation(){return this.#_}setOrientation(e){this.#_=e}init(){this.setInitialIndex()}setInitialIndex(){const e=this.#Ee.getGeometry().getSize(),t=new Array(e.length());t.fill(0),t[0]=Math.floor(e.get(0)/2),t[1]=Math.floor(e.get(1)/2),t[2]=Math.floor(e.get(2)/2),this.setCurrentIndex(new s(t),!0)}getPlaybackMilliseconds(e){return e||(e=10),Math.round(1e3/e)}#Be=function(e,t){return 255};getAlphaFunction(){return this.#Be}setAlphaFunction(e){this.#Be=e,this.#Re({type:"alphafuncchange"})}#Ge(){if(this.#Me&&void 0!==this.#Ue[this.#Me]&&void 0!==this.#Ue[this.#Me].perslice&&!0===this.#Ue[this.#Me].perslice){this.getCurrentIndex()||this.setInitialIndex();const e=this.getCurrentIndex(),t=this.#Ee.getSecondaryOffset(e),n=this.#Ue[this.#Me].wl[t];this.setWindowLevel(n,this.#Me,!0)}if(void 0===this.#Qe&&this.setWindowLevelPresetById(0,!0),void 0===this.#Ce||this.#Ee.isConstantRSI()!==this.#Ce){let e,t;this.#Ce=this.#Ee.isConstantRSI(),this.#Ce?(e=this.#Ee.getRescaleSlopeAndIntercept(),t=!0):(e=new Xe(1,0),t=!1);const n=new l(e,this.#Ee.getMeta().BitsStored);this.#qe=new S(n,this.#Ee.getMeta().IsSigned,t)}const e=this.#qe.getVoiLut();let t;if(void 0!==e&&(t=e.getWindowLevel()),void 0===e||!this.#Qe.equals(t)){const e=new h(this.#Qe);this.#qe.setVoiLut(e)}return this.#qe}getWindowPresets(){return this.#Ue}getWindowPresetsNames(){return Object.keys(this.#Ue)}setWindowPresets(e){this.#Ue=e}addWindowPresets(e){const t=Object.keys(e);let n=null;for(let i=0;i{this.#Ae.fireEvent(e)};getWindowLevelMinMax(){const e=this.getImage().getRescaledDataRange(),t=e.min;let n=e.max-t;return n<1&&(c.warn("Zero or negative window width, defaulting to one."),n=1),new u(t+n/2,n)}setWindowLevelMinMax(){const e=this.getWindowLevelMinMax();this.setWindowLevel(e,"minmax")}generateImageData(e,t){void 0===t&&(this.getCurrentIndex()||this.setInitialIndex(),t=this.getCurrentIndex());const n=this.getImage(),i=!n.isConstantRSI(),r=We(n,t,i,this.getOrientation()),o=n.getPhotometricInterpretation();switch(o){case"MONOCHROME1":case"MONOCHROME2":!function(e,t,n,i,r){let o=0,a=0,s=t.next();for(;!s.done;)a=i.getValue(s.value),e.data[o]=r.red[a],e.data[o+1]=r.green[a],e.data[o+2]=r.blue[a],e.data[o+3]=n(s.value,s.index),o+=4,s=t.next()}(e,r,this.getAlphaFunction(),this.#Ge(),this.#ke());break;case"PALETTE COLOR":!function(e,t,n,i,r){const o=function(e){return e>>8};r&&c.info("Scaling 16bits data to 8bits.");let a=0,s=0,l=t.next();for(;!l.done;)s=l.value,r?(e.data[a]=o(i.red[s]),e.data[a+1]=o(i.green[s]),e.data[a+2]=o(i.blue[s])):(e.data[a]=i.red[s],e.data[a+1]=i.green[s],e.data[a+2]=i.blue[s]),e.data[a+3]=n(s,l.index),a+=4,l=t.next()}(e,r,this.getAlphaFunction(),n.getPaletteColourMap(),16===n.getMeta().BitsStored);break;case"RGB":!function(e,t,n){let i=0,r=t.next();for(;!r.done;)e.data[i]=r.value[0],e.data[i+1]=r.value[1],e.data[i+2]=r.value[2],e.data[i+3]=n(r.value,r.index),i+=4,r=t.next()}(e,r,this.getAlphaFunction());break;case"YBR_FULL":!function(e,t,n){let i=0,r=null,o=t.next();for(;!o.done;)a=o.value[0],s=o.value[1],r={r:a+1.402*((l=o.value[2])-128),g:a-.34414*(s-128)-.71414*(l-128),b:a+1.772*(s-128)},e.data[i]=r.r,e.data[i+1]=r.g,e.data[i+2]=r.b,e.data[i+3]=n(o.value,o.index),i+=4,o=t.next();var a,s,l}(e,r,this.getAlphaFunction());break;default:throw new Error("Unsupported photometric interpretation: "+o)}}getScrollIndex(){let e=null;const t=this.getOrientation();return e=void 0!==t?t.getThirdColMajorDirection():2,e}isAquisitionOrientation(){return x(this.#_)}}class Bn{#He;#X;#ze;#We;#Ye;constructor(e,t){this.#He=e,this.#X=e.getRealSpacing(),this.#ze=e.getOrientation(),this.#We=t,this.#Ye=function(e,t){let n=e.asOneAndZeros().multiply(t);return e.asOneAndZeros().getAbs().equals(ht().getAbs())&&(n=n.getAbs()),n}(this.#ze,t)}getViewOrientation(){return this.#We}getTargetOrientation(){return this.#Ye}getOffset3DFromPlaneOffset(e){const t=new P(e.x,e.y,0),n=this.getTargetDeOrientedVector3D(t);return new P(n.getX()*this.#X.get(0),n.getY()*this.#X.get(1),n.getZ()*this.#X.get(2))}getPlaneOffsetFromOffset3D(e){const t=new P(e.x/this.#X.get(0),e.y/this.#X.get(1),e.z/this.#X.get(2)),n=this.getTargetOrientedVector3D(t);return{x:n.getX(),y:n.getY()}}getTargetOrientedVector3D(e){let t=e;return void 0!==this.#Ye&&(t=this.#Ye.getInverse().multiplyVector3D(e)),t}getTargetDeOrientedVector3D(e){let t=e;return void 0!==this.#Ye&&(t=this.#Ye.multiplyVector3D(e)),t}getTargetDeOrientedPoint3D(e){let t=e;return void 0!==this.#Ye&&(t=this.#Ye.multiplyPoint3D(e)),t}getImageOrientedVector3D(e){let t=e;if(void 0!==this.#We){const n=rt([e.getX(),e.getY(),e.getZ()],this.#We);t=new P(n[0],n[1],n[2])}return t}getImageOrientedPoint3D(e){let t=e;if(void 0!==this.#We){const n=rt([e.getX(),e.getY(),e.getZ()],this.#We);t=new F(n[0],n[1],n[2])}return t}getImageDeOrientedVector3D(e){let t=e;if(void 0!==this.#We){const n=it([e.getX(),e.getY(),e.getZ()],this.#We);t=new P(n[0],n[1],n[2])}return t}getImageDeOrientedPoint3D(e){let t=e;if(void 0!==this.#We){const n=it([e.getX(),e.getY(),e.getZ()],this.#We);t=new F(n[0],n[1],n[2])}return t}getPositionFromPlanePoint(e,t){const n=new F(e.getX(),e.getY(),t),i=this.getImageOrientedPoint3D(n);return this.#He.pointToWorld(i)}getPlanePointFromPosition(e){const t=this.#He.worldToPoint(e);return this.getImageDeOrientedPoint3D(t)}getCosines(){return[(e=this.#Ye).get(0,0),e.get(1,0),e.get(2,0),e.get(0,1),e.get(1,1),e.get(2,1)];var e}getPlanePoints(e){const t=this.getPlanePointFromPosition(e),n=this.getPositionFromPlanePoint(new R(0,0),t.getZ()),i=this.getCosines();return[n,new F(i[0],i[1],i[2]),new F(i[3],i[4],i[5])]}worldToIndex(e){return this.#He.worldToIndex(e)}isAquisitionOrientation(){return x(this.#We)}getTargetOrientedPositiveXYZ(e){const t=it([e.x,e.y,e.z],this.#Ye);return{x:t[0],y:t[1],z:t[2]}}getScrollIndex(){let e=null;return e=void 0!==this.#We?this.#We.getThirdColMajorDirection():2,e}getNativeScrollIndex(){let e=null;return e=void 0!==this.#ze?this.#ze.getThirdColMajorDirection():2,e}}class Gn{#x;#Xe;#je;#Ze=!1;constructor(e){if(void 0===e.getImage())throw new Error("View does not have an image, cannot setup controller");this.#x=e,this.#Xe=new Bn(e.getImage().getGeometry(),e.getOrientation()),"SEG"===e.getImage().getMeta().Modality&&(this.#Ze=!0)}getPlaneHelper(){return this.#Xe}isMask(){return this.#Ze}initialise(){this.setWindowLevelPresetById(0),this.setCurrentPosition(this.getPositionFromPlanePoint(new R(0,0)))}getModality(){return this.#x.getImage().getMeta().Modality}getWindowLevelPresetsNames(){return this.#x.getWindowPresetsNames()}addWindowLevelPresets(e){return this.#x.addWindowPresets(e)}setWindowLevelPreset(e){this.#x.setWindowLevelPreset(e)}setWindowLevelPresetById(e){this.#x.setWindowLevelPresetById(e)}isPlaying(){return void 0!==this.#je}getCurrentPosition(){return this.#x.getCurrentPosition()}getCurrentIndex(){return this.#x.getCurrentIndex()}getCurrentImageUid(){return this.#x.getCurrentImageUid()}getOriginForImageUid(e){return this.#x.getOriginForImageUid(e)}includesImageUid(e){return this.#x.includesImageUid(e)}getCurrentOrientedIndex(){let e=this.#x.getCurrentIndex();if(void 0!==this.#x.getOrientation()){const t=this.#Xe.getImageDeOrientedVector3D(new P(e.get(0),e.get(1),e.get(2)));e=new s([t.getX(),t.getY(),t.getZ()])}return e}getScrollIndex(){return this.#x.getScrollIndex()}getCurrentScrollIndexValue(){return this.#x.getCurrentIndex().get(this.#x.getScrollIndex())}getOrigin(e){return this.#x.getOrigin(e)}isAquisitionOrientation(){return this.#x.isAquisitionOrientation()}getPlanePoints(e){return this.#Xe.getPlanePoints(e)}getCurrentScrollPosition(){const e=this.#x.getScrollIndex();return this.#x.getCurrentPosition().get(e)}generateImageData(e,t){this.#x.generateImageData(e,t)}setImage(e){this.#x.setImage(e)}get2DSpacing(){return this.#x.getImage().getGeometry().getSpacing(this.#x.getOrientation()).get2D()}getRescaledImageValue(e){const t=this.#x.getImage();if(!t.canQuantify())return;const n=t.getGeometry(),i=n.worldToIndex(e);let r;return n.isIndexInBounds(i)&&(r=t.getRescaledValueAtIndex(i)),r}getPixelUnit(){return this.#x.getImage().getMeta().pixelUnit}#_e(e,t,n,i){const r=ze(We(e,t,n,i)),o=e.getGeometry().getSize(i).getValues();o[2]=1;const a=new je(o),s=e.getGeometry().getSpacing(i).getValues();s[2]=1;const l=new tt(s),c=new F(0,0,0),u=new nt(c,a,l);return new Un(u,r)}getImageRegionValues(e,t){let n=this.#x.getImage();const i=this.#x.getOrientation();let r=this.getCurrentIndex(),o=!0;x(i)||(n=this.#_e(n,r,o,i),r=new s([0,0,0]),o=!1);const a=function(e,t,n,i,r){if(1!==e.getNumberOfComponents())throw new Error("Unsupported number of components for region iterator: "+e.getNumberOfComponents());void 0===n&&(n=!1);let o=null;o=n?function(t){return e.getRescaledValueAtOffset(t)}:function(t){return e.getValueAtOffset(t)};const a=e.getGeometry().getSize();void 0===i&&(i=new R(0,0)),void 0===r&&(r=new R(a.get(0)-1,a.get(1)));const s=a.indexToOffset(t.getWithNew2D(i.getX(),i.getY())),l=a.indexToOffset(t.getWithNew2D(r.getX(),r.getY()-1)),c=Math.max(1,r.getX()-i.getX());return function(e,t,n,i,r,o){let a=t,s=0;return{next:function(){if(a{let e=!1;if(e=i?this.incrementScrollIndex():this.incrementIndex(3),!e){const e=this.getCurrentIndex().getValues(),t=this.#x.getOrientation();i?e[t.getThirdColMajorDirection()]=0:e[3]=0;const n=new s(e),r=this.#x.getImage().getGeometry();this.setCurrentPosition(r.indexToWorld(n))}}),n)}else this.stop()}stop(){void 0!==this.#je&&(clearInterval(this.#je),this.#je=void 0)}getWindowLevel(){return this.#x.getWindowLevel()}getCurrentWindowPresetName(){return this.#x.getCurrentWindowPresetName()}setWindowLevel(e){this.#x.setWindowLevel(e)}getColourMap(){return this.#x.getColourMap()}setColourMap(e){this.#x.setColourMap(e)}setViewAlphaFunction(e){this.#x.setAlphaFunction(e)}bindImageAndLayer(e){const t=this.#x.getImage();t.addEventListener("imagecontentchange",e.onimagecontentchange),t.addEventListener("imagegeometrychange",e.onimagegeometrychange)}unbindImageAndLayer(e){const t=this.#x.getImage();t.removeEventListener("imagecontentchange",e.onimagecontentchange),t.removeEventListener("imagegeometrychange",e.onimagegeometrychange)}}class kn{#tt=0;getSum(){return this.#tt}add(e){this.#tt+=function(e){if(void 0===e.wheelDeltaY)return-e.deltaY;{const t=45;return e.wheelDeltaY>t?1:e.wheelDeltaY<-t?-1:-e.deltaY/60}}(e)}clear(){this.#tt=0}isTick(){return Math.abs(this.#tt)>=1}}class Hn{#nt;#it=new kn;constructor(e){this.#nt=e}wheel(e){this.#it.add(e);const t=this.#it.getSum()>=0;if(!this.#it.isTick())return;this.#it.clear(),e.preventDefault();const n=Zi(e),i=this.#nt.getLayerGroupByDivId(n.groupDivId),r=i.getActiveViewLayer().getViewController();let o;i.canScroll()?o=t?r.getIncrementScrollPosition():r.getDecrementScrollPosition():i.moreThanOne(3)&&(o=t?r.getIncrementPosition(3):r.getDecrementPosition(3)),void 0!==o&&i.isPositionInBounds(o)&&r.setCurrentPosition(o)}}class zn{#rt;#ot;constructor(e,t){this.#rt=e,this.#ot=t}getBegin(){return this.#rt}getEnd(){return this.#ot}equals(e){return null!==e&&this.getBegin().equals(e.getBegin())&&this.getEnd().equals(e.getEnd())}getDeltaX(){return this.getEnd().getX()-this.getBegin().getX()}getDeltaY(){return this.getEnd().getY()-this.getBegin().getY()}getLength(){return Math.sqrt(this.getDeltaX()*this.getDeltaX()+this.getDeltaY()*this.getDeltaY())}getWorldLength(e){let t=null;if(null!==e){const n=this.getDeltaX()*e.x,i=this.getDeltaY()*e.y;t=Math.sqrt(n*n+i*i)}return t}getMidpoint(){return new R((this.getBegin().getX()+this.getEnd().getX())/2,(this.getBegin().getY()+this.getEnd().getY())/2)}getCentroid(){return this.getMidpoint()}getSlope(){return this.getDeltaY()/this.getDeltaX()}getIntercept(){return(this.getEnd().getX()*this.getBegin().getY()-this.getBegin().getX()*this.getEnd().getY())/this.getDeltaX()}getInclination(){return 180-180*Math.atan2(this.getDeltaY(),this.getDeltaX())/Math.PI}quantify(e){const t={},n=e.get2DSpacing(),i=this.getWorldLength(n);return null!==i&&(t.length={value:i,unit:"unit.mm"}),t}}function Wn(e,t){const n=e.getDeltaX(),i=e.getDeltaY(),r=t.getDeltaX(),o=t.getDeltaY(),a=n*r+i*o,s=n*o-i*r;return 360-(180-180*Math.atan2(s,a)/Math.PI)}function Yn(e,t){const n=e.getDeltaX(),i=e.getDeltaY();return n*t.getDeltaX()+i*t.getDeltaY()==0}function Xn(e,t,n,i){void 0===i&&(i={x:1,y:1});const r=-i.x*i.x/(i.y*i.y*e.getSlope());return Zn(r,t.getY()-r*t.getX(),t,n,i)}function jn(e,t,n,i){const r=Zn(e.getSlope(),e.getIntercept(),e.getBegin(),t,i);let o;return o=function(e,t){const n=Math.min(t.getBegin().getX(),t.getEnd().getX()),i=Math.max(t.getBegin().getX(),t.getEnd().getX()),r=Math.min(t.getBegin().getY(),t.getEnd().getY()),o=Math.max(t.getBegin().getY(),t.getEnd().getY());return e.getX()>=n&&e.getX()<=i&&e.getY()>=r&&e.getY()<=o}(r.getBegin(),e)?r.getBegin():r.getEnd(),Xn(e,o,n,i)}function Zn(e,t,n,i,r){void 0===r&&(r={x:1,y:1});let o=0,a=0,s=0,l=0;if(O(e,0,w))o=n.getX()-i/(2*r.x),a=n.getY(),s=n.getX()+i/(2*r.x),l=n.getY();else if(Math.abs(e)>1e6)o=n.getX(),a=n.getY()-i/(2*r.y),s=n.getX(),l=n.getY()+i/(2*r.y);else{const c=r.x*r.x,u=r.y*r.y,d=i/(2*Math.sqrt(c+u*e*e));o=n.getX()-d,a=e*o+t,s=n.getX()+d,l=e*s+t}return new zn(new R(o,a),new R(s,l))}var _n=o(944),Kn=o.n(_n);class Jn{#at;#Le={};#Ae=new ke;#st;#lt;constructor(e){this.#at=void 0!==e?e:[],this.#st=!0}getList(){return this.#at}getLength(){return this.#at.length}isEditable(){return this.#st}setEditable(e){this.#st=e,this.#Re({type:"annotationgroupeditablechange",data:e})}getColour(){return this.#lt}setColour(e){this.#lt=e}add(e){this.#at.push(e),this.#Re({type:"annotationadd",data:e})}update(e,t){const n=this.#at.findIndex((t=>t.id===e.id));-1!==n?(this.#at[n]=e,this.#Re({type:"annotationupdate",data:e,keys:t})):c.warn("Cannot find annotation to update")}remove(e){const t=this.#at.findIndex((t=>t.id===e));if(-1!==t){const e=this.#at.splice(t,1)[0];this.#Re({type:"annotationremove",data:e})}else c.warn("Cannot find annotation to remove")}setViewController(e){for(const t of this.#at)t.setViewController(e),t.updateQuantification()}find(e){return this.#at.find((t=>t.id===e))}getMeta(){return this.#Le}hasMeta(e){return void 0!==this.#Le[e]}getMetaValue(e){return this.#Le[e]}setMetaValue(e,t){this.#Le[e]=t}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{this.#Ae.fireEvent(e)}}class $n{#ct;getAnnotation(e){return this.#ct.find(e)}getAnnotationGroup(){return this.#ct}isAnnotationGroupEditable(){return this.#ct.isEditable()}setAnnotationGroupEditable(e){this.#ct.setEditable(e)}addAnnotation(e){this.#ct.add(e)}updateAnnotation(e,t){this.#ct.update(e,t)}removeAnnotation(e){this.#ct.remove(e)}removeAnnotationWithCommand(e,t){const n=this.getAnnotation(e);if(void 0===n)return void c.warn("Cannot create remove command for undefined annotation: "+e);const i=new vi(n,this);t(i),i.execute()}updateAnnotationWithCommand(e,t,n,i){const r=this.getAnnotation(e);if(void 0===r)return void c.warn("Cannot create update command for undefined annotation: "+e);const o=new Ii(r,t,n,this);i(o),o.execute()}removeAllAnnotationsWithCommand(e){for(const t of this.#ct.getList())this.removeAnnotationWithCommand(t.id,e)}constructor(e){this.#ct=void 0!==e?e:new Jn}hasAnnotationMeta(e){return this.#ct.hasMeta(e)}setAnnotationMeta(e,t){this.#ct.setMetaValue(e,t)}}class ei{#ut=10;#dt="Verdana";#ht="#fff";#St="#ffff80";#gt={x:1,y:1};#pt={x:1,y:1};#mt=2;#ft={x:.25,y:.25};#Dt=.2;#Ct=3;getFontFamily(){return this.#dt}getFontSize(){return this.#ut}getStrokeWidth(){return this.#mt}getTextColour(){return this.#ht}getLineColour(){return this.#St}setLineColour(e){this.#St=e}setBaseScale(e){this.#gt=e}setZoomScale(e){this.#pt=e}getBaseScale(){return this.#gt}getZoomScale(){return this.#pt}scale(e){return e/this.#gt.x}applyZoomScale(e){return{x:e/this.#pt.x,y:e/this.#pt.y}}applyZoomRatio(e){return e*this.#pt.x/this.#pt.y}getShadowOffset(){return this.#ft}getTagOpacity(){return this.#Dt}getTextPadding(){return this.#Ct}getFontStr(){return"normal "+this.getFontSize()+"px sans-serif"}getLineHeight(){return this.getFontSize()+this.getFontSize()/5}getScaledFontSize(){return this.scale(this.getFontSize())}getScaledStrokeWidth(){return this.scale(this.getStrokeWidth())}getShadowLineColour(){return e=this.getLineColour(),n=e,.001172549*(t={r:parseInt(n.substring(1,3),16),g:parseInt(n.substring(3,5),16),b:parseInt(n.substring(5,7),16)}).r+.002301961*t.g+447059e-9*t.b<.5?"#fff":"#000";var e,t,n}}function ti(e){return"label"===e.name()}function ni(e){return"shape"===e.name()}function ii(e){return"position-group"===e.name()}function ri(e){const t=e.getChildren(ni)[0];if(t instanceof Kn().Line)return t}function oi(e,t){const n=e.getChildren((function(e){return e.id()==="anchor"+t}))[0];if(n instanceof Kn().Ellipse)return n}function ai(e){return function(t){return t.id()===e}}function si(e,t,n,i){const r=i.applyZoomScale(6),o={x:Math.abs(r.x),y:Math.abs(r.y)};return new(Kn().Ellipse)({x:e,y:t,stroke:"#999",fill:"rgba(100,100,100,0.7",strokeWidth:i.getStrokeWidth(),strokeScaleEnabled:!1,radius:o,radiusX:o.x,radiusY:o.y,name:"anchor",id:n.toString(),dragOnTop:!1,draggable:!0,visible:!1})}function li(e){return parseInt(e.substring(6),10)}class ci{#rt;#ot;constructor(e,t){this.#rt=new R(Math.min(e.getX(),t.getX()),Math.min(e.getY(),t.getY())),this.#ot=new R(Math.max(e.getX(),t.getX()),Math.max(e.getY(),t.getY()))}getBegin(){return this.#rt}getEnd(){return this.#ot}equals(e){return null!==e&&this.getBegin().equals(e.getBegin())&&this.getEnd().equals(e.getEnd())}getSurface(){const e=this.getBegin(),t=this.getEnd();return Math.abs(t.getX()-e.getX())*Math.abs(t.getY()-e.getY())}getWorldSurface(e){return function(e,t,n){let i=null;return null!==t&&null!==n&&(i=e*t*n),i}(this.getSurface(),e.x,e.y)}getRealWidth(){return this.getEnd().getX()-this.getBegin().getX()}getRealHeight(){return this.getEnd().getY()-this.getBegin().getY()}getWidth(){return Math.abs(this.getRealWidth())}getHeight(){return Math.abs(this.getRealHeight())}getRound(){return{min:new R(Math.round(this.getBegin().getX()),Math.round(this.getBegin().getY())),max:new R(Math.round(this.getEnd().getX()),Math.round(this.getEnd().getY()))}}getCentroid(){return new R(this.getBegin().getX()+this.getWidth()/2,this.getBegin().getY()+this.getHeight()/2)}quantify(e,t){const n={},i=e.get2DSpacing();n.width={value:this.getWidth()*i.x,unit:"unit.mm"},n.height={value:this.getHeight()*i.y,unit:"unit.mm"};const r=this.getWorldSurface(i);if(null!==r&&(n.surface={value:r/100,unit:"unit.cm2"}),e.canQuantifyImage()){const i=this.getRound(),r=e.getImageRegionValues(i.min,i.max),o=e.getPixelUnit(),a=_e(r,t);n.min={value:a.min,unit:o},n.max={value:a.max,unit:o},n.mean={value:a.mean,unit:o},n.stdDev={value:a.stdDev,unit:o},void 0!==a.median&&(n.median={value:a.median,unit:o}),void 0!==a.p25&&(n.p25={value:a.p25,unit:o}),void 0!==a.p75&&(n.p75={value:a.p75,unit:o})}return n}}function ui(e,t,n){const i=e.getValues(),r=i.slice(),o=[],a=t[0],l=Math.floor(a/2),c=t[1],u=Math.floor(c/2),d=n[0],h=n[1];for(let e=0;e3)throw new Error("Too many points for a protractor");this.#yt=e.slice(0,3)}getPoint(e){return this.#yt[e]}getLength(){return this.#yt.length}getCentroid(){return this.#yt[1]}quantify(e,t){const n={};if(3===this.#yt.length){let e=Wn(new zn(this.#yt[0],this.#yt[1]),new zn(this.#yt[1],this.#yt[2]));e>180&&(e=360-e),n.angle={value:e,unit:"unit.degree"}}return n}}class Si{#vt;#It;#Tt;constructor(e,t,n){this.#vt=e,this.#It=t,this.#Tt=n}getCenter(){return this.#vt}getCentroid(){return this.#vt}getA(){return this.#It}getB(){return this.#Tt}equals(e){return null!==e&&this.getCenter().equals(e.getCenter())&&this.getA()===e.getA()&&this.getB()===e.getB()}getSurface(){return Math.PI*this.getA()*this.getB()}getWorldSurface(e){return function(e,t,n){let i=null;return null!==t&&null!==n&&(i=e*t*n),i}(this.getSurface(),e.x,e.y)}getRound(){const e=this.getCenter().getX(),t=this.getCenter().getY(),n=this.getA(),i=this.getB(),r=n/i,o=Math.pow(i,2),a=t+i,s=[];for(let n=t-i;n{this.#Ut(e)}:e=>{this.#Mt(e)},this.#qt(t)}#Rt(){this.#qt((function(e){e.remove()}))}#Ft(){if(!this.#Ot||!this.#Ot.getLayer())return;const e=this.#Ot.getParent(),t=this.#wt.getAnchors(this.#Ot,this.#nt.getStyle());for(let n=0;n{e.cancelBubble=!0,t={mathShape:this.#bt.mathShape,referencePoints:this.#bt.referencePoints}})),e.on("dragmove.edit",(e=>{const t=e.target;t instanceof Kn().Shape&&(function(e,t){const n=t.getParent();!function(e,t,n){let i=!1;e.x()n.getX()&&(e.x(n.getX()),i=!0),e.y()n.getY()&&(e.y(n.getY()),i=!0)}(t,new R(-n.x(),-n.y()),new R(e.x-n.x(),e.y-n.y()))}(this.#At.getBaseSize(),t),void 0!==this.#wt.constrainAnchorMove&&this.#wt.constrainAnchorMove(t),this.#wt.updateAnnotationOnAnchorMove(this.#bt,t),this.#wt.updateShapeGroupOnAnchorMove(this.#bt,t,this.#nt.getStyle()),t.getLayer()?t.getLayer().draw():c.warn("No layer to draw the anchor!"),e.cancelBubble=!0)})),e.on("dragend.edit",(e=>{const n={mathShape:this.#bt.mathShape,referencePoints:this.#bt.referencePoints},i=new Ii(this.#bt,t,n,this.#At.getDrawController());this.#nt.addToUndoStack(i),this.#Pt({type:"annotationupdate",data:this.#bt,dataid:this.#At.getDataId(),keys:Object.keys(n)}),t={mathShape:n.mathShape,referencePoints:n.referencePoints},e.cancelBubble=!0})),e.on("mousedown touchstart",(e=>{e.target.moveToTop()})),e.on("mouseover.edit",(e=>{const t=e.target;t instanceof Kn().Shape&&(t.stroke("#ddd"),t.getLayer()?t.getLayer().draw():c.warn("No layer to draw the anchor!"))})),e.on("mouseout.edit",(e=>{const t=e.target;t instanceof Kn().Shape&&(t.stroke("#999"),t.getLayer()?t.getLayer().draw():c.warn("No layer to draw the anchor!"))}))}#Mt(e){e.off("dragstart.edit"),e.off("dragmove.edit"),e.off("dragend.edit"),e.off("mousedown touchstart"),e.off("mouseover.edit"),e.off("mouseout.edit")}}class fi{#Qt;constructor(){this.createTrashIcon()}createTrashIcon(){this.#Qt=new(Kn().Group);const e=new(Kn().Line)({points:[-10,-10,10,10],stroke:"red"}),t=new(Kn().Line)({points:[10,-10,-10,10],stroke:"red"});this.#Qt.width(20),this.#Qt.height(20),this.#Qt.add(e),this.#Qt.add(t)}activate(e){const t=e.getKonvaStage(),n=t.scale(),i=e.getKonvaLayer(),r={x:1/n.x,y:1/n.y};this.#Qt.x(t.offset().x+t.width()/(2*n.x)),this.#Qt.y(t.offset().y+t.height()/(15*n.y)),this.#Qt.scale(r),i.add(this.#Qt),i.draw()}changeChildrenColourOnTrashHover(e,t,n){if(this.isOverTrash(e))return this.changeGroupChildrenColour(this.#Qt,"orange"),void this.changeGroupChildrenColour(t,"red");this.changeGroupChildrenColour(this.#Qt,"red"),this.changeGroupChildrenColour(t,n)}changeGroupChildrenColour(e,t){e.getChildren().forEach((function(e){e instanceof Kn().Shape&&void 0!==e.stroke&&e.stroke(t)}))}remove(){this.#Qt.remove()}isOverTrash(e){const t=this.#Qt.width()*Math.abs(this.#Qt.scaleX())/2,n=this.#Qt.height()*Math.abs(this.#Qt.scaleY())/2;return Math.abs(e.x-this.#Qt.x()){this.#Gt=e,this.#Ht()})),e.on("mouseout",(()=>{this.onMouseOutShapeGroup(),this.#Gt=void 0}))}#Wt(e){e.off("mouseover"),e.off("mouseout")}addShapeGroupListeners(e,t,n){this.#zt(e),this.#Yt(e,t,n),this.#Xt(e,t,n),e.on("dblclick",(()=>{const e=t.textExpr;ki.openRoiDialog(t,(t=>{const i=t.textExpr,r=new Ii(t,{textExpr:e},{textExpr:i},n.getDrawController());this.#nt.addToUndoStack(r),r.execute()}))}))}#Yt(e,t,n){const i=n.getKonvaLayer(),r=e.getChildren(ni)[0];if(!(r instanceof Kn().Shape))return;let o,a,s,l;r.draggable(!0),r.on("dragstart.draw",(e=>{l=r.stroke(),o={x:r.x(),y:r.y()},a={x:e.target.x(),y:e.target.y()},s={mathShape:t.mathShape,referencePoints:t.referencePoints},this.#Qt.activate(n),this.#Vt.setAnchorsActive(!1),i.draw()})),r.on("dragmove.draw",(o=>{const s=function(e,t){return{min:new R(0,0),max:new R(e.x-Math.abs(t.width()),e.y-Math.abs(t.height()))}}(n.getBaseSize(),r);if(s&&!function(e,t,n){const i=e.getClientRect({relativeTo:e.getParent()});return i.x>t.getX()&&i.xt.getY()&&i.y{if(this.#Qt.remove(),void 0===a||void 0===a.evt)return;const c=r.x(),u=r.y(),d=Wi(a.evt),h={x:d.getX(),y:d.getY()},S=this.#kt(h,n);if(this.#Qt.isOverTrash(S)){e.x(o.x),e.y(o.y),this.#Vt.disable(),this.#Vt.reset(),this.#Qt.changeGroupChildrenColour(e,l),t.mathShape=s.mathShape,t.referencePoints=s.referencePoints;const i=new vi(t,n.getDrawController());this.#nt.addToUndoStack(i),i.execute(),this.onMouseOutShapeGroup()}else{const e={x:c-o.x,y:u-o.y};if(0!==e.x||0!==e.y){const e={mathShape:t.mathShape,referencePoints:t.referencePoints},i=new Ii(t,s,e,n.getDrawController());this.#nt.addToUndoStack(i),this.#Pt({type:"annotationupdate",data:t,dataid:n.getDataId(),keys:Object.keys(e)}),s={mathShape:e.mathShape,referencePoints:e.referencePoints}}this.#Vt.setAnchorsActive(!0),this.#Vt.resetAnchors()}i.draw(),o={x:r.x(),y:r.y()}}))}#Xt(e,t,n){const i=e.getChildren(ti)[0];if(!(i instanceof Kn().Label))return;let r,o;i.draggable(!0),i.on("dragstart.draw",(()=>{r={x:i.x(),y:i.y()},o=t.labelPosition})),i.on("dragmove.draw",(()=>{t.getFactory().updateConnector(e)})),i.on("dragend.draw",(()=>{const e=i.x()-r.x,a=i.y()-r.y;if(0!==e||0!==a){const e=new R(i.x(),i.y());t.labelPosition=e;const r=new Ii(t,{labelPosition:o},{labelPosition:e},n.getDrawController());this.#nt.addToUndoStack(r),this.#Pt({type:"annotationupdate",data:t,dataid:n.getDataId(),keys:["labelPosition"]}),o=e}r={x:i.x(),y:i.y()}}))}removeShapeListeners(e){this.#Wt(e),e.off("dblclick");const t=e.getChildren(ni)[0];t instanceof Kn().Shape&&(t.draggable(!1),t.off("dragstart.draw"),t.off("dragmove.draw"),t.off("dragend.draw"));const n=e.getChildren(ti)[0];n instanceof Kn().Label&&(n.draggable(!1),n.off("dragstart.draw"),n.off("dragend.draw"))}}class Ci{#jt;#Zt=null;#_t;#Kt;#Jt={x:1,y:1};#$t={x:1,y:1,z:1};#en={x:0,y:0};#tn={x:0,y:0};#nn={x:0,y:0};#in={x:0,y:0};#rn;#Xe;#on;#an;#sn;#ln;#cn=!0;constructor(e){this.#jt=e,this.#jt.className+=" drawLayer"}setShapeHandler(e){this.#ln=e}getDataId(){return this.#on}getReferenceLayerId(){return this.#an}#Ae=new ke;getKonvaStage(){return this.#Zt}getKonvaLayer(){return this.#Zt.getLayers()[0]}getDrawController(){return this.#rn}setPlaneHelper(e){this.#Xe=e}getId(){return this.#jt.id}removeFromDOM(){this.#jt.remove()}getBaseSize(){return this.#_t}getOpacity(){return this.#Zt.opacity()}setOpacity(e){this.#Zt.opacity(Math.min(Math.max(e,0),1))}addFlipOffsetX(){const e=this.#Zt.scale(),t=this.#Zt.size();this.#in.x+=t.width/e.x;const n=this.#Zt.offset();n.x+=this.#in.x,this.#Zt.offset(n)}addFlipOffsetY(){const e=this.#Zt.scale(),t=this.#Zt.size();this.#in.y+=t.height/e.y;const n=this.#Zt.offset();n.y+=this.#in.y,this.#Zt.offset(n)}flipScaleX(){this.#$t.x*=-1}flipScaleY(){this.#$t.y*=-1}flipScaleZ(){this.#$t.z*=-1}setScale(e,t){const n=this.#Xe.getTargetOrientedPositiveXYZ({x:e.x*this.#$t.x,y:e.y*this.#$t.y,z:e.z*this.#$t.z}),i={x:this.#Jt.x*n.x,y:this.#Jt.y*n.y},r=this.#Zt.offset();if(1===Math.abs(e.x)&&1===Math.abs(e.y)&&1===Math.abs(e.z)){const e={x:r.x-this.#nn.x,y:r.y-this.#nn.y};this.#nn={x:0,y:0},this.#Zt.offset(e)}else if(void 0!==t){let e=this.#Xe.getPlaneOffsetFromOffset3D({x:t.getX(),y:t.getY(),z:t.getZ()});e={x:e.x+this.#en.x,y:e.y+this.#en.y};const n=_i(r,this.#Zt.scale(),i,e),o={x:this.#nn.x+n.x-r.x,y:this.#nn.y+n.y-r.y};this.#nn=o,this.#Zt.offset(n)}this.#Zt.scale(i),this.#un(i)}initScale(e,t){const n=this.#Xe.getTargetOrientedPositiveXYZ({x:e.x*this.#$t.x,y:e.y*this.#$t.y,z:e.z*this.#$t.z}),i={x:this.#Jt.x*n.x,y:this.#Jt.y*n.y};this.#Zt.scale(i),this.#nn={x:t.x/this.#Jt.x,y:t.y/this.#Jt.y};const r=this.#Zt.offset();this.#Zt.offset({x:r.x+this.#nn.x,y:r.y+this.#nn.y})}setOffset(e){const t=this.#Xe.getPlaneOffsetFromOffset3D(e);this.#Zt.offset({x:t.x+this.#tn.x+this.#en.x+this.#nn.x+this.#in.x,y:t.y+this.#tn.y+this.#en.y+this.#nn.y+this.#in.y})}setBaseOffset(e,t){const n=this.#Xe.getNativeScrollIndex(),i=this.#Xe.getPlaneOffsetFromOffset3D({x:0===n?e.getX():t.getX(),y:1===n?e.getY():t.getY(),z:2===n?e.getZ():t.getZ()}),r=this.#en.x!==i.x||this.#en.y!==i.y;if(r){const e=this.#Zt.offset();this.#Zt.offset({x:e.x-this.#en.x+i.x,y:e.y-this.#en.y+i.y}),this.#en=i}return r}display(e){this.#jt.style.display=e?"":"none"}isVisible(){return""===this.#jt.style.display}draw(){this.#Zt.draw()}initialise(e,t,n){this.#_t=e,this.#Kt=t,this.#an=n,this.#Zt=new(Kn().Stage)({container:this.#jt,width:this.#_t.x,height:this.#_t.y,listening:!1}),this.#Zt.getContent().setAttribute("style","");const i=new(Kn().Layer)({listening:!1,visible:!0});this.#Zt.add(i)}setAnnotationGroup(e,t,n){if(this.#on=t,e.addEventListener("annotationadd",(e=>{this.#dn(e.data,!0),this.getKonvaLayer().draw()})),e.addEventListener("annotationupdate",(e=>{this.#hn(e.data),this.getKonvaLayer().draw()})),e.addEventListener("annotationremove",(e=>{this.#Sn(e.data),this.getKonvaLayer().draw()})),e.addEventListener("annotationgroupeditablechange",(e=>{this.activateCurrentPositionShapes(e.data)})),this.#rn=new $n(e),0!==e.getLength())for(const t of e.getList())this.#dn(t,!1),n(new yi(t,this.getDrawController()))}activateCurrentPositionShapes(e){const t=this.getKonvaLayer();if(this.#Zt.listening(!1),void 0!==this.#ln){this.#ln.disableAndResetEditor();const e=t.getChildren();for(const t of e)t instanceof Kn().Group&&t.getChildren().forEach((e=>{e instanceof Kn().Group&&this.#ln.removeShapeListeners(e)}))}const n=this.getDrawController();if(e&&n.getAnnotationGroup().isEditable()){const e=this.#gn().getChildren();0!==e.length&&(this.#Zt.listening(!0),t.listening(!0)),void 0!==this.#ln&&e.forEach((e=>{if(e instanceof Kn().Group){const t=n.getAnnotation(e.id());this.#ln.addShapeGroupListeners(e,t,this)}}))}t.draw()}#pn(e){let t;return t=void 0!==e.planePoints?e.planePoints:[e.planeOrigin],this.#mn(t)}#mn(e){let t="";for(const n of e)0!==t.length&&(t+="-"),t+=G([B(n.getX(),2),B(n.getY(),2),B(n.getZ(),2)]);return t}#fn(e){let t;const n=this.#pn(e),i=this.getKonvaLayer().getChildren(ai(n));if(0!==i.length){const n=i[0];if(!(n instanceof Kn().Group))return;const r=n.getChildren(ai(e.id));0!==r.length&&r[0]instanceof Kn().Group&&(t=r[0])}return t}#dn(e,t){if(!e.isCompatibleView(this.#Xe))return;const n=this.#pn(e);let i=this.getKonvaLayer().getChildren(ai(n))[0];if(void 0===i&&(i=new(Kn().Group)({id:n,name:"position-group",visible:t}),this.getKonvaLayer().add(i)),!(i instanceof Kn().Group))return;const r=new ei,o=this.getKonvaStage();r.setZoomScale(o.scale());const a=e.getFactory().createShapeGroup(e,r);i.add(a),t&&void 0!==this.#ln&&this.#ln.addShapeGroupListeners(a,e,this),this.setLabelVisibility(a)}#Sn(e){const t=this.#fn(e);return t instanceof Kn().Group?(t.remove(),!0):(c.debug("No shape group to remove"),!1)}#hn(e){e.updateQuantification(),this.#Sn(e)&&this.#dn(e,!0)}fitToContainer(e,t,n){this.#Zt.width(e.x),this.#Zt.height(e.y);const i={x:t*this.#Kt.x,y:t*this.#Kt.y},r={x:this.#Zt.scale().x*i.x/this.#Jt.x,y:this.#Zt.scale().y*i.y/this.#Jt.y};this.#Zt.scale().x===r.x&&this.#Zt.scale().y===r.y||(this.#Jt=i,this.#Zt.scale(r));const o={x:n.x/i.x,y:n.y/i.y},a={x:e.x/i.x,y:e.y/i.y},s={x:0!==this.#in.x?a.x:0,y:0!==this.#in.y?a.y:0};this.#tn.x===o.x&&this.#tn.y===o.y&&this.#in.x===s.x&&this.#in.y===s.y||(this.#Zt.offset({x:this.#Zt.offset().x+o.x-this.#tn.x+s.x-this.#in.x,y:this.#Zt.offset().y+o.y-this.#tn.y+s.y-this.#in.y}),this.#in=s,this.#tn=o)}isAnnotationVisible(e){const t=this.#Dn(e);return void 0!==t&&t.isVisible()}setAnnotationVisibility(e,t){const n=this.#Dn(e);return void 0!==n&&(void 0===t&&(t=!n.isVisible()),n.visible(t),this.draw(),!0)}setLabelsVisibility(e){this.#cn=e;const t=this.getKonvaLayer().getChildren();for(const n of t)if(n instanceof Kn().Group){const t=n.getChildren();for(const n of t)n instanceof Kn().Group&&this.#Cn(n,e)}}#Cn(e,t){const n=e.getChildren(ti)[0];if(n instanceof Kn().Label&&(void 0===t&&(t=!n.isVisible()),void 0!==n.getText()&&0!==n.getText().text().length)){n.visible(t);const i=e.getChildren((e=>"Line"===e.className&&"connector"===e.name()))[0];i&&i.visible(t)}}setLabelVisibility(e){this.#Cn(e,this.#cn)}deleteDraw(e,t){}deleteDraws(e){}getNumberOfDraws(){const e=this.getKonvaLayer().getChildren();let t=0;for(const n of e)n instanceof Kn().Group&&(t+=n.getChildren().length);return t}bindInteraction(){this.#Zt.listening(!0),this.#jt.style.pointerEvents="auto";const e=Gi;for(let t=0;te.id()===this.#sn));let t;return 1===e.length?e[0]instanceof Kn().Group&&(t=e[0]):0===e.length?(t=new(Kn().Group),t.name("position-group"),t.id(this.#sn),t.visible(!0),this.getKonvaLayer().add(t)):c.warn("Unexpected number of draw position groups"),t}#Dn(e){return this.getKonvaLayer().findOne("#"+e)}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{e.srclayerid=this.getId(),e.dataid=this.#on,this.#Ae.fireEvent(e)};#un(e){const t=2/e.x,n=2/e.y,i=this.#Zt.find("Label");for(let e=0;e.33?0:1;t[n][e.data[n].length-2]=1,t[n][e.data[n].length-1]=1}t[e.data.length-2]=[],t[e.data.length-1]=[];for(let n=1;nMath.round(this.searchGran*this.cost[e.y][e.x]);setPoint(e){this.setWorking(!0),this.curPoint=e;let t=0,n=0;for(this.visited=[],n=0;nethis.getMax()?t:e))}}class Ei{getName(){return"Sharpen"}#On=null;setOriginalImage(e){this.#On=e}getOriginalImage(){return this.#On}update(){return this.getOriginalImage().convolute2D([0,-1,0,-1,5,-1,0,-1,0])}}class qi{getName(){return"Sobel"}#On=null;setOriginalImage(e){this.#On=e}getOriginalImage(){return this.#On}update(){const e=this.getOriginalImage(),t=e.convolute2D([1,0,-1,2,0,-2,1,0,-1]),n=e.convolute2D([1,2,1,0,0,0,-1,-2,-1]);return t.compose(n,(function(e,t){return Math.sqrt(e*e+t*t)}))}}class Ui{#An;#on;#nt;constructor(e,t,n){this.#An=e,this.#on=t,this.#nt=n}getName(){return"Filter-"+this.#An.getName()}execute(){this.#nt.setImage(this.#on,this.#An.update()),this.#nt.render(this.#on);const e={type:"filterrun",id:this.getName(),dataId:this.#on};this.onExecute(e)}undo(){this.#nt.setImage(this.#on,this.#An.getOriginalImage()),this.#nt.render(this.#on);const e={type:"filterundo",id:this.getName(),dataid:this.#on};this.onUndo(e)}onExecute(e){}onUndo(e){}}const Mi={},Qi={},Vi={WindowLevel:class{#nt;#bn=!1;#xn;#Rn;constructor(e){this.#nt=e,this.#Rn=new Hn(e)}#Fn(e,t){this.#nt.getLayerGroupByDivId(t).getActiveViewLayer().getViewController().isMonochrome()&&(this.#bn=!0,this.#xn=e)}#En(e,t){if(!this.#bn)return;const n=this.#nt.getLayerGroupByDivId(t).getActiveViewLayer().getViewController(),i=e.getX()-this.#xn.getX(),r=this.#xn.getY()-e.getY(),o=n.getImageRescaledDataRange(),a=.01*(o.max-o.min),s=n.getWindowLevel().center,l=n.getWindowLevel().width,c=s+Math.round(r*a);let d=l+Math.round(i*a);var h;d=(h=d)<1?1:h;const S=new u(c,d);n.setWindowLevel(S),this.#xn=e}#qn(){this.#bn&&(this.#bn=!1)}mousedown=e=>{const t=Wi(e),n=Zi(e);this.#Fn(t,n.groupDivId)};mousemove=e=>{const t=Wi(e),n=Zi(e);this.#En(t,n.groupDivId)};mouseup=e=>{this.#qn()};mouseout=e=>{this.#qn()};touchstart=e=>{const t=zi(e),n=Zi(e);this.#Fn(t[0],n.groupDivId)};touchmove=e=>{const t=zi(e),n=Zi(e);this.#En(t[0],n.groupDivId)};touchend=e=>{this.#qn()};dblclick=e=>{const t=Zi(e),n=Wi(e),i=this.#nt.getLayerGroupByDivId(t.groupDivId).getActiveViewLayer(),r=i.displayToPlaneIndex(n),o=i.getViewController();if(!o.isMonochrome())return;const a=this.#nt.getData(i.getDataId()).image,s=new u(a.getRescaledValueAtIndex(o.getCurrentIndex().getWithNew2D(r.get(0),r.get(1))),o.getWindowLevel().width);o.setWindowLevel(s)};wheel=e=>{this.#Rn.wheel(e)};keydown=e=>{e.context="WindowLevel",this.#nt.onKeydown(e)};activate(e){}init(){}setFeatures(e){}},Scroll:class{#nt;#bn=!1;#xn;#Rn;#Un;#Mn=!1;#Qn;constructor(e){this.#nt=e,this.#Rn=new Hn(e)}#Fn(e,t){this.#Vn();const n=this.#nt.getLayerGroupByDivId(t).getActiveViewLayer(),i=n.getViewController();i.isPlaying()&&i.stop(),this.#bn=!0,this.#xn=e;const r=n.displayToPlanePos(e),o=i.getPositionFromPlanePoint(r);i.setCurrentPosition(o)}#En(e,t){if(!this.#bn)return void(this.#Mn&&this.#Nn(e,t));const n=this.#nt.getLayerGroupByDivId(t),i=n.getActiveViewLayer().getViewController();let r;const o=e.getY()-this.#xn.getY(),a=Math.abs(o)>15;a&&n.canScroll()&&(r=o>0?i.getDecrementScrollPosition():i.getIncrementScrollPosition());const s=e.getX()-this.#xn.getX(),l=Math.abs(s)>15;l&&n.moreThanOne(3)&&(r=s>0?i.getIncrementPosition(3):i.getDecrementPosition(3)),void 0!==r&&n.isPositionInBounds(r)&&i.setCurrentPosition(r),(l||a)&&(this.#xn=e)}#qn(){this.#bn&&(this.#bn=!1)}mousedown=e=>{const t=Wi(e),n=Zi(e);this.#Fn(t,n.groupDivId)};mousemove=e=>{const t=Wi(e),n=Zi(e);this.#En(t,n.groupDivId)};mouseup=e=>{this.#qn()};mouseout=e=>{this.#qn(),this.#Vn()};touchstart=e=>{this.#Un=setTimeout((()=>{this.dblclick(e)}),500);const t=zi(e),n=Zi(e);this.#Fn(t[0],n.groupDivId)};touchmove=e=>{null!==this.#Un&&(clearTimeout(this.#Un),this.#Un=null);const t=zi(e),n=Zi(e);this.#En(t[0],n.groupDivId)};touchend=e=>{null!==this.#Un&&(clearTimeout(this.#Un),this.#Un=null),this.#qn()};wheel=e=>{this.#Rn.wheel(e)};keydown=e=>{e.context="Scroll",this.#nt.onKeydown(e)};dblclick=e=>{const t=Zi(e);this.#nt.getLayerGroupByDivId(t.groupDivId).getActiveViewLayer().getViewController().play()};#Nn(e,t){const n=this.#nt.getLayerGroupByDivId(t);this.#Qn=t,n.showTooltip(e)}#Vn(){void 0!==this.#Qn&&(this.#nt.getLayerGroupByDivId(this.#Qn).removeTooltipDiv(),this.#Qn=void 0)}activate(e){e||this.#Vn()}setFeatures(e){void 0!==e.displayTooltip&&(this.#Mn=e.displayTooltip)}init(){}},ZoomAndPan:class{#nt;#bn=!1;#xn;#Bn;#Gn;#kn;constructor(e){this.#nt=e}#Fn(e){this.#bn=!0,this.#xn=e,this.#Bn=!1}#Hn=e=>{this.#bn=!0,this.#xn=e[0],this.#Bn=!1,this.#Gn=new zn(e[0],e[1]),this.#kn=this.#Gn.getMidpoint()};#En(e,t){if(!this.#bn)return;this.#Bn=!0;const n=e.getX()-this.#xn.getX(),i=e.getY()-this.#xn.getY(),r=this.#nt.getLayerGroupByDivId(t),o=r.getActiveViewLayer(),a=o.getViewController(),s=o.displayToPlaneScale(new R(n,i)),l=a.getOffset3DFromPlaneOffset({x:s.getX(),y:s.getY()});r.addTranslation({x:l.getX(),y:l.getY(),z:l.getZ()}),r.draw(),this.#xn=e}#zn=(e,t)=>{if(!this.#bn)return;this.#Bn=!0;const n=new zn(e[0],e[1]).getLength()/this.#Gn.getLength(),i=this.#nt.getLayerGroupByDivId(t),r=i.getActiveViewLayer(),o=r.getViewController();if(1===n){const t=e[0].getY()-this.#xn.getY();if(Math.abs(t)<15)return;if(i.canScroll()){let e;e=t>0?o.getIncrementScrollPosition():o.getDecrementScrollPosition(),void 0!==e&&i.isPositionInBounds(e)&&o.setCurrentPosition(e)}}else{const e=(n-1)/10;if(Math.abs(e)%.1<=.05&&void 0!==this.#kn){const t=r.displayToMainPlanePos(this.#kn),n=o.getPlanePositionFromPlanePoint(t);i.addScale(e,n),i.draw()}}};#Wn(e,t){const n=this.#nt.getLayerGroupByDivId(t).getActiveViewLayer(),i=n.getViewController(),r=n.displayToPlanePos(e),o=i.getPositionFromPlanePoint(r);i.setCurrentPosition(o)}#qn(){this.#bn&&(this.#bn=!1)}mousedown=e=>{const t=Wi(e);this.#Fn(t)};mousemove=e=>{const t=Wi(e),n=Zi(e);this.#En(t,n.groupDivId)};mouseup=e=>{if(!this.#Bn){const t=Wi(e),n=Zi(e);this.#Wn(t,n.groupDivId)}this.#qn()};mouseout=e=>{this.#qn()};touchstart=e=>{const t=zi(e);1===t.length?this.#Fn(t[0]):2===t.length&&this.#Hn(t)};touchmove=e=>{const t=zi(e),n=Zi(e);1===t.length?this.#En(t[0],n.groupDivId):2===t.length&&this.#zn(t,n.groupDivId)};touchend=e=>{if(!this.#Bn){const t=Wi(e),n=Zi(e);this.#Wn(t,n.groupDivId)}this.#qn()};wheel=e=>{e.preventDefault();const t=-e.deltaY/500,n=Zi(e),i=Wi(e),r=this.#nt.getLayerGroupByDivId(n.groupDivId),o=r.getActiveViewLayer(),a=o.getViewController(),s=o.displayToMainPlanePos(i),l=a.getPlanePositionFromPlanePoint(s);r.addScale(t,l),r.draw()};keydown=e=>{e.context="ZoomAndPan",this.#nt.onKeydown(e)};activate(e){}init(){}setFeatures(e){}},Opacity:class{#nt;#bn=!1;#xn;#Rn;constructor(e){this.#nt=e,this.#Rn=new Hn(e)}#Fn(e){this.#bn=!0,this.#xn=e}#En(e,t){if(!this.#bn)return;const n=e.getX()-this.#xn.getX();if(Math.abs(n)>15){const i=this.#nt.getLayerGroupByDivId(t).getActiveViewLayer(),r=i.getOpacity();i.setOpacity(r+n/200),i.draw(),this.#xn=e}}#qn(){this.#bn&&(this.#bn=!1)}mousedown=e=>{const t=Wi(e);this.#Fn(t)};mousemove=e=>{const t=Wi(e),n=Zi(e);this.#En(t,n.groupDivId)};mouseup=e=>{this.#qn()};mouseout=e=>{this.#qn()};touchstart=e=>{const t=zi(e);this.#Fn(t[0])};touchmove=e=>{const t=zi(e),n=Zi(e);this.#En(t[0],n.groupDivId)};touchend=e=>{this.#qn()};wheel=e=>{this.#Rn.wheel(e)};keydown=e=>{e.context="Opacity",this.#nt.onKeydown(e)};activate(e){}init(){}setFeatures(e){}},Draw:class{#nt;#Rn;#Yn;#Xn=!1;#jn=null;#wt=null;#Zn=null;#_n;#yt=[];#Kn=null;#Jn=!0;#$n=[];#ln;#ei=!1;#H={};#ti=!1;#ni=[];constructor(e){this.#nt=e,this.#Rn=new Hn(e),this.#ln=new Di(e,this.#Re),this.#Yn=e.getStyle()}#ii(e,t){const n=this.#nt.getLayerGroupByDivId(t);let i=n.getActiveDrawLayer();if(void 0===i){const e=n.getActiveViewLayer().getDataId(),r=this.#nt.getData(e).image.getMeta().SeriesInstanceUID;if(this.#$n.includes(r))return void this.#Re({type:"warn",message:"Cannot create draw layer, data is in black list"});const o=this.#nt.createAnnotationData(e);this.#nt.addAndRenderAnnotationData(o,t,e),i=n.getActiveDrawLayer(),i.setShapeHandler(this.#ln),n.setActiveDrawLayerByDataId(i.getDataId())}const r=i.getDrawController().getAnnotationGroup(),o=i.getKonvaStage();if(this.#Yn.setZoomScale(o.scale()),r.isEditable()){const t=o.getIntersection({x:e.getX(),y:e.getY()});t?this.#ri(i,t):this.#oi(n,e)}}#oi(e,t){this.#ln.disableAndResetEditor(),this.#ai();const n=e.getActiveViewLayer();this.#Kn=n.displayToPlanePos(t),this.#yt.push(this.#Kn)}#ai(){this.#Xn=!0,this.#wt=new this.#jn[this.#_n],this.#yt=[]}#si(){this.#Xn=!1,this.#yt=[]}#ri(e,t){let n=t.getParent();t instanceof Kn().Tag&&(n=n.getParent());const i=n.find(".shape")[0];i instanceof Kn().Shape&&(this.#Re({type:"annotationselect",annotationid:n.id(),dataid:e.getDataId()}),this.#ln.setEditorShape(i,e))}#li(e,t){const n=this.#nt.getLayerGroupByDivId(t),i=n.getActiveViewLayer().displayToPlanePos(e);(Math.abs(i.getX()-this.#Kn.getX())>0||Math.abs(i.getY()-this.#Kn.getY())>0)&&(this.#ti&&this.#yt.pop(),this.#Kn=i,this.#ti=!0,this.#yt.push(this.#Kn),this.#ci(this.#yt,n))}#ui(e){if(0!==this.#yt.length){if(this.#yt.length===this.#wt.getNPoints()){const t=this.#nt.getLayerGroupByDivId(e);this.#di(this.#yt,t),this.#si()}this.#ti=!1}else c.warn("Draw mouseup but no points...")}mousedown=e=>{if(this.#Xn)return;const t=Wi(e),n=Zi(e);this.#ii(t,n.groupDivId)};mousemove=e=>{if(!this.#Xn)return;const t=Wi(e),n=Zi(e);this.#li(t,n.groupDivId)};mouseup=e=>{if(!this.#Xn)return;const t=Zi(e);this.#ui(t.groupDivId)};dblclick=e=>{if(this.#wt&&void 0!==this.#wt.getNPoints())return;if(!this.#Xn)return;if(0===this.#yt.length)return void c.warn("Draw dblclick but no points...");const t=Zi(e),n=this.#nt.getLayerGroupByDivId(t.groupDivId);this.#di(this.#yt,n),this.#si()};mouseout=e=>{if(!this.#Xn)return;const t=Zi(e);this.#ui(t.groupDivId)};touchstart=e=>{if(this.#Xn)return;const t=zi(e),n=Zi(e);this.#ii(t[0],n.groupDivId)};touchmove=e=>{if(!this.#Xn)return;const t=Zi(e),n=zi(e),i=this.#nt.getLayerGroupByDivId(t.groupDivId),r=i.getActiveViewLayer().displayToPlanePos(n[0]);(Math.abs(r.getX()-this.#Kn.getX())>0||Math.abs(r.getY()-this.#Kn.getY())>0)&&(1!==this.#yt.length&&this.#yt.pop(),this.#Kn=r,this.#yt.push(this.#Kn),this.#yt.length{this.#yt.push(this.#Kn)}),this.#wt.getTimeout())),this.#ci(this.#yt,i))};touchend=e=>{this.dblclick(e)};wheel=e=>{this.#Jn&&this.#Rn.wheel(e)};keydown=e=>{this.#Xn||(e.context="Draw",this.#nt.onKeydown(e));const t=this.#ln.getEditorAnnotation();if(("Delete"===e.key||"Backspace"===e.key)&&void 0!==t){const e=this.#nt.getActiveLayerGroup().getActiveDrawLayer().getDrawController(),n=new vi(t,e);this.#nt.addToUndoStack(n),n.execute(),this.#ln.onMouseOutShapeGroup()}if("Escape"===e.key&&null!==this.#Zn){const e=this.#Zn.getLayer();this.#Zn.destroy(),this.#Zn=null,this.#si(),e.draw()}};#ci(e,t){this.#Zn&&(this.#Zn.destroy(),this.#Zn=null);const n=t.getActiveDrawLayer(),i=n.getDrawController(),r=n.getKonvaLayer(),o=t.getActiveViewLayer().getViewController();if(this.#ei){const e=["#ffff80","#ff80ff","#80ffff","#80ff80","8080ff","ff8080"],t=n.getId(),i=t.substring(t.length-1),r=e[parseInt(i,10)-1];void 0!==r&&this.#Yn.setLineColour(r)}const a=new Bi,s=i.getAnnotationGroup().getColour();a.colour=void 0!==s?s:this.#Yn.getLineColour(),a.init(o),this.#wt.setAnnotationMathShape(a,e),this.#Zn=this.#wt.createShapeGroup(a,this.#Yn),n.setLabelVisibility(this.#Zn),this.#Zn.getChildren(ni)[0].listening(!1),r.listening(!1),r.add(this.#Zn),r.draw()}#di(e,t){this.#Zn&&(this.#Zn.destroy(),this.#Zn=null);const n=t.getActiveDrawLayer(),i=n.getKonvaLayer(),r=n.getDrawController(),o=t.getActiveViewLayer().getViewController(),a=new Bi,s=r.getAnnotationGroup().getColour();a.colour=void 0!==s?s:this.#Yn.getLineColour(),a.id=$e(),a.init(o),this.#wt.setAnnotationMathShape(a,e);const l=new yi(a,r);this.#nt.addToUndoStack(l),l.execute(),i.listening(!0)}#hi(e){const t=e.getId();return void 0===this.#ni[t]&&(this.#ni[t]=()=>{e.activateCurrentPositionShapes(!0)}),this.#ni[t]}#Si(e,t){e.setShapeHandler(this.#ln),e.activateCurrentPositionShapes(t),t?this.#nt.addEventListener("positionchange",this.#hi(e)):this.#nt.removeEventListener("positionchange",this.#hi(e))}activate(e){e||this.#ln.onMouseOutShapeGroup();const t=this.#nt.getDrawLayers();for(const n of t)void 0!==n&&this.#Si(n,e);this.#nt.addEventListener("drawlayeradd",(t=>{const n=this.#nt.getDrawLayers((function(e){return e.getId()===t.layerid}));1===n.length&&this.#Si(n[0],e)}))}setOptions(e){this.#jn=e}getOptionsType(){return"factory"}setFeatures(e){if(void 0!==e.autoShapeColour&&(this.#ei=e.autoShapeColour),void 0!==e.shapeColour&&(this.#Yn.setLineColour(e.shapeColour),this.#ei=!1),void 0!==e.shapeName){if(!this.hasShape(e.shapeName))throw new Error("Unknown shape: '"+e.shapeName+"'");this.#_n=e.shapeName}void 0!==e.mouseOverCursor&&this.#ln.storeMouseOverCursor(e.mouseOverCursor),void 0!==e.withScroll&&(this.#Jn=e.withScroll),void 0!==e.blacklist&&(this.#$n=e.blacklist)}init(){}getEventNames(){return["annotationupdate","annotationselect","warn"]}addEventListener(e,t){void 0===this.#H[e]&&(this.#H[e]=[]),this.#H[e].push(t)}removeEventListener(e,t){if(void 0!==this.#H[e])for(let n=0;n{if(void 0!==this.#H[e.type])for(let t=0;t{e.context="Filter",this.#nt.onKeydown(e)};getEventNames(){return["filterrun","filterundo"]}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{this.#Ae.fireEvent(e)};getSelectedFilter(){return this.#pi}setFeatures(e){if(void 0!==e.filterName){if(!this.hasFilter(e.filterName))throw new Error("Unknown filter: '"+e.filterName+"'");this.#pi&&this.#pi.activate(!1),this.#pi=this.#gi[e.filterName],this.#pi.activate(!0)}if(void 0!==e.run&&e.run){let t={};void 0!==e.runArgs&&(t=e.runArgs),this.getSelectedFilter().run(t)}}getFilterList(){return this.#gi}hasFilter(e){return this.#gi[e]}},Floodfill:class{#nt;constructor(e){this.#nt=e}#mi=5;#fi=0;#Di=2e3;#Ci=null;#yi=null;#vi=10;#Ii=null;#bn=!1;#bt;#Ti;#Li=null;#Pi=[];#wi=!1;#Yn=new ei;#Ae=new ke;setExtend(e){this.#wi=e}getExtend(){return this.#wi}#Oi=(e,t)=>{const n=this.#nt.getLayerGroupByDivId(t).getActiveViewLayer().displayToPlaneIndex(e);return{x:n.get(0),y:n.get(1)}};#Ai(e,t,n){this.#Pi=[];const i={data:this.#Ci.data,width:this.#Ci.width,height:this.#Ci.height,bytes:4};this.#yi=Li().floodFill(i,e.x,e.y,t),this.#yi=Li().gaussBlurOnlyBorder(this.#yi,this.#mi);let r=Li().traceContours(this.#yi);if(r=Li().simplifyContours(r,this.#fi,this.#Di),r.length>0&&r[0].points[0].x){if(n)return r[0].points;for(let e=0,t=r[0].points.length;eo&&this.#bi(this.#Ti,a,n);t--)i.decrementIndex(2);i.setCurrentPosition(r)}onThresholdChange(e){}#Fn(e,t){const n=this.#nt.getLayerGroupByDivId(t),i=n.getActiveViewLayer();let r=n.getActiveDrawLayer();if(void 0===r){const e=n.getActiveViewLayer().getDataId(),i=this.#nt.createAnnotationData(e);this.#nt.addAndRenderAnnotationData(i,t,e),r=n.getActiveDrawLayer(),n.setActiveDrawLayerByDataId(r.getDataId())}this.#Ci=i.getImageData(),this.#Ci?(this.#Yn.setZoomScale(r.getKonvaLayer().getAbsoluteScale()),this.#bn=!0,this.#Ti=this.#Oi(e,t),this.#bi(this.#Ti,this.#vi,n),this.onThresholdChange(this.#vi)):c.error("No image found")}#En(e,t){if(!this.#bn)return;const n=this.#Oi(e,t);this.#Ii=Math.round(Math.sqrt(Math.pow(this.#Ti.x-n.x,2)+Math.pow(this.#Ti.y-n.y,2))/2),this.#Ii=this.#Ii{const t=Wi(e),n=Zi(e);this.#Fn(t,n.groupDivId)};mousemove=e=>{const t=Wi(e),n=Zi(e);this.#En(t,n.groupDivId)};mouseup=e=>{this.#qn()};mouseout=e=>{this.#qn()};touchstart=e=>{const t=zi(e),n=Zi(e);this.#Fn(t[0],n.groupDivId)};touchmove=e=>{const t=zi(e),n=Zi(e);this.#En(t[0],n.groupDivId)};touchend=e=>{this.#qn()};keydown=e=>{e.context="Floodfill",this.#nt.onKeydown(e)};activate(e){e&&(this.#Yn.setBaseScale(this.#nt.getBaseScale()),this.setFeatures({shapeColour:this.#Yn.getLineColour()}))}init(){}getEventNames(){return["drawcreate","drawchange","drawmove","drawdelete"]}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}setFeatures(e){void 0!==e.shapeColour&&this.#Yn.setLineColour(e.shapeColour)}},Livewire:class{#nt;constructor(e){this.#nt=e}#bn=!1;#xn;#bt;#Yn=new ei;#xi=new Pi;#Ri=new Pi;#Pi=[];#Fi=5;#Ae=new ke;#Ei(e){const t=e.get(1);for(let e=0;e{const t=Wi(e),n=Zi(e);this.#Fn(t,n.groupDivId)};mousemove=e=>{const t=Wi(e),n=Zi(e);this.#En(t,n.groupDivId)};mouseup(e){}mouseout=e=>{};dblclick=e=>{this.#Mi()};touchstart=e=>{const t=zi(e),n=Zi(e);this.#Fn(t[0],n.groupDivId)};touchmove=e=>{const t=zi(e),n=Zi(e);this.#En(t[0],n.groupDivId)};touchend=e=>{};keydown=e=>{e.context="Livewire",this.#nt.onKeydown(e)};activate(e){if(e){const e=this.#nt.getActiveLayerGroup().getActiveViewLayer(),t=e.getViewController().getImageSize();this.#Ui.setDimensions(t.get(0),t.get(1)),this.#Ui.setData(e.getImageData().data),this.#Yn.setBaseScale(this.#nt.getBaseScale()),this.setFeatures({shapeColour:this.#Yn.getLineColour()})}}init(){}getEventNames(){return["drawcreate","drawchange","drawmove","drawdelete"]}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}setFeatures(e){void 0!==e.shapeColour&&this.#Yn.setLineColour(e.shapeColour)}}},Ni={draw:{ArrowFactory:class{#Qi="arrow";#Vi=new Ri(this.#Ni);static supports(e){return e instanceof R}getName(){return this.#Qi}getGroupName(){return this.#Qi+"-group"}getNPoints(){return 2}getTimeout(){return 0}setAnnotationMathShape(e,t){e.mathShape=this.#Bi(t),e.referencePoints=[t[1]],e.setTextExpr(this.#Gi()),e.updateQuantification()}createShapeGroup(e,t){const n=new(Kn().Group);n.name(this.getGroupName()),n.visible(!0),n.id(e.id);const i=this.#ki(e,t);n.add(i);const r=this.#Hi(e,t);for(const e of r)n.add(e);const o=this.#Vi.create(e,t);n.add(o);const a=this.#zi(i);return n.add(this.#Vi.getConnector(a,o,t)),n}#zi(e){const t=e.points(),n=e.x(),i=e.y(),r=(t[0]+t[2])/2+n,o=(t[1]+t[3])/2+i;return[new R(r,o)]}#Wi(e){const t=e.points(),n=e.x(),i=e.y();return[new R(t[0]+n,t[1]+i),new R(t[2]+n,t[3]+i)]}getAnchors(e,t){const n=this.#Wi(e),i=[];for(let e=0;e180&&(o=360-o,a+=o);const s=33*Math.min(i.getLength(),r.getLength())/100;return[new(Kn().Arc)({innerRadius:s,outerRadius:s,stroke:e.colour,strokeWidth:t.getStrokeWidth(),strokeScaleEnabled:!1,angle:o,rotation:-a,x:n.getPoint(1).getX(),y:n.getPoint(1).getY(),name:"shape-arc"})]}#Ni(e){const t=e.mathShape,n=new zn(t.getPoint(0),t.getPoint(1)),i=new zn(t.getPoint(1),t.getPoint(2)),r=(n.getMidpoint().getX()+i.getMidpoint().getX())/2,o=(n.getMidpoint().getY()+i.getMidpoint().getY())/2;return new R(r,o)}#Yi(e,t,n){const i=e.mathShape,r=new zn(i.getPoint(0),i.getPoint(1)),o=new zn(i.getPoint(1),i.getPoint(2)),a=t.getParent();if(!(a instanceof Kn().Group))return;const s=this.#Xi(a);s.position({x:0,y:0}),s.points([i.getPoint(0).getX(),i.getPoint(0).getY(),i.getPoint(1).getX(),i.getPoint(1).getY(),i.getPoint(2).getX(),i.getPoint(2).getY()]);const l=a.getChildren((function(e){return"shape-arc"===e.name()}))[0];if(!(l instanceof Kn().Arc))return;const c=oi(a,0),u=oi(a,1),d=oi(a,2);switch(t.id()){case"anchor0":c.x(t.x()),c.y(t.y());break;case"anchor1":u.x(t.x()),u.y(t.y());break;case"anchor2":d.x(t.x()),d.y(t.y())}let h=Wn(r,o),S=r.getInclination();h>180&&(h=360-h,S+=h);const g=33*Math.min(r.getLength(),o.getLength())/100;l.innerRadius(g),l.outerRadius(g),l.angle(h),l.rotation(-S);const p={x:u.x(),y:u.y()};l.position(p),s.hitFunc((function(e){e.beginPath(),e.moveTo(i.getPoint(0).getX(),i.getPoint(0).getY()),e.lineTo(i.getPoint(1).getX(),i.getPoint(1).getY()),e.lineTo(i.getPoint(2).getX(),i.getPoint(2).getY()),e.closePath(),e.fillStrokeShape(s)}))}#ji(e,t){}#Zi(e,t){}},RectangleFactory:class{#Qi="rectangle";#Vi=new Ri(this.#Ni);static supports(e){return e instanceof ci}getName(){return this.#Qi}getGroupName(){return this.#Qi+"-group"}getNPoints(){return 2}getTimeout(){return 0}setAnnotationMathShape(e,t){e.mathShape=this.#Bi(t),e.setTextExpr(this.#Gi()),e.updateQuantification()}createShapeGroup(e,t){const n=new(Kn().Group);n.name(this.getGroupName()),n.visible(!0),n.id(e.id);const i=this.#ki(e,t);n.add(i);const r=this.#Vi.create(e,t);n.add(r);const o=this.#zi(i);return n.add(this.#Vi.getConnector(o,r,t)),n}#zi(e){const t=e.x(),n=e.y(),i=e.width(),r=e.height();return[new R(t+i/2,n),new R(t,n+r/2),new R(t+i/2,n+r),new R(t+i,n+r/2)]}#Wi(e){const t=e.x(),n=e.y(),i=e.width(),r=e.height();return[new R(t,n),new R(t+i,n),new R(t+i,n+r),new R(t,n+r)]}getAnchors(e,t){const n=this.#Wi(e),i=[];for(let e=0;e{this.#Ae.fireEvent(e)}},Sobel:class{#nt;constructor(e){this.#nt=e}#Ae=new ke;activate(e){}init(){}run(e){if(void 0===e.dataId)throw new Error("No dataId to run sobel filter on.");const t=new qi,n=this.#nt.getData(e.dataId).image;t.setOriginalImage(n);const i=new Ui(t,e.dataId,this.#nt);i.onExecute=this.#Re,i.onUndo=this.#Re,i.execute(),this.#nt.addToUndoStack(i)}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{this.#Ae.fireEvent(e)}},Sharpen:class{#nt;constructor(e){this.#nt=e}#Ae=new ke;activate(e){}init(){}run(e){if(void 0===e.dataId)throw new Error("No dataId to run sharpen filter on.");const t=new Ei,n=this.#nt.getData(e.dataId).image;t.setOriginalImage(n);const i=new Ui(t,e.dataId,this.#nt);i.onExecute=this.#Re,i.onUndo=this.#Re,i.execute(),this.#nt.addToUndoStack(i)}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{this.#Ae.fireEvent(e)}}}};class Bi{id;referenceSopUID;mathShape;referencePoints;colour;quantification;textExpr;labelPosition;planeOrigin;planePoints;#Ki;getOrientationName(){let e;return void 0!==this.planePoints&&(e=ft(this.planePoints[1].getValues().concat(this.planePoints[2].getValues()))),e}init(e){void 0===this.referenceSopUID?(this.#Ki=e,this.referenceSopUID=e.getCurrentImageUid(),this.planeOrigin=e.getOriginForImageUid(this.referenceSopUID),e.isAquisitionOrientation()||(this.planePoints=e.getPlanePoints(e.getCurrentPosition()))):c.debug("Cannot initialise annotation twice")}isCompatibleView(e){let t=!1;if(void 0===this.planePoints)e.isAquisitionOrientation()&&(t=!0);else{const n=e.getCosines(),i=new F(n[0],n[1],n[2]),r=new F(n[3],n[4],n[5]);i.equals(this.planePoints[1])&&r.equals(this.planePoints[2])&&(t=!0)}return t}setViewController(e){e.includesImageUid(this.referenceSopUID)&&this.isCompatibleView(e.getPlaneHelper())&&(this.#Ki=e,this.planeOrigin=e.getOriginForImageUid(this.referenceSopUID))}getCentroid(){let e;if(void 0!==this.#Ki&&void 0!==this.mathShape.getCentroid){let t=this.planeOrigin;void 0!==this.planePoints&&(t=this.planePoints[0]);const n=new E([t.getX(),t.getY(),t.getZ()]),i=this.#Ki.getIndexFromPosition(n),r=this.#Ki.getScrollIndex(),o=i.getValues()[r],a=this.mathShape.getCentroid();e=this.#Ki.getPositionFromPlanePoint(a,o)}return e}setTextExpr(e){if(void 0!==this.#Ki){const t=this.#Ki.getModality();void 0!==e[t]?this.textExpr=e[t]:this.textExpr=e["*"]}else c.warn("Cannot set text expr without a view controller")}getText(){return function(e,t){let n="";if(null==e)return n;if(n=e,null==t)return n;const i=Q(e);for(let e=0;e{this.#on===e.dataid&&(this.#Ki.setImage(e.value[0]),this.#gr(this.#Ki.getImageSize().get2D()),this.#ar=!0)};bindImage(){this.#Ki&&this.#Ki.bindImageAndLayer(this)}unbindImage(){this.#Ki&&this.#Ki.unbindImageAndLayer(this)}onimagecontentchange=e=>{this.#on===e.dataid&&(this.#tr=this.#Ki.isPositionInBounds(),this.#ar=!0,this.draw())};onimagegeometrychange=e=>{if(this.#on===e.dataid){const e=this.#Ki.getImageSize().get2D();if(this.#_t.x!==e.x||this.#_t.y!==e.y){if(void 0!==this.#lr&&void 0!==this.#cr){const e=this.#Ki.getOrigin(),t=this.#cr.minus(e),n=this.#Ki.getOrigin(this.#Ki.getCurrentPosition()),i=this.#lr.minus(n);this.setBaseOffset(t,i)}this.#gr(e),this.#ar=!0,this.draw()}}};getId(){return this.#jt.id}removeFromDOM(){this.#jt.remove()}getBaseSize(){return this.#_t}getImageWorldSize(){return this.#Ki.getImageWorldSize()}getOpacity(){return this.#ir}setOpacity(e){if(e===this.#ir)return;this.#ir=Math.min(Math.max(e,0),1);const t={type:"opacitychange",value:[this.#ir]};this.#Re(t)}addFlipOffsetX(){this.#in.x+=this.#Ji.width/this.#rr.x,this.#or.x+=this.#in.x}addFlipOffsetY(){this.#in.y+=this.#Ji.height/this.#rr.y,this.#or.y+=this.#in.y}flipScaleX(){this.#$t.x*=-1}flipScaleY(){this.#$t.y*=-1}flipScaleZ(){this.#$t.z*=-1}setScale(e,t){const n=this.#Ki.getPlaneHelper(),i=n.getTargetOrientedPositiveXYZ({x:e.x*this.#$t.x,y:e.y*this.#$t.y,z:e.z*this.#$t.z}),r={x:this.#Jt.x*i.x,y:this.#Jt.y*i.y};if(1===Math.abs(e.x)&&1===Math.abs(e.y)&&1===Math.abs(e.z)){const e={x:this.#or.x-this.#nn.x,y:this.#or.y-this.#nn.y};this.#nn={x:0,y:0},this.#or=e}else if(void 0!==t){let e=n.getPlaneOffsetFromOffset3D({x:t.getX(),y:t.getY(),z:t.getZ()});e={x:e.x+this.#en.x,y:e.y+this.#en.y};const i=_i(this.#or,this.#rr,r,e),o={x:this.#nn.x+i.x-this.#or.x,y:this.#nn.y+i.y-this.#or.y};this.#nn=o,this.#or=i}this.#rr=r}initScale(e,t){const n=this.#Ki.getPlaneHelper().getTargetOrientedPositiveXYZ({x:e.x*this.#$t.x,y:e.y*this.#$t.y,z:e.z*this.#$t.z}),i={x:this.#Jt.x*n.x,y:this.#Jt.y*n.y};this.#rr=i,this.#nn={x:t.x/this.#Jt.x,y:t.y/this.#Jt.y},this.#or={x:this.#or.x+this.#nn.x,y:this.#or.y+this.#nn.y}}setBaseOffset(e,t,n,i){const r=this.#Ki.getPlaneHelper(),o=r.getNativeScrollIndex(),a=r.getPlaneOffsetFromOffset3D({x:0===o?e.getX():t.getX(),y:1===o?e.getY():t.getY(),z:2===o?e.getZ():t.getZ()}),s=this.#en.x!==a.x||this.#en.y!==a.y;return void 0!==n&&void 0!==i&&(this.#lr=n,this.#cr=i),s&&(this.#or={x:this.#or.x-this.#en.x+a.x,y:this.#or.y-this.#en.y+a.y},this.#en=a),s}setOffset(e){const t=this.#Ki.getPlaneHelper().getPlaneOffsetFromOffset3D(e);this.#or={x:t.x+this.#tn.x+this.#en.x+this.#nn.x+this.#in.x,y:t.y+this.#tn.y+this.#en.y+this.#nn.y+this.#in.y}}displayToPlaneIndex(e){const t=this.displayToPlanePos(e);return new s([Math.floor(t.getX()),Math.floor(t.getY())])}displayToPlaneScale(e){return new R(e.getX()/this.#rr.x,e.getY()/this.#rr.y)}displayToPlanePos(e){const t=this.displayToPlaneScale(e);return new R(t.getX()+this.#or.x,t.getY()+this.#or.y)}planePosToDisplay(e){let t=(e.getX()-this.#or.x+this.#en.x)*this.#rr.x,n=(e.getY()-this.#or.y+this.#en.y)*this.#rr.y;return(t<0||t>=this.#Ji.width)&&(t=void 0),(n<0||n>=this.#Ji.height)&&(n=void 0),new R(t,n)}displayToMainPlanePos(e){const t=this.displayToPlanePos(e);return new R(t.getX()-this.#en.x,t.getY()-this.#en.y)}display(e){this.#jt.style.display=e?"":"none"}isVisible(){return""===this.#jt.style.display}draw(){if(!this.#tr)return;let e={type:"renderstart",layerid:this.getId(),dataid:this.getDataId()};this.#Re(e),this.#ar&&this.#pr(),this.#er.globalAlpha=this.#ir,this.clear(),this.#er.setTransform(this.#rr.x,0,0,this.#rr.y,-1*this.#or.x*this.#rr.x,-1*this.#or.y*this.#rr.y),this.#er.imageSmoothingEnabled=this.#sr,this.#er.drawImage(this.#$i,0,0),e={type:"renderend",layerid:this.getId(),dataid:this.getDataId()},this.#Re(e)}initialise(e,t,n){this.#Kt=t,this.#ir=Math.min(Math.max(n,0),1),this.#Ji=document.createElement("canvas"),this.#jt.appendChild(this.#Ji),this.#Ji.getContext?(this.#er=this.#Ji.getContext("2d"),this.#er?(this.#$i=document.createElement("canvas"),this.#gr(e),this.#ar=!0):alert("Error: failed to get the 2D context.")):alert("Error: no canvas.getContext method.")}#gr(e){if(!Yi(e.x,e.y))throw new Error("Cannot create canvas with size "+e.x+", "+e.y);this.#_t=e,this.#$i.width=this.#_t.x,this.#$i.height=this.#_t.y,this.#er.clearRect(0,0,this.#_t.x,this.#_t.y),this.#nr=this.#er.createImageData(this.#_t.x,this.#_t.y)}fitToContainer(e,t,n){let i=!1;if(this.#Ji.width!==e.x||this.#Ji.height!==e.y){if(!Yi(e.x,e.y))throw new Error("Cannot resize canvas "+e.x+", "+e.y);this.#Ji.width=e.x,this.#Ji.height=e.y,i=!0}const r={x:t*this.#Kt.x,y:t*this.#Kt.y},o={x:this.#rr.x*r.x/this.#Jt.x,y:this.#rr.y*r.y/this.#Jt.y};this.#rr.x===o.x&&this.#rr.y===o.y||(this.#Jt=r,this.#rr=o,i=!0);const a={x:n.x/r.x,y:n.y/r.y},s={x:e.x/r.x,y:e.y/r.y},l={x:0!==this.#in.x?s.x:0,y:0!==this.#in.y?s.y:0};this.#tn.x===a.x&&this.#tn.y===a.y&&this.#in.x===l.x&&this.#in.y===l.y||(this.#or={x:this.#or.x+a.x-this.#tn.x+l.x-this.#in.x,y:this.#or.y+a.y-this.#tn.y+l.y-this.#in.y},this.#in=l,this.#tn=a,i=!0),i&&this.draw()}bindInteraction(){this.#jt.style.pointerEvents="auto";const e=Gi;for(let t=0;t{e.srclayerid=this.getId(),e.dataid=this.#on,this.#Ae.fireEvent(e)};#pr(){this.#Ki.generateImageData(this.#nr),this.#$i.getContext("2d").putImageData(this.#nr,0,0),this.#ar=!1}#ur=e=>{void 0!==e.skipGenerate&&!0===e.skipGenerate||(this.#ar=!0,this.draw())};#dr=e=>{void 0!==e.skipGenerate&&!0===e.skipGenerate||(this.#ar=!0,this.draw())};#hr=e=>{if(void 0===e.skipGenerate||!0!==e.skipGenerate){let t=!0;if(void 0!==e.valid&&(t=e.valid),t){const t=[0,1,2],n=t.indexOf(this.#Ki.getScrollIndex());t.splice(n,1),0===e.diffDims.filter((function(e){return-1===t.indexOf(e)})).length&&this.#tr||(this.#tr=!0,this.#ar=!0,this.draw())}else this.#tr&&(this.#tr=!1,this.clear())}};#Sr=e=>{void 0!==e.skipGenerate&&!0===e.skipGenerate||(this.#ar=!0,this.draw())};setCurrentPosition(e,t){return this.#Ki.setCurrentPosition(e)}clear(){this.#er.save(),this.#er.setTransform(1,0,0,1,0,0),this.#er.clearRect(0,0,this.#Ji.width,this.#Ji.height),this.#er.restore()}}function ji(e){const t=e.split("-layer-");return 2!==t.length&&c.warn("Not the expected layer div id format..."),{groupDivId:t[0],layerIndex:t[1],layerId:e}}function Zi(e){let t=null;const n=e.target.closest(".layer");return n&&void 0!==n.id&&(t=ji(n.id)),t}function _i(e,t,n,i){const r=(i.x-e.x)*t.x,o=(i.y-e.y)*t.y;return{x:i.x-r/n.x,y:i.y-o/n.y}}class Ki{#jt;#mr=[];#rr={x:1,y:1,z:1};#gt={x:1,y:1,z:1};#or={x:0,y:0,z:0};#fr=void 0;#Dr=void 0;#Ae=new ke;#Cr=!1;#yr=[];#vr;#Ne;#sr=!1;constructor(e){this.#jt=e}getShowCrosshair(){return this.#Cr}setShowCrosshair(e){this.#Cr=e,e?(this.addEventListener("offsetchange",this.#Ir),this.addEventListener("zoomchange",this.#Ir),this.#Tr()):(this.removeEventListener("offsetchange",this.#Ir),this.removeEventListener("zoomchange",this.#Ir),this.#Lr())}setImageSmoothing(e){this.#sr=e;for(const t of this.#mr)t instanceof Xi&&t.setImageSmoothing(e)}#Ir=e=>{this.#Tr()};getDivId(){return this.#jt.id}getScale(){return this.#rr}getBaseScale(){return this.#gt}getAddedScale(){return{x:this.#rr.x/this.#gt.x,y:this.#rr.y/this.#gt.y,z:this.#rr.z/this.#gt.z}}getOffset(){return this.#or}getNumberOfLayers(){let e=0;return this.#mr.forEach((t=>{void 0!==t&&e++})),e}includes(e){if(void 0===e)return!1;for(const t of this.#mr)if(void 0!==t&&t.getId()===e)return!0;return!1}getViewLayers(e){void 0===e&&(e=function(){return!0});const t=[];for(const n of this.#mr)n instanceof Xi&&e(n)&&t.push(n);return t}someViewLayer(e){let t=!1;for(const n of this.#mr)if(n instanceof Xi&&e(n)){t=!0;break}return t}getDrawLayers(e){void 0===e&&(e=function(){return!0});const t=[];for(const n of this.#mr)n instanceof Ci&&e(n)&&t.push(n);return t}getNumberOfViewLayers(){let e=0;return this.#mr.forEach((t=>{void 0!==t&&t instanceof Xi&&e++})),e}getActiveViewLayer(){let e;if(void 0!==this.#fr){const t=this.#mr[this.#fr];t instanceof Xi&&(e=t)}return e}getBaseViewLayer(){let e;for(const t of this.#mr)if(t instanceof Xi){e=t;break}if(void 0!==e)return e;c.warn("No layer found")}getViewLayersByDataId(e){return this.getViewLayers((function(t){return t.getDataId()===e}))}searchViewLayers(e){const t=[];for(const n of this.#mr)n instanceof Xi&&n.getViewController().equalImageMeta(e)&&t.push(n);return t}getViewDataIndices(){const e=[];for(const t of this.#mr)t instanceof Xi&&e.push(t.getDataId());return e}getActiveDrawLayer(){let e;if(void 0!==this.#Dr){const t=this.#mr[this.#Dr];t instanceof Ci&&(e=t)}return e}getDrawLayersByDataId(e){return this.getDrawLayers((function(t){return t.getDataId()===e}))}setActiveViewLayer(e){this.#mr[e]instanceof Xi?(this.#fr=e,this.#Re({type:"activelayerchange",value:[this.#mr[e]]})):c.warn("No view layer to set as active with index: "+e)}setActiveViewLayerByDataId(e){let t;for(let n=0;n0;)e[0].remove()}removeLayersByDataId(e){for(const t of this.#mr)void 0!==t&&t.getDataId()===e&&this.removeLayer(t)}removeLayer(e){const t=this.#mr.findIndex((t=>t===e));if(-1===t)throw new Error("Cannot find layer to remove");e instanceof Xi?(this.#Ar(e),this.#fr===t&&(this.#fr=void 0)):(this.#br(e),this.#Dr===t&&(this.#Dr=void 0)),this.#mr[t]=void 0,e.removeFromDOM()}#Tr(e){let t;void 0===e&&(e=this.#Ne),this.#Lr();for(const e of this.#mr)if(e instanceof Xi){t=e;break}if(void 0===t)return void c.warn("No layer to show crosshair");const n=t.getViewController().getPlanePositionFromPosition(e),i=t.planePosToDisplay(n);if(void 0!==i.getY()){const e=document.createElement("hr");e.id=this.getDivId()+"-scroll-crosshair-horizontal",e.className="horizontal",e.style.width=this.#jt.offsetWidth+"px",e.style.left="0px",e.style.top=i.getY()+"px",this.#yr.push(e),this.#jt.appendChild(e)}if(void 0!==i.getX()){const e=document.createElement("hr");e.id=this.getDivId()+"-scroll-crosshair-vertical",e.className="vertical",e.style.width=this.#jt.offsetHeight+"px",e.style.left=i.getX()+"px",e.style.top="0px",this.#yr.push(e),this.#jt.appendChild(e)}}#Lr(){for(const e of this.#yr)e.remove();this.#yr=[]}showTooltip(e){this.removeTooltipDiv();const t=this.getActiveViewLayer(),n=t.getViewController(),i=t.displayToPlanePos(e),r=n.getPositionFromPlanePoint(i),o=n.getRescaledImageValue(r);if(void 0!==o){const t=document.createElement("span");t.id="scroll-tooltip",t.style.left=e.getX()+10+"px",t.style.top=e.getY()+10+"px";let i=B(o,3).toString();void 0!==n.getPixelUnit()&&(i+=" "+n.getPixelUnit()),t.appendChild(document.createTextNode(i)),this.#vr=t,this.#jt.appendChild(t)}}removeTooltipDiv(){void 0!==this.#vr&&(this.#vr.remove(),this.#vr=void 0)}isPositionInBounds(e){return this.someViewLayer((function(t){return t.getViewController().isPositionInBounds(e)}))}canScroll(){return this.someViewLayer((function(e){return e.getViewController().canScroll()}))}moreThanOne(e){return this.someViewLayer((function(t){return t.getViewController().moreThanOne(e)}))}updateLayersToPositionChange=e=>{for(const e of this.#mr)void 0!==e&&(e.removeEventListener("positionchange",this.updateLayersToPositionChange),e.removeEventListener("positionchange",this.#Re));const t=new s(e.value[0]),n=new E(e.value[1]);this.#Ne=n,this.#Cr&&this.#Tr(n);const i={};let r,o;for(const a of this.#mr){if(void 0===a)continue;let s=!1;if(a instanceof Xi){const e=a.getViewController(),t=e.getOrigin(),l=e.getOrigin(n);let c,u;if(void 0===o)r=t,o=l,c=new P(0,0,0),u=new P(0,0,0);else if(e.isPositionInBounds(n)&&void 0!==l){const e=r.minus(t);c=new P(e.getX(),e.getY(),e.getZ());const n=o.minus(l);u=new P(n.getX(),n.getY(),n.getZ())}void 0!==c&&void 0!==u&&(s=a.setBaseOffset(c,u,o,r),i[a.getId()]={scroll:c,plane:u})}if(a instanceof Ci){const e=i[a.getReferenceLayerId()];void 0!==e&&(s=a.setBaseOffset(e.scroll,e.plane))}let l=!1;a.getId()!==e.srclayerid&&(l=a.setCurrentPosition(n,t)),!l&&s&&a.draw()}for(const e of this.#mr)void 0!==e&&(e.addEventListener("positionchange",this.updateLayersToPositionChange),e.addEventListener("positionchange",this.#Re))};getDivToWorldSizeRatio(){if(0===this.#jt.offsetWidth&&0===this.#jt.offsetHeight)throw new Error("Cannot fit to zero sized container.");const e=this.getMaxWorldSize();if(void 0!==e){if(0===this.#jt.offsetHeight){const t=this.#jt.offsetWidth/e.x,n=e.y*t;this.#jt.style.height=n+"px"}return Math.min(this.#jt.offsetWidth/e.x,this.#jt.offsetHeight/e.y)}}fitToContainer(e){const t=this.getMaxWorldSize();if(void 0===t)return;const n={x:this.#jt.offsetWidth,y:this.#jt.offsetHeight},i={x:-.5*(n.x-Math.floor(t.x*e)),y:-.5*(n.y-Math.floor(t.y*e))};for(const t of this.#mr)void 0!==t&&t.fitToContainer(n,e,i);this.#Cr&&this.#Tr()}getMaxWorldSize(){let e={x:0,y:0};for(const t of this.#mr)if(t instanceof Xi){const n=t.getImageWorldSize();n.x>e.x&&(e.x=n.x),n.y>e.y&&(e.y=n.y)}return 0===e.x&&0===e.y&&(e=void 0),e}flipScaleZ(){this.#gt.z*=-1,this.setScale(this.#gt)}addScale(e,t){const n={x:this.#rr.x*(1+e),y:this.#rr.y*(1+e),z:this.#rr.z*(1+e)};this.setScale(n,t)}setScale(e,t){this.#rr=e;for(const e of this.#mr)void 0!==e&&e.setScale(this.#rr,t);const n=[e.x,e.y,e.z];void 0!==t&&(n.push(t.getX()),n.push(t.getY()),n.push(t.getZ())),this.#Re({type:"zoomchange",value:n})}addTranslation(e){this.setOffset({x:this.#or.x-e.x,y:this.#or.y-e.y,z:this.#or.z-e.z})}setOffset(e){this.#or=e;for(const e of this.#mr)void 0!==e&&e.setOffset(this.#or);this.#Re({type:"offsetchange",value:[this.#or.x,this.#or.y,this.#or.z]})}reset(){this.setScale(this.#gt),this.setOffset({x:0,y:0,z:0})}draw(){for(const e of this.#mr)void 0!==e&&e.draw()}display(e){for(const t of this.#mr)void 0!==t&&t.display(e)}addEventListener(e,t){this.#Ae.add(e,t)}removeEventListener(e,t){this.#Ae.remove(e,t)}#Re=e=>{this.#Ae.fireEvent(e)}}const Ji={WindowLevelBinder:class{getEventType=function(){return"wlchange"};getCallback=function(e){return function(t){const n=e.getViewLayersByDataId(t.dataid);if(0!==n.length){const e=n[0].getViewController();if(2===t.value.length){const n=new u(t.value[0],t.value[1]);e.setWindowLevel(n)}3===t.value.length&&e.setWindowLevelPreset(t.value[2])}}}},PositionBinder:class{getEventType=function(){return"positionchange"};getCallback=function(e){return function(t){const n=t.value[1],i=e.getActiveViewLayer().getViewController(),r=i.getCurrentPosition(),o=r.length(),a=n.length;a!==o&&(a===o-1?n.push(r.get(o-1)):a===o+1&&n.pop()),i.setCurrentPosition(new E(n))}}},ZoomBinder:class{getEventType=function(){return"zoomchange"};getCallback=function(e){return function(t){const n={x:t.value[0],y:t.value[1],z:t.value[2]};let i;6===t.value.length&&(i=new F(t.value[3],t.value[4],t.value[5])),e.setScale(n,i),e.draw()}}},OffsetBinder:class{getEventType=function(){return"offsetchange"};getCallback=function(e){return function(t){e.setOffset({x:t.value[0],y:t.value[1],z:t.value[2]}),e.draw()}}},OpacityBinder:class{getEventType=function(){return"opacitychange"};getCallback=function(e){return function(t){if(void 0===t.dataid)return;const n=e.getViewLayersByDataId(t.dataid),i=e.getBaseViewLayer();0!==n.length&&i!==n[0]&&(n[0].setOpacity(t.value),n[0].draw())}}},ColourMapBinder:class{getEventType=function(){return"colourmapchange"};getCallback=function(e){return function(t){const n=e.getViewLayersByDataId(t.dataid);0!==n.length&&n[0].getViewController().setColourMap(t.value[0])}}}};class $i{#xr=[];#Rr;#sr=!1;#Fr=[];#ni=null;getLayerGroup(e){return this.#xr[e]}getNumberOfLayerGroups(){return this.#xr.length}getActiveLayerGroup(){return this.getLayerGroup(this.#Rr)}setActiveLayerGroup(e){void 0!==this.getLayerGroup(e)?this.#Rr=e:c.warn("No layer group to set as active with index: "+e)}getViewLayersByDataId(e){let t=[];for(let n=0;nt===e));if(-1===t)throw new Error("Cannot find layerGroup to remove");this.unbindLayerGroups(),e.empty(),this.#xr.splice(t,1),this.#Rr===t&&(this.#Rr=void 0),this.bindLayerGroups()}reset(){for(let e=0;e{this.#qr(t,e),e.getCallback(this.#xr[t])(n),this.#Er(t,e)}},this.#ni[t].push(n)),n.callback}#Er(e,t){for(let n=0;n0&&(--this.#kr,this.#Gr[this.#kr].undo(),this.#Re({type:"undo",command:this.#Gr[this.#kr].getName()}))}redo(){this.#kr{this.#Ae.fireEvent(e)}}class lr{#Hr;#zr=null;#ni=[];#Wr={};constructor(e){this.#Hr=e}init(){for(const e in this.#Hr)this.#Hr[e].init();this.enableShortcuts(!0)}enableShortcuts(e){e?window.addEventListener("keydown",this.#Yr("window","keydown"),!0):window.removeEventListener("keydown",this.#Yr("window","keydown"),!0)}getToolList(){return this.#Hr}hasTool(e){return void 0!==this.getToolList()[e]}getSelectedTool(){return this.#zr}getSelectedToolEventHandler(e){return this.getSelectedTool()[e]}setSelectedTool(e){if(!this.hasTool(e))throw new Error("Unknown tool: '"+e+"'");this.#zr&&this.#zr.activate(!1),this.#zr=this.#Hr[e],this.#zr.activate(!0)}setToolFeatures(e){this.getSelectedTool()&&this.getSelectedTool().setFeatures(e)}bindLayerGroup(e,t){const n=e.getDivId();e.addEventListener("activelayerchange",this.#Xr(n)),this.#jr(n,t)}#jr(e,t){void 0!==this.#Wr[e]&&this.#Zr(this.#Wr[e]),this.#Wr[e]=t,this.#_r(t)}#Xr(e){return t=>{const n=t.value[0];void 0!==n&&this.#jr(e,n)}}#_r(e){e.bindInteraction();const t=Gi;for(let n=0;n{if(this.#zr){const t=this.#zr[e.type];t&&t(e)}};this.#ni[e][t]=n}return this.#ni[e][t]}}class cr{#Kr=[];#Jr=2;#$r;constructor(e){this.#$r=e}setNumberOfDimensions(e){this.#Jr=e}setNToLoad(e){for(let t=0;t{if(!e.lengthComputable)return;if(void 0===e.subindex)return;if(void 0===e.index)return;const t=100*e.loaded/e.total;this.#Kr[e.index][e.subindex]=t;let n=null;n=void 0!==e.item?e.item:{loaded:this.#eo(e.index),total:100,source:e.source},this.#$r({lengthComputable:!0,loaded:this.#to(),total:100,item:n})};#eo(e){let t=0;for(let n=0;n{n.index=e,n.subindex=t,this.onprogress(n)}}getUndefinedMonoProgressHandler(e){return t=>{t.subindex=e,this.onprogress(t)}}}class ur{#no=null;#io=[];#ro=null;#oo=0;#ao=0;#so;#F;getDefaultCharacterSet(){return this.#F}setDefaultCharacterSet(e){this.#F=e}#lo(e){this.#no=e,this.#oo=0,this.#ao=0,this.#so=!1,this.#co(),this.#uo()}#do(e){this.#io.push(e)}#co(){this.#io=[]}#ho(e){this.#ro=e}#uo(){this.#ro=null}#So=e=>{this.#oo++,this.#oo===this.#no.length&&this.onload({source:this.#no})};#go=e=>{this.#ao++,this.#ao===this.#no.length&&this.onloadend({source:this.#no})};#po(e,t){return n=>{n.source=t,e(n)}}load(e,t){this.onloadstart({source:e}),1===e.length&&(M(e[0],"DICOMDIR")||M(e[0],".dcmdir"))?this.#mo(e[0],t):this.#fo(e,t)}#Do(e,t,n){return i=>{const r=i.target.status;200!==r&&0!==r?(this.onerror({source:t,error:"GET "+i.target.responseURL+" "+i.target.status+" ("+i.target.statusText+")",target:i.target}),this.#go()):e.load(i.target.response,t,n)}}#fo(e,t){if(void 0===e||0===e.length)return;this.#lo(e);const n=new cr(this.onprogress);n.setNToLoad(e.length);const i=[];for(let e=0;e{s{this.#go(),s(e)};const c=this.#po(this.onabort,r);a.onabort=e=>{this.#go(),c(e)},1===o.loadUrlAs()&&(a.responseType="arraybuffer"),this.#do(a)}let c=this.#io.length;void 0!==t&&void 0!==t.batchSize&&0!==c&&(c=Math.min(t.batchSize,this.#io.length));for(let e=0;e{const i=n.target.status;if(200!==i&&0!==i)this.onerror({source:e,error:"GET "+n.target.responseURL+" "+n.target.status+" ("+n.target.statusText+")",target:n.target}),this.onloadend({});else{const i=function(e){const t=new Ge;t.parse(e);const n=t.getDicomElements();if(void 0===n["00041220"]||void 0===n["00041220"].value)return void c.warn("No Directory Record Sequence found in DICOMDIR.");const i=n["00041220"].value;if(0===i.length)return void c.warn("The Directory Record Sequence of the DICOMDIR is empty.");const r=[];let o=null,a=null;for(let e=0;e{this.#po(this.onerror,e)(t),this.onloadend({})},n.onabort=t=>{this.#po(this.onabort,e)(t),this.onloadend({})},n.send(null)}abort(){this.#so=!0;for(let e=0;e0){const t=this.freeThreads.shift();this.runningThreads.push(t),t.run(e)}else this.taskQueue.push(e)}abort(){this.#Co(),this.onabort({type:"work-abort"}),this.onworkend({type:"work-end"})}onTaskEnd(e){if(this.taskQueue.length>0){const t=this.taskQueue.shift();e.run(t)}else{e.stop(),this.freeThreads.push(e);for(let t=0;t{this.#Co(),this.onerror({error:e}),this.onworkend({type:"work-end"})};#Co(){this.taskQueue=[];for(let e=0;e{e.itemNumber=this.runningTask.info.itemNumber,e.numberOfItems=this.runningTask.info.numberOfItems,e.index=this.runningTask.info.index,this.parentPool.onworkitem(e),this.parentPool.onTaskEnd(this)};onerror=e=>{e.itemNumber=this.runningTask.info.itemNumber,e.numberOfItems=this.runningTask.info.numberOfItems,e.index=this.runningTask.info.index,this.parentPool.handleWorkerError(e),this.stop()}}class Sr{constructor(e,t,n){this.script=e,this.startMessage=t,this.info=n}}const gr="undefined"!=typeof JpegImage,pr="undefined"!=typeof jpeg&&void 0!==jpeg.lossless,mr="undefined"!=typeof JpxImage,fr={jpeg2000:"","jpeg-lossless":"","jpeg-baseline":"",rle:""};class Dr{#yo;#vo=new dr(10);#Io=!1;constructor(e,t){this.#yo=e}decode(e,t,n){this.#Io||(this.#Io=!0,this.#vo.onworkstart=this.ondecodestart,this.#vo.onworkitem=this.ondecodeditem,this.#vo.onwork=this.ondecoded,this.#vo.onworkend=this.ondecodeend,this.#vo.onerror=this.onerror,this.#vo.onabort=this.onabort);const i=new Sr(this.#yo,{buffer:e,meta:t},n);this.#vo.addWorkerTask(i)}abort(){this.#vo.abort()}ondecodestart(e){}ondecodeditem(e){}ondecoded(e){}ondecodeend(e){}onerror(e){}onabort(e){}}class Cr{#To;#Lo;constructor(e,t){this.#To=e,this.#Lo=t}#Po=0;decode(e,t,n){++this.#Po;let i=null,r=null;if("jpeg-lossless"===this.#To){if(!pr)throw new Error("No JPEG Lossless decoder provided");const n=t.bitsAllocated/8,o=new Uint8Array(e);i=new jpeg.lossless.Decoder;const a=i.decode(o.buffer,0,o.buffer.byteLength,n);8===t.bitsAllocated?r=t.isSigned?new Int8Array(a.buffer):new Uint8Array(a.buffer):16===t.bitsAllocated&&(r=t.isSigned?new Int16Array(a.buffer):new Uint16Array(a.buffer))}else if("jpeg-baseline"===this.#To){if(!gr)throw new Error("No JPEG Baseline decoder provided");i=new JpegImage,i.parse(e),r=i.getData(i.width,i.height)}else if("jpeg2000"===this.#To){if(!mr)throw new Error("No JPEG 2000 decoder provided");i=new JpxImage,i.parse(e),r=i.tiles[0].items}else"rle"===this.#To&&(i=new dwvdecoder.RleDecoder,r=i.decode(e,t.bitsAllocated,t.isSigned,t.sliceSize,t.samplesPerPixel,t.planarConfiguration));this.ondecodeditem({data:[r],index:n.index,numberOfItems:n.numberOfItems,itemNumber:n.itemNumber}),this.#Po===this.#Lo&&(this.ondecoded({}),this.ondecodeend({}))}abort(){this.onabort({}),this.ondecodeend({})}ondecodestart(e){}ondecodeditem(e){}ondecoded(e){}ondecodeend(e){}onerror(e){}onabort(e){}}class yr{#Io=!1;#wo=null;constructor(e,t){void 0!==fr&&void 0!==fr[e]?this.#wo=new Dr(fr[e],t):this.#wo=new Cr(e,t)}decode(e,t,n){this.#Io||(this.#Io=!0,this.#wo.ondecodestart=this.ondecodestart,this.#wo.ondecodeditem=this.ondecodeditem,this.#wo.ondecoded=this.ondecoded,this.#wo.ondecodeend=this.ondecodeend,this.#wo.onerror=this.onerror,this.#wo.onabort=this.onabort),this.#wo.decode(e,t,n)}abort(){this.#wo.abort()}ondecodestart(e){}ondecodeditem(e){}ondecoded(e){}ondecodeend(e){}onerror(e){}onabort(e){}}const vr={NumericValue:"0040A30A",FloatingPointValue:"0040A161",RationalNumeratorValue:"0040A162",RationalDenominatorValue:"0040A163",MeasurementUnitsCodeSequence:"004008EA"};class Ir{numericValue;floatingPointValue;rationalNumeratorValue;rationalDenominatorValue;measurementUnitsCode;toString(){return this.numericValue+" "+this.measurementUnitsCode.toString()}}function Tr(e){const t={};return void 0!==e.measurementUnitsCode&&(t.MeasurementUnitsCodeSequence={value:[Wt(e.measurementUnitsCode)]}),void 0!==e.floatingPointValue&&(t.FloatingPointValue=e.floatingPointValue),void 0!==e.rationalNumeratorValue&&(t.RationalNumeratorValue=e.rationalNumeratorValue),void 0!==e.rationalDenominatorValue&&(t.RationalDenominatorValue=e.rationalDenominatorValue),void 0!==e.numericValue&&(t.NumericValue=e.numericValue),t}const Lr={MeasuredValueSequence:"0040A300",NumericValueQualifierCodeSequence:"0040A301"};class Pr{measuredValue;numericValueQualifierCode;toString(){let e=this.measuredValue.toString();return void 0!==this.numericValueQualifierCode&&(e+=" "+this.numericValueQualifierCode.toString()),e}}function wr(e){const t={};return void 0!==e.measuredValue&&(t.MeasuredValueSequence={value:[Tr(e.measuredValue)]}),void 0!==e.numericValueQualifierCode&&(t.NumericValueQualifierCodeSequence={value:[Wt(e.numericValueQualifierCode)]}),t}const Or={ReferencedSOPClassUID:"00081150",ReferencedSOPInstanceUID:"00081155"};class Ar{referencedSOPClassUID;referencedSOPInstanceUID;toString(){return this.referencedSOPInstanceUID+" (class: "+this.referencedSOPClassUID+")"}}function br(e){const t=new Ar;return void 0!==e[Or.ReferencedSOPClassUID]&&(t.referencedSOPClassUID=e[Or.ReferencedSOPClassUID].value[0]),void 0!==e[Or.ReferencedSOPInstanceUID]&&(t.referencedSOPInstanceUID=e[Or.ReferencedSOPInstanceUID].value[0]),t}function xr(e){const t={};return void 0!==e.referencedSOPClassUID&&(t.ReferencedSOPClassUID=e.referencedSOPClassUID),void 0!==e.referencedSOPInstanceUID&&(t.ReferencedSOPInstanceUID=e.referencedSOPInstanceUID),t}const Rr={ReferencedFrameNumber:"00081160",ReferencedSOPSequence:"00081199",ReferencedSegmentNumber:"0062000B"};class Fr{referencedSOPSequence;referencedFrameNumber;referencedSegmentNumber;fiducialUID;toString(){return this.referencedSOPSequence.toString()}}function Er(e){const t={};return void 0!==e.referencedFrameNumber&&(t.ReferencedFrameNumber=e.referencedFrameNumber),void 0!==e.referencedSOPSequence&&(t.ReferencedSOPSequence={value:[xr(e.referencedSOPSequence)]}),void 0!==e.referencedSegmentNumber&&(t.ReferencedSegmentNumber=e.referencedSegmentNumber),t}const qr={PixelOriginInterpretation:"00480301",GraphicData:"00700022",GraphicType:"00700023",FiducialUID:"0070031A"},Ur="POINT",Mr="MULTIPOINT",Qr="POLYLINE",Vr="CIRCLE",Nr="ELLIPSE";class Br{graphicData;graphicType;pixelOriginInterpretation;fiducialUID;toString(){return this.graphicType+" {"+this.graphicData+"}"}}function Gr(e){const t={};return void 0!==e.pixelOriginInterpretation&&(t.PixelOriginInterpretation=e.pixelOriginInterpretation),void 0!==e.graphicData&&(t.GraphicData=e.graphicData),void 0!==e.graphicType&&(t.GraphicType=e.graphicType),void 0!==e.fiducialUID&&(t.FiducialUID=e.fiducialUID),t}const kr={GraphicData:"00700022",GraphicType:"00700023",ReferencedFrameofReferenceUID:"30060024",FiducialUID:"0070031A"};class Hr{graphicData;graphicType;referencedFrameofReferenceUID;fiducialUID;toString(){return this.graphicType+"{"+this.graphicData+"}"}}function zr(e){const t={};return void 0!==e.graphicData&&(t.GraphicData=e.graphicData),void 0!==e.graphicType&&(t.GraphicType=e.graphicType),void 0!==e.referencedFrameofReferenceUID&&(t.ReferencedFrameofReferenceUID=e.referencedFrameofReferenceUID),void 0!==e.fiducialUID&&(t.FiducialUID=e.fiducialUID),t}const Wr={ReferencedSOPSequence:"00081199",RelationshipType:"0040A010",ValueType:"0040A040",ConceptNameCodeSequence:"0040A043",ConceptCodeSequence:"0040A168",ContentSequence:"0040A730",DateTime:"0040A120",Date:"0040A121",Time:"0040A122",UID:"0040A124",PersonName:"0040A123",TextValue:"0040A160",ContinuityOfContent:"0040A050"},Yr="CONTAINS",Xr="HAS PROPERTIES",jr="SELECTED FROM",Zr={text:"TEXT",num:"NUM",code:"CODE",date:"DATE",time:"TIME",datetime:"DATETIME",uidref:"UIDREF",pname:"PNAME",composite:"COMPOSITE",image:"IMAGE",waveform:"WAVEFORM",scoord:"SCOORD",scoord3d:"SCOORD3D",tcoord:"TCOORD",container:"CONTAINER",table:"TABLE"},_r={TEXT:"TextValue",DATE:"Date",TIME:"Time",DATETIME:"DateTime",UIDREF:"UID",PNAME:"PersonName",CONTAINER:"ContinuityOfContent"};class Kr{valueType;conceptNameCode;relationshipType;contentSequence;value;constructor(e){this.valueType=e}toString(e){void 0===e&&(e="");let t="";if(void 0!==this.relationshipType&&(t+="("+this.relationshipType+") "),t+=this.valueType+": ",void 0!==this.conceptNameCode&&(t+=this.conceptNameCode.toString()),t+=" = "+this.value.toString(),void 0!==this.contentSequence)for(const n of this.contentSequence)t+="\n"+e+"- "+n.toString(e+" ");return t}}function Jr(e){let t="";void 0!==e[Wr.ValueType]&&(t=e[Wr.ValueType].value[0]);const n=new Kr(t);if(void 0!==e[Wr.RelationshipType]&&(n.relationshipType=e[Wr.RelationshipType].value[0]),void 0!==e[Wr.ConceptNameCodeSequence]&&(n.conceptNameCode=zt(e[Wr.ConceptNameCodeSequence].value[0])),t===Zr.code)n.value=zt(e[Wr.ConceptCodeSequence].value[0]);else if(t===Zr.num)n.value=function(e){const t=new Pr;return void 0!==e[Lr.MeasuredValueSequence]&&(t.measuredValue=function(e){const t=new Ir;return void 0!==e[vr.NumericValue]&&(t.numericValue=e[vr.NumericValue].value[0]),void 0!==e[vr.FloatingPointValue]&&(t.floatingPointValue=e[vr.FloatingPointValue].value[0]),void 0!==e[vr.RationalNumeratorValue]&&(t.rationalNumeratorValue=e[vr.RationalNumeratorValue].value[0]),void 0!==e[vr.RationalDenominatorValue]&&(t.rationalDenominatorValue=e[vr.RationalDenominatorValue].value[0]),void 0!==e[vr.MeasurementUnitsCodeSequence]&&(t.measurementUnitsCode=zt(e[vr.MeasurementUnitsCodeSequence].value[0])),t}(e[Lr.MeasuredValueSequence].value[0])),void 0!==e[Lr.NumericValueQualifierCodeSequence]&&(t.numericValueQualifierCode=zt(e[Lr.NumericValueQualifierCodeSequence].value[0])),t}(e);else if(t===Zr.image)n.value=function(e){const t=new Fr;return void 0!==e[Rr.ReferencedFrameNumber]&&(t.referencedFrameNumber=e[Rr.ReferencedFrameNumber].value[0]),void 0!==e[Rr.ReferencedSOPSequence]&&(t.referencedSOPSequence=br(e[Rr.ReferencedSOPSequence].value[0])),void 0!==e[Rr.ReferencedSegmentNumber]&&(t.referencedSegmentNumber=e[Rr.ReferencedSegmentNumber].value[0]),t}(e);else if(t===Zr.composite)n.value=br(e[Wr.ReferencedSOPSequence].value[0]);else if(t===Zr.scoord)n.value=function(e){const t=new Br;return void 0!==e[qr.GraphicData]&&(t.graphicData=e[qr.GraphicData].value),void 0!==e[qr.GraphicType]&&(t.graphicType=e[qr.GraphicType].value[0]),void 0!==e[qr.PixelOriginInterpretation]&&(t.pixelOriginInterpretation=e[qr.PixelOriginInterpretation].value[0]),void 0!==e[qr.FiducialUID]&&(t.fiducialUID=e[qr.FiducialUID].value[0]),t}(e);else if(t===Zr.scoord3d)n.value=function(e){const t=new Hr;return void 0!==e[kr.GraphicData]&&(t.graphicData=e[kr.GraphicData].value),void 0!==e[kr.GraphicType]&&(t.graphicType=e[kr.GraphicType].value[0]),void 0!==e[kr.ReferencedFrameofReferenceUID]&&(t.referencedFrameofReferenceUID=e[kr.ReferencedFrameofReferenceUID].value[0]),void 0!==e[kr.FiducialUID]&&(t.fiducialUID=e[kr.FiducialUID].value[0]),t}(e);else{const i=_r[t];void 0!==i?n.value=e[Wr[i]].value[0]:console.warn("Unsupported input ValueType: "+t)}if(void 0!==e[Wr.ContentSequence]){n.contentSequence=[];for(const t of e[Wr.ContentSequence].value)n.contentSequence.push(Jr(t))}return n}function $r(e){let t={};if(void 0!==e.relationshipType&&(t.RelationshipType=e.relationshipType),void 0!==e.valueType&&(t.ValueType=e.valueType),void 0!==e.conceptNameCode&&(t.ConceptNameCodeSequence={value:[Wt(e.conceptNameCode)]}),"CODE"===e.valueType)t.ConceptCodeSequence={value:[Wt(e.value)]};else if(e.valueType===Zr.num)t={...t,...wr(e.value)};else if(e.valueType===Zr.image)t={...t,...Er(e.value)};else if(e.valueType===Zr.composite)t={...t,...xr(e.value)};else if(e.valueType===Zr.scoord)t={...t,...Gr(e.value)};else if(e.valueType===Zr.scoord3d)t={...t,...zr(e.value)};else{const n=_r[e.valueType];void 0!==n?t[n]=e.value:console.warn("Unsupported output ValueType: "+e.valueType)}if(void 0!==e.contentSequence){t.ContentSequence={value:[]};for(const n of e.contentSequence)t.ContentSequence.value.push($r(n))}return t}function eo(e,t,n){const i=function(e){const t=rn[e];let n;return void 0!==t&&(n=Zt(t.key,t.scheme)),n}(e);if(void 0===i)return;const r=new Kr(Zr.num);r.relationshipType=Yr,r.conceptNameCode=i;const o=new Ir;o.numericValue=t,o.measurementUnitsCode=function(e){const t=an[e];let n;return void 0!==t?n=Zt(t,"UCUM"):void 0===t&&(n=Zt("1","UCUM")),n}(n);const a=new Pr;return a.measuredValue=o,r.value=a,r}class to{#$;getWarning(){return this.#$}checkElements(e){this.#$=void 0;const t=Jr(e);return void 0!==t.conceptNameCode?t.conceptNameCode.value!==_t().value&&(this.#$="Not a measurement group"):this.#$="No root concept name code",this.#$}#Oo(e){const t=new Bi;t.mathShape=function(e){const t=e.graphicData.length;if(t%2!=0)throw new Error("Expecting even number of coordinates in scroord data");const n=[];for(let i=0;i2){const e=n[0],t=n[r-1];i=e.equals(t)}let o;if(e.graphicType===Ur){if(1!==n.length)throw new Error("Expecting 1 point for point");o=n[0]}else if(e.graphicType===Vr){if(2!==n.length)throw new Error("Expecting 2 points for circles");const e=n[0],t=n[1].getDistance(e);o=new pi(e,t)}else if(e.graphicType===Nr){if(4!==n.length)throw new Error("Expecting 4 points for ellipses");const e=n[0].getDistance(n[1])/2,t=n[2].getDistance(n[3])/2,i=new R(n[0].getX()+e,n[0].getY());o=new Si(i,e,t)}else if(e.graphicType===Qr)if(i)if(5===n.length){const e=new zn(n[0],n[1]),t=new zn(n[1],n[2]),i=new zn(n[2],n[3]),r=new zn(n[3],n[4]);o=Yn(e,t)&&Yn(t,i)&&Yn(i,r)?new ci(n[0],n[2]):new di(n.slice(0,-1))}else o=new di(n.slice(0,-1));else 2===n.length?o=new zn(n[0],n[1]):3===n.length&&(o=new hi([n[0],n[1],n[2]]));return o}(e.value),t.id=$e(),t.textExpr="";for(const n of e.contentSequence){if(n.valueType===Zr.image&&n.relationshipType===jr&&Ht(n.conceptNameCode,Jt())&&(t.referenceSopUID=n.value.referencedSOPSequence.referencedSOPInstanceUID),n.valueType===Zr.uidref&&n.relationshipType===Xr&&Ht(n.conceptNameCode,$t())&&(t.id=n.value),n.valueType===Zr.text&&n.relationshipType===Xr&&Ht(n.conceptNameCode,en())&&(t.textExpr=n.value,void 0!==n.contentSequence))for(const e of n.contentSequence)e.valueType===Zr.scoord&&e.relationshipType===Xr&&Ht(e.conceptNameCode,tn())&&(t.labelPosition=new R(e.value.graphicData[0],e.value.graphicData[1]));if(n.valueType===Zr.text&&n.relationshipType===Xr&&Ht(n.conceptNameCode,nn())&&(t.colour=n.value),n.valueType===Zr.scoord&&n.relationshipType===Xr&&Ht(n.conceptNameCode,tn())&&n.value.graphicType===Mr){const e=[];for(let t=0;t{this.#Ae.fireEvent(e)};#Ro(e){return t=>{t.dataid=e,this.#Re(t)}}}class ro{#Fo;setOptions(e){this.#Fo=e}#wo=null;#Eo=[];#qo=[];#Uo=[];#Mo=[];#Qo(e){let t;const n=e["00080060"];if(void 0!==n){const e=n.value[0];"SEG"===e?t=new Fn:"SR"===e&&(t=new to)}return void 0===t&&void 0!==e["7FE00010"]&&(t=new Pt),t}#Vo(e,t){const n=this.#Eo[e].getDicomElements(),i=this.#Mo[e];if(void 0!==i)try{const r=new no(n);i instanceof to?r.annotationGroup=i.create(n):r.image=i.create(n,this.#qo[e],this.#Fo.numberOfFiles),this.onloaditem({data:r,source:t,warn:i.getWarning()})}catch(e){this.onerror({error:e,source:t}),this.onloadend({source:t})}}#No(e,t){this.onprogress({lengthComputable:!0,loaded:100,total:100,index:e,source:t}),this.#Vo(e,t),this.onload({source:t}),this.onloadend({source:t})}#Bo(e,t,n){const i=this.#Eo[e],r={bitsAllocated:i.getDicomElements()["00280100"].value[0],isSigned:1===i.getDicomElements()["00280103"].value[0]},o=i.getDicomElements()["00280011"],a=i.getDicomElements()["00280010"];void 0!==o&&void 0!==a&&(r.sliceSize=o.value[0]*a.value[0]);const s=i.getDicomElements()["00280002"];void 0!==s&&(r.samplesPerPixel=s.value[0]);const l=i.getDicomElements()["00280006"];void 0!==l&&(r.planarConfiguration=l.value[0]);const c=t.length;null===this.#wo&&(this.#wo=new yr(n,c),this.#wo.ondecodeditem=e=>{this.#Go(e),e.itemNumber+1===e.numberOfItems&&(this.onload(e),this.onloadend(e))},this.#wo.onerror=this.onerror,this.#wo.onabort=this.onabort);for(let n=0;n2^"+e+") for decompressed data.")}return this.#wo.abort(),this.onerror({error:e,source:origin}),void this.onloadend({source:origin})}}n.length!==this.#Uo[t]&&c.warn("Unsupported varying decompressed data size: "+n.length+" != "+this.#Uo[t]),this.#qo[t].set(n,this.#Uo[t]*e.itemNumber)}else this.#qo[t]=n;0===e.itemNumber&&this.#Vo(t,origin)}#ko(e,t){this.#Vo(e,t),this.onload({source:t}),this.onloadend({source:t})}#Ho(e,t){const n=this.#Eo[e],i=n.getDicomElements()["7FE00010"].value;n.getDicomElements()["7FE00010"].value=[],this.#qo[e]=i[0];const r=function(e){let t;return Ee(e)?t="jpeg2000":Re(e)?t="jpeg-baseline":Fe(e)?t="jpeg-lossless":qe(e)&&(t="rle"),t}(n.getDicomElements()["00020010"].value[0]);void 0!==r?this.#Bo(e,i,r):this.#No(e,t)}convert(e,t,n){this.onloadstart({source:t,index:n});const i=new Ge;let r;void 0!==this.#Fo.defaultCharacterSet&&i.setDefaultCharacterSet(this.#Fo.defaultCharacterSet);try{i.parse(e),r=this.#Qo(i.getDicomElements()),void 0!==r&&r.checkElements(i.getDicomElements())}catch(e){return this.onerror({error:e,source:t}),void this.onloadend({source:t})}this.#Eo[n]=i,this.#Mo[n]=r,r instanceof to?this.#ko(n,t):this.#Ho(n,t)}abort(){this.#wo&&this.#wo.abort()}onloadstart(e){}onloaditem(e){}onprogress(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}}class oo{#no=null;#ro=null;#oo=0;#ao=0;#F;getDefaultCharacterSet(){return this.#F}setDefaultCharacterSet(e){this.#F=e}#lo(e){this.#no=e,this.#oo=0,this.#ao=0,this.#uo()}#ho(e){this.#ro=e}#uo(){this.#ro=null}#So=e=>{this.#oo++,this.#oo===this.#no.length&&this.onload({source:this.#no})};#go=e=>{this.#ao++,this.#ao===this.#no.length&&this.onloadend({source:this.#no})};load(e){if(void 0===e||0===e.length)return;this.#lo(e),this.onloadstart({source:e});const t=new cr(this.onprogress);t.setNToLoad(e.length),t.setNumberOfDimensions(1);const n=[];for(let e=0;e{this.#zo=!1,this.onloadend(e)},this.#Wo.onerror=e=>{e.source=t,this.onerror(e)},this.#Wo.onabort=this.onabort),this.#zo=!0,this.#Wo.convert(e,t,n)}abort(){this.#zo=!1,this.#Wo.abort()}canLoadFile(e){const t=V(e.name);return null===t||"dcm"===t}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"dicom"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n){const e="application/dicom";return U(n.value,e)&&"+"!==n.value[e.length]}}}const n=or(e),i=V(n.pathname),r=null===i,o="dcm"===i,a=n.searchParams.get("contentType");return null!=a?"application/dicom"===a:r||o}canLoadMemory(e){const t=e["Content-Type"];if(void 0!==t&&t.startsWith("application/dicom"))return!0;if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ho.ArrayBuffer}loadUrlAs(){return 1}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}},class{#zo=!1;setOptions(e){}isLoading(){return this.#zo}load(e,t,n){this.#zo=!0,this.onloadstart({source:t});try{this.onprogress({lengthComputable:!0,loaded:100,total:100,index:n,source:t});const i={data:e,source:t};this.onloaditem(i),this.onload(i)}catch(e){this.onerror({error:e,source:t})}finally{this.#zo=!1,this.onloadend({source:t})}}abort(){this.#zo=!1,this.onabort({}),this.onloadend({})}canLoadFile(e){return"json"===V(e.name)}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"json"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n)return U(n.value,"application/json")||U(n.value,"application/dicom+json")}}return"json"===V(or(e).pathname)}canLoadMemory(e){const t=e["Content-Type"];if(void 0!==t&&t.startsWith("application/json"))return!0;if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ho.Text}loadUrlAs(){return 0}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}},class{#zo=!1;setOptions(e){}isLoading(){return this.#zo}load(e,t,n){this.onloadstart({source:t}),this.#zo=!0;const i=new oo;i.onprogress=e=>{e.loaded=50+e.loaded/2,e.index=n,this.onprogress(e)},i.onloaditem=this.onloaditem,i.onload=this.onload,i.onloadend=e=>{this.#zo=!1,this.onloadend(e)},i.onerror=this.onerror,i.onabort=this.onabort,i.load(function(e){const t=new Uint8Array(e),n=[];if(0===t.length)return n;const i=Y(new Uint8Array([13,10,13,10]));let r=W(t,i,0);if(void 0===r)throw new Error("Can't find the end of the first multipart header");const o=z(t.slice(0,r)).split("\r\n");let a;for(let e=0;e{try{if(!this.#Yo){this.onprogress({lengthComputable:!0,loaded:100,total:100,index:n,source:t});const e=function(e,t,n){const i=e.width,r=e.height,o=document.createElement("canvas");o.width=i,o.height=r;const a=o.getContext("2d");a.drawImage(e,0,0);const s=a.getImageData(0,0,i,r),l={};"string"==typeof t?l.origin={value:t}:(l.fileName={value:t.name},l.fileType={value:t.type},l.fileLastModifiedDate={value:t.lastModified}),l.imageWidth={value:i},l.imageHeight={value:r};const c=n||0;return l.imageUid={value:c},{data:{image:so(i,r,c,ao(s),1,c.toString()),info:l},source:t}}(i,t,n);this.onloaditem(e),this.onload(e)}}catch(e){this.onerror({error:e,source:t})}finally{this.onloadend({source:t})}},"string"==typeof e)i.src=e;else if("string"==typeof t){const n=t.split(".").pop().toLowerCase();i.src=this.#Xo(e,n)}}abort(){this.#Yo=!0,this.onabort({}),this.onloadend({})}canLoadFile(e){return void 0!==e.type&&null!==e.type.match("image.*")}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"rawimage"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n)return U(n.value,"image/")}}const n=or(e),i=V(n.pathname),r="jpeg"===i||"jpg"===i||"png"===i||"gif"===i,o=n.searchParams.get("contentType");return null!=o?"image/jpeg"===o||"image/png"===o||"image/gif"===o:r}canLoadMemory(e){if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ho.DataURL}loadUrlAs(){return 1}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}},class{setOptions(e){}isLoading(){return!0}#Xo(e,t){const n=new Uint8Array(e);let i="";for(let e=0;e{try{!function(e,t,n,i,r,o,a){const s=e.videoWidth,l=e.videoHeight,c=Math.ceil(30*e.duration),u={};"string"==typeof o?u.origin={value:o}:(u.fileName={value:o.name},u.fileType={value:o.type},u.fileLastModifiedDate={value:o.lastModified}),u.imageWidth={value:s},u.imageHeight={value:l},u.numberOfFrames={value:c},u.imageUid={value:0};const d=document.createElement("canvas");d.width=s,d.height=l;const h=d.getContext("2d");e.addEventListener("seeked",(function d(m){(function(){i({lengthComputable:!0,loaded:S,total:c,index:a,source:o}),h.drawImage(e,0,0);const n=ao(h.getImageData(0,0,s,l));0===S?(g=so(s,l,1,n,c,a.toString()),t({data:{image:g,info:u},source:o})):g.appendFrameBuffer(n,S),++S})(),p+=1/30,p<=m.target.duration?this.currentTime=p:(n({source:o}),r({source:o}),e.removeEventListener("seeked",d))}),!1);let S=0,g=null,p=0;e.currentTime=p}(e.target,this.onloaditem,this.onload,this.onprogress,this.onloadend,t,n)}catch(e){this.onerror({error:e,source:t}),this.onloadend({source:t})}}}abort(){this.onabort({}),this.onloadend({})}canLoadFile(e){return void 0!==e.type&&null!==e.type.match("video.*")}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"rawvideo"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n)return U(n.value,"video/")}}const n=V(or(e).pathname);return"mp4"===n||"ogg"===n||"webm"===n}canLoadMemory(e){if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ho.DataURL}loadUrlAs(){return 1}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}},class{#zo=!1;setOptions(e){}isLoading(){return this.#zo}#jo="";#Zo=[];#_o=null;#Ko(e,t,n){this.#Zo.push({filename:this.#jo,data:e});const i=100*this.#Zo.length/this.#_o.length;if(this.onprogress({lengthComputable:!0,loaded:i/2,total:100,index:n,item:{loaded:i,total:100,source:t}}),this.#Zo.length{this.#Ko(e,t,n)}))}else{const e=new oo;e.onprogress=e=>{e.loaded=50+e.loaded/2,e.index=n,this.onprogress(e)},e.onloaditem=this.onloaditem,e.onload=this.onload,e.onloadend=e=>{this.#zo=!1,this.onloadend(e)},e.onerror=this.onerror,e.onabort=this.onabort,e.load(this.#Zo)}}load(e,t,n){this.onloadstart({source:t}),this.#zo=!0,co().loadAsync(e).then((e=>{this.#Zo=[],this.#_o=e.file(/.*\.dcm/);const i=this.#Zo.length;this.#jo=this.#_o[i].name,this.#_o[i].async("arrayBuffer").then((e=>{this.#Ko(e,t,n)}))}))}abort(){this.#zo=!1,this.onabort({}),this.onloadend({})}canLoadFile(e){return"zip"===V(e.name)}canLoadUrl(e,t){if(void 0!==t){if(void 0!==t.forceLoader&&"zip"===t.forceLoader)return!0;if(void 0!==t.requestHeaders){const e=function(e){return"Accept"===e.name},n=t.requestHeaders.find(e);if(void 0!==n)return U(n.value,"application/zip")}}return"zip"===V(or(e).pathname)}canLoadMemory(e){const t=e["Content-Type"];if(void 0!==t&&t.startsWith("application/zip"))return!0;if(void 0!==e.filename){const t=new File(["from memory"],e.filename);return this.canLoadFile(t)}return!1}loadFileAs(){return ho.ArrayBuffer}loadUrlAs(){return 1}onloadstart(e){}onprogress(e){}onloaditem(e){}onload(e){}onloadend(e){}onerror(e){}onabort(e){}}],ho={Text:0,ArrayBuffer:1,DataURL:2};class So{#no=null;#Jo=[];#ro=null;#oo=0;#ao=0;#F;getDefaultCharacterSet(){return this.#F}setDefaultCharacterSet(e){this.#F=e}#lo(e){this.#no=e,this.#oo=0,this.#ao=0,this.#$o(),this.#uo()}#ea(e){this.#Jo.push(e)}#$o(){this.#Jo=[]}#ho(e){this.#ro=e}#uo(){this.#ro=null}#So=e=>{this.#oo++,this.#oo===this.#no.length&&this.onload({source:this.#no})};#go=e=>{this.#ao++,this.#ao===this.#no.length&&this.onloadend({source:this.#no})};#po(e,t){return n=>{n.source=t,e(n)}}#Do(e,t,n){return i=>{e.load(i.target.result,t,n)}}load(e){if(void 0===e||0===e.length)return;this.#lo(e),this.onloadstart({source:e});const t=new cr(this.onprogress);t.setNToLoad(e.length);const n=[];for(let e=0;e{this.#go(),a(e)};const s=this.#po(this.onabort,i);o.onabort=e=>{this.#go(),s(e)},r.loadFileAs()===ho.Text?o.readAsText(i):r.loadFileAs()===ho.DataURL?o.readAsDataURL(i):r.loadFileAs()===ho.ArrayBuffer&&o.readAsArrayBuffer(i)}}abort(){for(let e=0;e{this.#ta[i]={loader:t,isFirstItem:!0},this.#po(this.onloadstart,o)(e)},t.onprogress=this.#po(this.onprogress,o),t.onloaditem=e=>{const t={loadtype:n,dataid:i};void 0!==this.#ta[i]&&(t.isfirstitem=this.#ta[i].isFirstItem),this.#po(this.onloaditem,t)(e),void 0!==this.#ta[i]&&this.#ta[i].isFirstItem&&(this.#ta[i].isFirstItem=!1)},t.onload=this.#po(this.onload,o),t.onloadend=e=>{delete this.#ta[i],this.#po(this.onloadend,o)(e)},t.onerror=this.#po(this.onerror,o),t.onabort=this.#po(this.onabort,o);try{t.load(e,r)}catch(e){return this.onerror({error:e,dataid:i}),void this.onloadend({dataid:i})}}#po(e,t){return function(n){const i=Object.keys(t);for(let e=0;e{e.dataid===this.#on&&void 0!==e.data&&void 0!==e.data.imageUid&&this.#da!==e.data.imageUid&&(this.#da=e.data.imageUid,this.#Sa(e))};#Sa=e=>{if(e.dataid!==this.#on)return;const t=this.#ua[this.#da];if(void 0!==t){for(let n=0;n{null!==this.#Da&&this.#Da.add(e)};removeFromUndoStack=e=>{let t=!1;return null!==this.#Da&&(t=this.#Da.remove(e)),t};init(e){if(this.#Fo=e,void 0===this.#Fo.viewOnFirstLoadItem&&(this.#Fo.viewOnFirstLoadItem=!0),void 0===this.#Fo.dataViewConfigs&&(this.#Fo.dataViewConfigs={}),void 0===this.#Fo.rootDocument&&(this.#Fo.rootDocument=document),this.#Da=new sr,this.#Da.addEventListener("undoadd",this.#Re),this.#Da.addEventListener("undo",this.#Re),this.#Da.addEventListener("redo",this.#Re),void 0!==this.#Fo.tools){const e={},t=Object.keys(this.#Fo.tools);for(let n=0;n{const t=this.#ga.getNextDataId();0!==e.length?this.#ma.loadFiles(e,t):c.warn("Ignoring empty input file list.")};loadURLs=(e,t)=>{const n=this.#ga.getNextDataId();0!==e.length?this.#ma.loadURLs(e,n,t):c.warn("Ignoring empty input url list.")};loadFromUri=(e,t)=>{const n=function(e){const t=ar(e);return 0===Object.keys(t).length?null:t.query}(e),i=()=>{this.removeEventListener("loadend",i),this.loadURLs([n.state])};n&&void 0!==n.input&&(void 0!==n.state&&this.addEventListener("loadend",i),function(e,t,n){e.type&&"manifest"===e.type?function(e,t){let n="";"/"===e.input[0]&&(n=window.location.protocol+"//"+window.location.host),n+=e.input;const i=new XMLHttpRequest;i.open("GET",decodeURIComponent(n),!0),i.responseType="document",i.onload=function(n){t(function(e,t){const n=[],i=e.getElementsByTagName("wado_query")[0].getAttribute("wadoURL")+"?requestType=WADO&contentType=application/dicom&",r=e.getElementsByTagName("Patient");r.length>1&&c.warn("More than one patient, loading first one.");const o=r[0].getElementsByTagName("Study");o.length>1&&c.warn("More than one study, loading first one.");const a=o[0].getAttribute("StudyInstanceUID"),s=o[0].getElementsByTagName("Series");s.length>1&&c.warn("More than one series, loading first one.");const l=s[0].getAttribute("SeriesInstanceUID"),u=s[0].getElementsByTagName("Instance");let d=u.length;t{const t=this.#ga.getNextDataId();this.#ma.loadImageObject(e,t)};abortAllLoads(){const e=this.#ma.getLoadingDataIds();for(const t of e)this.abortLoad(t)}abortLoad(e){this.#ma.abort(e),this.#ga.remove(e),this.#fa.removeLayersByDataId(e)}fitToContainer(){this.#fa.fitToContainer()}initWLDisplay(){this.#fa.getActiveLayerGroup().getActiveViewLayer().getViewController().initialise()}setImageSmoothing(e){this.#fa.setImageSmoothing(e),this.#fa.draw()}getViewConfigs(e,t){if(null===this.#Fo.dataViewConfigs||void 0===this.#Fo.dataViewConfigs)throw new Error("No available data view configuration");let n=[];return void 0!==this.#Fo.dataViewConfigs[e]?n=this.#Fo.dataViewConfigs[e]:t||void 0===this.#Fo.dataViewConfigs["*"]||(n=this.#Fo.dataViewConfigs["*"]),n}getViewConfig(e,t,n){return this.getViewConfigs(e,n).find((function(e){return e.divId===t}))}getDataViewConfigs(){return this.#Fo.dataViewConfigs}setDataViewConfigs(e){this.#fa.empty(),this.#Fo.dataViewConfigs=e,this.#Oa(e)}addDataViewConfig(e,t){const n=this.#Fo.dataViewConfigs;if(void 0===n[e]&&(n[e]=[]),-1!==n[e].findIndex((function(e){return e.divId===t.divId})))throw new Error("Duplicate view config for data "+e+" and div "+t.divId);this.#Fo.dataViewConfigs[e].push(t),void 0===this.#fa.getLayerGroupByDivId(t.divId)&&this.#Aa(t),void 0!==this.#ga.get(e)&&this.render(e,[t])}removeDataViewConfig(e,t){const n=this.#Fo.dataViewConfigs;if(void 0===n[e])return;const i=n[e].findIndex((function(e){return e.divId===t}));if(-1!==i&&(n[e].splice(i,1),0===n[e].length&&delete n[e],void 0!==this.#ga.get(e))){const n=this.#fa.getLayerGroupByDivId(t);if(void 0!==n){const t=n.getViewLayersByDataId(e);1===t.length&&n.removeLayer(t[0]);const i=n.getDrawLayersByDataId(e);if(1===i.length&&n.removeLayer(i[0]),0===t.length&&0===i.length)throw new Error("Expected one layer, got none");0===n.getNumberOfLayers()&&this.#fa.removeLayerGroup(n)}}}updateDataViewConfig(e,t,n){const i=this.#Fo.dataViewConfigs;if(void 0===i[e])throw new Error("No config for dataId: "+e);const r=i[e].findIndex((function(e){return e.divId===t}));if(-1===r)throw new Error("No config for dataId: "+e+" and divId: "+t);const o=i[e][r];for(const e in n)o[e]=n[e];const a=this.#fa.getLayerGroupByDivId(o.divId);if(void 0!==a){const t=a.getViewLayersByDataId(e);1===t.length&&a.removeLayer(t[0]);const n=a.getDrawLayersByDataId(e);if(1===n.length&&a.removeLayer(n[0]),0===t.length&&0===n.length)throw new Error("Expected one layer, got none")}void 0!==this.#ga.get(e)&&this.render(e,[o])}#Oa(e){const t=Object.keys(e),n=[];for(let i=0;i{this.fitToContainer()};onKeydown=e=>{this.#Re(e)};defaultOnKeydown=e=>{if(e.ctrlKey)if(e.shiftKey){const t=this.#fa.getActiveLayerGroup(),n=t.getActiveViewLayer().getViewController();"ArrowLeft"===e.key?n.moreThanOne(3)&&n.decrementIndex(3):"ArrowUp"===e.key?t.canScroll()&&n.incrementScrollIndex():"ArrowRight"===e.key?t.moreThanOne(3)&&n.incrementIndex(3):"ArrowDown"===e.key&&t.canScroll()&&n.decrementScrollIndex()}else if("y"===e.key)this.#Da.redo();else if("z"===e.key)this.#Da.undo();else if(" "===e.key)for(let e=0;ee.divId===t));if(void 0===r)throw new Error("No reference data view config for draw");const o=new Co(t);o.orientation=r.orientation,this.addDataViewConfig(i,o),this.render(i)}#Re=e=>{this.#Ae.fireEvent(e)};#ya=e=>{void 0!==this.#Fo.overlayConfig&&(this.#Ca[e.dataid]=new Do(this,e.dataid,this.#Fo.overlayConfig)),e.type="loadstart",this.#Re(e)};#va=e=>{e.type="loadprogress",this.#Re(e)};#Ia=e=>{void 0===e.data&&c.error("Missing loaditem event data."),void 0===e.loadtype&&c.error("Missing loaditem event load type.");const t=e.isfirstitem;let n=null;"image"===e.loadtype?(t?this.#ga.add(e.dataid,e.data):this.#ga.update(e.dataid,e.data),n=e.data.meta):"state"===e.loadtype&&(this.applyJsonState(e.data,e.dataid),n="state"),this.#Re({type:"loaditem",data:n,source:e.source,loadtype:e.loadtype,dataid:e.dataid,isfirstitem:e.isfirstitem,warn:e.warn}),void 0!==this.#Ca&&void 0!==this.#Ca[e.dataid]&&this.#Ca[e.dataid].addItemMeta(n),"image"===e.loadtype&&0!==this.getViewConfigs(e.dataid).length&&t&&this.#Fo.viewOnFirstLoadItem&&this.render(e.dataid)};#Ta=e=>{e.type="load",this.#Re(e)};#La=e=>{e.type="loadend",this.#Re(e)};#Pa=e=>{void 0===e.type&&(e.type="error"),this.#Re(e)};#wa=e=>{void 0===e.type&&(e.type="abort"),this.#Re(e)};#ba(e){e.addEventListener("zoomchange",this.#Re),e.addEventListener("offsetchange",this.#Re),e.addEventListener("renderstart",this.#Re),e.addEventListener("renderend",this.#Re);for(let t=0;t{const t=ji(e.srclayerid).groupDivId,n=this.getViewConfig(e.dataid,t,!0);void 0!==n&&(n.windowCenter=void 0,n.windowWidth=void 0,n.wlPresetName=void 0,3===e.value.length&&(n.windowCenter=e.value[0],n.windowWidth=e.value[1],n.wlPresetName=e.value[2]))})),e.addEventListener("opacitychange",(e=>{const t=ji(e.srclayerid).groupDivId,n=this.getViewConfig(e.dataid,t,!0);void 0!==n&&(n.opacity=e.value[0])})),e.addEventListener("colourmapchange",(e=>{const t=ji(e.srclayerid).groupDivId,n=this.getViewConfig(e.dataid,t,!0);void 0!==n&&(n.colourMap=e.value[0])}))}#xa(e,t){const n=this.#ga.get(e);if(!n)throw new Error("Cannot initialise layer with missing data, id: "+e);const i=this.#fa.getLayerGroupByDivId(t.divId);if(!i)throw new Error("Cannot initialise layer with missing group, id: "+t.divId);const r=n.image.getGeometry();this.#fa.unbindLayerGroups();const o=(new Mn).create(n.meta,n.image),a=Ct(r.getOrientation(),gt(t.orientation));o.setOrientation(a),"SEG"===n.image.getMeta().Modality&&o.setAlphaFunction((function(e){return 0===e?0:255}));const s=0===i.getNumberOfViewLayers();let l=1;void 0!==t.opacity?l=t.opacity:s||(l=.5);const c=i.addViewLayer();c.setView(o,e);const d=r.getSize(a).get2D(),h=r.getSpacing(a).get2D();c.initialise(d,h,l);const S=c.getViewController();if(void 0!==t.wlPresetName)S.setWindowLevelPreset(t.wlPresetName);else if(void 0!==t.windowCenter&&void 0!==t.windowWidth){const e=new u(t.windowCenter,t.windowWidth);S.setWindowLevel(e)}void 0!==t.colourMap?S.setColourMap(t.colourMap):s||("PT"===n.image.getMeta().Modality?S.setColourMap("hot"):S.setColourMap("rainbow")),this.#ga.addEventListener("dataimageset",c.onimageset);const g=[S.getCurrentIndex().getValues(),S.getCurrentPosition().getValues()];i.updateLayersToPositionChange({value:g,srclayerid:c.getId()}),this.#fa.fitToContainer(),c.setOffset(i.getOffset());const p=this.#Ra(r.getOrientation(),t.orientation);if(this.#Fa(p,c),s)c.setScale(i.getScale());else{const e=i.getBaseViewLayer();c.initScale(i.getScale(),e.getAbsoluteZoomOffset())}this.#fa.bindLayerGroups(),this.#pa&&this.#pa.bindLayerGroup(i,c),this.#Re({type:"viewlayeradd",layerid:c.getId(),layergroupid:i.getDivId(),dataid:e}),s&&this.#pa&&this.#pa.init()}addDrawLayer(e,t){const n=this.#fa.getLayerGroupByDivId(t.divId);if(!n)throw new Error("Cannot initialise layer with missing group, id: "+t.divId);const i=this.#ga.get(e);if(!i)throw new Error("Cannot initialise layer with missing data, id: "+e);const r=i.annotationGroup.getMetaValue("ReferencedSeriesSequence").value[0].SeriesInstanceUID,o=n.searchViewLayers({SeriesInstanceUID:r});if(0===o.length)return void console.warn("No loaded data that matches the measurement reference series UID");const a=o[0],s=a.getDataId();this.#fa.unbindLayerGroups();const l=a.getViewController();i.annotationGroup.setViewController(l);const c=this.#ga.get(s);if(!c)throw new Error("Cannot initialise layer without reference data, id: "+s);const u=c.image.getGeometry(),d=Ct(u.getOrientation(),gt(t.orientation)),h=u.getSize(d).get2D(),S=u.getSpacing(d).get2D(),g=n.addDrawLayer();g.initialise(h,S,a.getId());const p=new Bn(u,d);g.setPlaneHelper(p);const m=[l.getCurrentIndex().getValues(),l.getCurrentPosition().getValues()];n.updateLayersToPositionChange({value:m,srclayerid:g.getId()}),this.#fa.fitToContainer(),g.setOffset(n.getOffset());const f=this.#Ra(u.getOrientation(),t.orientation);this.#Fa(f,g),g.initScale(n.getScale(),a.getAbsoluteZoomOffset()),g.setAnnotationGroup(i.annotationGroup,e,this.addToUndoStack),g.setCurrentPosition(l.getCurrentPosition(),l.getCurrentIndex()),this.#fa.bindLayerGroups(),this.#pa&&this.#pa.bindLayerGroup(n,g),this.#Re({type:"drawlayeradd",layerid:g.getId(),layergroupid:n.getDivId(),dataid:e})}#Ra(e,t){const n=pt(e.asOneAndZeros());if(void 0===n)throw new Error("Unsupported undefined orientation code");const i=void 0===t,r=!i&&t===St.Axial,o=!i&&t===St.Coronal,a=!i&&t===St.Sagittal,s={x:!1,y:!1},l={x:!1,y:!1,z:!1};return"LPS"===n?(o||a)&&(l.z=!0,s.y=!0):"LAI"===n?i||r?s.y=!0:o?l.z=!0:a&&(l.z=!0,s.x=!0):"RPI"===n?i||r?s.x=!0:o?(l.z=!0,s.x=!0):a&&(l.z=!0):"RAS"===n?(s.x=!0,s.y=!0,(o||a)&&(l.z=!0)):"LSA"===n?(s.y=!0,i||o?l.z=!0:r?l.y=!0:a&&(s.x=!0,l.y=!0,l.z=!0)):"RSP"===n?i||o?(s.x=!0,s.y=!0,l.x=!0,l.z=!0):r?(s.x=!0,l.x=!0):a&&(s.y=!0,l.z=!0):"RIA"===n?(s.x=!0,i||o?l.x=!0:r?(s.y=!0,l.x=!0,l.y=!0):a&&(l.y=!0)):"PSL"===n?(l.z=!0,(i||a||o)&&(s.y=!0)):"PIR"===n?(l.z=!0,(r||o)&&(s.x=!0)):"ASR"===n?(s.x=!0,s.y=!0,(i||a||o)&&(l.z=!0)):"AIL"===n?i||a?(s.x=!0,l.z=!0):r?s.y=!0:o&&(l.z=!0):c.warn("Unsupported orientation code: "+n+", display could be incorrect"),{scale:l,offset:s}}#Fa(e,t){e.offset.x&&t.addFlipOffsetX(),e.offset.y&&t.addFlipOffsetY(),e.scale.x&&t.flipScaleX(),e.scale.y&&t.flipScaleY(),e.scale.z&&t.flipScaleZ()}}class To{#yi;#Ea;constructor(e){this.#yi=e;const t=e.getMeta();void 0===t.custom&&(t.custom={}),void 0===t.custom.segments&&(t.custom.segments=[]),this.#Ea=t.custom.segments}#qa(e){return this.#Ea.findIndex((function(t){return t.number===e}))}hasSegment(e){return-1!==this.#qa(e)}getNumberOfSegments(){return this.#Ea.length}maskHasSegments(e){const t=[],n=[];for(let i=0;ie.number===this.#Ua.number))}execute(){0!==this.#Qa.length&&this.#yi.setAtOffsets(this.#Qa,0),new To(this.#yi).removeSegment(this.#Ua.number),this.#Ma||this.onExecute({type:"masksegmentdelete",segmentnumber:this.#Ua.number})}undo(){0!==this.#Qa.length&&(void 0!==this.#Ua.displayRGBValue?this.#yi.setAtOffsets(this.#Qa,this.#Ua.number):this.#yi.setAtOffsets(this.#Qa,this.#Ua.displayValue)),new To(this.#yi).addSegment(this.#Ua),this.onUndo({type:"masksegmentredraw",segmentnumber:this.#Ua.number})}onExecute(e){}onUndo(e){}}class Po{#yi;#Ua;#Va;#Na;#Ma;#Qa;constructor(e,t,n,i){this.#yi=e,this.#Ua=t,this.#Va=n,this.#Ma=void 0!==i&&i,void 0!==t.displayRGBValue?this.#Na=t.displayRGBValue:(this.#Na=t.displayValue,this.#Qa=e.getOffsets(this.#Na))}getName(){return"Change-segment-colour"}isValid(){let e=!0;return void 0!==this.#Qa&&(e=0!==this.#Qa.length),e}execute(){"number"==typeof this.#Va?(this.#yi.setAtOffsets(this.#Qa,this.#Va),this.#Ua.displayValue=this.#Va):(this.#yi.updatePaletteColourMap(this.#Ua.number,this.#Va),this.#Ua.displayRGBValue=this.#Va),this.#Ma||this.onExecute({type:"changemasksegmentcolour",segmentnumber:this.#Ua.number,value:[this.#Va]})}undo(){"number"==typeof this.#Na?(this.#yi.setAtOffsets(this.#Qa,this.#Na),this.#Ua.displayValue=this.#Na):(this.#yi.updatePaletteColourMap(this.#Ua.number,this.#Na),this.#Ua.displayRGBValue=this.#Na),this.onUndo({type:"changemasksegmentcolour",segmentnumber:this.#Ua.number,value:[this.#Na]})}onExecute(e){}onUndo(e){}}class wo{#Ba=[];#Ga(e){return this.#Ba.indexOf(e)}isHidden(e){return-1!==this.#Ga(e)}addToHidden(e){this.isHidden(e)?c.warn("Not hidding segment, it is allready in the hidden list: "+e):this.#Ba.push(e)}removeFromHidden(e){const t=this.#Ga(e);-1!==t?this.#Ba.splice(t,1):c.warn("Cannot remove segment, it is not in the hidden list: "+e)}getAlphaFunc(){return e=>Array.isArray(e)||0!==e&&!this.#Ba.includes(e)?255:0}}class Oo{x;y}class Ao{x;y;z}return a}()})); //# sourceMappingURL=dwv.min.js.map \ No newline at end of file diff --git a/dist/dwv.min.js.map b/dist/dwv.min.js.map index f6275c1c20..b4ec1ecccf 100644 --- a/dist/dwv.min.js.map +++ b/dist/dwv.min.js.map @@ -1 +1 @@ -{"version":3,"file":"dwv.min.js","mappings":"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AK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAC35BD,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,GACllCD,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,G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,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC1sCC,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC58BC,KAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,MAM12BQ,IAAK,CACHV,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC1kCC,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC9lCC,KAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,MAMrpCS,eAAgB,CACdX,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC7iCC,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC19BC,KAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,MAMxmCU,WAAY,CACVZ,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KACpnCC,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC3lCC,KAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,OC1L3gC,MAAMW,EAMXrG,EAMAsG,EAMAC,EAMAlG,WAAAA,CAAYL,EAAGsG,EAAGC,GAChBlI,KAAK2B,EAAIA,EACT3B,KAAKiI,EAAIA,EACTjI,KAAKkI,EAAIA,CACX,EAUK,SAASC,EAAWC,EAAIC,GAC7B,OAAc,OAAPD,GACE,OAAPC,QACc,IAAPD,QACO,IAAPC,GACPD,EAAGzG,IAAM0G,EAAG1G,GACZyG,EAAGH,IAAMI,EAAGJ,GACZG,EAAGF,IAAMG,EAAGH,CAChB,CA6GO,SAASI,EAAaC,GAK3B,MAAO,CACLlF,EAAG,OAASkF,EAAQlF,EACpBvC,EAAG,IAAMyH,EAAQzH,EAAI,MACrBoH,EAAG,IAAMK,EAAQL,EAAI,MAEzB,CAOA,MAAMM,EAAM,CACVC,EAAG,QACHC,EAAG,IACHC,EAAG,SA0KE,SAASC,EAAaL,GAC3B,OA1HK,SAAwBA,GAO7B,SAASM,EAAQJ,GACf,IAAIK,EAAM,KAUV,OANEA,EADEL,EAAI,WACA9E,KAAKC,IAAI6E,EAAG,YAIZ,YAAcA,EAAI,WAEnBK,CACT,CAEA,MAAMC,EAAaP,EACbQ,EAAKH,EAAQN,EAAQG,EAAIK,EAAWL,GAE1C,MAAO,CACLrF,EAAG,IAAM2F,EAAK,GACdlI,EAAG,KAAO+H,EAAQN,EAAQE,EAAIM,EAAWN,GAAKO,GAC9Cd,EAAG,KAAOc,EAAKH,EAAQN,EAAQI,EAAII,EAAWJ,IAElD,CA6FSM,CA7CF,SAAsBV,GAO3B,SAASW,EAAaT,GACpB,IAAIK,EAAM,KAMV,OAJEA,EADEL,GAAK,OACDA,EAAI,MAEJ9E,KAAKC,KAAK6E,EAAI,MAAS,MAAO,KAE/BK,CACT,CAEA,MAAMK,EAAKD,EAAaX,EAAQ5G,EAAI,KAC9ByH,EAAKF,EAAaX,EAAQN,EAAI,KAC9BoB,EAAKH,EAAaX,EAAQL,EAAI,KAEpC,MAAO,CACLO,EAAG,KAAO,MAASU,EAAK,MAASC,EAAK,MAASC,GAC/CX,EAAG,KAAO,MAASS,EAAK,MAASC,EAAK,MAASC,GAC/CV,EAAG,KAAO,MAASQ,EAAK,MAASC,EAAK,MAASC,GAEnD,CAmBwBC,CAAaf,GACrC,CAQO,SAASgB,EAAgBC,GAE9B,MAAMC,EAAO,CACXC,OAAQ,UACRC,IAAK,UACLC,MAAO,UACPC,MAAO,UACPC,KAAM,UACNC,KAAM,UACNC,QAAS,UACTC,MAAO,WAET,IAAInB,EAAM,UAIV,YAH0B,IAAfW,EAAKD,KACdV,EAAMW,EAAKD,IAENV,CACT,CC5XO,MAAMoB,EAOX,GAOA,GAOA,GAOAlI,WAAAA,CAAYyG,EAAGC,EAAGC,GAChB3I,MAAK,EAAKyI,EACVzI,MAAK,EAAK0I,EACV1I,MAAK,EAAK2I,CACZ,CAOAwB,IAAAA,GACE,OAAOnK,MAAK,CACd,CAOAoK,IAAAA,GACE,OAAOpK,MAAK,CACd,CAOAqK,IAAAA,GACE,OAAOrK,MAAK,CACd,CAQA6C,MAAAA,CAAOD,GACL,OAAe,OAARA,GACL5C,MAAK,IAAO4C,EAAIuH,QAChBnK,MAAK,IAAO4C,EAAIwH,QAChBpK,MAAK,IAAO4C,EAAIyH,MACpB,CAOA7H,QAAAA,GACE,MAAO,IAAMxC,MAAK,EAChB,KAAOA,MAAK,EACZ,KAAOA,MAAK,EAAK,GACrB,CAOAsK,IAAAA,GACE,OAAO3G,KAAK4G,KACTvK,MAAK,EAAKA,MAAK,EACfA,MAAK,EAAKA,MAAK,EACfA,MAAK,EAAKA,MAAK,EAEpB,CAYAwK,YAAAA,CAAaC,GACX,OAAO,IAAIP,EACRlK,MAAK,EAAKyK,EAASJ,OAAWI,EAASL,OAASpK,MAAK,EACrDA,MAAK,EAAKyK,EAASN,OAAWM,EAASJ,OAASrK,MAAK,EACrDA,MAAK,EAAKyK,EAASL,OAAWK,EAASN,OAASnK,MAAK,EAC1D,CAUA0K,UAAAA,CAAWD,GACT,OAAQzK,MAAK,EAAKyK,EAASN,OACxBnK,MAAK,EAAKyK,EAASL,OACnBpK,MAAK,EAAKyK,EAASJ,MACxB,CAQAM,eAAAA,CAAgBF,GAOd,OAAOzK,KAAK0K,WAAWD,GAAY,CACrC,ECzIyBG,OAAOC,QAA3B,MAEMC,EAAqB,KAW3B,SAASC,EAAUjK,EAAGoH,EAAG8C,GAI9B,YAHmB,IAARA,IACTA,EAAMJ,OAAOC,SAERlH,KAAKsH,IAAInK,EAAIoH,GAAK8C,CAC3B,CAKO,MAAME,EAOX,GAOA,GAKAlJ,WAAAA,CAAYC,GACVjC,MAAK,EAAUiC,CACjB,CASAZ,GAAAA,CAAI8J,EAAKC,GACP,OAAOpL,MAAK,EAAc,EAANmL,EAAUC,EAChC,CAQAC,UAAAA,GAIE,YAH6B,IAAlBrL,MAAK,IACdA,MAAK,EAiOX,SAA0BsL,GACxB,MAAMC,EAAMD,EAAEjK,IAAI,EAAG,GACfmK,EAAMF,EAAEjK,IAAI,EAAG,GACfoK,EAAMH,EAAEjK,IAAI,EAAG,GACfqK,EAAMJ,EAAEjK,IAAI,EAAG,GACfsK,EAAML,EAAEjK,IAAI,EAAG,GACfuK,EAAMN,EAAEjK,IAAI,EAAG,GACfwK,EAAMP,EAAEjK,IAAI,EAAG,GACfyK,EAAMR,EAAEjK,IAAI,EAAG,GACf0K,EAAMT,EAAEjK,IAAI,EAAG,GAEf2K,EAAQL,EAAMI,EAAMH,EAAME,EAC1BG,EAAQL,EAAMC,EAAMH,EAAMK,EAC1BG,EAAQR,EAAMI,EAAMH,EAAME,EAEhC,IAAIM,EAAMZ,EAAMS,EAAQR,EAAMS,EAAQR,EAAMS,EAC5C,GAAY,IAARC,EAkBJ,OAdAA,EAAM,EAAIA,EAcH,IAAIjB,EAZI,CACbiB,EAAMH,EACNG,GAAOV,EAAMK,EAAMN,EAAMO,GACzBI,GAAOX,EAAMI,EAAMH,EAAME,GACzBQ,EAAMF,EACNE,GAAOZ,EAAMQ,EAAMN,EAAMI,GACzBM,GAAOV,EAAMC,EAAMH,EAAMK,GACzBO,EAAMD,EACNC,GAAOX,EAAMK,EAAMN,EAAMO,GACzBK,GAAOZ,EAAMI,EAAMH,EAAME,KAdzBvH,EAAOa,KAAK,kDAkBhB,CApQsBoH,CAAiBpM,OAE5BA,MAAK,CACd,CAUA6C,MAAAA,CAAOD,EAAKyJ,GAGV,IAAK,IAAI9J,EAAI,EAAGA,EAAI,IAAKA,EACvB,IAAK,IAAIa,EAAI,EAAGA,EAAI,IAAKA,EACvB,IAAK2H,EAAU/K,KAAKqB,IAAIkB,EAAGa,GAAIR,EAAIvB,IAAIkB,EAAGa,GAAIiJ,GAC5C,OAAO,EAIb,OAAO,CACT,CAOA7J,QAAAA,GACE,IAAI8J,EAAM,IACV,IAAK,IAAI/J,EAAI,EAAGA,EAAI,IAAKA,EAAG,CAChB,IAANA,IACF+J,GAAO,SAET,IAAK,IAAIlJ,EAAI,EAAGA,EAAI,IAAKA,EACb,IAANA,IACFkJ,GAAO,MAETA,GAAOtM,KAAKqB,IAAIkB,EAAGa,EAEvB,CAEA,OADAkJ,GAAO,IACAA,CACT,CAQAC,QAAAA,CAAS3J,GACP,MAAMX,EAAS,GACf,IAAK,IAAIM,EAAI,EAAGA,EAAI,IAAKA,EACvB,IAAK,IAAIa,EAAI,EAAGA,EAAI,IAAKA,EAAG,CAC1B,IAAIoJ,EAAM,EACV,IAAK,IAAIC,EAAI,EAAGA,EAAI,IAAKA,EACvBD,GAAOxM,KAAKqB,IAAIkB,EAAGkK,GAAK7J,EAAIvB,IAAIoL,EAAGrJ,GAErCnB,EAAOgB,KAAKuJ,EACd,CAEF,OAAO,IAAItB,EAASjJ,EACtB,CAOAyK,MAAAA,GACE,MAAMzK,EAAS,GACf,IAAK,IAAIM,EAAI,EAAGA,EAAI,IAAKA,EACvB,IAAK,IAAIa,EAAI,EAAGA,EAAI,IAAKA,EACvBnB,EAAOgB,KAAKU,KAAKsH,IAAIjL,KAAKqB,IAAIkB,EAAGa,KAGrC,OAAO,IAAI8H,EAASjJ,EACtB,CAQA0K,eAAAA,CAAgBC,GACd,GAAuB,IAAnBA,EAAQzK,OACV,MAAM,IAAID,MAAM,iDACd0K,EAAQzK,QAEZ,MAAMF,EAAS,GACf,IAAK,IAAIM,EAAI,EAAGA,EAAI,IAAKA,EAAG,CAC1B,IAAIiK,EAAM,EACV,IAAK,IAAIpJ,EAAI,EAAGA,EAAI,IAAKA,EACvBoJ,GAAOxM,KAAKqB,IAAIkB,EAAGa,GAAKwJ,EAAQxJ,GAElCnB,EAAOgB,KAAKuJ,EACd,CACA,OAAOvK,CACT,CAQA4K,gBAAAA,CAAiBpC,GACf,MAAMmC,EAAU5M,KAAK2M,gBACnB,CAAClC,EAASN,OAAQM,EAASL,OAAQK,EAASJ,SAE9C,OAAO,IAAIH,EAAS0C,EAAQ,GAAIA,EAAQ,GAAIA,EAAQ,GACtD,CAQAE,eAAAA,CAAgBC,GACd,MAAMH,EAAU5M,KAAK2M,gBACnB,CAACI,EAAQ5C,OAAQ4C,EAAQ3C,OAAQ2C,EAAQ1C,SAE3C,OAAO,IAAI2C,EAAQJ,EAAQ,GAAIA,EAAQ,GAAIA,EAAQ,GACrD,CAQAK,eAAAA,CAAgBC,GACd,MAAMN,EAAU5M,KAAK2M,gBAAgBO,EAAQzK,aAC7C,OAAO,IAAIV,EAAM6K,EACnB,CAQAO,YAAAA,CAAahC,GACX,MAAMlJ,EAAS,CACb0B,KAAKsH,IAAIjL,KAAKqB,IAAI8J,EAAK,IACvBxH,KAAKsH,IAAIjL,KAAKqB,IAAI8J,EAAK,IACvBxH,KAAKsH,IAAIjL,KAAKqB,IAAI8J,EAAK,KAEnBiC,EAASzJ,KAAK0J,IAAIvJ,MAAM,KAAM7B,GAC9BqL,EAAQrL,EAAOsL,QAAQH,GAC7B,MAAO,CACLtL,MAAO9B,KAAKqB,IAAI8J,EAAKmC,GACrBA,MAAOA,EAEX,CAQAE,YAAAA,CAAapC,GACX,MAAMnJ,EAAS,CACb0B,KAAKsH,IAAIjL,KAAKqB,IAAI,EAAG+J,IACrBzH,KAAKsH,IAAIjL,KAAKqB,IAAI,EAAG+J,IACrBzH,KAAKsH,IAAIjL,KAAKqB,IAAI,EAAG+J,KAEjBgC,EAASzJ,KAAK0J,IAAIvJ,MAAM,KAAM7B,GAC9BqL,EAAQrL,EAAOsL,QAAQH,GAC7B,MAAO,CACLtL,MAAO9B,KAAKqB,IAAIiM,EAAOlC,GACvBkC,MAAOA,EAEX,CAOAG,aAAAA,GACE,MAAM3E,EAAM,GACZ,IAAK,IAAI1F,EAAI,EAAGA,EAAI,IAAKA,EAAG,CAC1B,MAAMiK,EAAMrN,KAAKmN,aAAa/J,GACxBsK,EAAOL,EAAIvL,MAAQ,EAAI,GAAK,EAClC,IAAK,IAAIS,EAAI,EAAGA,EAAI,IAAKA,EACnBA,IAAM8K,EAAIC,MACZxE,EAAI7F,KAAK,EAAIyK,GAEb5E,EAAI7F,KAAK,EAGf,CACA,OAAO,IAAIiI,EAASpC,EACtB,CAOA6E,yBAAAA,GACE,OAAO3N,KAAKwN,aAAa,GAAGF,KAC9B,EAyDK,SAASM,IAEd,OAAO,IAAI1C,EAAS,CAClB,EAAG,EAAG,EACN,EAAG,EAAG,EACN,EAAG,EAAG,GAGV,CAQO,SAAS2C,EAAgBC,GAC9B,OAAOA,EAAMjL,OAAO+K,IACtB,CCjWO,MAAMG,EAOX,GAOA,GAMA/L,WAAAA,CAAYyG,EAAGC,GACb1I,MAAK,EAAKyI,EACVzI,MAAK,EAAK0I,CACZ,CAOAyB,IAAAA,GACE,OAAOnK,MAAK,CACd,CAOAoK,IAAAA,GACE,OAAOpK,MAAK,CACd,CAOAyC,SAAAA,GACE,MAAO,CAACzC,MAAK,EAAIA,MAAK,EACxB,CAOAgO,WAAAA,GACE,OAAOhO,IACT,CAQA6C,MAAAA,CAAOD,GACL,OAAOA,SAEL5C,MAAK,IAAO4C,EAAIuH,QAChBnK,MAAK,IAAO4C,EAAIwH,MACpB,CAOA5H,QAAAA,GACE,MAAO,IAAMxC,MAAK,EAAK,KAAOA,MAAK,EAAK,GAC1C,CAQAiO,WAAAA,CAAYC,GACV,MAAMC,EAAKnO,MAAK,EAAKkO,EAAQ/D,OACvBiE,EAAKpO,MAAK,EAAKkO,EAAQ9D,OAC7B,OAAOzG,KAAK4G,KAAK4D,EAAKA,EAAKC,EAAKA,EAClC,EAOK,MAAMpB,EAOX,GAOA,GAOA,GAOAhL,WAAAA,CAAYyG,EAAGC,EAAGC,GAChB3I,MAAK,EAAKyI,EACVzI,MAAK,EAAK0I,EACV1I,MAAK,EAAK2I,CACZ,CAOAwB,IAAAA,GACE,OAAOnK,MAAK,CACd,CAOAoK,IAAAA,GACE,OAAOpK,MAAK,CACd,CAOAqK,IAAAA,GACE,OAAOrK,MAAK,CACd,CAOAyC,SAAAA,GACE,MAAO,CAACzC,MAAK,EAAIA,MAAK,EAAIA,MAAK,EACjC,CAQA6C,MAAAA,CAAOD,GACL,OAAe,OAARA,GACL5C,MAAK,IAAO4C,EAAIuH,QAChBnK,MAAK,IAAO4C,EAAIwH,QAChBpK,MAAK,IAAO4C,EAAIyH,MACpB,CAUAU,SAAAA,CAAUnI,EAAKoI,GACb,OAAe,OAARpI,GACLmI,EAAU/K,MAAK,EAAI4C,EAAIuH,OAAQa,IAC/BD,EAAU/K,MAAK,EAAI4C,EAAIwH,OAAQY,IAC/BD,EAAU/K,MAAK,EAAI4C,EAAIyH,OAAQW,EACnC,CAOAxI,QAAAA,GACE,MAAO,IAAMxC,MAAK,EAChB,KAAOA,MAAK,EACZ,KAAOA,MAAK,EAAK,GACrB,CAQAiO,WAAAA,CAAYlB,GACV,OAAOpJ,KAAK4G,KAAKvK,MAAK,EAAoB+M,GAC5C,CASA,GAAoBA,GAClB,MAAMoB,EAAKnO,MAAK,EAAK+M,EAAQ5C,OACvBiE,EAAKpO,MAAK,EAAK+M,EAAQ3C,OACvBiE,EAAKrO,MAAK,EAAK+M,EAAQ1C,OAC7B,OAAO8D,EAAKA,EAAKC,EAAKA,EAAKC,EAAKA,CAClC,CAQAC,UAAAA,CAAWC,GACT,IAAIC,EAAW,EAEXC,EAAUzO,MAAK,EAAoBuO,EAAUC,IACjD,IAAK,IAAIjM,EAAI,EAAGA,EAAIgM,EAAUpM,SAAUI,EAAG,CACzC,MAAMmM,EAAO1O,MAAK,EAAoBuO,EAAUhM,IAC5CmM,EAAOD,IACTD,EAAWjM,EACXkM,EAAUC,EAEd,CACA,OAAOF,CACT,CAQAG,KAAAA,CAAM5B,GACJ,OAAO,IAAI7C,EACRlK,MAAK,EAAK+M,EAAQ5C,OAClBnK,MAAK,EAAK+M,EAAQ3C,OAClBpK,MAAK,EAAK+M,EAAQ1C,OACvB,EAsBK,MAAMuE,EAOX,GAKA5M,WAAAA,CAAYC,GACV,IAAKA,QAA4B,IAAXA,EACpB,MAAM,IAAIC,MAAM,uCAElB,GAAsB,IAAlBD,EAAOE,OACT,MAAM,IAAID,MAAM,0CAKlB,IAAKD,EAAOG,OAHO,SAAUC,GAC3B,OAAQC,MAAMD,EAChB,IAEE,MAAM,IAAIH,MAAM,+CAElBlC,MAAK,EAAUiC,CACjB,CAQAZ,GAAAA,CAAIkB,GACF,OAAOvC,MAAK,EAAQuC,EACtB,CAOAJ,MAAAA,GACE,OAAOnC,MAAK,EAAQmC,MACtB,CAOAK,QAAAA,GACE,MAAO,IAAMxC,MAAK,EAAQwC,WAAa,GACzC,CAOAC,SAAAA,GACE,OAAOzC,MAAK,EAAQ0C,OACtB,CAQAC,UAAAA,CAAWC,GAET,QAAKA,GAID5C,KAAKmC,WAAaS,EAAIT,QAK5B,CAQAU,MAAAA,CAAOD,GAEL,IAAK5C,KAAK2C,WAAWC,GACnB,OAAO,EAGT,IAAK,IAAIL,EAAI,EAAGO,EAAO9C,KAAKmC,SAAUI,EAAIO,IAAQP,EAChD,GAAIvC,KAAKqB,IAAIkB,KAAOK,EAAIvB,IAAIkB,GAC1B,OAAO,EAIX,OAAO,CACT,CAQAQ,OAAAA,CAAQH,GAEN,IAAK5C,KAAK2C,WAAWC,GACnB,OAAO,KAGT,MAAMI,EAAW,GACjB,IAAK,IAAIT,EAAI,EAAGO,EAAO9C,KAAKmC,SAAUI,EAAIO,IAAQP,EAC5CvC,KAAKqB,IAAIkB,KAAOK,EAAIvB,IAAIkB,IAC1BS,EAASC,KAAKV,GAGlB,OAAOS,CACT,CAOA6L,KAAAA,GACE,OAAO,IAAI7B,EAAQhN,KAAKqB,IAAI,GAAIrB,KAAKqB,IAAI,GAAIrB,KAAKqB,IAAI,GACxD,CAQA6B,GAAAA,CAAIN,GAEF,IAAK5C,KAAK2C,WAAWC,GACnB,OAAO,KAET,MAAMX,EAAS,GACT6M,EAAU9O,KAAKyC,YACfsM,EAAUnM,EAAIH,YACpB,IAAK,IAAIF,EAAI,EAAGA,EAAIuM,EAAQ3M,SAAUI,EACpCN,EAAOgB,KAAK6L,EAAQvM,GAAKwM,EAAQxM,IAEnC,OAAO,IAAIqM,EAAM3M,EACnB,CAQA+M,WAAAA,CAAYpM,GACV,MAAMX,EAASjC,KAAKyC,YAIpB,OAHAR,EAAO,GAAKW,EAAIuH,OAChBlI,EAAO,GAAKW,EAAIwH,OAChBnI,EAAO,GAAKW,EAAIyH,OACT,IAAIuE,EAAM3M,EACnB,ECvcK,MAAMgN,EAAO,CAQlBC,CAAAA,CAAElO,GACA,IAAI8H,EAAM9H,EACV,MAAMmO,EAAQnO,EAAIoO,MAAM,KAWxB,OATqB,IAAjBD,EAAMhN,QACK,SAAbgN,EAAM,KAMNrG,EALc,CACZuG,GAAI,KACJC,IAAK,MACLC,OAAQ,KAEEJ,EAAM,KAEbrG,CACT,GCAK,SAAS0G,EAAWlD,EAAKmD,EAAQC,GACtC,GAAI,MAAOpD,GAAP,MACKmD,EACP,OAAO,EAET,MAAME,EAAMD,EAAS,EAAa,EAATA,EAAa,EACtC,OAAOpD,EAAIsD,UAAUD,EAAKA,EAAMF,EAAOtN,UAAYsN,CACrD,CASO,SAASI,EAASvD,EAAKmD,GAC5B,OAAI,MAAOnD,GAAP,MACKmD,GAGFnD,EAAIsD,UAAUtD,EAAInK,OAASsN,EAAOtN,UAAYsN,CACvD,CAwCO,SAASK,EAASC,GACvB,MAAMC,EAAQ,GAEd,GAAID,QACF,OAAOC,EAIT,MAAMC,EAAQ,WAEd,IAAIC,EAAQD,EAAME,KAAKJ,GACvB,KAAOG,GACLF,EAAM/M,KAAKiN,EAAM,IACjBA,EAAQD,EAAME,KAAKJ,GAErB,OAAOC,CACT,CAsEO,SAASI,EAAiBC,GAC/B,IAAIC,EAAM,KACV,GAAI,MAAOD,GAEO,MAAhBA,EAAS,GAAY,CACrB,MAAME,EAAYF,EAASG,cAAcpB,MAAM,KACtB,IAArBmB,EAAUpO,SACZmO,EAAMC,EAAUE,MAED,QACHC,KAAKJ,KAAQA,EAAIK,SAAS,OACpCL,EAAM,MAGZ,CACA,OAAOA,CACT,CAQO,SAASM,EAAmBtE,GACjC,MAAMuE,EAAM,IAAIC,WAAWxE,EAAInK,QAC/B,IAAK,IAAII,EAAI,EAAGO,EAAOwJ,EAAInK,OAAQI,EAAIO,EAAMP,IAC3CsO,EAAItO,GAAK+J,EAAIyE,WAAWxO,GAE1B,OAAOsO,CACT,CAeO,SAASG,EAAeC,EAAQC,GACrC,MAAMC,EAASxN,KAAKC,IAAI,GAAIsN,GACtBE,EAAQ,IAAOD,EACrB,OAAOxN,KAAK0N,MAAMJ,EAASE,EAASC,GAASD,CAC/C,CCtNO,SAASG,EAAWT,EAAKU,GAE9B,QAAoB,IAATA,EAAsB,CAC/BA,EAAO,GACP,IAAK,IAAIhP,EAAI,EAAGA,EAAIsO,EAAI1O,SAAUI,EAChCgP,EAAKtO,KAAKV,EAEd,CAEA,IAAK,IAAIA,EAAI,EAAGA,EAAIgP,EAAKpP,SAAUI,EACjC,GAAIgP,EAAKhP,IAAMsO,EAAI1O,OACjB,MAAM,IAAID,MAAM,sCAIpB,IAAI4G,EAAM,GACV,IAAK,IAAIvG,EAAI,EAAGA,EAAIgP,EAAKpP,SAAUI,EACvB,IAANA,IACFuG,GAAO,KAETA,GAAO,IAAMyI,EAAKhP,GAAK,IAAMsO,EAAIU,EAAKhP,IAExC,OAAOuG,CACT,CA0EO,SAAS0I,EAAgBC,EAAMC,GACpC,OAAa,OAATD,GACO,OAATC,QACgB,IAATD,QACS,IAATC,GAKFC,EAFYF,EAAK/O,QAAQkP,OACbF,EAAKhP,QAAQkP,OAElC,CASO,SAASD,EAAYF,EAAMC,GAChC,OAAa,OAATD,GACO,OAATC,QACgB,IAATD,QACS,IAATC,GAGLD,EAAKtP,SAAWuP,EAAKvP,QAGlBsP,EAAKrP,OAAM,SAAUyP,EAASvE,GACnC,OAAOuE,IAAYH,EAAKpE,EAC1B,GACF,CAQO,SAASwE,EAAmBjB,GACjC,OAAOkB,OAAOC,aAAalO,MAAMiO,OAAQlB,EAC3C,CAYO,SAASoB,EAAkBpB,EAAKqB,EAAYC,EAAOC,SAEnC,IAAVD,GACTA,EAAQ,GACRA,GAAStB,EAAI1O,UAEbgQ,EAAQ,SAES,IAARC,GACTA,GAAOD,GACPC,EAAMvB,EAAI1O,UACViQ,EAAMvB,EAAI1O,QAGZ,IAAK,IAAII,EAAI4P,EAAO5P,EAAI6P,IAAO7P,EAC7B,GAAI2P,EAAWrB,EAAItO,GAAIA,EAAGsO,GACxB,OAAOtO,CAIb,CAQO,SAAS8P,EAA4BX,GAC1C,OAAO,SAAUG,EAASvE,EAAOmE,GAC/B,IAAK,IAAIlP,EAAI,EAAGA,EAAImP,EAAKvP,SAAUI,EACjC,GAAIkP,EAAKnE,EAAQ/K,KAAOmP,EAAKnP,GAC3B,OAAO,EAGX,OAAO,CACT,CACF,CAuHO,SAAS+P,EAAeC,EAAOC,GACpC,MAAMC,EAAY,OAElB,IAAIC,EAAY,EAChB,MAAMC,EAAU,GAChB,IAAK,IAAIpQ,EAAI,EAAGA,EAAIgQ,EAAMpQ,SAAUI,EAAG,CACrC,IAAIqQ,EAAY,GACN,IAANrQ,IACFqQ,GAAaH,GAEfG,GAAa,KAAOJ,EAAWC,EAC/B,MAAMI,EAAW3R,OAAO4R,KAAKP,EAAMhQ,IACnC,IAAK,IAAIkK,EAAI,EAAGA,EAAIoG,EAAS1Q,SAAUsK,EAAG,CACxC,MAAMzL,EAAM6R,EAASpG,GACT,SAARzL,IACF4R,GAAa5R,EAAM,KAAOuR,EAAMhQ,GAAGvB,GAAOyR,EAE9C,CACAG,GAAaH,EACb,MAAMM,EAASnC,EAAmBgC,GAClCD,EAAQ1P,KAAK8P,GACbL,GAAaK,EAAOC,WAAaT,EAAMhQ,GAAG0Q,KAAKD,UACjD,CAEA,MACME,EAAUtC,EADG6B,SAAmBD,EAAW,KAAOC,GAIlDU,EAAS,IAAIrC,WAAW4B,EAAYQ,EAAQF,YAClD,IAAI9O,EAAS,EAEb,IAAK,IAAId,EAAI,EAAGA,EAAImP,EAAMpQ,SAAUiB,EAClC+P,EAAOC,IAAIT,EAAQvP,GAAIc,GACvBA,GAAUyO,EAAQvP,GAAG4P,WACrBG,EAAOC,IAAI,IAAItC,WAAWyB,EAAMnP,GAAG6P,MAAO/O,GAC1CA,GAAUqO,EAAMnP,GAAG6P,KAAKD,WAM1B,OAHAG,EAAOC,IAAIF,EAAShP,GAGbiP,CACT,CCjVO,MAAME,EAAa,CACxB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,UACpB,OAAQ,CAAC,KAAM,MAAO,oBACtB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,IAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,MAAO,2BACtB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,IAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,UACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,SACpB,OAAQ,CAAC,KAAM,IAAK,SACpB,OAAQ,CAAC,KAAM,MAAO,aAExB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,uBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,MAAO,2BACtB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,2DACpB,KAAQ,CAAC,KAAM,IAAK,0DACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,MAAO,oBACtB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,MAAO,6CACtB,KAAQ,CAAC,KAAM,IAAK,uBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,MAAO,wBACtB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,MAAO,aACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,MAAO,6BACtB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,MAAO,4BACtB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,MAAO,qBACtB,OAAQ,CAAC,KAAM,MAAO,qBACtB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,MAAO,sCACtB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,MAAO,2BACtB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,GAAI,GAAI,IACjB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,MAAO,iCACtB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,MAAO,8BACtB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,MAAO,uCACtB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,MAAO,mCACtB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,IAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,MAAO,sBACtB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,MAAO,2BACtB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,MAAO,gCACtB,KAAQ,CAAC,KAAM,IAAK,gDACpB,KAAQ,CAAC,KAAM,MAAO,iBACtB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,MAAO,iCACtB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,mDACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,MAAO,uBACtB,KAAQ,CAAC,KAAM,MAAO,yBACtB,KAAQ,CAAC,KAAM,MAAO,mBACtB,KAAQ,CAAC,KAAM,OAAQ,uBACvB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,qDACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,MAAO,qBACtB,KAAQ,CAAC,KAAM,MAAO,mBACtB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,mDACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,yDACpB,KAAQ,CAAC,KAAM,IAAK,0DACpB,OAAQ,CAAC,KAAM,IAAK,2DACpB,OAAQ,CAAC,KAAM,IAAK,sDACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,MAAO,8BACtB,KAAQ,CAAC,KAAM,MAAO,uBACtB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,IAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,uBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,IAAQ,CAAC,KAAM,MAAO,mBACtB,KAAQ,CAAC,KAAM,MAAO,qBACtB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,MAAO,+BACtB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,IAAQ,CAAC,KAAM,MAAO,iBACtB,KAAQ,CAAC,KAAM,MAAO,aACtB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,MAAO,2BACtB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,IAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,0BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,MAAO,0BACtB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,sDACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,gDAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,MAAO,qBACtB,OAAQ,CAAC,KAAM,MAAO,wBACtB,OAAQ,CAAC,KAAM,MAAO,6BACtB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,MAAO,sBACtB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,MAAO,uBACtB,OAAQ,CAAC,KAAM,MAAO,gCACtB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,MAAO,kBACtB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,MAAO,wBACtB,KAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,MAAO,mDACtB,OAAQ,CAAC,KAAM,MAAO,8CACtB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,MAAO,iBACtB,OAAQ,CAAC,KAAM,MAAO,iBACtB,OAAQ,CAAC,KAAM,MAAO,gBACtB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,MAAO,6BACtB,OAAQ,CAAC,KAAM,MAAO,iCACtB,OAAQ,CAAC,KAAM,MAAO,6BACtB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,qBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,cACtB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,MAAO,uCACtB,OAAQ,CAAC,KAAM,MAAO,kCACtB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,MAAO,iCACtB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,MAAO,eACtB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,MAAO,eACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,UACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,MAAO,kBACtB,KAAQ,CAAC,KAAM,IAAK,+BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,MAAO,oBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,eACtB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,MAAO,gBACtB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,MAAO,0BACtB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,OACpB,OAAQ,CAAC,KAAM,IAAK,IACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,MAAO,eACtB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,IAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,UACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,MAAO,8BACtB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,MAAO,0CACtB,OAAQ,CAAC,KAAM,MAAO,iCACtB,OAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,MAAO,oBACtB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,MAAO,oBACtB,KAAQ,CAAC,KAAM,MAAO,wBACtB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,MAAO,mBACtB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,MAAO,0BACtB,KAAQ,CAAC,KAAM,MAAO,yBACtB,KAAQ,CAAC,KAAM,MAAO,8BACtB,KAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,MAAO,kBACtB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,MAAO,kBACtB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,MAAO,yBACtB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,MAAO,iBACtB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,MAAO,QACtB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,MAAO,iBACtB,KAAQ,CAAC,KAAM,MAAO,gBACtB,KAAQ,CAAC,KAAM,MAAO,gBACtB,KAAQ,CAAC,KAAM,MAAO,cACtB,KAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,MAAO,yBACtB,KAAQ,CAAC,KAAM,MAAO,yBACtB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,MAAO,qBACtB,KAAQ,CAAC,KAAM,MAAO,yBACtB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,wDACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,MAAO,sBACtB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,OACpB,KAAQ,CAAC,KAAM,IAAK,QACpB,KAAQ,CAAC,KAAM,IAAK,SACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,MAAO,mCACtB,KAAQ,CAAC,KAAM,MAAO,qCACtB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,MAAO,gBACtB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,OAAQ,iCACvB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,MAAO,mBACtB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,OAAQ,oCACvB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,MAAO,oBACtB,KAAQ,CAAC,KAAM,MAAO,oBACtB,KAAQ,CAAC,KAAM,MAAO,2BACtB,KAAQ,CAAC,KAAM,MAAO,6BACtB,KAAQ,CAAC,KAAM,MAAO,uBACtB,KAAQ,CAAC,KAAM,MAAO,4BACtB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,MAAO,gBACtB,IAAQ,CAAC,KAAM,IAAK,uBACpB,IAAQ,CAAC,KAAM,MAAO,eACtB,KAAQ,CAAC,KAAM,MAAO,kBACtB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,IAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,MAAO,uBACtB,KAAQ,CAAC,KAAM,MAAO,uBACtB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,MAAO,sBACtB,OAAQ,CAAC,KAAM,MAAO,0BACtB,KAAQ,CAAC,KAAM,MAAO,mBACtB,KAAQ,CAAC,KAAM,IAAK,+BACpB,IAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,MAAO,4BACtB,KAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,MAAO,kBACtB,KAAQ,CAAC,KAAM,MAAO,0BACtB,KAAQ,CAAC,KAAM,MAAO,0BACtB,KAAQ,CAAC,KAAM,MAAO,+BACtB,KAAQ,CAAC,KAAM,MAAO,+BACtB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,MAAO,iBACtB,KAAQ,CAAC,KAAM,MAAO,0BACtB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,MAAO,oBACtB,KAAQ,CAAC,KAAM,MAAO,uBACtB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,MAAO,oCACtB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,MAAO,uBACtB,KAAQ,CAAC,KAAM,MAAO,qBACtB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,MAAO,kBACtB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,MAAO,wBACtB,KAAQ,CAAC,KAAM,MAAO,mBACtB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,qDACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,MAAO,0BACtB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,MAAO,+BACtB,KAAQ,CAAC,KAAM,MAAO,6BACtB,KAAQ,CAAC,KAAM,MAAO,uBACtB,KAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,gDACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,MAAO,+BACtB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,gDACpB,KAAQ,CAAC,KAAM,IAAK,iDACpB,KAAQ,CAAC,KAAM,IAAK,mDACpB,KAAQ,CAAC,KAAM,IAAK,mDACpB,KAAQ,CAAC,KAAM,IAAK,gDACpB,KAAQ,CAAC,KAAM,IAAK,gDACpB,KAAQ,CAAC,KAAM,MAAO,sDACtB,KAAQ,CAAC,GAAI,GAAI,IACjB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,MAAO,gCACtB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,MAAO,iBACtB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,MAAO,gCACtB,KAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,MAAO,4BACtB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,mDACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,sDACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,MAAO,0CACtB,KAAQ,CAAC,KAAM,MAAO,+BACtB,OAAQ,CAAC,KAAM,MAAO,6CACtB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,4BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,MAAO,gBACtB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,IAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,MAAO,aACtB,OAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,MAAO,qBACtB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,MAAO,kBACtB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,IAAQ,CAAC,KAAM,IAAK,iBACpB,IAAQ,CAAC,KAAM,MAAO,+BACtB,KAAQ,CAAC,KAAM,MAAO,2CACtB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,MAAO,wBACtB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,iDACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,KAAM,mCACrB,OAAQ,CAAC,KAAM,KAAM,8BACrB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,MAAO,oBACtB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,wBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,OAAQ,wBACvB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,iDACpB,KAAQ,CAAC,KAAM,IAAK,4DACpB,KAAQ,CAAC,KAAM,IAAK,sDACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,gDACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,sDACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,wDACpB,KAAQ,CAAC,KAAM,IAAK,4DACpB,KAAQ,CAAC,KAAM,IAAK,4DACpB,KAAQ,CAAC,KAAM,IAAK,uDACpB,KAAQ,CAAC,KAAM,IAAK,oDACpB,KAAQ,CAAC,KAAM,IAAK,mDACpB,KAAQ,CAAC,KAAM,IAAK,oDACpB,KAAQ,CAAC,KAAM,IAAK,gDACpB,KAAQ,CAAC,KAAM,IAAK,kDACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,sDACpB,KAAQ,CAAC,KAAM,IAAK,qDACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,6DACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,kDACpB,KAAQ,CAAC,KAAM,IAAK,gDACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,uDACpB,KAAQ,CAAC,KAAM,IAAK,0DACpB,KAAQ,CAAC,KAAM,IAAK,wDACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,iDACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,MAAO,wBACtB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,4BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qDACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,0DACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,mDACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,8DACpB,OAAQ,CAAC,KAAM,IAAK,oDACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,oDACpB,OAAQ,CAAC,KAAM,IAAK,sDACpB,OAAQ,CAAC,KAAM,IAAK,uDACpB,OAAQ,CAAC,KAAM,IAAK,kEACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uDACpB,OAAQ,CAAC,KAAM,IAAK,wDACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,6BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,MAAO,yBACtB,OAAQ,CAAC,KAAM,MAAO,yBACtB,OAAQ,CAAC,KAAM,IAAK,QACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,UACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,GAAI,GAAI,IACjB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,MAAO,oBACtB,OAAQ,CAAC,KAAM,MAAO,kBACtB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,MAAO,uBACtB,OAAQ,CAAC,KAAM,MAAO,2BACtB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,MAAO,kBACtB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,MAAO,sBACtB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,MAAO,4BACtB,OAAQ,CAAC,KAAM,MAAO,yBACtB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,MAAO,qBACtB,OAAQ,CAAC,KAAM,MAAO,6BACtB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,MAAO,wBACtB,OAAQ,CAAC,KAAM,MAAO,aACtB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,MAAO,oBACtB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,MAAO,aACtB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,MAAO,qBACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,MAAO,qBACtB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,MAAO,gBACtB,KAAQ,CAAC,KAAM,MAAO,eACtB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,MAAO,gCACtB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,WAAY,uBAC3B,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,IAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,MAAO,8BACtB,KAAQ,CAAC,KAAM,MAAO,+BACtB,IAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,WAAY,WAC3B,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,IAAQ,CAAC,KAAM,IAAK,6BACpB,IAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,MAAO,0BACtB,KAAQ,CAAC,KAAM,MAAO,8BACtB,KAAQ,CAAC,KAAM,MAAO,uBACtB,KAAQ,CAAC,KAAM,MAAO,gBACtB,KAAQ,CAAC,KAAM,MAAO,gBACtB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,OAAQ,wBACvB,KAAQ,CAAC,KAAM,MAAO,oBACtB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,IAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,MAAO,wBACtB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,MAAO,2BACtB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,MAAO,0BACtB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,OAAQ,uBACvB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,OAAQ,wBACvB,KAAQ,CAAC,KAAM,OAAQ,iBACvB,KAAQ,CAAC,KAAM,KAAM,iCACrB,KAAQ,CAAC,KAAM,IAAK,4CAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,IAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,MAAO,iCACtB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,IAAQ,CAAC,KAAM,IAAK,kBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,6BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,IAAQ,CAAC,KAAM,IAAK,kBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,MAAO,iBACtB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,mDACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,oCAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,MAAO,2BACtB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,sDACpB,OAAQ,CAAC,KAAM,MAAO,wBACtB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,kDACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,2DACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,MAAO,eACtB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,MAAO,sCACtB,KAAQ,CAAC,KAAM,IAAK,qDACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,MAAO,0BACtB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,iDACpB,KAAQ,CAAC,KAAM,IAAK,iDACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,qDACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,gDACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,0DACpB,KAAQ,CAAC,KAAM,IAAK,0DACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,gEACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,kDACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,kDACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,gDACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,MAAO,yBACtB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,sDACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,MAAO,gCACtB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,kDACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,+CACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,OAAQ,8BACvB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,kDACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,QACpB,KAAQ,CAAC,KAAM,IAAK,QACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,OACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,MAAO,6BACtB,KAAQ,CAAC,KAAM,MAAO,0BACtB,KAAQ,CAAC,KAAM,MAAO,yBACtB,KAAQ,CAAC,KAAM,MAAO,sBACtB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,MAAO,sBACtB,KAAQ,CAAC,KAAM,MAAO,0BACtB,KAAQ,CAAC,KAAM,MAAO,4BACtB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,OAAQ,4BACvB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,MAAO,gBACtB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,6CACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,MAAO,mCACtB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,oBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,IAAK,+BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,MAAO,eACtB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,mCAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,OAAQ,+BACvB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,qBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,gCAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,2BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,MAAO,sBACtB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,MAAO,kBACtB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,MAAO,eACtB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,MAAO,kBACtB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,MAAO,oBACtB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,MAAO,kBACtB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,MAAO,eACtB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,MAAO,qBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,MAAO,iBACtB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,IAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,SACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,MAAO,uBACtB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,MAAO,8BACtB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,MAAO,kBACtB,KAAQ,CAAC,KAAM,IAAK,2BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,IAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,MAAO,kBAExB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,+CACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,MAAO,wBACtB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,MAAO,2BACtB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,gBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,8CAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,MAAO,kBACtB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,2DACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,oDACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,+BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,MAAO,uCACtB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,8CACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,mDAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,kDACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,MAAO,mCACtB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,MAAO,0BACtB,OAAQ,CAAC,KAAM,IAAK,wBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,MAAO,eACtB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,QACpB,OAAQ,CAAC,KAAM,IAAK,UACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,KAAM,mEACrB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,QACpB,KAAQ,CAAC,KAAM,MAAO,8BACtB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,MAAO,oCACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,SACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,oDACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,gDACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,iDACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,mBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,MAAO,2BACtB,OAAQ,CAAC,KAAM,MAAO,yCACtB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,MAAO,4BACtB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,MAAO,wBACtB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,MAAO,4BACtB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,MAAO,uBACtB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,+CACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,oCAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,IAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,4CACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kDACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,oCACpB,KAAQ,CAAC,KAAM,IAAK,wCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,KAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,qCACpB,KAAQ,CAAC,KAAM,MAAO,gCACtB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,kDACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,2CACpB,KAAQ,CAAC,KAAM,IAAK,yCACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,oCAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,wCAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,2DACpB,OAAQ,CAAC,KAAM,IAAK,+CACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,kDACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,sDACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,+CAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,MAAO,qCACtB,OAAQ,CAAC,KAAM,OAAQ,oCACvB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,kCAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,6BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,OAAQ,kBAEzB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,8CAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,MAAO,sBACtB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,IACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,OACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,yBAEtB,IAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,sBAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,MAAO,aAExB,IAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,kCAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,MAAO,oCACtB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,MAAO,gCACtB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,QACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,yCAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,gCAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,eAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,OAAQ,gCACvB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,sCAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,sCAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,8CAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,iBAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,+BAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,0BAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,+CACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,MAAO,qBACtB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,oBAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,kBAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,MAAO,yBACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,MAAO,iCACtB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,OAAQ,WACvB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,gBAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,MAAO,oBACtB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,OAAQ,eACvB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,KAAM,wCACrB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,mCAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,MAAO,8BACtB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,mDACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,oDACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,kBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,MAAO,sBACtB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,MAAO,kBACtB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,MAAO,0BACtB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,MAAO,8CACtB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,MAAO,+BACtB,OAAQ,CAAC,KAAM,MAAO,4BACtB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,OAAQ,aACvB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,OAAQ,oBACvB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,uDACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,MAAO,+BACtB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,MAAO,mCACtB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,YACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,kDACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,qDACpB,OAAQ,CAAC,KAAM,IAAK,oDACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,MAAO,sBACtB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,MAAO,6BACtB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,MAAO,uBACtB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,MAAO,2BACtB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,OAAQ,0BACvB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,MAAO,oBACtB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,oDACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,6DACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,MAAO,qCACtB,OAAQ,CAAC,KAAM,MAAO,oCACtB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,MAAO,2CACtB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,2DACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,+CACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,mDACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,+CACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,IACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,4DACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,oDACpB,OAAQ,CAAC,KAAM,IAAK,gDACpB,OAAQ,CAAC,KAAM,IAAK,yDACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,KAAM,sBACrB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,gCAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,sCAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,iBAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,sDACpB,OAAQ,CAAC,KAAM,IAAK,8CACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,uDACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,iDACpB,OAAQ,CAAC,KAAM,IAAK,4DACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,+CACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,yDACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,MAAO,4BACtB,OAAQ,CAAC,KAAM,MAAO,2BACtB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,MAAO,8BACtB,OAAQ,CAAC,KAAM,MAAO,+BACtB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,wCACpB,OAAQ,CAAC,KAAM,IAAK,0CACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,MAAO,6BACtB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,2CACpB,OAAQ,CAAC,KAAM,IAAK,4CACpB,OAAQ,CAAC,KAAM,IAAK,6CACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,MAAO,oCACtB,OAAQ,CAAC,KAAM,MAAO,8CAExB,IAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,IAAQ,CAAC,KAAM,IAAK,iBAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,oCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,OAAQ,CAAC,KAAM,IAAK,uCACpB,OAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,IAAQ,CAAC,KAAM,IAAK,oBAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,QACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,MAAO,mBACtB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,MAAO,eACtB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,MAAO,sCACtB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,OAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,8BACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,YACpB,KAAQ,CAAC,KAAM,IAAK,eACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,6BACpB,KAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,kBACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,KAAQ,CAAC,KAAM,IAAK,2BACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,yCACpB,OAAQ,CAAC,KAAM,IAAK,sCACpB,KAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,KAAQ,CAAC,KAAM,IAAK,4BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,iCACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,mCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,+BACpB,OAAQ,CAAC,KAAM,IAAK,qCACpB,OAAQ,CAAC,KAAM,IAAK,yBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,0BAEtB,IAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,MAAO,aACtB,OAAQ,CAAC,KAAM,MAAO,cACtB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,MAAO,0BACtB,OAAQ,CAAC,KAAM,MAAO,0BACtB,OAAQ,CAAC,KAAM,MAAO,cACtB,OAAQ,CAAC,KAAM,MAAO,uBACtB,OAAQ,CAAC,KAAM,MAAO,wBACtB,OAAQ,CAAC,KAAM,MAAO,uBACtB,KAAQ,CAAC,KAAM,IAAK,wBACpB,IAAQ,CAAC,KAAM,IAAK,aACpB,KAAQ,CAAC,KAAM,IAAK,qBACpB,KAAQ,CAAC,KAAM,IAAK,oBACpB,KAAQ,CAAC,KAAM,IAAK,mBACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,KAAQ,CAAC,KAAM,IAAK,cACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,+BACpB,IAAQ,CAAC,KAAM,IAAK,cAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,kCACpB,KAAQ,CAAC,KAAM,IAAK,qCAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,iBAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,kCACpB,OAAQ,CAAC,KAAM,IAAK,qBAEtB,IAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,eACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,0BACpB,OAAQ,CAAC,KAAM,IAAK,gCACpB,OAAQ,CAAC,KAAM,IAAK,2BACpB,OAAQ,CAAC,KAAM,IAAK,iCACpB,OAAQ,CAAC,KAAM,MAAO,kCACtB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,iBACpB,OAAQ,CAAC,KAAM,IAAK,mBACpB,OAAQ,CAAC,KAAM,MAAO,oBACtB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,MAAO,4BACtB,OAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,0BACpB,KAAQ,CAAC,KAAM,IAAK,yBACpB,KAAQ,CAAC,KAAM,MAAO,gBACtB,KAAQ,CAAC,KAAM,MAAO,eACtB,KAAQ,CAAC,KAAM,MAAO,iBACtB,KAAQ,CAAC,KAAM,MAAO,gBACtB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,WACpB,KAAQ,CAAC,KAAM,IAAK,wBACpB,KAAQ,CAAC,KAAM,IAAK,gBACpB,IAAQ,CAAC,KAAM,IAAK,eACpB,IAAQ,CAAC,KAAM,IAAK,oBAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,qBACpB,OAAQ,CAAC,KAAM,IAAK,yBACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,4BACpB,OAAQ,CAAC,KAAM,IAAK,6BAEtB,OAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,OAAQ,CAAC,KAAM,IAAK,uBACpB,OAAQ,CAAC,KAAM,IAAK,8BACpB,OAAQ,CAAC,KAAM,IAAK,kBACpB,OAAQ,CAAC,KAAM,IAAK,wBACpB,OAAQ,CAAC,KAAM,IAAK,aACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,oBACpB,OAAQ,CAAC,KAAM,IAAK,qBAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,8BAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,KAAM,IAAK,2BAEtB,KAAQ,CACN,OAAQ,CAAC,KAAM,IAAK,sBACpB,KAAQ,CAAC,OAAQ,IAAK,QACtB,KAAQ,CAAC,OAAQ,IAAK,wBACtB,KAAQ,CAAC,OAAQ,IAAK,8BAYnB,SAASC,EAAoBC,EAAOC,GAEzCH,EAAWE,GAASC,CACtB,CASO,MAAMC,EAAY,CACvB,OAAQ,UACR,OAAQ,eACR,OAAQ,WAER,OAAQ,cACR,OAAQ,kBACR,OAAQ,UACR,OAAQ,iBACR,OAAQ,cACR,OAAQ,kBACR,OAAQ,QACR,OAAQ,YACR,OAAQ,eACR,OAAQ,qBACR,OAAQ,QACR,OAAQ,QACR,OAAQ,WACR,OAAQ,YAER,OAAQ,wBACR,OAAQ,sBAER,OAAQ,mBACR,OAAQ,YACR,OAAQ,qBACR,OAAQ,mBACR,OAAQ,UAER,OAAQ,gBACR,OAAQ,oBACR,IAAQ,aACR,KAAQ,YACR,IAAQ,eACR,KAAQ,WACR,KAAQ,YACR,KAAQ,aACR,KAAQ,cACR,KAAQ,mBACR,KAAQ,YACR,KAAQ,UACR,KAAQ,QACR,KAAQ,gBACR,KAAQ,iBACR,KAAQ,WACR,KAAQ,UACR,KAAQ,kBACR,KAAQ,eACR,OAAQ,UACR,OAAQ,kBACR,OAAQ,cACR,IAAQ,OACR,KAAQ,UACR,OAAQ,iBACR,IAAQ,QACR,KAAQ,QACR,KAAQ,QACR,KAAQ,QACR,KAAQ,QACR,OAAQ,QACR,OAAQ,QACR,OAAQ,QACR,KAAQ,gBACR,IAAQ,WACR,KAAQ,WACR,KAAQ,WACR,KAAQ,WACR,OAAQ,WACR,OAAQ,WACR,OAAQ,WACR,KAAQ,UACR,OAAQ,aACR,KAAQ,WAWJC,EAAY,CAChBC,IAAI,EACJC,IAAI,EACJC,IAAI,EACJC,IAAI,EACJC,IAAI,EACJC,IAAI,EACJC,IAAI,EACJC,IAAI,EACJC,IAAI,EACJC,IAAI,EACJC,IAAI,EACJC,IAAI,EACJC,IAAI,EACJC,IAAI,GASC,SAASC,EAAYC,GAC1B,YAAgC,IAAlBhB,EAAUgB,EAC1B,CAUA,MAAMC,EAAkB,CACtBC,IAAI,EACJC,IAAI,EACJV,IAAI,EACJW,IAAI,EACJC,IAAI,EACJT,IAAI,EACJU,IAAI,GASC,SAASC,GAAkBP,GAChC,YAAsC,IAAxBC,EAAgBD,EAChC,CASO,MAAMQ,GAAU,CACrBC,GAAI,SACJC,GAAI,SACJC,QAAI7U,EACJ8U,GAAI,SACJC,GAAI,SACJC,GAAI,SACJC,GAAI,SACJC,GAAI,UACJC,GAAI,UACJC,GAAI,SACJf,GAAI,SACJE,GAAI,SACJpB,GAAI,QACJC,GAAI,SACJC,GAAI,SACJC,GAAI,SACJC,GAAI,SACJC,GAAI,SACJgB,GAAI,SACJJ,GAAI,SACJiB,GAAI,QACJ5B,QAAIzT,EACJsV,GAAI,QACJhB,GAAI,SACJZ,GAAI,QACJ6B,GAAI,SACJ5B,GAAI,SACJ6B,GAAI,SACJC,GAAI,SACJ7B,GAAI,QACJC,GAAI,SACJ6B,GAAI,SACJ5B,GAAI,SACJC,GAAI,UAUO4B,GAAmB,CAC9B,oBAAqB,4BACrB,sBAAuB,4BACvB,yBAA0B,sDAC1B,yBAA0B,qCAC1B,sBAAuB,mCACvB,yBAA0B,4BAC1B,yBAA0B,gCAC1B,yBAA0B,0CAC1B,yBAA0B,sEAC1B,yBAA0B,sEAC1B,yBAA0B,sEAC1B,yBAA0B,sEAC1B,yBAA0B,+CAC1B,yBAA0B,yDAC1B,yBAA0B,0DAC1B,yBAA0B,0DAC1B,yBAA0B,oEAC1B,yBAA0B,oEAC1B,yBAA0B,kEAC1B,yBAA0B,kEAC1B,yBAA0B,qDAC1B,yBAA0B,qDAC1B,yBAA0B,2FAC1B,yBAA0B,qCAC1B,yBAA0B,kDAC1B,yBAA0B,8CAC1B,yBAA0B,8BAC1B,yBAA0B,qEAC1B,yBAA0B,qDAC1B,yBAA0B,kBAC1B,yBAA0B,0BAC1B,0BAA2B,kCAC3B,0BAA2B,kCAC3B,0BAA2B,4CAC3B,0BAA2B,0DAC3B,0BAA2B,yDAC3B,0BAA2B,yDAC3B,0BAA2B,mDAC3B,0BAA2B,sCAC3B,0BAA2B,yCAC3B,sBAAuB,eACvB,wBAAyB,wCACzB,wBAAyB,yBACzB,wBAAyB,yDACzB,wBAAyB,wDACzB,wBAAyB,qCACzB,qBAAsB,iDAQXC,GACa,oBADbA,GAEa,sBAFbA,GAKU,sBALVA,GAMO,yBANPA,GAOQ,yBAPRA,GAaG,yBAbHA,GAuBM,yBAvBNA,GAyCE,sBCn6KR,MAAMC,GAOX,GAOA,GAMArU,WAAAA,CAAYuR,EAAO1B,GACjB,IAAK0B,QAA0B,IAAVA,EACnB,MAAM,IAAIrR,MAAM,oCAElB,GAAqB,IAAjBqR,EAAMpR,OACR,MAAM,IAAID,MAAM,6CAA+CqR,GAEjE,IAAK1B,QAA8B,IAAZA,EACrB,MAAM,IAAI3P,MAAM,sCAElB,GAAuB,IAAnB2P,EAAQ1P,OACV,MAAM,IAAID,MAAM,+CAAiD2P,GAEnE7R,MAAK,EAASuT,EACdvT,MAAK,EAAW6R,CAClB,CAOAyE,QAAAA,GACE,OAAOtW,MAAK,CACd,CAOAuW,UAAAA,GACE,OAAOvW,MAAK,CACd,CAOAwC,QAAAA,GACE,OAAOxC,KAAKwW,SAAW,KAAOxW,KAAKyW,uBACrC,CAQA5T,MAAAA,CAAOD,GACL,OAAOA,SAEL5C,MAAK,IAAW4C,EAAI0T,YACpBtW,MAAK,IAAa4C,EAAI2T,YAC1B,CAOAC,MAAAA,GACE,OAAOxW,MAAK,EAASA,MAAK,CAC5B,CAOA0W,YAAAA,GACE,OAAOjD,EAAUzT,MAAK,EACxB,CASA2W,QAAAA,GACE,QAAyB,SAAhB3W,MAAK,IACO,SAAlBA,MAAK,GACY,SAAlBA,MAAK,GACa,SAAlBA,MAAK,GAET,CAUA4W,SAAAA,GACE,OAAOC,SAAS7W,MAAK,EAAQ,IAAM,GAAM,CAC3C,CAOA,KACE,IAAI+E,EAMJ,YALuC,IAA5BsO,EAAWrT,MAAK,SAEvB,IADKqT,EAAWrT,MAAK,GAAQA,MAAK,KAEpC+E,EAAOsO,EAAWrT,MAAK,GAAQA,MAAK,IAE/B+E,CACT,CAOA+R,mBAAAA,GACE,IAAIpC,EACJ,MAAM3P,EAAO/E,MAAK,IAIlB,YAHoB,IAAT+E,IACT2P,EAAK3P,EAAK,IAEL2P,CACT,CAOA+B,qBAAAA,GACE,IAAIjN,EACJ,MAAMzE,EAAO/E,MAAK,IAIlB,YAHoB,IAAT+E,IACTyE,EAAOzE,EAAK,IAEPyE,CACT,EAaK,SAASuN,GAAmBjW,EAAGoH,GAEpC,IAAIY,EAAM+N,SAAS/V,EAAEwV,WAAY,IAAMO,SAAS3O,EAAEoO,WAAY,IAK9D,OAJY,IAARxN,IAEFA,EAAM+N,SAAS/V,EAAEyV,aAAc,IAAMM,SAAS3O,EAAEqO,aAAc,KAEzDzN,CACT,CAQO,SAASkO,GAAchW,GAC5B,IAAKA,QAAsB,IAARA,EACjB,MAAM,IAAIkB,MAAM,kCAElB,GAAmB,IAAflB,EAAImB,OACN,MAAM,IAAID,MAAM,2CAA6ClB,GAE/D,OAAO,IAAIqV,GAAIrV,EAAI4O,UAAU,EAAG,GAAI5O,EAAI4O,UAAU,EAAG,GACvD,CAmCO,SAASqH,KACd,OAAO,IAAIZ,GAAI,OAAQ,OACzB,CAQO,SAASa,GAAUC,GAExB,MAAwB,aAAjBA,EAAIX,QACb,CAiBO,SAASY,GAA0BD,GAExC,MAAwB,aAAjBA,EAAIX,QACb,CAiBO,SAASa,GAA8BF,GAE5C,MAAwB,aAAjBA,EAAIX,QACb,CAOO,SAASc,KACd,OAAO,IAAIjB,GAAI,OAAQ,OACzB,CAQO,SAASkB,GAAeJ,GAE7B,MAAwB,aAAjBA,EAAIX,QACb,CAQO,SAASgB,GAAqBC,GACnC,GAAI,MAAOA,EACT,OAAO,KAET,IAAIlE,EAAQ,KACR1B,EAAU,KACd,MAAMpI,EAAO4J,EACPqE,EAAQxW,OAAO4R,KAAKrJ,GAC1B,IAiBI0N,EAjBAQ,EAAQ,KACRC,GAAW,EAEf,IAAK,IAAIC,EAAK,EAAGC,EAAQJ,EAAMvV,OAAQ0V,EAAKC,IAASD,EAAI,CACvDtE,EAAQmE,EAAMG,GACdF,EAAQzW,OAAO4R,KAAKrJ,EAAK8J,IACzB,IAAK,IAAIwE,EAAK,EAAGC,EAAQL,EAAMxV,OAAQ4V,EAAKC,IAASD,EAEnD,GADAlG,EAAU8F,EAAMI,GACZtO,EAAK8J,GAAO1B,GAAS,KAAO4F,EAAS,CACvCG,GAAW,EACX,KACF,CAEF,GAAIA,EACF,KAEJ,CAKA,OAHIA,IACFT,EAAM,IAAId,GAAI9C,EAAO1B,IAEhBsF,CACT,CC1VO,MAAMc,GAMXvD,GAMA5S,MAUAqV,IAOAe,GAOAC,gBAOAC,YAOAC,UAOAC,MAOAtW,WAAAA,CAAY0S,GACV1U,KAAK0U,GAAKA,CACZ,EC3DF,SAAS6D,GAAoBC,GAC3B,MAAMC,EAAOD,EAAMxF,WACb0F,EAAK,IAAI5H,WAAW0H,EAAMrF,OAAQqF,EAAMG,WAAYF,GACpDG,EAAMJ,EAAMK,kBAClB,IAAIrM,EACJ,IAAK,IAAIjK,EAAI,EAAGA,EAAIkW,EAAMlW,GAAKqW,EAC7B,IAAK,IAAIxV,EAAIb,EAAIqW,EAAM,EAAGnM,EAAIlK,EAAGa,EAAIqJ,EAAGrJ,IAAKqJ,IAC3CD,EAAMkM,EAAGjM,GACTiM,EAAGjM,GAAKiM,EAAGtV,GACXsV,EAAGtV,GAAKoJ,CAGd,CAKO,MAAMsM,GAOX,GAOA,IAAkB,EAOlB,GAhDK,WACL,OAAO,IAAIC,UAAU,IAAIC,WAAW,CAAC,IAAI7F,QAAQ,GAAK,CACxD,CA8C0B8F,GAOxB,GAOA,GAOAjX,WAAAA,CAAYmR,EAAQ+F,GAClBlZ,MAAK,EAAUmT,OAEe,IAAnB+F,IACTlZ,MAAK,EAAkBkZ,GAEzBlZ,MAAK,EAAaA,MAAK,IAAoBA,MAAK,EAChDA,MAAK,EAAQ,IAAImZ,SAAShG,EAC5B,CAQAiG,UAAAA,CAAWT,GACT,OAAO3Y,MAAK,EAAMqZ,UAAUV,EAAY3Y,MAAK,EAC/C,CAQAsZ,SAAAA,CAAUX,GACR,OAAO3Y,MAAK,EAAMuZ,SAASZ,EAAY3Y,MAAK,EAC9C,CAQAwZ,UAAAA,CAAWb,GACT,OAAO3Y,MAAK,EAAMyZ,UAAUd,EAAY3Y,MAAK,EAC/C,CAQA0Z,aAAAA,CAAcf,GACZ,OAAO3Y,MAAK,EAAM2Z,aAAahB,EAAY3Y,MAAK,EAClD,CAQA4Z,SAAAA,CAAUjB,GACR,OAAO3Y,MAAK,EAAM6Z,SAASlB,EAAY3Y,MAAK,EAC9C,CAQA8Z,YAAAA,CAAanB,GACX,OAAO3Y,MAAK,EAAM+Z,YAAYpB,EAAY3Y,MAAK,EACjD,CAQAga,WAAAA,CAAYrB,GACV,OAAO3Y,MAAK,EAAMia,WAAWtB,EAAY3Y,MAAK,EAChD,CAQAka,WAAAA,CAAYvB,GACV,OAAO3Y,MAAK,EAAMma,WAAWxB,EAAY3Y,MAAK,EAChD,CASAoa,eAAAA,CAAgBzB,EAAYtS,GAE1B,MAAMgU,EAAW,IAAIvJ,WAAW9Q,MAAK,EAAS2Y,EAAYtS,GAEpDiU,EAAkB,EAAID,EAASlY,OAC/B8Q,EAAO,IAAInC,WAAWwJ,GAC5B,IAAIC,EAAY,EACZC,EAAW,EACf,IAAK,IAAIjY,EAAI,EAAGA,EAAI+X,IAAmB/X,EACrCgY,EAAYhY,EAAI,EAChBiY,EAAW7W,KAAKiD,MAAMrE,EAAI,GAG1B0Q,EAAK1Q,GAAK,OAAQ8X,EAASG,GAAa,GAAKD,GAE/C,OAAOtH,CACT,CASAwH,cAAAA,CAAe9B,EAAYtS,GACzB,OAAO,IAAIyK,WAAW9Q,MAAK,EAAS2Y,EAAYtS,EAClD,CASAqU,aAAAA,CAAc/B,EAAYtS,GACxB,OAAO,IAAI0S,UAAU/Y,MAAK,EAAS2Y,EAAYtS,EACjD,CASAsU,eAAAA,CAAgBhC,EAAYtS,GAC1B,MAAMuS,EAAMgC,YAAY/B,kBAClBgC,EAAYxU,EAAOuS,EACzB,IAAI3F,EAAO,KAEX,GAAI0F,EAAaC,GAAQ,EACvB3F,EAAO,IAAI2H,YAAY5a,MAAK,EAAS2Y,EAAYkC,GAC7C7a,MAAK,GACPuY,GAAoBtF,OAEjB,CACLA,EAAO,IAAI2H,YAAYC,GACvB,IAAIvN,EAAQqL,EACZ,IAAK,IAAIpW,EAAI,EAAGA,EAAIsY,IAAatY,EAC/B0Q,EAAK1Q,GAAKvC,KAAKoZ,WAAW9L,GAC1BA,GAASsL,CAEb,CACA,OAAO3F,CACT,CASA6H,cAAAA,CAAenC,EAAYtS,GACzB,MAAMuS,EAAMI,WAAWH,kBACjBgC,EAAYxU,EAAOuS,EACzB,IAAI3F,EAAO,KAEX,GAAI0F,EAAaC,GAAQ,EACvB3F,EAAO,IAAI+F,WAAWhZ,MAAK,EAAS2Y,EAAYkC,GAC5C7a,MAAK,GACPuY,GAAoBtF,OAEjB,CACLA,EAAO,IAAI+F,WAAW6B,GACtB,IAAIvN,EAAQqL,EACZ,IAAK,IAAIpW,EAAI,EAAGA,EAAIsY,IAAatY,EAC/B0Q,EAAK1Q,GAAKvC,KAAKsZ,UAAUhM,GACzBA,GAASsL,CAEb,CACA,OAAO3F,CACT,CASA8H,eAAAA,CAAgBpC,EAAYtS,GAC1B,MAAMuS,EAAMoC,YAAYnC,kBAClBgC,EAAYxU,EAAOuS,EACzB,IAAI3F,EAAO,KAEX,GAAI0F,EAAaC,GAAQ,EACvB3F,EAAO,IAAI+H,YAAYhb,MAAK,EAAS2Y,EAAYkC,GAC7C7a,MAAK,GACPuY,GAAoBtF,OAEjB,CACLA,EAAO,IAAI+H,YAAYH,GACvB,IAAIvN,EAAQqL,EACZ,IAAK,IAAIpW,EAAI,EAAGA,EAAIsY,IAAatY,EAC/B0Q,EAAK1Q,GAAKvC,KAAKwZ,WAAWlM,GAC1BA,GAASsL,CAEb,CACA,OAAO3F,CACT,CASAgI,eAAAA,CAAgBtC,EAAYtS,GAC1B,MAAMuS,EAAMsC,eAAerC,kBACrBgC,EAAYxU,EAAOuS,EACzB,IAAI3F,EAAO,KAEX,GAAI0F,EAAaC,GAAQ,EACvB3F,EAAO,IAAIiI,eAAelb,MAAK,EAAS2Y,EAAYkC,GAChD7a,MAAK,GACPuY,GAAoBtF,OAEjB,CACLA,EAAO,IAAIiI,eAAeL,GAC1B,IAAIvN,EAAQqL,EACZ,IAAK,IAAIpW,EAAI,EAAGA,EAAIsY,IAAatY,EAC/B0Q,EAAK1Q,GAAKvC,KAAK0Z,cAAcpM,GAC7BA,GAASsL,CAEb,CACA,OAAO3F,CACT,CASAkI,cAAAA,CAAexC,EAAYtS,GACzB,MAAMuS,EAAMwC,WAAWvC,kBACjBgC,EAAYxU,EAAOuS,EACzB,IAAI3F,EAAO,KAEX,GAAI0F,EAAaC,GAAQ,EACvB3F,EAAO,IAAImI,WAAWpb,MAAK,EAAS2Y,EAAYkC,GAC5C7a,MAAK,GACPuY,GAAoBtF,OAEjB,CACLA,EAAO,IAAImI,WAAWP,GACtB,IAAIvN,EAAQqL,EACZ,IAAK,IAAIpW,EAAI,EAAGA,EAAIsY,IAAatY,EAC/B0Q,EAAK1Q,GAAKvC,KAAK4Z,UAAUtM,GACzBA,GAASsL,CAEb,CACA,OAAO3F,CACT,CASAoI,cAAAA,CAAe1C,EAAYtS,GACzB,MAAMuS,EAAM0C,cAAczC,kBACpBgC,EAAYxU,EAAOuS,EACzB,IAAI3F,EAAO,KAEX,GAAI0F,EAAaC,GAAQ,EACvB3F,EAAO,IAAIqI,cAActb,MAAK,EAAS2Y,EAAYkC,GAC/C7a,MAAK,GACPuY,GAAoBtF,OAEjB,CACLA,EAAO,IAAIqI,cAAcT,GACzB,IAAIvN,EAAQqL,EACZ,IAAK,IAAIpW,EAAI,EAAGA,EAAIsY,IAAatY,EAC/B0Q,EAAK1Q,GAAKvC,KAAK8Z,aAAaxM,GAC5BA,GAASsL,CAEb,CACA,OAAO3F,CACT,CASAsI,gBAAAA,CAAiB5C,EAAYtS,GAC3B,MAAMuS,EAAM/U,aAAagV,kBACnBgC,EAAYxU,EAAOuS,EACzB,IAAI3F,EAAO,KAEX,GAAI0F,EAAaC,GAAQ,EACvB3F,EAAO,IAAIpP,aAAa7D,MAAK,EAAS2Y,EAAYkC,GAC9C7a,MAAK,GACPuY,GAAoBtF,OAEjB,CACLA,EAAO,IAAIpP,aAAagX,GACxB,IAAIvN,EAAQqL,EACZ,IAAK,IAAIpW,EAAI,EAAGA,EAAIsY,IAAatY,EAC/B0Q,EAAK1Q,GAAKvC,KAAKga,YAAY1M,GAC3BA,GAASsL,CAEb,CACA,OAAO3F,CACT,CASAuI,gBAAAA,CAAiB7C,EAAYtS,GAC3B,MAAMuS,EAAM6C,aAAa5C,kBACnBgC,EAAYxU,EAAOuS,EACzB,IAAI3F,EAAO,KAEX,GAAI0F,EAAaC,GAAQ,EACvB3F,EAAO,IAAIwI,aAAazb,MAAK,EAAS2Y,EAAYkC,GAC9C7a,MAAK,GACPuY,GAAoBtF,OAEjB,CACLA,EAAO,IAAIwI,aAAaZ,GACxB,IAAIvN,EAAQqL,EACZ,IAAK,IAAIpW,EAAI,EAAGA,EAAIsY,IAAatY,EAC/B0Q,EAAK1Q,GAAKvC,KAAKka,YAAY5M,GAC3BA,GAASsL,CAEb,CACA,OAAO3F,CACT,CAQAyI,OAAAA,CAAQ/C,GAEN,MAAMrM,EAAMtM,KAAKoZ,WAAWT,GAAYnW,SAAS,IAEjD,MAAO,OAAOoN,UAAU,EAAG,EAAItD,EAAInK,QAAUmK,EAAIqP,aACnD,EChaK,SAASC,KACd,MAAO,eACT,CAWO,SAASC,GAAe1I,GAG7B,QAAIA,EAAOH,WAAa,MAOyB,SAJ7B,IAAIlC,WAAWqC,EAAQ,IAAK,GAI7B2I,QAHG,SAAUC,EAAUC,GACxC,OAAOD,EAAYhK,OAAOC,aAAagK,EACzC,GACyC,GAC3C,CAIA,MAAMC,GAAMlK,OAAOC,aAAa,SAkFhC,MAAMkK,GAOJC,MAAAA,CAAOhJ,GACL,IAAIiJ,EAAS,GACb,IAAK,IAAI7Z,EAAI,EAAGO,EAAOqQ,EAAOhR,OAAQI,EAAIO,IAAQP,EAChD6Z,GAAUrK,OAAOC,aAAamB,EAAO5Q,IAEvC,OAAO6Z,CACT,EASK,SAASC,GAAsBC,GACpC,IAAKA,EACH,OAAO,KAGT,MAAMC,EAAU,CACdC,EAAG,IACHC,EAAG,IACHC,EAAG,IACHC,EAAG,IACHC,EAAG,IACHC,EAAG,KAGL,IAAIC,EAAO,GACX,IAAK,IAAIpc,EAAI,EAAGA,EAAI4b,EAAIna,OAAQzB,IAAK,CACnC,MACMiB,EAAI4a,EADAD,EAAI1M,UAAUlP,EAAGA,EAAI,IAE3BiB,IACFmb,GAAQnb,EAEZ,CAEA,OAAOmb,CACT,CAQO,SAASC,GAAyBC,GACvC,OAAOA,IAAW5G,EACpB,CAQO,SAAS6G,GAA0BD,GACxC,OAAOA,IAAW5G,EACpB,CAQO,SAAS8G,GAA6BF,GAC3C,OAAOA,IAAW5G,IAChB4G,IAAW5G,EACf,CAQO,SAAS+G,GAA6BH,GAC3C,OAAOA,IAAW5G,IAChB4G,IAAW5G,EACf,CAQO,SAASgH,GAAyBJ,GACvC,OAAiD,OAA1CA,EAAO9M,MAAM,wBACtB,CAQA,SAASmN,GAAoBL,GAC3B,OAAOA,IAAW5G,EACpB,CAyHO,SAASkH,GAAcC,EAAeC,EAAqBnX,GAChE,IAAIyC,EAAM,KACV,IACwB,IAAlByU,GAAyC,IAAlBA,EAEvBzU,EAD0B,IAAxB0U,EACI,IAAI1M,WAAWzK,GAEf,IAAI0S,UAAU1S,GAEK,KAAlBkX,EAEPzU,EAD0B,IAAxB0U,EACI,IAAI5C,YAAYvU,GAEhB,IAAI2S,WAAW3S,GAEI,KAAlBkX,IAEPzU,EAD0B,IAAxB0U,EACI,IAAIxC,YAAY3U,GAEhB,IAAI+U,WAAW/U,GAG3B,CAAE,MAAOpB,GACP,GAAIA,aAAiBwY,WAAY,CAC/B,MAAMC,EAAW/Z,KAAKiD,MAAMjD,KAAKga,IAAItX,GAAQ1C,KAAKga,IAAI,IACtDxZ,EAAOc,MAAM,kCACXoB,EAAO,QAAUqX,EAAW,KAChC,CACF,CACA,OAAO5U,CACT,CA6BO,SAAS8U,GAA6BlJ,EAAImJ,GAC/C,OAAOA,EAAa,EAAIpJ,EAAYC,GAAM,GAAK,CACjD,CAiBA,MAAMoJ,GAGY,WAHZA,GAIW,WAJXA,GAKiB,WALjBA,GAMO,WA6BN,MAAMC,GAOX,GAAgB,CAAC,EAOjB,GAOA,GAAsB,IAAI7B,GAO1B,GAAelc,MAAK,EAQpB,GAAcmT,GACZ,OAAOnT,MAAK,EAAoBmc,OAAOhJ,EACzC,CAQA,GAAqBA,GACnB,OAAOnT,MAAK,EAAamc,OAAOhJ,EAClC,CAOA6K,sBAAAA,GACE,OAAOhe,MAAK,CACd,CAOAie,sBAAAA,CAAuBC,GACrBle,MAAK,EAAuBke,CAC9B,CAOAC,sBAAAA,CAAuBD,GAQrBle,MAAK,EAAe,IAAIoe,YAAYF,EACtC,CASAG,gBAAAA,GACE,OAAOre,MAAK,CACd,CASA,GAASse,EAAQpa,GAEf,MAAMqP,EAAQ+K,EAAO5C,QAAQxX,GAC7BA,GAAU0W,YAAY/B,kBAEtB,MAAMhH,EAAUyM,EAAO5C,QAAQxX,GAG/B,OAFAA,GAAU0W,YAAY/B,kBAEf,CACL1B,IAAK,IAAId,GAAI9C,EAAO1B,GACpBwG,UAAWnU,EAEf,CAUA,GAAqBoa,EAAQpa,EAAQqa,GACnC,MAAMC,EAAW,CAAC,EAGlB,IAAIC,EAAOze,MAAK,EAAiBse,EAAQpa,EAAQqa,GAIjD,GAHAra,EAASua,EAAKpG,UAGVhB,GAA8BoH,EAAKtH,KACrC,MAAO,CACLlE,KAAMuL,EACNnG,UAAWoG,EAAKpG,UAChBqG,YAAY,GAYhB,GAPAF,EAASC,EAAKtH,IAAIX,UAAY,CAC5BW,IAAKsH,EAAKtH,IACVzC,GAAI,OACJwD,GAAIuG,EAAKvG,GACTC,gBAAiBsG,EAAKtG,iBAGnBsG,EAAKtG,gBASH,CAEL,IAAIwG,GAAc,EAClB,MAAQA,GACNF,EAAOze,MAAK,EAAiBse,EAAQpa,EAAQqa,GAC7Cra,EAASua,EAAKpG,UACdsG,EAAcvH,GAA0BqH,EAAKtH,KACxCwH,IACHH,EAASC,EAAKtH,IAAIX,UAAYiI,EAGpC,KApB2B,CAEzB,MAAMpG,EAAYnU,EAElB,IADAA,GAAUua,EAAKvG,GACRhU,EAASmU,GACdoG,EAAOze,MAAK,EAAiBse,EAAQpa,EAAQqa,GAC7Cra,EAASua,EAAKpG,UACdmG,EAASC,EAAKtH,IAAIX,UAAYiI,CAElC,CAaA,MAAO,CACLxL,KAAMuL,EACNnG,UAAWnU,EACXwa,YAAY,EAEhB,CAWA,GACEJ,EAAQpa,EAAQqa,GAChB,MAAMC,EAAW,GAGjB,IAAIC,EAAOze,MAAK,EAAiBse,EAAQpa,EAAQqa,GACjD,MAAMK,EAAgBH,EAAKvG,GAC3BhU,EAASua,EAAKpG,UAGd,IAAIqG,GAAa,EACjB,MAAQA,GACND,EAAOze,MAAK,EAAiBse,EAAQpa,EAAQqa,GAC7Cra,EAASua,EAAKpG,UACdqG,EAAarH,GAA8BoH,EAAKtH,KAC3CuH,IAEHD,EAAK/J,GAAK,KACV8J,EAASvb,KAAKwb,IAIlB,MAAO,CACLxL,KAAMuL,EACNnG,UAAWnU,EACX0a,cAAeA,EAEnB,CAYA,GAAiBN,EAAQpa,EAAQqa,GAE/B,MAAMM,EAAa7e,MAAK,EAASse,EAAQpa,GACnCiT,EAAM0H,EAAW1H,IACvBjT,EAAS2a,EAAWxG,UAGpB,IAAI3D,EAAK,KACLoK,GAAY,EACZ3H,EAAIR,WAEF4H,GACF7J,EAAKyC,EAAIL,2BACS,IAAPpC,IACTA,EAAK,MAEPoK,GAAY,IAEZpK,EAAK1U,MAAK,EAAcse,EAAO7D,eAAevW,EAAQ,IACtDA,GAAU,EAAI4M,WAAW+H,kBACzBiG,EAAYrK,EAAYC,GAEpBoK,IACF5a,GAAU,EAAI4M,WAAW+H,qBAI7BnE,EAAK,OACLoK,GAAY,GAzSlB,SAAmBpK,GAGjB,OADmBxT,OAAO4R,KAAKoC,IAAS6J,OADnB,CAAC,OAAQ,KAAM,KAAM,OAExBpO,SAAS+D,EAC7B,CAySSsK,CAAUtK,KACbvQ,EAAOa,KAAK,eAAiB0P,EAC3B,aAAeyC,EAAIX,SAAW,uBAChC9B,EAAK,MAIP,IAAIwD,EAAK,EACL4G,GACF5G,EAAKoG,EAAO9E,WAAWtV,GACvBA,GAAU8W,YAAYnC,oBAEtBX,EAAKoG,EAAOlF,WAAWlV,GACvBA,GAAU0W,YAAY/B,mBAIxB,IAAIV,GAAkB,EACX,aAAPD,IACFC,GAAkB,EAClBD,EAAK,GAIHf,EAAIP,aAAsB,OAAPlC,GAAsB,IAAPwD,IACpCxD,EAAK,MAGP,IAIIzB,EAJAmF,EAAclU,EACdmU,EAAYD,EAAcF,EAI9B,GAAIX,GAAeJ,IAAQgB,EAAiB,CAE1C,MAAM8G,EACJjf,MAAK,EAA0Bse,EAAQpa,EAAQqa,GACjDra,EAAS+a,EAAY5G,UACrBD,GAAe6G,EAAYL,cAC3B3L,EAAOgM,EAAYhM,KACnBoF,EAAYnU,EACZgU,EAAKhU,EAASkU,CAChB,MAAO,GAAW,OAAP1D,EAAa,CAGtB,IAAI8J,EACJ,GAFAvL,EAAO,GAEFkF,EAYE,CAEL,IAAIuG,GAAa,EACjB,MAAQA,GACNF,EAAWxe,MAAK,EAAqBse,EAAQpa,EAAQqa,GACrDG,EAAaF,EAASE,WACtBxa,EAASsa,EAASnG,UAEbqG,GACHzL,EAAKhQ,KAAKub,EAASvL,MAGvBoF,EAAYnU,EACZgU,EAAKhU,EAASkU,CAChB,MAzBE,GAAW,IAAPF,EAAU,CAEZ,MAAMgH,EAAchb,EAASgU,EAC7B,KAAOhU,EAASgb,GACdV,EAAWxe,MAAK,EAAqBse,EAAQpa,EAAQqa,GACrDtL,EAAKhQ,KAAKub,EAASvL,MACnB/O,EAASsa,EAASnG,UAEpBA,EAAYnU,EACZgU,EAAKhU,EAASkU,CAChB,CAgBJ,CAGA,MAAMvG,EAAU,IAAIoG,GAAYvD,GAYhC,OAXA7C,EAAQsF,IAAMA,EACdtF,EAAQqG,GAAKA,EACbrG,EAAQuG,YAAcA,EACtBvG,EAAQwG,UAAYA,EAEhBF,IACFtG,EAAQsG,gBAAkBA,GAExBlF,IACFpB,EAAQyG,MAAQrF,GAEXpB,CACT,CAYA,GACEA,EAASyM,EAAQd,EAAqBD,GAEtC,MAAMpG,EAAMtF,EAAQsF,IACde,EAAKrG,EAAQqG,GACbxD,EAAK7C,EAAQ6C,GACbxQ,EAAS2N,EAAQuG,YAGvB,IAAInF,EAAO,KACX,MAAMkM,EAASjK,GAAQR,GACvB,GAAI6C,GAAeJ,GACjB,GAAItF,EAAQsG,gBAAiB,CAE3BlF,EAAO,GACP,IAAK,IAAI7P,EAAI,EAAGA,EAAIyO,EAAQyG,MAAMnW,SAAUiB,EAC1C6P,EAAKhQ,KAAKjD,MAAK,EACb6R,EAAQyG,MAAMlV,GAAIkb,EAClBd,EAAqBD,WAGlB1L,EAAQyG,KACjB,MAYE,GATIiF,EAAgB,GAAY,OAAP7I,IACvBvQ,EAAOa,KACL,2EAGF6M,EAAQ6C,GAAK,MAGfzB,EAAO,GACe,IAAlBsK,EACFtK,EAAKhQ,KAAKqb,EAAOlE,gBAAgBlW,EAAQgU,SACpC,GAAsB,IAAlBqF,EACmB,IAAxBC,EACFvK,EAAKhQ,KAAKqb,EAAO7D,eAAevW,EAAQgU,IAExCjF,EAAKhQ,KAAKqb,EAAO5D,cAAcxW,EAAQgU,QAEpC,IAAsB,KAAlBqF,EAOT,MAAM,IAAIrb,MAAM,+BAAiCqb,GANrB,IAAxBC,EACFvK,EAAKhQ,KAAKqb,EAAO3D,gBAAgBzW,EAAQgU,IAEzCjF,EAAKhQ,KAAKqb,EAAOxD,eAAe5W,EAAQgU,GAI5C,MAEG,QAAsB,IAAXiH,EAChB,GAAe,UAAXA,EACFlM,EAAOqL,EAAO7D,eAAevW,EAAQgU,QAChC,GAAe,WAAXiH,EACTlM,EAAOqL,EAAO3D,gBAAgBzW,EAAQgU,GAExB,MAAVxD,EAAG,KACLzB,EAAOmM,MAAMC,KAAKpM,SAEf,GAAe,WAAXkM,EACTlM,EAAOqL,EAAOvD,gBAAgB7W,EAAQgU,GAExB,MAAVxD,EAAG,KACLzB,EAAOmM,MAAMC,KAAKpM,SAEf,GAAe,WAAXkM,EACTlM,EAAOqL,EAAOrD,gBAAgB/W,EAAQgU,QACjC,GAAe,UAAXiH,EACTlM,EAAOmM,MAAMC,KAAKf,EAAOxD,eAAe5W,EAAQgU,SAC3C,GAAe,UAAXiH,EACTlM,EAAOmM,MAAMC,KAAKf,EAAOnD,eAAejX,EAAQgU,SAC3C,GAAe,UAAXiH,EACTlM,EAAOqL,EAAOjD,eAAenX,EAAQgU,QAChC,GAAe,YAAXiH,EACTlM,EAAOmM,MAAMC,KAAKf,EAAO/C,iBAAiBrX,EAAQgU,SAC7C,GAAe,YAAXiH,EACTlM,EAAOmM,MAAMC,KAAKf,EAAO9C,iBAAiBtX,EAAQgU,QAC7C,IAAe,WAAXiH,EAST,MAAM,IAAIjd,MAAM,oBAAsBid,GATR,CAC9B,MAAMG,EAAShB,EAAO7D,eAAevW,EAAQgU,GAE3CjF,EADEgC,GAAkBP,GACb1U,MAAK,EAAqBsf,GAE1Btf,MAAK,EAAcsf,GAE5BrM,EAz1BD,SAAqBlD,GAC1B,IAAIjH,EAAMiH,EAEV,MAAMwP,EAAYxP,EAAS5N,OAAS,EAOpC,OANI4N,EAASwP,KAAetD,KAC1BnT,EAAMiH,EAASH,UAAU,EAAG2P,IAG9BzW,EAAMA,EAAI0W,OAEH1W,CACT,CA80Be2W,CAAYxM,GAAM7D,MAAM,KACjC,CAEA,MACK,GAAW,OAAPsF,EAETzB,EAAOmM,MAAMC,KAAKf,EAAO3D,gBAAgBzW,EAAQgU,SAC5C,GAAW,OAAPxD,EAILzB,EAFkB,IAAlBsK,EAC0B,IAAxBC,EACK4B,MAAMC,KAAKf,EAAO7D,eAAevW,EAAQgU,IAEzCkH,MAAMC,KAAKf,EAAO5D,cAAcxW,EAAQgU,IAGrB,IAAxBsF,EACK4B,MAAMC,KAAKf,EAAO3D,gBAAgBzW,EAAQgU,IAE1CkH,MAAMC,KAAKf,EAAOxD,eAAe5W,EAAQgU,SAG/C,GAAW,OAAPxD,EAGPzB,EAD0B,IAAxBuK,EACK4B,MAAMC,KAAKf,EAAO3D,gBAAgBzW,EAAQgU,IAE1CkH,MAAMC,KAAKf,EAAOxD,eAAe5W,EAAQgU,SAE7C,GAAW,OAAPxD,EAAa,CAEtB,MAAMgL,EAAMpB,EAAO3D,gBAAgBzW,EAAQgU,GAC3CjF,EAAO,GACP,IAAK,IAAI1Q,EAAI,EAAGO,EAAO4c,EAAIvd,OAAQI,EAAIO,EAAMP,GAAK,EAAG,CACnD,MAAMod,EAAOD,EAAInd,GAAGC,SAAS,IACvBod,EAAQF,EAAInd,EAAI,GAAGC,SAAS,IAClC,IAAI8J,EAAM,IACVA,GAAO,OAAOsD,UAAU,EAAG,EAAI+P,EAAKxd,QAAUwd,EAAKhE,cACnDrP,GAAO,IACPA,GAAO,OAAOsD,UAAU,EAAG,EAAIgQ,EAAMzd,QAAUyd,EAAMjE,cACrDrP,GAAO,IACP2G,EAAKhQ,KAAKqJ,EACZ,CACF,MAAO,GAAW,OAAPoI,EAAa,CAEtBzB,EAAO,GACP,IAAK,IAAIxG,EAAI,EAAGA,EAAIoF,EAAQyG,MAAMnW,SAAUsK,EAAG,CAC7C,MAAMgS,EAAO5M,EAAQyG,MAAM7L,GACrB+R,EAAW,CAAC,EACZ1L,EAAO5R,OAAO4R,KAAK2L,GACzB,IAAIoB,EAAkBtC,EAClBuC,EAAwBtC,EAC5B,IAAK,IAAIna,EAAI,EAAGA,EAAIyP,EAAK3Q,SAAUkB,EAAG,CAGpC,IAAI0c,EAActB,EAAKX,SACI,IAAhBiC,QACoB,IAAtBA,EAAYje,QACnB+d,EAAkBE,EAAYje,MAAM,IAItCie,EAActB,EAAKX,SACQ,IAAhBiC,QACoB,IAAtBA,EAAYje,QACnBge,EAAwBC,EAAYje,MAAM,IAE5C,MAAMke,EAAavB,EAAK3L,EAAKzP,IAC7B2c,EAAWle,MAAQ9B,MAAK,EACtBggB,EAAY1B,EACZwB,EAAuBD,UAClBG,EAAW7I,WACX6I,EAAW9H,UACX8H,EAAW5H,mBACX4H,EAAW3H,UAClBmG,EAAS1L,EAAKzP,IAAM2c,CACtB,CACA/M,EAAKhQ,KAAKub,EACZ,QAEO3M,EAAQyG,KACjB,KAAkB,SAAP5D,GAITvQ,EAAOa,KAAK,eAAiB0P,EAC3B,aAAe7C,EAAQsF,IAAIX,SAAW,KAHxCvD,EAAO,GAQT,OAAOA,CACT,CAWA,GACEgN,EAAU3B,EACVd,EAAqBD,GAErB,MAAMzK,EAAO5R,OAAO4R,KAAKmN,GACzB,IAAK,IAAI1d,EAAI,EAAGA,EAAIuQ,EAAK3Q,SAAUI,EAAG,CACpC,MAAMsP,EAAUoO,EAASnN,EAAKvQ,SACD,IAAlBsP,EAAQ/P,QACjB+P,EAAQ/P,MAAQ9B,MAAK,EACnB6R,EAASyM,EAAQd,EAAqBD,WAGnC1L,EAAQsF,WACRtF,EAAQqG,UACRrG,EAAQuG,mBACRvG,EAAQwG,SACjB,CACF,CAQA6H,KAAAA,CAAM/M,GACJ,IAAIjP,EAAS,EACT8Y,EAAS,GACT+C,EAAc,KAElB,MAAMI,EAAa,IAAIrH,GAAW3F,GAClC,IAAIiN,EAAa,IAAItH,GAAW3F,GAGhCjP,EAAS,IACT,MAAMmc,EAAYrgB,MAAK,EAAcmgB,EAAW1F,eAAevW,EAAQ,IAEvE,GADAA,GAAU,EAAI4M,WAAW+H,kBACP,SAAdwH,EAAsB,CAExBN,EAAc/f,MAAK,EAAiBmgB,EAAYjc,GAAQ,GACxD6b,EAAYje,MAAQ9B,MAAK,EAAkB+f,EAAaI,GAExDjc,EAAS6b,EAAY1H,UAErBrY,MAAK,EAAc+f,EAAY5I,IAAIX,UAAYuJ,EAE/C,MAGMO,EAAUpc,EAHG6b,EAAYje,MAAM,GAIrC,KAAOoC,EAASoc,GAEdP,EAAc/f,MAAK,EAAiBmgB,EAAYjc,GAAQ,GACxDA,EAAS6b,EAAY1H,UAErBrY,MAAK,EAAc+f,EAAY5I,IAAIX,UAAYuJ,EAKjD,GADAA,EAAc/f,MAAK,EAhoBP,iBAioBe,IAAhB+f,EACT,MAAM,IAAI7d,MAAM,uDAElB6d,EAAYje,MAAQ9B,MAAK,EAAkB+f,EAAaI,GACxDnD,EAAS+C,EAAYje,MAAM,EAE7B,KAAO,CACLqC,EAAOa,KAAK,mDAEZ+a,EAAc/f,MAAK,EAAiBogB,EAAY,GAAG,GAEnD,MAAMG,EAtxBZ,SAA6BC,GAC3B,MACMC,EAA0B,OAE1BlN,EAAQiN,EAAiBrJ,IAAIb,WACnC,GAJ6B,SAIzB/C,GACFA,IAAUkN,EACV,MAAM,IAAIve,MACR,yFAKJ,MAAMwS,EAAK8L,EAAiB9L,GACtBgM,EAAMhM,EAAG3D,WAAW,GACpB4P,EAAMjM,EAAG3D,WAAW,GACpBwN,IAAYmC,GAAO,IAAMA,GAAO,IAAMC,GAAO,IAAMA,GAAO,IAGhE,IAAI3D,EAAS,KACb,GAAIzJ,IAAUkN,EAEVzD,EADEuB,EACOnI,GAEAA,OAEN,CACL,GAAImI,EAEF,MAAM,IAAIrc,MACR,wFAIF8a,EAAS5G,EAEb,CAEA,MAAM2J,EAAc,IAAI9H,GAAY,MAOpC,OANA8H,EAAY5I,IHrIL,IAAId,GAAI,OAAQ,QGsIvB0J,EAAYje,MAAQ,CAACkb,GACrB+C,EAAY7H,GAAK6H,EAAYje,MAAM,GAAGK,OACtC4d,EAAY3H,YAAcoI,EAAiBpI,YAC3C2H,EAAY1H,UAAY0H,EAAY3H,YAAc2H,EAAY7H,GAEvD6H,CACT,CAwuBwBa,CAAoBb,GAEtC/f,MAAK,EAAcugB,EAAUpJ,IAAIX,UAAY+J,EAC7CvD,EAASuD,EAAUze,MAAM,GAEzBoC,EAAS,CACX,CAGA,IAj0BJ,SAAuC8Y,GACrC,OAAQA,IAAW5G,IACjB4G,IAAW5G,IACX4G,IAAW5G,IACX8G,GAA6BF,IAC7BG,GAA6BH,IAC7BI,GAAyBJ,IACzBK,GAAoBL,EACxB,CAyzBS6D,CAA8B7D,GACjC,MAAM,IAAI9a,MAAM,uCAA0C8a,EACxD,MAnzBD,SAA+BA,GACpC,IAAIxT,EAAO,UAIX,YAHwC,IAA7B2M,GAAiB6G,KAC1BxT,EAAO2M,GAAiB6G,IAEnBxT,CACT,CA6yBiBsX,CAAsB9D,GAAU,KAI7C,IAAIuB,GAAW,EAWf,IAVIxB,GAAyBC,KAC3BuB,GAAW,GAITtB,GAA0BD,KAC5BoD,EAAa,IAAItH,GAAW3F,GAAQ,IAI/BjP,EAASiP,EAAOH,YAAY,CAEjC+M,EAAc/f,MAAK,EAAiBogB,EAAYlc,EAAQqa,GAExDra,EAAS6b,EAAY1H,UAErB,MAAMrX,EAAM+e,EAAY5I,IAAIX,cACW,IAA5BxW,MAAK,EAAcgB,GAC5BhB,MAAK,EAAcgB,GAAO+e,EAE1B5b,EAAOa,KAAK,6BAA+BhE,EAE/C,CAGA,GAAIsB,MAAM4B,GACR,MAAM,IAAIhC,MAAM,qCAEdiR,EAAOH,aAAe9O,GACxBC,EAAOa,KAAK,wCACVd,EAAS,OAASiP,EAAOH,YAO7B,IAAIwK,EAAsB,EACtBD,EAAgB,GA6BpB,QA5BqD,IAA1Cvd,MAAK,EAAc8d,MAE5BiC,EAAc/f,MAAK,EAAc8d,SACN,IAAhBiC,GACTA,EAAYje,MAAQ9B,MAAK,EAAkB+f,EAAaK,GACxD5C,EAAsBuC,EAAYje,MAAM,IAExCqC,EAAOa,KACL,8DAIJ+a,EAAc/f,MAAK,EAAc8d,SACN,IAAhBiC,GACTA,EAAYje,MAAQ9B,MAAK,EAAkB+f,EAAaK,GACxD7C,EAAgBwC,EAAYje,MAAM,IAElCqC,EAAOa,KAAK,8DAKyB,IAA9BhF,MAAK,GACdA,KAAKme,uBAAuBne,MAAK,GAInC+f,EAAc/f,MAAK,EA7tBC,iBA8tBO,IAAhB+f,EAA6B,CAEtC,IAAIgB,EADJhB,EAAYje,MAAQ9B,MAAK,EAAkB+f,EAAaK,GAEvB,IAA7BL,EAAYje,MAAMK,OACpB4e,EAAchB,EAAYje,MAAM,IAEhCif,EAAchB,EAAYje,MAAM,GAChCqC,EAAOa,KAAK,oDACV+b,EAAc,OAElB/gB,KAAKme,uBA5kCX,SAAqB4C,GACnB,IAAIC,EAAQ,QAwCZ,MAvCoB,eAAhBD,EACFC,EAAQ,aACiB,eAAhBD,EACTC,EAAQ,aACiB,eAAhBD,EACTC,EAAQ,aACiB,eAAhBD,EACTC,EAAQ,aACiB,eAAhBD,EACTC,EAAQ,aACiB,eAAhBD,EACTC,EAAQ,aACiB,eAAhBD,EACTC,EAAQ,aACiB,eAAhBD,EACTC,EAAQ,aACiB,eAAhBD,EACTC,EAAQ,aACiB,cAAhBD,EACTC,EAAQ,YACiB,eAAhBD,EACTC,EAAQ,cACiB,mBAAhBD,EACTC,EAAQ,cACiB,oBAAhBD,GAGgB,mBAAhBA,IAGgB,eAAhBA,EACTC,EAAQ,QACiB,YAAhBD,EACTC,EAAQ,UACiB,WAAhBD,EACTC,EAAQ,SACiB,QAAhBD,IACTC,EAAQ,YAEHA,CACT,CAkiCkCC,CAAYF,GAC1C,CAYA,GATA/gB,MAAK,EACHA,MAAK,EAAeogB,EACpB5C,EAAqBD,GAMvBwC,EAAc/f,MAAK,EAAc8d,SACN,IAAhBiC,GACLA,EAAY5H,gBAAiB,CAC/B,IAAI+I,EAAiB,OACqC,IAA/ClhB,MAAK,EAAc8d,MAC5BoD,EAAiBtW,OACf5K,MAAK,EAAc8d,IAAwBhc,MAAM,KAGrD,MAAMqf,EAAWpB,EAAYje,MAC7B,GAAIqf,EAAShf,OAAS,GAAKgf,EAAShf,OAAS+e,EAAgB,CAK3D,MAAME,EAAgBD,EAAShf,OAAS+e,EAClCG,EAAc,GACpB,IAAI/T,EAAQ,EACZ,IAAK,IAAIgU,EAAI,EAAGA,EAAIJ,IAAkBI,EAAG,CACvChU,EAAQgU,EAAIF,EAEZ,IAAI/a,EAAO,EACX,IAAK,IAAI9D,EAAI,EAAGA,EAAI6e,IAAiB7e,EACnC8D,GAAQ8a,EAAS7T,EAAQ/K,GAAGJ,OAG9B,MAAMof,EAAY,IAAIJ,EAAS,GAAGnf,YAAYqE,GAE9C,IAAImb,EAAa,EACjB,IAAK,IAAIpe,EAAI,EAAGA,EAAIge,IAAiBhe,EACnCme,EAAUnO,IAAI+N,EAAS7T,EAAQlK,GAAIoe,GACnCA,GAAcL,EAAS7T,EAAQlK,GAAGjB,OAEpCkf,EAAYC,GAAKC,CACnB,CAEAxB,EAAYje,MAAQuf,CACtB,CACF,CAEJ,ECttCK,MAAMI,GAMX,GAAa,CAAC,EASdve,GAAAA,CAAIwe,EAAMC,QAE6B,IAA1B3hB,MAAK,EAAW0hB,KACzB1hB,MAAK,EAAW0hB,GAAQ,IAG1B1hB,MAAK,EAAW0hB,GAAMze,KAAK0e,EAC7B,CASAC,MAAAA,CAAOF,EAAMC,GAEX,QAAqC,IAA1B3hB,MAAK,EAAW0hB,GACzB,OAGF,IAAIG,EAAS,EACb,IAAK,IAAItf,EAAI,EAAGA,EAAIvC,MAAK,EAAW0hB,GAAMvf,SAAUI,EAC9CvC,MAAK,EAAW0hB,GAAMnf,KAAOof,MAC7BE,EACF7hB,MAAK,EAAW0hB,GAAMI,OAAOvf,EAAG,IAGrB,IAAXsf,GACF1d,EAAOW,MAAM,iDAAmD4c,EAEpE,CAOAK,UAAaC,IAEX,QAA2C,IAAhChiB,MAAK,EAAWgiB,EAAMN,MAC/B,OAIF,MAAMO,EAAQjiB,MAAK,EAAWgiB,EAAMN,MAAMhf,QAC1C,IAAK,IAAIH,EAAI,EAAGA,EAAI0f,EAAM9f,SAAUI,EAClC0f,EAAM1f,GAAGyf,EACX,ECNG,SAASE,GAAMC,EAAchQ,EAAOiQ,EAASC,EAClDC,EAAcC,EAAgBC,EAAUC,QAChB,IAAbD,IACTA,GAAW,QAEW,IAAbC,IACTA,GAAW,GAIb,IAAIC,EAAYvQ,EAEZqQ,GACFD,IAAmB,EACfE,EAEFC,IAAcJ,EAAe,GAAKD,EAElCA,IAAc,GAGZI,IAEFC,IAAcJ,EAAe,GAAKD,EAClCA,IAAc,GAGlB,MAAMM,EAAsBJ,EAAiBD,EAAeD,EAG5D,IAAIO,EAAY,EACZC,EAAa,EAEjB,MAAO,CACLC,KAAM,WACJ,GAAIF,EAAYR,EAAS,CACvB,MAAMhG,EAAS,CACbta,MAAOqgB,EAAaO,GACpBK,MAAM,EACNzV,MAAOoV,GAST,OAPAA,GAAaL,IACXO,IACAC,EACEA,IAAeP,IACjBO,EAAa,EACbH,GAAaC,GAERvG,CACT,CACA,MAAO,CACL2G,MAAM,EACNzV,MAAOoV,EAEX,EAEJ,CAgPO,SAASM,GAAkBC,GAChC,MAAMhhB,EAAS,GACf,IAAIihB,EAAOD,EAASH,OACpB,MAAQI,EAAKH,MACX9gB,EAAOgB,KAAKigB,EAAKphB,OACjBohB,EAAOD,EAASH,OAElB,OAAO7gB,CACT,CAWO,SAASkhB,GACdC,EAAOC,EAAUC,EAAYC,GAC7B,MAAMld,EAAO+c,EAAMI,cAAcC,UAEjC,IAAIC,EAAe,EACfH,QAA8C,IAApBA,IAC5BG,EAAeH,EAAgB/V,aAAa,GAAGF,OAEjD,MAAMqW,EAAYN,EAAS5gB,YAKrBmhB,EAAW,IAAI7hB,EAAM4hB,EAAUE,KAHjB,SAAUhS,EAASvE,GACrC,OAAQA,IAAUoW,GAAgBpW,EAAQ,EAAKuE,EAAU,CAC3D,KAEA,IAAIM,EAAQ9L,EAAKyd,cAAcF,QAGL,IAAfN,IACTA,GAAa,GAEf,IAAInB,EAAe,KAEjBA,EADEmB,EACa,SAAUpf,GACvB,OAAOkf,EAAMW,yBAAyB7f,EACxC,EAEe,SAAUA,GACvB,OAAOkf,EAAMY,iBAAiB9f,EAChC,EAGF,MAAM+f,EAAQ5d,EAAKhF,IAAI,GACjB6iB,EAAQ7d,EAAKhF,IAAI,GACjB8iB,EAAU9d,EAAKhF,IAAI,GACzB,IAAI+iB,EAAY/d,EAAKge,WAAW,GAEhC,MAAMC,EAAQlB,EAAMmB,wBACdC,EAA8C,IAAnCpB,EAAMqB,yBACjBC,EAAW,SACfvC,EAAchQ,EAAOiQ,EAASC,EAC9BC,EAAcC,EAAgBC,EAAUC,GACxC,OAAc,IAAV6B,EACKpC,GAAMC,EAAchQ,EAAOiQ,EAASC,EACzCC,EAAcC,EAAgBC,EAAUC,GACvB,IAAV6B,EAnIR,SAAiBnC,EAAchQ,EAAOiQ,EAASC,EACpDC,EAAcC,EAAgBC,EAAUC,EAAU+B,GAClD,MAAMG,EAAQ,GAgCd,OA/BIH,GACFG,EAAM1hB,KAAKif,GACTC,EAAchQ,EAAOiQ,EAASC,EAC9BC,EAAcC,EAAgBC,EAAUC,IAE1CkC,EAAM1hB,KAAKif,GACTC,EAAchQ,EAAQiQ,EAAUC,EAAWD,EAASC,EACpDC,EAAcC,EAAgBC,EAAUC,IAE1CkC,EAAM1hB,KAAKif,GACTC,EAAchQ,EAAQ,EAAIiQ,EAAUC,EAAWD,EAASC,EACxDC,EAAcC,EAAgBC,EAAUC,MAG1CJ,GAAa,EACbE,GAAkB,EAClBoC,EAAM1hB,KAAKif,GACTC,EAAchQ,EAAOiQ,EAASC,EAC9BC,EAAcC,EAAgBC,EAAUC,IAE1CkC,EAAM1hB,KAAKif,GACTC,EAAchQ,EAAQ,EAAGiQ,EAASC,EAClCC,EAAcC,EAAgBC,EAAUC,IAE1CkC,EAAM1hB,KAAKif,GACTC,EAAchQ,EAAQ,EAAGiQ,EAASC,EAClCC,EAAcC,EAAgBC,EAAUC,KAKrC,CACLK,KAAM,WACJ,MAAM8B,EAAKD,EAAM,GAAG7B,OACd+B,EAAKF,EAAM,GAAG7B,OACdgC,EAAKH,EAAM,GAAG7B,OACpB,OAAK8B,EAAG7B,KAeD,CACLA,MAAM,EACNzV,MAAOwX,EAAGxX,OAhBH,CACLxL,MAAO,CACL8iB,EAAG9iB,MACH+iB,EAAG/iB,MACHgjB,EAAGhjB,OAELihB,MAAM,EACNzV,MAAO,CACLsX,EAAGtX,MACHuX,EAAGvX,MACHwX,EAAGxX,OAQX,EAEJ,CAwEayX,CAAQ5C,EAAc,EAAIhQ,EAAOiQ,EAASC,EAC/CC,EAAcC,EAAgBC,EAAUC,EAAU+B,QAF/C,CAIT,EAEA,IAAIQ,EAAW,KACf,GAAIzB,QAA8C,IAApBA,EAAiC,CAC7D,MAAM0B,EAAU1B,EAAgB/V,aAAa,GACvC0X,EAAU3B,EAAgB/V,aAAa,GAGvCgV,GAAW,EACXC,GAAW,EAEjB,IAAIL,EAAU,KACd,GAAsB,IAAlB8C,EAAQ5X,MAEV8U,EAAU6B,EAAQC,EAGhBc,EAFoB,IAAlBC,EAAQ3X,MAECoX,EAASvC,EAClBhQ,EAAOiQ,EAAS,EAAG6B,EAAOA,EAAOzB,EAAUC,GAGlCiC,EAASvC,EAClBhQ,EAAOiQ,EAAS6B,EAAOC,EAAO,EAAG1B,EAAUC,QAE1C,GAAsB,IAAlByC,EAAQ5X,MAEjB8U,EAAU+B,EAAUD,EAGlBc,EAFoB,IAAlBC,EAAQ3X,MAECoX,EAASvC,EAClBhQ,EAAOiQ,EAAS6B,EAAOC,EAAOE,EAAW5B,EAAUC,GAG1CiC,EAASvC,EAClBhQ,EAAOiQ,EAASgC,EAAWD,EAASF,EAAOzB,EAAUC,OAEpD,IAAsB,IAAlByC,EAAQ5X,MAajB,MAAM,IAAIpL,MAAM,sBAAwBgjB,EAAQ5X,OAXhD8U,EAAU+B,EAAUF,EAGlBe,EAFoB,IAAlBC,EAAQ3X,MAECoX,EAASvC,EAClBhQ,EAAOiQ,EAAS,EAAG6B,EAAOG,EAAW5B,EAAUC,GAGtCiC,EAASvC,EAClBhQ,EAAOiQ,EAASgC,EAAWD,EAAS,EAAG3B,EAAUC,EAIvD,CACF,MACE,GAAsC,IAAlCW,EAAMmB,wBACRS,EA5cC,SAAqB7C,EAAchQ,EAAOC,EAAKiQ,QAC3B,IAAdA,IACTA,EAAY,GAEd,IAAIK,EAAYvQ,EAEhB,MAAO,CACL2Q,KAAM,WACJ,GAAIJ,EAAYtQ,EAAK,CACnB,MAAMgK,EAAS,CACbta,MAAOqgB,EAAaO,GACpBK,MAAM,EACNzV,MAAOoV,GAGT,OADAA,GAAaL,EACNjG,CACT,CACA,MAAO,CACL2G,MAAM,EACNzV,MAAO8E,EAEX,EAEJ,CAqbiB+S,CAAYhD,EAAchQ,EAAOA,EAAQiS,OAC/C,IAAsC,IAAlChB,EAAMmB,wBAOf,MAAM,IAAIriB,MAAM,qCACdkhB,EAAMmB,yBANRpS,GAAS,EACTiS,GAAa,EACbY,EAlQC,SACL7C,EAAchQ,EAAOC,EAAKiQ,EAAWmC,QACZ,IAAdnC,IACTA,EAAY,QAEU,IAAbmC,IACTA,GAAW,GAEb,IAAI9B,EAAYvQ,EACZiT,EAAqB,EACrBZ,EACFY,GAAsBhT,EAAMD,GAAS,EAErCkQ,GAAa,EAEf,IAAIgD,EAAa3C,EAAY0C,EACzBE,EAAa5C,EAAY,EAAI0C,EAGjC,MAAO,CACLtC,KAAM,WACJ,GAAIJ,EAAYtQ,EAAK,CACnB,MAAMgK,EAAS,CACbta,MAAO,CACLqgB,EAAaO,GACbP,EAAakD,GACblD,EAAamD,IAEfvC,MAAM,EACNzV,MAAO,CAACoV,EAAW2C,EAAYC,IAKjC,OAHA5C,GAAaL,EACbgD,GAAchD,EACdiD,GAAcjD,EACPjG,CACT,CACA,MAAO,CACL2G,MAAM,EACNzV,MAAO,CAAC8E,GAEZ,EAEJ,CAwNiBmT,CACTpD,EAAchQ,EAAOA,EAAQiS,EAAW,EAAGI,EAI/C,CAGF,OAAOQ,CACT,CAiJO,SAASQ,GAAWvjB,EAAQmQ,GACjC,IAAIsQ,EAAY,EACZ+C,EAAiB,EAErB,MAAO,CACL3C,KAAM,WACJ,GAAIJ,EAAYtQ,EAAK,CACfqT,EAAiB,EAAIxjB,EAAOE,QAC9BugB,GAAazgB,EAAOwjB,EAAiB,GAAGnY,SACtCmY,EAEJ,MAAMrJ,EAAS,CACbta,MAAOG,EAAOwjB,GAAgB3jB,MAC9BihB,MAAM,EACNzV,MAAOoV,GAGT,QADEA,EACKtG,CACT,CACA,MAAO,CACL2G,MAAM,EACNzV,MAAO8E,EAEX,EAEJ,CCtpBO,MAAMsT,GAOX,GAOA,GAMA1jB,WAAAA,CAAY2jB,EAAOC,GASjB5lB,MAAK,EAAS2lB,EACd3lB,MAAK,EAAa4lB,CACpB,CAOAlf,QAAAA,GACE,OAAO1G,MAAK,CACd,CAOA6lB,YAAAA,GACE,OAAO7lB,MAAK,CACd,CAQA8D,KAAAA,CAAMhC,GACJ,OAAOA,EAAQ9B,MAAK,EAASA,MAAK,CACpC,CAQA6C,MAAAA,CAAOD,GACL,OAAOA,SAEL5C,KAAK0G,aAAe9D,EAAI8D,YACxB1G,KAAK6lB,iBAAmBjjB,EAAIijB,cAChC,CAOAniB,IAAAA,GACE,OAA4B,IAApB1D,KAAK0G,YAA4C,IAAxB1G,KAAK6lB,cACxC,ECvEK,MAAMC,GAOX,GAKA9jB,WAAAA,CAAYC,GACV,IAAKA,QAA4B,IAAXA,EACpB,MAAM,IAAIC,MAAM,sCAElB,GAAsB,IAAlBD,EAAOE,OACT,MAAM,IAAID,MAAM,yCAKlB,IAAKD,EAAOG,OAHO,SAAUC,GAC3B,OAAQC,MAAMD,IAAgB,IAARA,CACxB,IAEE,MAAM,IAAIH,MAAM,sDAElBlC,MAAK,EAAUiC,CACjB,CAQAZ,GAAAA,CAAIkB,GACF,OAAOvC,MAAK,EAAQuC,EACtB,CAOAJ,MAAAA,GACE,OAAOnC,MAAK,EAAQmC,MACtB,CAOAK,QAAAA,GACE,MAAO,IAAMxC,MAAK,EAAQwC,WAAa,GACzC,CAOAC,SAAAA,GACE,OAAOzC,MAAK,EAAQ0C,OACtB,CAQAqjB,WAAAA,CAAYC,GACV,OAAOhmB,KAAKmC,UAAY6jB,EAAY,GAA6B,IAAxBhmB,KAAKqB,IAAI2kB,EACpD,CAQAC,WAAAA,CAAY1C,GACV,IAAIyC,EAAY,EAIhB,YAH+B,IAApBzC,IACTyC,EAAYzC,EAAgB5V,6BAEvB3N,KAAK+lB,YAAYC,EAC1B,CASAE,SAAAA,CAAU3C,GACR,IAAI2C,EAAYlmB,KAAKimB,YAAY1C,GAEjC,IAAK,IAAIhhB,EAAI,EAAGA,EAAIvC,KAAKmC,WAAYI,EACnC2jB,EAAYA,GAAalmB,KAAK+lB,YAAYxjB,GAE5C,OAAO2jB,CACT,CASA7B,UAAAA,CAAW2B,EAAW7T,GACpB,GAAI6T,EAAYhmB,KAAKmC,SACnB,OAAO,KAET,QAAqB,IAAVgQ,EACTA,EAAQ,OAER,GAAIA,EAAQ,GAAKA,EAAQ6T,EACvB,MAAM,IAAI9jB,MAAM,sCAGpB,IAAImE,EAAO,EACX,IAAK,IAAI9D,EAAI4P,EAAO5P,EAAIyjB,IAAazjB,EACnC8D,GAAQrG,KAAKqB,IAAIkB,GAEnB,OAAO8D,CACT,CAQA8f,YAAAA,CAAahU,GACX,OAAOnS,KAAKqkB,WAAWrkB,KAAKmC,SAAUgQ,EACxC,CAQAtP,MAAAA,CAAOD,GAEL,IAAKA,EACH,OAAO,EAGT,MAAMT,EAASnC,KAAKmC,SACpB,GAAIA,IAAWS,EAAIT,SACjB,OAAO,EAGT,IAAK,IAAII,EAAI,EAAGA,EAAIJ,IAAUI,EAC5B,GAAIvC,KAAKqB,IAAIkB,KAAOK,EAAIvB,IAAIkB,GAC1B,OAAO,EAIX,OAAO,CACT,CASA6jB,UAAAA,CAAW9Y,EAAO+Y,GAEhB,IAAK/Y,EACH,OAAO,EAGT,MAAMnL,EAASnC,KAAKmC,SACpB,GAAIA,IAAWmL,EAAMnL,SACnB,OAAO,EAGT,QAAoB,IAATkkB,EAAsB,CAC/BA,EAAO,GACP,IAAK,IAAIjjB,EAAI,EAAGA,EAAIjB,IAAUiB,EAC5BijB,EAAKpjB,KAAKG,EAEd,MACE,IAAK,IAAIqJ,EAAI,EAAGA,EAAItK,IAAUsK,EAC5B,GAAI4Z,EAAK5Z,GAAKtK,EAAS,EACrB,MAAM,IAAID,MAAM,0BAA4BmkB,EAAK5Z,IASvD,IAAK,IAAIlK,EAAI,EAAGA,EAAI8jB,EAAKlkB,SAAUI,EACjC,GALwBT,EAKXwL,EAAMjM,IAAIglB,EAAK9jB,IALG8D,EAKErG,KAAKqB,IAAIglB,EAAK9jB,MAJxCT,GAAS,GAAKA,EAAQuE,GAK3B,OAAO,EANK,IAAUvE,EAAOuE,EAUjC,OAAO,CACT,CASAyd,aAAAA,CAAcxW,EAAO6E,GAEnB,GAAI7E,EAAMnL,SAAWnC,KAAKmC,SACxB,MAAM,IAAID,MAAM,sCAElB,QAAqB,IAAViQ,EACTA,EAAQ,OAER,GAAIA,EAAQ,GAAKA,EAAQnS,KAAKmC,SAAW,EACvC,MAAM,IAAID,MAAM,yCAGpB,IAAIgC,EAAS,EACb,IAAK,IAAI3B,EAAI4P,EAAO5P,EAAIvC,KAAKmC,WAAYI,EACvC2B,GAAUoJ,EAAMjM,IAAIkB,GAAKvC,KAAKqkB,WAAW9hB,EAAG4P,GAE9C,OAAOjO,CACT,CAQAoiB,aAAAA,CAAcpiB,GACZ,MAAMjC,EAAS,IAAImd,MAAMpf,KAAKmC,UAC9B,IAAIokB,EAAMriB,EACNsiB,EAAU,EACd,IAAK,IAAIjkB,EAAIvC,KAAKmC,SAAW,EAAGI,EAAI,IAAKA,EACvCikB,EAAUxmB,KAAKqkB,WAAW9hB,GAC1BN,EAAOM,GAAKoB,KAAKiD,MAAM2f,EAAMC,GAC7BD,GAAYtkB,EAAOM,GAAKikB,EAG1B,OADAvkB,EAAO,GAAKskB,EACL,IAAIxkB,EAAME,EACnB,CAOAwkB,KAAAA,GACE,MAAO,CACLhe,EAAGzI,KAAKqB,IAAI,GACZqH,EAAG1I,KAAKqB,IAAI,GAEhB,EClRK,MAAMqlB,GAMXC,IAMAtZ,IAMAuZ,KAMAC,OAMAC,OAMAC,IAMAC,IAQAhlB,WAAAA,CAAY2kB,EAAKtZ,EAAKuZ,EAAMC,GAC1B7mB,KAAK2mB,IAAMA,EACX3mB,KAAKqN,IAAMA,EACXrN,KAAK4mB,KAAOA,EACZ5mB,KAAK6mB,OAASA,CAChB,EAWK,SAASI,GAAShlB,EAAQ+N,GAC/B,OAaF,SAAgCA,GAC9B,OAAO,MAAOA,IAEXA,EAAMW,SAAS,WAChBX,EAAMW,SAAS,QACfX,EAAMW,SAAS,OACnB,CAnBMuW,CAAuBlX,GAgE7B,SAAsB/N,GAEpB,MAAMklB,EAAQC,GAAcnlB,GAW5B,OARAA,EAAO2P,MAAK,SAAU9Q,EAAGoH,GACvB,OAAOpH,EAAIoH,CACb,IAEAif,EAAML,OAASO,GAAcplB,EAAQ,IACrCklB,EAAMJ,IAAMM,GAAcplB,EAAQ,KAClCklB,EAAMH,IAAMK,GAAcplB,EAAQ,KAE3BklB,CACT,CA7EWG,CAAarlB,GAEbmlB,GAAcnlB,EAEzB,CAuBO,SAASmlB,GAAcnlB,GAC5B,IAAI0kB,EAAM1kB,EAAO,GACboL,EAAMsZ,EACNY,EAAM,EACNC,EAAS,EACTnlB,EAAM,EACV,MAAMF,EAASF,EAAOE,OACtB,IAAK,IAAII,EAAI,EAAGA,EAAIJ,IAAUI,EAC5BF,EAAMJ,EAAOM,GACTF,EAAMskB,EACRA,EAAMtkB,EACGA,EAAMgL,IACfA,EAAMhL,GAERklB,GAAOllB,EACPmlB,GAAUnlB,EAAMA,EAGlB,MAAMukB,EAAOW,EAAMplB,EAEnB,IAAIslB,EAAWD,EAASrlB,EAASykB,EAAOA,EACpCa,EAAW,IACbA,EAAW,GAEb,MAAMZ,EAASljB,KAAK4G,KAAKkd,GAEzB,OAAO,IAAIf,GAAWC,EAAKtZ,EAAKuZ,EAAMC,EACxC,CAkCA,SAASQ,GAAcplB,EAAQylB,GAE7B,GAAsB,IAAlBzlB,EAAOE,OACT,MAAM,IAAID,MAAM,oDAElB,GAAIwlB,EAAQ,GAAKA,EAAQ,EACvB,MAAM,IAAIxlB,MACR,sDAAwDwlB,GAG5D,GAAc,IAAVA,EACF,OAAOzlB,EAAO,GACT,GAAc,IAAVylB,EACT,OAAOzlB,EAAOA,EAAOE,OAAS,GAGhC,MAAMI,GAAKN,EAAOE,OAAS,GAAKulB,EAC1BC,EAAKhkB,KAAKiD,MAAMrE,GAChBqlB,EAAK3lB,EAAO0lB,GAElB,OAAOC,GADI3lB,EAAO0lB,EAAK,GACLC,IAAOrlB,EAAIolB,EAC/B,CAUO,SAASE,KACd,OAAOlkB,KAAKmkB,SAAStlB,SAAS,IAAIoN,UAAU,EAAG,GACjD,CAKO,MAAMmY,GAIXpB,IAIAtZ,IAKArL,WAAAA,CAAY2kB,EAAKtZ,GACfrN,KAAK2mB,IAAMA,EACX3mB,KAAKqN,IAAMA,CACb,EC5MK,MAAM2a,GAOX,GAKAhmB,WAAAA,CAAYC,GACV,IAAKA,QAA4B,IAAXA,EACpB,MAAM,IAAIC,MAAM,yCAElB,GAAsB,IAAlBD,EAAOE,OACT,MAAM,IAAID,MAAM,4CAKlB,IAAKD,EAAOG,OAHO,SAAUC,GAC3B,OAAQC,MAAMD,IAAgB,IAARA,CACxB,IAEE,MAAM,IAAIH,MAAM,yDAElBlC,MAAK,EAAUiC,CACjB,CAQAZ,GAAAA,CAAIkB,GACF,OAAOvC,MAAK,EAAQuC,EACtB,CAOAJ,MAAAA,GACE,OAAOnC,MAAK,EAAQmC,MACtB,CAOAK,QAAAA,GACE,MAAO,IAAMxC,MAAK,EAAQwC,WAAa,GACzC,CAOAC,SAAAA,GACE,OAAOzC,MAAK,EAAQ0C,OACtB,CAQAG,MAAAA,CAAOD,GAEL,IAAKA,EACH,OAAO,EAGT,MAAMT,EAASnC,KAAKmC,SACpB,GAAIA,IAAWS,EAAIT,SACjB,OAAO,EAGT,IAAK,IAAII,EAAI,EAAGA,EAAIJ,IAAUI,EAC5B,GAAIvC,KAAKqB,IAAIkB,KAAOK,EAAIvB,IAAIkB,GAC1B,OAAO,EAIX,OAAO,CACT,CAOAkkB,KAAAA,GACE,MAAO,CACLhe,EAAGzI,KAAKqB,IAAI,GACZqH,EAAG1I,KAAKqB,IAAI,GAEhB,EC1FK,MAAM4mB,GAOX,GAOA,GAOA,GAOA,GAAe,CAAC,EAOhB,GAOA,GAAera,IAOf,IAAc,EAUd5L,WAAAA,CAAYkmB,EAAQ7hB,EAAM8hB,EAASC,EAAaC,GAC9CroB,MAAK,EAAW,CAACkoB,GACjBloB,MAAK,EAAQqG,EACbrG,MAAK,EAAWmoB,OACI,IAATE,IACTroB,MAAK,EAAeqoB,EACpBroB,MAAK,EAAaqoB,GAAQ,CAACH,SAGF,IAAhBE,IACTpoB,MAAK,EAAeooB,EAExB,CAOAE,cAAAA,GACE,OAAOtoB,MAAK,CACd,CASAuoB,6BAAAA,GACE,MAAMzV,EAAO5R,OAAO4R,KAAK9S,MAAK,GAC9B,GAAoB,IAAhB8S,EAAK3Q,OACP,OAAOnC,MAAK,EAASmC,OAEvB,IAAIqmB,EAAQ,EACZ,IAAK,IAAIjmB,EAAI,EAAGA,EAAIuQ,EAAK3Q,SAAUI,EACjCimB,GAASxoB,MAAK,EAAa8S,EAAKvQ,IAAIJ,OAEtC,OAAOqmB,CACT,CAQAC,eAAAA,CAAgBJ,GACd,YAA0C,IAA5BroB,MAAK,EAAaqoB,EAClC,CASAK,kCAAAA,CAAmCL,GACjC,MAAMvV,EAAO5R,OAAO4R,KAAK9S,MAAK,GAC9B,GAAoB,IAAhB8S,EAAK3Q,OACP,OAEF,IAAIqmB,EAAQ,EACZ,IAAK,IAAIjmB,EAAI,EAAGA,EAAIuQ,EAAK3Q,SAAUI,EAAG,CACpC,MAAMvB,EAAM8R,EAAKvQ,GACjB,GAAIsU,SAAS7V,EAAK,MAAQqnB,EACxB,MAEFG,GAASxoB,MAAK,EAAagB,GAAKmB,MAClC,CACA,OAAOqmB,CACT,CAQAG,SAAAA,GACE,OAAO3oB,MAAK,EAAS,EACvB,CAOA4oB,UAAAA,GACE,OAAO5oB,MAAK,CACd,CAUA6oB,cAAAA,CAAe9b,EAAS/B,GACtB,IAAK,IAAIzI,EAAI,EAAGA,EAAIvC,MAAK,EAASmC,SAAUI,EAC1C,GAAIvC,MAAK,EAASuC,GAAGwI,UAAUgC,EAAS/B,GACtC,OAAO,EAGX,OAAO,CACT,CAUAyY,OAAAA,CAAQF,GACN,IAAIza,EAAM9I,MAAK,EACf,GAAIujB,QAA8C,IAApBA,EAAiC,CAC7D,IAAIthB,EAAS6mB,GACX,CACE9oB,MAAK,EAAMqB,IAAI,GACfrB,MAAK,EAAMqB,IAAI,GACfrB,MAAK,EAAMqB,IAAI,IAEjBkiB,GACFthB,EAASA,EAAO4hB,IAAIlgB,KAAKsH,KACzBnC,EAAM,IAAIgd,GAAK7jB,EAAO8c,OAAO/e,MAAK,EAAMyC,YAAYC,MAAM,IAC5D,CACA,OAAOoG,CACT,CAMA,KACE,MAAMigB,EAyWH,SAAiCC,GAEtC,GAAIA,EAAQ7mB,QAAU,EACpB,OAGF,MAAM8mB,EAAW,GACjB,IAAK,IAAI1mB,EAAI,EAAGA,EAAIymB,EAAQ7mB,OAAS,IAAKI,EAAG,CAC3C,MAAM2mB,EAAUF,EAAQzmB,GAClB4mB,EAAUH,EAAQzmB,EAAI,GACtB6mB,EAAeF,EAAQjb,YAAYkb,GACzC,GAAqB,IAAjBC,EACF,MAAM,IAAIlnB,MAAM,sBACdgnB,EAAQ1mB,WAAa,IAAM2mB,EAAQ3mB,YAEvCymB,EAAShmB,KAAKmmB,EAChB,CAGA,MAAMjC,EAAQC,GAAc6B,GACtBd,EAAUnX,EAAemW,EAAMP,KAAM,GAW3C,OARIO,EAAMN,OAAS/b,GACjB3G,EAAOa,KAAK,iCAAmCmjB,EAC7C,WAAahB,EAAMP,KACnB,UAAYO,EAAMR,IAClB,UAAYQ,EAAM9Z,IAClB,aAAe8Z,EAAMN,OAAS,KAG3BsB,CACT,CAzY4BkB,CAAwBrpB,MAAK,GAErD,QAA+B,IAApB+oB,GACT/oB,MAAK,EAASqB,IAAI,KAAO0nB,EAAiB,CAC1C5kB,EAAOQ,MAAM,2BAA6BokB,EACxC,2BAA6B/oB,MAAK,EAASqB,IAAI,IACjD,MAAMY,EAASjC,MAAK,EAASyC,YAC7BR,EAAO,GAAK8mB,EACZ/oB,MAAK,EAAW,IAAIgoB,GAAQ/lB,EAC9B,CACF,CAUAqnB,UAAAA,CAAW/F,GAELvjB,MAAK,IACPA,MAAK,IACLA,MAAK,GAAc,GAErB,IAAI8I,EAAM9I,MAAK,EACf,GAAIujB,QAA8C,IAApBA,EAAiC,CAC7D,IAAIgG,EAAiBT,GACnB,CACE9oB,MAAK,EAASqB,IAAI,GAClBrB,MAAK,EAASqB,IAAI,GAClBrB,MAAK,EAASqB,IAAI,IAEpBkiB,GACFgG,EAAiBA,EAAe1F,IAAIlgB,KAAKsH,KACzCnC,EAAM,IAAIkf,GAAQuB,EACpB,CACA,OAAOzgB,CACT,CAOA0gB,cAAAA,GAEE,OAAOxpB,KAAKspB,WACVtpB,MAAK,EAAaqL,aAAaoC,gBAEnC,CAOAgc,cAAAA,GACE,OAAOzpB,MAAK,CACd,CAeA0pB,aAAAA,CAAcC,EAAOtB,GAInB,IAAIuB,EAAe5pB,MAAK,OACJ,IAATqoB,IACTuB,EAAe5pB,MAAK,EAAaqoB,IAInC,MAAMwB,EAAqBF,EAAMrb,WAAWsb,GACtCE,EAAgBF,EAAaC,GAG7BE,EAAWJ,EAAMhb,MAAMmb,GAe7B,OAZe,IAAI5f,EACjBlK,MAAK,EAAaqB,IAAI,EAAG,GACzBrB,MAAK,EAAaqB,IAAI,EAAG,GACzBrB,MAAK,EAAaqB,IAAI,EAAG,IAKIsJ,gBAAgBof,GAE3CF,EAAqB,EAAIA,CAG/B,CASAG,YAAAA,CAAa9B,EAAQ5a,EAAO+a,GAE1B,MAAM4B,EAAgB,SAAUpY,GAC9B,OAAOA,EAAQhP,OAAOqlB,EACxB,EACA,QAAoB,IAATG,EAAsB,CAG/B,QAAqB,IADProB,MAAK,EAAaqoB,GAAM6B,KAAKD,GAEzC,MAAM,IAAI/nB,MAAM,wCAGlBlC,MAAK,EAAaqoB,GAAMvG,OAAOxU,EAAO,EAAG4a,EAC3C,CACA,QAAoB,IAATG,GAAwBA,IAASroB,MAAK,EAAc,CAG7D,QAAqB,IADPA,MAAK,EAASkqB,KAAKD,GAE/B,MAAM,IAAI/nB,MAAM,mCAGlBlC,MAAK,GAAc,EAEnBA,MAAK,EAAS8hB,OAAOxU,EAAO,EAAG4a,GAE/B,MAAMjmB,EAASjC,MAAK,EAAMyC,YAC1BR,EAAO,IAAM,EACbjC,MAAK,EAAQ,IAAI8lB,GAAK7jB,EACxB,CACF,CAQAkoB,WAAAA,CAAYjC,EAAQG,GAElBroB,MAAK,EAAaqoB,GAAQ,CAACH,GAE3B,MAAMkC,EAAapqB,MAAK,EAAMyC,YACxB4nB,EAAgBrqB,MAAK,EAASyC,YACV,IAAtB2nB,EAAWjoB,OACbioB,EAAW,IAAM,GAEjBA,EAAWnnB,KAAK,GAChBonB,EAAcpnB,KAAK,IAErBjD,MAAK,EAAQ,IAAI8lB,GAAKsE,GACtBpqB,MAAK,EAAW,IAAIgoB,GAAQqC,EAC9B,CAOA7nB,QAAAA,GACE,MAAO,WAAaxC,KAAK2oB,YACvB,WAAa3oB,KAAKyjB,UAClB,cAAgBzjB,KAAKspB,aACrB,kBAAoBtpB,KAAKypB,gBAC7B,CAQA5mB,MAAAA,CAAOD,GACL,OAAe,OAARA,GACL5C,KAAK2oB,YAAY9lB,OAAOD,EAAI+lB,cAC5B3oB,KAAKyjB,UAAU5gB,OAAOD,EAAI6gB,YAC1BzjB,KAAKspB,aAAazmB,OAAOD,EAAI0mB,aACjC,CAQAlD,UAAAA,CAAWuD,GACT,OAAO3pB,KAAKsqB,gBAAgBtqB,KAAKuqB,aAAaZ,GAChD,CASAW,eAAAA,CAAgBhd,EAAO+Y,GACrB,OAAOrmB,KAAKyjB,UAAU2C,WAAW9Y,EAAO+Y,EAC1C,CAQAmE,YAAAA,CAAald,GAGX,MAAM6a,EAAUnoB,KAAKspB,aACfmB,EAAkB,IAAIzd,EAC1BM,EAAMjM,IAAI,GAAK8mB,EAAQ9mB,IAAI,GAC3BiM,EAAMjM,IAAI,GAAK8mB,EAAQ9mB,IAAI,GAC3BiM,EAAMjM,IAAI,GAAK8mB,EAAQ9mB,IAAI,IAGvB0L,EAAU/M,KAAKypB,iBAAiB3c,gBAAgB2d,GAEhDxoB,EAASqL,EAAM7K,YACfylB,EAASloB,KAAK2oB,YAKpB,OAJA1mB,EAAO,GAAKimB,EAAO/d,OAAS4C,EAAQ5C,OACpClI,EAAO,GAAKimB,EAAO9d,OAAS2C,EAAQ3C,OACpCnI,EAAO,GAAKimB,EAAO7d,OAAS0C,EAAQ1C,OAE7B,IAAIuE,EAAM3M,EACnB,CAQAyoB,YAAAA,CAAaf,GAGX,MAAMxB,EAAUnoB,KAAKspB,aACfmB,EAAkB,IAAIzd,EAC1B2c,EAAMxf,OAASge,EAAQ9mB,IAAI,GAC3BsoB,EAAMvf,OAAS+d,EAAQ9mB,IAAI,GAC3BsoB,EAAMtf,OAAS8d,EAAQ9mB,IAAI,IAGvB0L,EAAU/M,KAAKypB,iBAAiB3c,gBAAgB2d,GAEhDvC,EAASloB,KAAK2oB,YACpB,OAAO,IAAI3b,EACTkb,EAAO/d,OAAS4C,EAAQ5C,OACxB+d,EAAO9d,OAAS2C,EAAQ3C,OACxB8d,EAAO7d,OAAS0C,EAAQ1C,OAE5B,CAQAkgB,YAAAA,CAAaZ,GAIX,MAAMzB,EAASloB,KAAK2oB,YACd5b,EAAU,IAAIC,EAClB2c,EAAMtoB,IAAI,GAAK6mB,EAAO/d,OACtBwf,EAAMtoB,IAAI,GAAK6mB,EAAO9d,OACtBuf,EAAMtoB,IAAI,GAAK6mB,EAAO7d,QAGlBogB,EACJzqB,KAAKypB,iBAAiBpe,aAAayB,gBAAgBC,GAE/C9K,EAAS0nB,EAAMlnB,YAEf0lB,EAAUnoB,KAAKspB,aAMrB,OALArnB,EAAO,GAAK0B,KAAK0N,MAAMoZ,EAAgBtgB,OAASge,EAAQ9mB,IAAI,IAC5DY,EAAO,GAAK0B,KAAK0N,MAAMoZ,EAAgBrgB,OAAS+d,EAAQ9mB,IAAI,IAC5DY,EAAO,GAAK0B,KAAK0N,MAAMoZ,EAAgBpgB,OAAS8d,EAAQ9mB,IAAI,IAGrD,IAAIU,EAAME,EACnB,CAQA0oB,YAAAA,CAAahB,GAGX,MAAMzB,EAASloB,KAAK2oB,YACd5b,EAAU,IAAIC,EAClB2c,EAAMtoB,IAAI,GAAK6mB,EAAO/d,OACtBwf,EAAMtoB,IAAI,GAAK6mB,EAAO9d,OACtBuf,EAAMtoB,IAAI,GAAK6mB,EAAO7d,QAGlBogB,EACJzqB,KAAKypB,iBAAiBpe,aAAayB,gBAAgBC,GAE/C9K,EAAS0nB,EAAMlnB,YAEf0lB,EAAUnoB,KAAKspB,aAMrB,OALArnB,EAAO,GAAKwoB,EAAgBtgB,OAASge,EAAQ9mB,IAAI,GACjDY,EAAO,GAAKwoB,EAAgBrgB,OAAS+d,EAAQ9mB,IAAI,GACjDY,EAAO,GAAKwoB,EAAgBpgB,OAAS8d,EAAQ9mB,IAAI,GAG1C,IAAI2L,EAAQ/K,EAAO,GAAIA,EAAO,GAAIA,EAAO,GAClD,EAWK,SAAS6mB,GAAmBlc,EAASwb,GAG1C,OAAOA,EAAY/c,aAAasB,gBAAgBC,EAClD,CASO,SAASge,GAAqBhe,EAASwb,GAE5C,OAAOA,EAAYzb,gBAAgBC,EACrC,CCpjBA,SAASie,GAAgBve,GACvB,OAAQ,IAAMA,GAAK5J,OAAO,EAC5B,CASO,SAASooB,GAAQjZ,GACtB,QAAuB,IAAZA,EACT,OAEF,GAA6B,IAAzBA,EAAQ/P,MAAMK,OAChB,OAEF,MAAM4oB,EAAUlZ,EAAQ/P,MAAM,GAI9B,IAAIkpB,EAAkB,EAClBC,EAAgB,EAapB,OAZuB,KAAnBF,EAAQ5oB,SACV6oB,EAAkB,EAClBC,EAAgB,GAUX,CACLC,KATcrU,SAASkU,EAAQnb,UAAU,EAAG,GAAI,IAUhDub,WARmBJ,EAAQ5oB,QAAU6oB,EAAkB,EACrDnU,SAASkU,EAAQnb,UACjBob,EAAiBA,EAAkB,GAAI,IAAM,EAAI,EAOnDI,IANYL,EAAQ5oB,SAAW8oB,EAAgB,EAC7CpU,SAASkU,EAAQnb,UACjBqb,EAAeA,EAAgB,GAAI,IAAM,EAM/C,CASO,SAASI,GAAQxZ,GACtB,QAAuB,IAAZA,EACT,OAEF,GAA6B,IAAzBA,EAAQ/P,MAAMK,OAChB,OAGF,MAAMmpB,EAAUzZ,EAAQ/P,MAAM,GACxBypB,EAAU1U,SAASyU,EAAQ1b,UAAU,EAAG,GAAI,IAC5C4b,EAAYF,EAAQnpB,QAAU,EAChC0U,SAASyU,EAAQ1b,UAAU,EAAG,GAAI,IAAM,EACtC6b,EAAYH,EAAQnpB,QAAU,EAChC0U,SAASyU,EAAQ1b,UAAU,EAAG,GAAI,IAAM,EACtC8b,EAAmBJ,EAAQnpB,QAAU,EACvCmpB,EAAQ1b,UAAU,EAAG,IAAM,EAI/B,MAAO,CACL+b,MAAOJ,EACPK,QAASJ,EACTK,QAASJ,EACTK,aAP0C,IAArBJ,EAAyB,EAC5C7U,SAAS6U,EAAkB,IAC3B/nB,KAAKC,IAAI,GAAI,EAAI8nB,EAAiBvpB,QAOxC,CAuCO,SAAS4pB,GAAcC,GAC5B,MAAO,CACLd,KAAMc,EAAKC,cAAczpB,WACzB2oB,WAAYN,IAAiBmB,EAAKE,WAAa,GAAG1pB,YAClD4oB,IAAKP,GAAgBmB,EAAKlB,UAAUtoB,YAExC,CAQO,SAAS2pB,GAAcH,GAC5B,MAAO,CACLL,MAAOd,GAAgBmB,EAAKI,WAAW5pB,YACvCopB,QAASf,GAAgBmB,EAAKK,aAAa7pB,YAC3CqpB,QAAShB,GAAgBmB,EAAKM,aAAa9pB,YAE/C,CAQO,SAAS+pB,GAAaC,GAE3B,OACEA,EAAQtB,KACRsB,EAAQrB,WACRqB,EAAQpB,GAEZ,CAQO,SAASqB,GAAaD,GAE3B,OACEA,EAAQb,MACRa,EAAQZ,QACRY,EAAQX,OAEZ,CCjKO,SAASa,KAEd,OAAO,IAAIxhB,EAAS,CAClB,EAAG,EAAG,EACN,EAAG,EAAG,EACN,GAAI,EAAG,GAGX,CAoBO,MAAMyhB,GAAc,CAIzBC,MAAO,QAIPC,QAAS,UAITC,SAAU,YASL,SAASC,GAAkBvjB,GAChC,IAAIwjB,EAQJ,OAPIxjB,IAASmjB,GAAYC,MACvBI,EAASpf,IACApE,IAASmjB,GAAYE,QAC9BG,EAASN,KACAljB,IAASmjB,GAAYG,WAC9BE,EAvCK,IAAI9hB,EAAS,CAClB,EAAG,GAAI,EACP,EAAG,EAAG,EACN,GAAI,EAAG,KAsCF8hB,CACT,CAUO,SAASC,GAAwBD,GACtC,MAAMpF,EAAK,IAAI1d,EACb8iB,EAAO3rB,IAAI,EAAG,GACd2rB,EAAO3rB,IAAI,EAAG,GACd2rB,EAAO3rB,IAAI,EAAG,IAEV6rB,EAAK,IAAIhjB,EACb8iB,EAAO3rB,IAAI,EAAG,GACd2rB,EAAO3rB,IAAI,EAAG,GACd2rB,EAAO3rB,IAAI,EAAG,IAEV8rB,EAAK,IAAIjjB,EACb8iB,EAAO3rB,IAAI,EAAG,GACd2rB,EAAO3rB,IAAI,EAAG,GACd2rB,EAAO3rB,IAAI,EAAG,IAEhB,OAAO+rB,GAAmBxF,GACxBwF,GAAmBF,GACnBE,GAAmBD,EACvB,CASA,SAASC,GAAmBC,GAC1B,IAAIpiB,EAAM,IAAIf,EACZvG,KAAKsH,IAAIoiB,EAAOljB,QAChBxG,KAAKsH,IAAIoiB,EAAOjjB,QAChBzG,KAAKsH,IAAIoiB,EAAOhjB,SAGd+d,EAAc,GAClB,MAAMkF,EAAeD,EAAOljB,OAAS,EAAI,IAAM,IACzCojB,EAAeF,EAAOjjB,OAAS,EAAI,IAAM,IAGzCojB,EAAeH,EAAOhjB,OAAS,EAAI,IAAM,IAEzCojB,EAAY,KAElB,IAAK,IAAIlrB,EAAI,EAAGA,EAAI,EAAGA,IACrB,GAAI0I,EAAId,OAASsjB,GACfxiB,EAAId,OAASc,EAAIb,QACjBa,EAAId,OAASc,EAAIZ,OACjB+d,GAAekF,EACfriB,EAAM,IAAIf,EAAS,EAAGe,EAAIb,OAAQa,EAAIZ,aACjC,GAAIY,EAAIb,OAASqjB,GACtBxiB,EAAIb,OAASa,EAAId,QACjBc,EAAIb,OAASa,EAAIZ,OACjB+d,GAAemF,EACftiB,EAAM,IAAIf,EAASe,EAAId,OAAQ,EAAGc,EAAIZ,YACjC,MAAIY,EAAIZ,OAASojB,GACtBxiB,EAAIZ,OAASY,EAAId,QACjBc,EAAIZ,OAASY,EAAIb,QAIjB,MAHAge,GAAeoF,EACfviB,EAAM,IAAIf,EAASe,EAAId,OAAQc,EAAIb,OAAQ,EAG7C,CAGF,OAAOge,CACT,CAkCO,SAASsF,GAAmBC,GACjC,IAAInkB,EACJ,MAAMokB,EAAeC,GAA0BF,GAK/C,YAJ4B,IAAjBC,IAETpkB,EA/BJ,SAAqBskB,GACnB,IAAIC,EAcJ,MAZE,CAAC,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,OAKrCpd,SAASmd,GACtBC,EAAYpB,GAAYC,MAJxB,CAAC,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,OAK5Bjc,SAASmd,GAC/BC,EAAYpB,GAAYE,QAJxB,CAAC,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,OAK3Blc,SAASmd,KAChCC,EAAYpB,GAAYG,UAEnBiB,CACT,CAeWC,CADQf,GAAwBW,EAAangB,mBAG/CjE,CACT,CASO,SAASqkB,GAA0BF,GACxC,IAAIM,EACJ,QAAuB,IAAZN,GAA8C,IAAnBA,EAAQxrB,OAAc,CAC1D,MAAM+rB,EAAa,IAAIhkB,EAASyjB,EAAQ,GAAIA,EAAQ,GAAIA,EAAQ,IAC1DQ,EAAa,IAAIjkB,EAASyjB,EAAQ,GAAIA,EAAQ,GAAIA,EAAQ,IAC1DS,EAASF,EAAW1jB,aAAa2jB,GAEvCF,EAAoB,IAAI/iB,EAAS,CAC/BgjB,EAAW/jB,OAAQgkB,EAAWhkB,OAAQikB,EAAOjkB,OAC7C+jB,EAAW9jB,OAAQ+jB,EAAW/jB,OAAQgkB,EAAOhkB,OAC7C8jB,EAAW7jB,OAAQ8jB,EAAW9jB,OAAQ+jB,EAAO/jB,QAGjD,CACA,OAAO4jB,CACT,CA4BO,SAASI,GAAmBC,EAAkBC,GACnD,IAAIhL,EAAkB3V,IAWtB,YAViC,IAAtB2gB,IAMThL,EACE+K,EAAiB7gB,gBAAgBpC,aAAakB,SAASgiB,IAGpDhL,EAAgB7W,QACzB,CCsHO,SAAS8hB,GAAevO,GAE7B,MAAMwO,EAAOxO,EAAS,YACtB,QAAoB,IAATwO,EACT,MAAM,IAAIvsB,MAAM,sCAElB,GAA0B,IAAtBusB,EAAK3sB,MAAMK,OACb,MAAM,IAAID,MAAM,oCAGlB,MAAMwsB,EAAUzO,EAAS,YACzB,QAAuB,IAAZyO,EACT,MAAM,IAAIxsB,MAAM,yCAElB,GAA6B,IAAzBwsB,EAAQ5sB,MAAMK,OAChB,MAAM,IAAID,MAAM,uCAElB,MAAO,CAACwsB,EAAQ5sB,MAAM,GAAI2sB,EAAK3sB,MAAM,GACvC,CAkJO,SAAS6sB,GAAsBC,GAEpC,QAAwC,IAA7BA,EAAa,YACtB,OAAO,KAET,MAAMC,EAAeD,EAAa,YAE5BvE,EAAgB,CACpByE,WAAWD,EAAa/sB,MAAM,IAC9BgtB,WAAWD,EAAa/sB,MAAM,KAMhC,YAHwC,IAA7B8sB,EAAa,aACtBvE,EAAcpnB,KAAK6rB,WAAWF,EAAa,YAAY9sB,MAAM,KAExD,IAAIkmB,GAAQqC,EACrB,CA0HO,SAAS0E,GAAaC,GAC3B,OAAQA,GAA+E,OAAlDA,EAA0B9e,MAAM,aACvE,CAWA,SAAS+e,GAASpd,EAASrI,EAAMvH,GAC/B,IAAIitB,EAAU,GACd,QAAuB,IAAZrd,EACTqd,GAAW,IAAM1lB,EAAO,sBACnB,GAA6B,IAAzBqI,EAAQ/P,MAAMK,OACvB+sB,GAAW,IAAM1lB,EAAO,kBAExB,QAAsB,IAAXvH,EACT,IAAK,IAAIM,EAAI,EAAGA,EAAIN,EAAOE,SAAUI,EAE9BsP,EAAQ/P,MAAM6O,SAAS1O,EAAOM,MACjC2sB,GAAW,IAAM1lB,EAAO,qBAAuBvH,EAAOM,GACpD,YAAcsP,EAAQ/P,MAAQ,MAKxC,OAAOotB,CACT,CA2TO,MAAMC,GAOX9D,OAAAA,CAAQ+D,GAGR,EC/9BK,MAAMC,GAOX,GAOA,IAQAC,UAAAA,GACE,OAAOtvB,MAAK,CACd,CAQAuvB,aAAAA,CAAcX,GAMZ,IAAIY,EAJJxvB,MAAK,OAAWQ,EAEhBguB,GAAeI,GAGf,MAAM/c,EAAU+c,EAAa,YAC7B,QAAuB,IAAZ/c,IACT2d,EAAW3d,EAAQ/P,MAAM,GAER,OAAb0tB,GAAmB,CACrB,MAAMR,ED0iBP,SAAsCJ,GAC3C,MAAMI,EAA4BJ,EAAa,YACzCa,EAAgBb,EAAa,YAC7Bc,EAAMd,EAAa,YAEzB,IAAIe,EAAkB,EAKtB,QAJmB,IAARD,IACTC,EAAkBD,EAAI5tB,MAAM,SAGW,IAA9BktB,QACc,IAAlBS,EAA+B,CACpC,IAAIG,EAAQZ,EAA0BltB,MAAM,GAAG6Z,cAE/C,MAAMqB,EAASyS,EAAc3tB,MAAM,GAC7B+tB,EAAWzS,GAAyBJ,GACpC8S,EAAW5S,GAA6BF,GACxC+S,EAAW5S,GAA6BH,GAU9C,OARK6S,GAAYC,GAAYC,IAChB,gBAAVH,GAAqC,gBAAVA,IAC5BA,EAAQ,OAGI,QAAVA,GAAuC,IAApBD,IACrBC,EAAQ,iBAEHA,CACT,CACF,CCtkBQI,CAA6BpB,GACvBqB,ED+gBP,SAAwBrB,GAC7B,MAAMqB,EAAcrB,EAAa,YACjC,QAA2B,IAAhBqB,EACT,OAAOA,EAAYnuB,MAAM,EAG7B,CCrhB4BouB,CAAetB,GACnC,GD4hBD,SAA4BqB,GAEjC,OAAQA,GADQ,sCACevf,KAAKuf,EACtC,CC/hBYE,CAAmBF,KACdlB,GAAaC,GACpB,OAAOhvB,MAAK,EAEd,MAAMowB,EDizBP,SAAsBnQ,GAC3B,IAAIiP,EAAU,GACd,MAAM9S,EAAS,CAAC,EAiBhB,IAAIiU,EAXJnB,GAAWD,GADShP,EAAS,YADL,6BAE0B,CAAC,OAAQ,SAI3DiP,GAAWD,GADShP,EAAS,YADL,8BAE0B,CAAC,UAInDiP,GAAWD,GADIhP,EAAS,YADL,mBAEqB,CAAC,SAIzC,MACMqQ,EAAcrQ,EAAS,YACvBjb,EAAOiqB,GAASqB,EAFG,6BAGzB,GAAoB,IAAhBtrB,EAAK7C,OAAc,CACrB,MAAMouB,EAASzB,WAAWwB,EAAYxuB,MAAM,IACvCQ,MAAMiuB,GAGTrB,GAAW,iCAFXmB,EAAYE,CAIhB,MACErB,GAAWlqB,EAIb,MAAMwrB,EApOR,SAAwBvQ,GACtB,IACIjb,EADAkqB,EAAU,GAId,MACMuB,EAAgB3F,GADD7K,EAAS,aAG9B,IAAIyQ,EACAC,EACAC,EAEJ,MACMC,EAAc5Q,EAAS,YAE7B,GADAiP,GAAWD,GAAS4B,EAFG,0DAGI,IAAhBA,EAA6B,CACL,IAA7BA,EAAY/uB,MAAMK,QACpBgC,EAAOa,KACL,yEAKJ,MAAM8rB,EAAe,mCACfC,EAAcF,EAAY/uB,MAAM,GAAG,YAEzC,GADAkD,EAAOiqB,GAAS8B,EAAaD,GACT,IAAhB9rB,EAAK7C,OAAc,CACrB,MAAM6uB,EAAOlC,WAAWiC,EAAYjvB,MAAM,IACrCQ,MAAM0uB,GAGT9B,GAAW,6BAFXwB,EAAYM,CAIhB,MACE9B,GAAWlqB,EAIb,MAAMisB,EAAc,kCACdC,EAAaL,EAAY/uB,MAAM,GAAG,YAExC,GADAkD,EAAOiqB,GAASiC,EAAYD,GACR,IAAhBjsB,EAAK7C,OAAc,CACrB,MAAMgvB,EAAKrC,WAAWoC,EAAWpvB,MAAM,IAClCQ,MAAM6uB,GAGTjC,GAAW,4BAFXyB,EAAWQ,CAIf,MACEjC,GAAWlqB,EAIb,MAAMosB,EAAuBP,EAAY/uB,MAAM,GAAG,YAClD,IAAIuvB,EACAC,EACJ,QAAoC,IAAzBF,EAETC,EAAoBZ,EAGpBa,EAAoBjG,GADKwF,EAAY/uB,MAAM,GAAG,iBAEzC,CACL,MAAMyvB,EF5qBL,SAAqB1f,GAC1B,QAAuB,IAAZA,EACT,OAEF,GAA6B,IAAzBA,EAAQ/P,MAAMK,OAChB,OAGF,MAEMqvB,EAFc3f,EAAQ/P,MAAM,GAENsN,MAAM,KAAK,GACjCqiB,EAAkB,IAAIxZ,GAAY,MACxCwZ,EAAgB3vB,MAAQ,CAAC0vB,EAAQ5hB,UAAU,EAAG,IAC9C,MAAM8hB,EAAS5G,GAAQ2G,GACjBE,EAAkB,IAAI1Z,GAAY,MAIxC,OAHA0Z,EAAgB7vB,MAAQ,CAAC0vB,EAAQ5hB,UAAU,IAGpC,CACLoc,KAAM0F,EACNrJ,KAJamJ,EAAQrvB,QAAU,EAC7BkpB,GAAQsG,QAAmBnxB,EAKjC,CEspBiCoxB,CAAYR,GACvCC,EAAoBE,EAAmBvF,KACvCsF,EAAoBC,EAAmBlJ,IACzC,MACiC,IAAtBiJ,IACTA,EAAoB,CAClB3F,MAAO,EAAGC,QAAS,EAAGC,QAAS,EAAGC,aAAc,IAGpD8E,EAAa,IAAIiB,KACfR,EAAkBnG,KAClBmG,EAAkBlG,WAClBkG,EAAkBjG,IAClBkG,EAAkB3F,MAClB2F,EAAkB1F,QAClB0F,EAAkBzF,QAClByF,EAAkBxF,aAEtB,CAGA,MACMgG,EAAgBzG,GADDpL,EAAS,aAG9B,IAAI8R,EAAY,IAAIF,KAClBpB,EAAcvF,KACduF,EAActF,WACdsF,EAAcrF,IACd0G,EAAcnG,MACdmG,EAAclG,QACdkG,EAAcjG,QACdiG,EAAchG,cAKhB,MAAMkG,EAAY/R,EAAS,YAErBgS,EAAYhS,EAAS,YAC3B,QAAyB,IAAd+R,QACY,IAAdC,EAA2B,CAClC,MAAMC,EAAapH,GAAQkH,GACrBG,EAAa9G,GAAQ4G,GACrBG,EAAU,IAAIP,KAClBK,EAAWhH,KACXgH,EAAW/G,WACX+G,EAAW9G,IACX+G,EAAWxG,MACXwG,EAAWvG,QACXuG,EAAWtG,QACXsG,EAAWrG,cAGb,GAAIiG,EAAYK,EAAS,CACvB,MACMptB,EAAO,yDADA+sB,EAAU1G,UAAY+G,EAAQ/G,WAEpC7oB,WAAa,OACpB2B,EAAOW,MAAME,GAKb,IAAIqtB,EAAe,EACnB,MAAMC,EAAoB,gCACpBC,EAAiBtS,EAAS,YAChCiP,GAAWD,GAASsD,EAAgBD,QACN,IAAnBC,IACTF,EAAeE,EAAezwB,MAAM,IAEtC,IAAI0wB,EAAsB,EAC1B,MAAMC,EAA2B,kCAC3BC,EAAwBzS,EAAS,YAKvC,GAJAiP,GAAWD,GAASyD,EAAuBD,QACN,IAA1BC,IACTF,EAAsBE,EAAsB5wB,MAAM,IAEhDuwB,EAAe,GAAKG,EAAsB,EAAG,CAE/CA,GAA4C,IAC5CH,GAA8B,IAC9B,MAAMM,EAAgBhvB,KAAKga,IAAI,GAAKgT,EAC9BiC,EAAmBD,EAAgBH,EAKnCK,EAHJ,EACAF,EACAhvB,KAAKga,IAAIiV,GAAoB,EAAIjvB,KAAKmvB,KAAKF,KACWP,EACxDN,EAAY,IAAIF,KACdK,EAAWhH,KACXgH,EAAW/G,WACX+G,EAAW9G,IACX+G,EAAWxG,MACXwG,EAAWvG,QACXuG,EAAWtG,QAAUgH,EACrBV,EAAWrG,aAEf,CACF,CACF,CAGA,IAAI0E,EACJ,QAAyB,IAAduB,QACa,IAAfnB,QACc,IAAdF,QACa,IAAbC,EAA0B,CAEjC,MAAMoC,GAAahB,EAAU1G,UAAYuF,EAAWvF,WAAa,IAEjEmF,EAAcE,EADA/sB,KAAKC,IAAI,GAAKmvB,EAAYpC,EAE1C,CAEA,MAAO,CACL7uB,MAAO0uB,EACPtB,QAASA,EAEb,CAiDsB8D,CAAe/S,GAWnC,OAVAiP,GAAWsB,EAAYtB,QAGA,IAAnBA,EAAQ/sB,OACVia,EAAO8S,QAAU,4BAA8BA,EAG/C9S,EAAOta,MAAqB,IAAZuuB,EAAoBG,EAAY1uB,MAG3Csa,CACT,CCh2B0B6W,CAAarE,GAC/B5uB,MAAK,GAAaowB,EAAUtuB,MAC5B9B,MAAK,EAAWowB,EAAUlB,OAC5B,CAGF,OAAOlvB,MAAK,CACd,CAYAkzB,MAAAA,CAAOtE,EAAcuE,EAAaC,GAChC,MAAMC,EAAS7E,GAAeI,GACxBxE,EAAa,CAACiJ,EAAO,GAAIA,EAAO,GAAI,GAGpCC,EAAmB1E,EAAa,YACtC,QAAgC,IAArB0E,EAAkC,CAC3C,MAAMriB,EAAS4F,SAASyc,EAAiBxxB,MAAM,GAAI,IAC/CmP,EAAS,GACXmZ,EAAWnnB,KAAKgO,EAEpB,CAGA,MAAM5K,EAAO,IAAIyf,GAAKsE,GAGhBjC,EDgRH,SAAyBlI,GAE9B,IAAIsT,EAAa,EACbC,EAAgB,EAMpB,MAAM1gB,EAAO,CAAC,WAAY,WAAY,WAAY,YAClD,IAAK,IAAIrG,EAAI,EAAGA,EAAIqG,EAAK3Q,SAAUsK,EAAG,CACpC,MAAM0b,EAAUlI,EAASnN,EAAKrG,IAC9B,GAAI0b,GAAoC,IAAzBA,EAAQrmB,MAAMK,OAAc,CAEzCoxB,EAAazE,WAAW3G,EAAQrmB,MAAM,IACtC0xB,EAAgB1E,WAAW3G,EAAQrmB,MAAM,IACzC,KACF,CACF,CAcA,OAXsB,IAAlB0xB,IACFrvB,EAAOa,KAAK,wBACZwuB,EAAgB,GAEC,IAAfD,IACFpvB,EAAOa,KAAK,qBACZuuB,EAAa,GAKR,IAAIvL,GAAQ,CAACwL,EAAeD,EAAY,GACjD,CCjToBE,CAAgB7E,GAG1B5R,EAAS4R,EAAa,YAAY9sB,MAAM,GACxC+tB,EAAWzS,GAAyBJ,GACpC8S,EAAW5S,GAA6BF,GACxC+S,EAAW5S,GAA6BH,GAGxC0W,EAAuB9E,EAAa,YAE1C,IAAI+E,EAAgB,IAAIvU,MAAM,EAAG,EAAG,QACA,IAAzBsU,IACTC,EAAgB,CACd7E,WAAW4E,EAAqB5xB,MAAM,IACtCgtB,WAAW4E,EAAqB5xB,MAAM,IACtCgtB,WAAW4E,EAAqB5xB,MAAM,MAK1C,MAAMmsB,ED6ZH,SAA8BW,GACnC,MAAMgF,EAA0BhF,EAAa,YAC7C,IAAIX,EASJ,YANuC,IAA5B2F,IACT3F,EACEJ,GACE+F,EAAwB9xB,MAAM+hB,KAAKpF,GAASqQ,WAAWrQ,OAGtDwP,CACT,CCza8B4F,CAAqBjF,GAGzC1G,EAAS,IAAIlb,EACjB2mB,EAAc,GAAIA,EAAc,GAAIA,EAAc,IAE9CtL,GADY,IAAI8G,IACC9D,QAAQuD,GACzBkF,EAAW,IAAI7L,GACnBC,EAAQ7hB,EAAM8hB,EAAS8F,EAAmB5F,GAG5C,IAAI0L,EACJ,MAAMC,EAAMpF,EAAa,iBACN,IAARoF,IACTD,EAAiBC,EAAIlyB,MAAM,IAI7B,IAAI6tB,EAAkB,EACtB,MAAMD,EAAMd,EAAa,iBACN,IAARc,IACTC,EAAkBD,EAAI5tB,MAAM,IAI9B,MAAMmyB,EAAa5tB,EAAK8f,eAAiBwJ,EACzC,GAAIsE,IAAed,EAAYhxB,OAAQ,CAGrC,GAFAgC,EAAOa,KAAK,6BACVmuB,EAAYhxB,OAAS,OAAS8xB,KAC5BA,EAAad,EAAYhxB,QAG3B,MAAM,IAAID,MAAM,+CAFhBixB,EAAcA,EAAYzwB,MAAM,EAAG2D,EAAK8f,eAI5C,CAGA,MAAM/C,EAAQ,IAAI8Q,GAAMJ,EAAUX,EAAa,CAACY,IAE1C/E,EAA4BJ,EAAa,YAC/C,QAAyC,IAA9BI,EAA2C,CACpD,IAAIY,EAAQZ,EAA0BltB,MAAM,GAAG6Z,eAE1CkU,GAAYC,GAAYC,IAChB,gBAAVH,GAAqC,gBAAVA,IAC5BA,EAAQ,OAGI,QAAVA,GAAuC,IAApBD,IACrBC,EAAQ,iBAEVxM,EAAM+Q,6BAA6BvE,EACrC,CAEA,MAAMwE,EAAsBxF,EAAa,iBACN,IAAxBwF,GACThR,EAAMiR,uBAAuBD,EAAoBtyB,MAAM,IAIzD,IAAI6jB,EAAQ,EAEZ,MAAM2O,EAAe1F,EAAa,YAClC,QAA4B,IAAjB0F,EAA8B,CACvC,MAAMxyB,EAAQgtB,WAAWwF,EAAaxyB,MAAM,IACvCQ,MAAMR,KACT6jB,EAAQ7jB,EAEZ,CACA,IAAI8jB,EAAY,EAEhB,MAAM2O,EAAmB3F,EAAa,YACtC,QAAgC,IAArB2F,EAAkC,CAC3C,MAAMzyB,EAAQgtB,WAAWyF,EAAiBzyB,MAAM,IAC3CQ,MAAMR,KACT8jB,EAAY9jB,EAEhB,CAGA,MAAM0yB,EAAO,CACXpB,cAAeA,GAIX5D,EAAWZ,EAAa,iBACN,IAAbY,IACTgF,EAAKC,SAAWjF,EAAS1tB,MAAM,IAIjC,IAAI4yB,GAAe,EACfC,EAAkB,OACS,IAApB30B,MAAK,KACd00B,GAAe,EACfC,EAAkB30B,MAAK,GACvBmE,EAAOY,KAAK,iCAAmC4vB,GAC/ChP,GAASgP,EACT/O,GAAa+O,GAEf,MAAMnxB,EAAM,IAAIkiB,GAAyBC,EAAOC,GAChDxC,EAAMwR,4BAA4BpxB,GAElC,MAAMqxB,EAAU,SAAU7zB,GACxB,IAAI8H,EACJ,MAAM+I,EAAU+c,EAAa5tB,GAI7B,YAHuB,IAAZ6Q,IACT/I,EAAM+I,EAAQ/P,MAAM,IAEfgH,CACT,EA0CA,GAvCA0rB,EAAKM,kBAAoBD,EAAQ,YACjCL,EAAKO,wBAA0BF,EAAQ,YACvCL,EAAKvE,YAAc4E,EAAQ,YAC3BL,EAAKC,SAAWI,EAAQ,YACxBL,EAAKQ,UAAYH,EAAQ,YACzBL,EAAKS,gBAAkBJ,EAAQ,YAC/BL,EAAKU,0BAA4BL,EAAQ,YACzCL,EAAKW,oBAAsBN,EAAQ,YACnCL,EAAKY,cAAgBP,EAAQ,YAC7BL,EAAKa,WAAaR,EAAQ,YAC1BL,EAAKc,QAAUT,EAAQ,YAGvBL,EAAKe,UAAYV,EAAQ,YACzBL,EAAKgB,UAAYX,EAAQ,YACzBL,EAAKiB,iBAAmBZ,EAAQ,YAChCL,EAAKkB,QAAUb,EAAQ,YAEvBL,EAAKmB,kBAAoBd,EAAQ,YACjCL,EAAKoB,aAAef,EAAQ,YAE5BL,EAAKqB,uBAAyBhB,EAAQ,YAEtCL,EAAKsB,YAAcjB,EAAQ,YAC3BL,EAAKuB,UAAYlB,EAAQ,YACzBL,EAAKwB,iBAAmBnB,EAAQ,YAChCL,EAAKyB,WAAapB,EAAQ,YAE1BL,EAAK0B,aAAerB,EAAQ,YAC5BL,EAAK2B,sBAAwBtB,EAAQ,YACrCL,EAAK4B,mBAAqBvB,EAAQ,YAClCL,EAAK6B,iBAAmBxB,EAAQ,YAEhCL,EAAK8B,wBAA0BzB,EAAQ,YACvCL,EAAK+B,oBAAsB1B,EAAQ,YAGnCL,EAAKgC,SAAwC,IAA7BhC,EAAKW,oBAEjBT,EACFF,EAAKiC,UAAY,UACZ,CACL,MAAMA,EDyIL,SAAsBxW,GAC3B,IAAIyW,EAGJ,MAAM5jB,EAAO,CAAC,WAAY,YAC1B,IAAK,IAAIvQ,EAAI,EAAGA,EAAIuQ,EAAK3Q,SAAUI,EAAG,CACpC,MAAMsP,EAAUoO,EAASnN,EAAKvQ,IAC9B,QAAuB,IAAZsP,EAAyB,CAClC6kB,EAAO7kB,EAAQ/P,MAAM,GACrB,KACF,CACF,CAEA,QAAoB,IAAT40B,EAAsB,CAC/B,MAAM7kB,EAAUoO,EAAS,iBACF,IAAZpO,GAEQ,OADAA,EAAQ/P,MAAM,KAE7B40B,EAAO,KAGb,CACA,OAAOA,CACT,CChKwBC,CAAa/H,QACN,IAAd6H,IACTjC,EAAKiC,UAAYA,EAErB,CAEA,MAAMG,EAAgB,CAAC,EACjBC,EAAejI,EAAa,YAC5BkI,EAAclI,EAAa,YAC3BmI,EAAsBnI,EAAa,YACzC,QAA4B,IAAjBiI,QACc,IAAhBC,EAA6B,CACpC,IAAIttB,EACJ,IAAK,IAAIpG,EAAI,EAAGA,EAAIyzB,EAAa/0B,MAAMK,SAAUiB,EAAG,CAClD,MAAM+B,EAAS2pB,WAAW+H,EAAa/0B,MAAMsB,IAC7C,IAAIgC,EAAQ0pB,WAAWgI,EAAYh1B,MAAMsB,IACrC+B,GAAUC,GAAmB,IAAVA,IACrBoE,EAAO,QAC4B,IAAxButB,IACTvtB,EAAOutB,EAAoBj1B,MAAMsB,IAEtB,KAAToG,IACFA,EAAO,UAAYpG,GAErBgC,GAASuvB,EACLvvB,EAAQ,IACVA,EAAQ,GAEVwxB,EAAcptB,GAAQ,CACpB3D,GAAI,CAAC,IAAIX,EACPC,EAASwvB,EACTvvB,IAEFoE,KAAMA,IAGI,IAAVpE,GACFjB,EAAOa,KAAK,oCAEhB,CACF,CAIA,GAHAwvB,EAAKoC,cAAgBA,EAGwB,kBAAzCxT,EAAM4M,+BAAoD,CAE5D,MAAMgH,EAAgBpI,EAAa,YAE7BqI,EAAkBrI,EAAa,YAE/BsI,EAAiBtI,EAAa,YACpC,IAAIuI,EACAC,EACAC,EAMJ,MAAMC,EAAa1I,EAAa,YAChC,QAA0B,IAAf0I,GACmB,IAA5BA,EAAWx1B,MAAMK,OACjB,GAA4B,KAAxBm1B,EAAWx1B,MAAM,GAAW,CAC9B,IAAIy1B,GAAU,EAIVC,EAAWF,EAAWx1B,MAAM,GAKf,IAAb01B,IACFA,EAAW,OAIb,MAAMC,EAAST,EAAc9e,GAkB7B,GAhBIuf,IAAW,EAAID,IACjBD,GAAU,EACVpzB,EAAOY,KAAK,4CACVyyB,EAAW,QAAUC,IAOH,IAFA5gB,SACpB+X,EAAa,YAAY9sB,MAAM,GAAI,MAEnCy1B,GAAU,EACVpzB,EAAOY,KACL,wDAGAwyB,EAAS,CACX,MAAMG,EAAW,SAAU51B,GACzB,OAAOA,GAAS,CAClB,EAEAq1B,EAASH,EAAcl1B,MAAM+hB,IAAI6T,GACjCN,EAAWH,EAAgBn1B,MAAM+hB,IAAI6T,GACrCL,EAAUH,EAAep1B,MAAM+hB,IAAI6T,EACrC,CACF,MAAO,GAA4B,IAAxBJ,EAAWx1B,MAAM,GAAU,CAEpCqC,EAAOY,KACL,2DACF,IAAI4yB,EAAQX,EAAcl1B,MAAMY,MAAM,GAEtCy0B,EAAS/X,MAAMC,KAAK,IAAIvO,WAAW6mB,EAAMxkB,SACzCwkB,EAAQV,EAAgBn1B,MAAMY,MAAM,GAEpC00B,EAAWhY,MAAMC,KAAK,IAAIvO,WAAW6mB,EAAMxkB,SAC3CwkB,EAAQT,EAAep1B,MAAMY,MAAM,GAEnC20B,EAAUjY,MAAMC,KAAK,IAAIvO,WAAW6mB,EAAMxkB,QAC5C,CAGFiQ,EAAMwU,oBAAoB,IAAI1wB,EAAUiwB,EAAQC,EAAUC,GAC5D,CAGA,MAAMQ,EAA8BjJ,EAAa,YASjD,YAR2C,IAAhCiJ,IACTrD,EAAKsD,4BAA8BjhB,SACjCghB,EAA4B/1B,MAAM,GAAI,KAI1CshB,EAAM2U,QAAQvD,GAEPpR,CACT,EChbK,MAAM4U,GAOX,IAAkB,EAOlB,GAOAh2B,WAAAA,CAAYmR,EAAQ+F,QAEY,IAAnBA,IACTlZ,MAAK,EAAkBkZ,GAEzBlZ,MAAK,EAAQ,IAAImZ,SAAShG,EAC5B,CASA8kB,UAAAA,CAAWtf,EAAY7W,GAErB,OADA9B,MAAK,EAAMk4B,SAASvf,EAAY7W,GACzB6W,EAAa7H,WAAW+H,iBACjC,CASAsf,SAAAA,CAAUxf,EAAY7W,GAEpB,OADA9B,MAAK,EAAMo4B,QAAQzf,EAAY7W,GACxB6W,EAAaI,UAAUF,iBAChC,CASAwf,WAAAA,CAAY1f,EAAY7W,GAEtB,OADA9B,MAAK,EAAMs4B,UAAU3f,EAAY7W,EAAO9B,MAAK,GACtC2Y,EAAaiC,YAAY/B,iBAClC,CASA0f,UAAAA,CAAW5f,EAAY7W,GAErB,OADA9B,MAAK,EAAMw4B,SAAS7f,EAAY7W,EAAO9B,MAAK,GACrC2Y,EAAaK,WAAWH,iBACjC,CASA4f,WAAAA,CAAY9f,EAAY7W,GAEtB,OADA9B,MAAK,EAAM04B,UAAU/f,EAAY7W,EAAO9B,MAAK,GACtC2Y,EAAaqC,YAAYnC,iBAClC,CASA8f,WAAAA,CAAYhgB,EAAY7W,GAEtB,OADA9B,MAAK,EAAM44B,aAAajgB,EAAY7W,EAAO9B,MAAK,GACzC2Y,EAAauC,eAAerC,iBACrC,CASAggB,UAAAA,CAAWlgB,EAAY7W,GAErB,OADA9B,MAAK,EAAM84B,SAASngB,EAAY7W,EAAO9B,MAAK,GACrC2Y,EAAayC,WAAWvC,iBACjC,CASAkgB,UAAAA,CAAWpgB,EAAY7W,GAErB,OADA9B,MAAK,EAAMg5B,YAAYrgB,EAAY7W,EAAO9B,MAAK,GACxC2Y,EAAa2C,cAAczC,iBACpC,CASAogB,YAAAA,CAAatgB,EAAY7W,GAEvB,OADA9B,MAAK,EAAMk5B,WAAWvgB,EAAY7W,EAAO9B,MAAK,GACvC2Y,EAAa9U,aAAagV,iBACnC,CASAsgB,YAAAA,CAAaxgB,EAAY7W,GAEvB,OADA9B,MAAK,EAAMo5B,WAAWzgB,EAAY7W,EAAO9B,MAAK,GACvC2Y,EAAa8C,aAAa5C,iBACnC,CASAwgB,QAAAA,CAAS1gB,EAAYrM,GAEnB,MAAMxK,EAAQ+U,SAASvK,EAAK,IAE5B,OADAtM,MAAK,EAAMs4B,UAAU3f,EAAY7W,EAAO9B,MAAK,GACtC2Y,EAAaiC,YAAY/B,iBAClC,CASAygB,gBAAAA,CAAiB3gB,EAAYH,GAC3B,GAAIA,EAAMrW,OAAS,GAAM,EACvB,MAAM,IAAID,MAAM,yCAElB,IAAIq3B,EAAO,KACPl3B,EAAM,KACV,IAAK,IAAIE,EAAI,EAAGi3B,EAAMhhB,EAAMrW,OAAQI,EAAIi3B,EAAKj3B,GAAK,EAAG,CACnDg3B,EAAO,EACP,IAAK,IAAIn2B,EAAI,EAAGA,EAAI,IAAKA,EACvBf,EAAuB,IAAjBmW,EAAMjW,EAAIa,GAAW,EAAI,EAC/Bm2B,GAAQl3B,GAAOe,EAEjBuV,EAAa3Y,KAAKi4B,WAAWtf,EAAY4gB,EAC3C,CACA,OAAO5gB,CACT,CASA8gB,eAAAA,CAAgB9gB,EAAYH,GAC1B,IAAK,IAAIjW,EAAI,EAAGi3B,EAAMhhB,EAAMrW,OAAQI,EAAIi3B,IAAOj3B,EAC7CoW,EAAa3Y,KAAKi4B,WAAWtf,EAAYH,EAAMjW,IAEjD,OAAOoW,CACT,CASA+gB,cAAAA,CAAe/gB,EAAYH,GACzB,IAAK,IAAIjW,EAAI,EAAGi3B,EAAMhhB,EAAMrW,OAAQI,EAAIi3B,IAAOj3B,EAC7CoW,EAAa3Y,KAAKm4B,UAAUxf,EAAYH,EAAMjW,IAEhD,OAAOoW,CACT,CASAghB,gBAAAA,CAAiBhhB,EAAYH,GAC3B,IAAK,IAAIjW,EAAI,EAAGi3B,EAAMhhB,EAAMrW,OAAQI,EAAIi3B,IAAOj3B,EAC7CoW,EAAa3Y,KAAKq4B,YAAY1f,EAAYH,EAAMjW,IAElD,OAAOoW,CACT,CASAihB,eAAAA,CAAgBjhB,EAAYH,GAC1B,IAAK,IAAIjW,EAAI,EAAGi3B,EAAMhhB,EAAMrW,OAAQI,EAAIi3B,IAAOj3B,EAC7CoW,EAAa3Y,KAAKu4B,WAAW5f,EAAYH,EAAMjW,IAEjD,OAAOoW,CACT,CASAkhB,gBAAAA,CAAiBlhB,EAAYH,GAC3B,IAAK,IAAIjW,EAAI,EAAGi3B,EAAMhhB,EAAMrW,OAAQI,EAAIi3B,IAAOj3B,EAC7CoW,EAAa3Y,KAAKy4B,YAAY9f,EAAYH,EAAMjW,IAElD,OAAOoW,CACT,CASAmhB,gBAAAA,CAAiBnhB,EAAYH,GAC3B,IAAK,IAAIjW,EAAI,EAAGi3B,EAAMhhB,EAAMrW,OAAQI,EAAIi3B,IAAOj3B,EAC7CoW,EAAa3Y,KAAK24B,YAAYhgB,EAAYH,EAAMjW,IAElD,OAAOoW,CACT,CASAohB,eAAAA,CAAgBphB,EAAYH,GAC1B,IAAK,IAAIjW,EAAI,EAAGi3B,EAAMhhB,EAAMrW,OAAQI,EAAIi3B,IAAOj3B,EAC7CoW,EAAa3Y,KAAK64B,WAAWlgB,EAAYH,EAAMjW,IAEjD,OAAOoW,CACT,CASAqhB,eAAAA,CAAgBrhB,EAAYH,GAC1B,IAAK,IAAIjW,EAAI,EAAGi3B,EAAMhhB,EAAMrW,OAAQI,EAAIi3B,IAAOj3B,EAC7CoW,EAAa3Y,KAAK+4B,WAAWpgB,EAAYH,EAAMjW,IAEjD,OAAOoW,CACT,CASAshB,iBAAAA,CAAkBthB,EAAYH,GAC5B,IAAK,IAAIjW,EAAI,EAAGi3B,EAAMhhB,EAAMrW,OAAQI,EAAIi3B,IAAOj3B,EAC7CoW,EAAa3Y,KAAKi5B,aAAatgB,EAAYH,EAAMjW,IAEnD,OAAOoW,CACT,CASAuhB,iBAAAA,CAAkBvhB,EAAYH,GAC5B,IAAK,IAAIjW,EAAI,EAAGi3B,EAAMhhB,EAAMrW,OAAQI,EAAIi3B,IAAOj3B,EAC7CoW,EAAa3Y,KAAKm5B,aAAaxgB,EAAYH,EAAMjW,IAEnD,OAAOoW,CACT,EC/RF,IAAIwhB,GAAY,EAKT,MAAMC,GAMXC,OAMAv4B,MAKAE,WAAAA,CAAYq4B,GACVr6B,KAAKq6B,OAASA,CAChB,EAQF,MAAMC,GAAgB,CACpBC,KAAM,SAAU9b,GACd,OAAOA,CACT,EACAmD,OAAQ,WACN,OAAO,IACT,EACA4Y,MAAO,SAAU/b,GAEf,OADAA,EAAK3c,MAAQ,GACN2c,CACT,EACAgc,QAAS,SAAUhc,EAAM3c,GAEvB,OADA2c,EAAK3c,MAAQ,CAACA,GACP2c,CACT,GAiCK,SAASic,GAAOjjB,GACrB,MAAMkjB,EAASC,gCACf,IAAIC,EAAM,GACV,GAAgB,2BAAZpjB,EACFojB,EAAMF,Eb7FD,oBa8FA,CAEL,MACMG,EAAW,KADH,IAAIjJ,MAAQkJ,cAAcN,QAAQ,MAAO,IAC3B7qB,UAAU,EAAG,IAEzCuqB,IAAa,EACb,MAAMa,EAAY,IAAMb,GAGxBU,EAAMF,EAGN,MAAMM,EAAeN,GAAgBK,EAAU74B,OAAS24B,EAAS34B,OAC3DW,EAAOa,KAAKgjB,IAAIlP,EAAQtV,OAAQ,GAAK84B,GAC3C,GAAIn4B,EAAO,EAAG,CACZ,IAAIo4B,EAAY,GAChB,IAAK,IAAI34B,EAAI,EAAGA,EAAIO,IAAQP,EAC1B24B,GAAazjB,EAAQ1G,WAAWxO,GAElCs4B,GAAOK,EAAUtrB,UAAU,EAAG9M,EAChC,CAGA+3B,GAAOC,EAAWE,CACpB,CACA,OAAOH,CACT,CAQA,SAASM,GAAOlqB,GACd,OAAOA,EAAS,GAAM,CACxB,CAqBA,SAASmqB,GAAW1mB,GAClB,MAAMyK,EAASjK,GAAQR,GACvB,YAAyB,IAAXyK,GACD,WAAXA,CACJ,CAuCA,SAASkc,GAAexqB,EAAK/O,GAC3B,MAAMw5B,EAAS,IAAIxqB,WAAWD,EAAI1O,OAAS,GAG3C,OAFAm5B,EAAOloB,IAAIvC,GACXyqB,EAAOloB,IAAItR,EAAO+O,EAAI1O,QACfm5B,CACT,CAiEA,MAAMC,GAOJC,MAAAA,CAAOlvB,GACL,MAAM8P,EAAS,IAAItL,WAAWxE,EAAInK,QAClC,IAAK,IAAII,EAAI,EAAGO,EAAOwJ,EAAInK,OAAQI,EAAIO,IAAQP,EAC7C6Z,EAAO7Z,GAAK+J,EAAIyE,WAAWxO,GAE7B,OAAO6Z,CACT,EAMF,MAAM0B,GAEkB,WAFlBA,GAGW,WAkCV,MAAM2d,GAQX,KAAuB,EAQvB,KAAgB,EAOhB,IAAgB,CACdC,QAAS,CAACrB,OAAQ,OAAQv4B,MAAO,OAQnC,IAAS9B,MAAK,GAOd,IAAkB,GAOlB,IAAsB,IAAIu7B,GAO1B,IAAev7B,MAAK,GAOpB27B,sBAAAA,CAAuBC,GACrB57B,MAAK,GAAuB47B,CAC9B,CAOAC,eAAAA,CAAgBD,GACd57B,MAAK,GAAgB47B,CACvB,CAeAE,QAAAA,CAASC,EAAOC,GAOd,GANAh8B,MAAK,GAAS+7B,EAGd/7B,MAAK,GAAkB,GAGnBg8B,EAAgB,CAClB,MAAMlpB,EAAO5R,OAAO4R,KAAKipB,GACzB,IAAK,MAAM/6B,KAAO8R,EAAM,CACtB,MAAMmpB,EAAOF,EAAM/6B,GACnB,GAAoB,YAAhBi7B,EAAK5B,aACe,IAAf4B,EAAKn6B,OACG,OAAfm6B,EAAKn6B,MAAgB,CAErB,IAMIo6B,EANAC,GAAQ,EAOZ,GANmB,IAAfn7B,EAAImB,SAENg6B,OAA+C,IADnCnlB,GAAchW,GACPyV,yBAIjB0lB,EACFD,EAASl7B,MACJ,CAEL,MAAMmW,EAAMK,GAAqBxW,QACd,IAARmW,IACT+kB,EAAS/kB,EAAIX,SAEjB,MAEsB,IAAX0lB,GACTl8B,MAAK,GAAgBiD,KAAKi5B,EAE9B,CACF,CACF,CACF,CAQA,IAAc5vB,GACZ,OAAOtM,MAAK,GAAoBw7B,OAAOlvB,EACzC,CAQA,IAAqBA,GACnB,OAAOtM,MAAK,GAAaw7B,OAAOlvB,EAClC,CAKA8vB,qBAAAA,GAQEp8B,MAAK,GAAe,IAAIq8B,WAC1B,CASAC,iBAAAA,CAAkBzqB,GAEhB,MAAM0qB,EAAY1qB,EAAQsF,IAAIT,eACxBe,EAAU5F,EAAQsF,IAAIV,wBAG5B,IAAIwlB,EAgBJ,OAbEA,OAF+C,IAAtCj8B,MAAK,GAAO6R,EAAQsF,IAAIX,UAE1BxW,MAAK,GAAO6R,EAAQsF,IAAIX,eACH,IAAZiB,QACgB,IAAzBzX,MAAK,GAAOyX,GAEZzX,MAAK,GAAOyX,QACwB,IAA3BzX,MAAK,GAAOu8B,GAErBv8B,MAAK,GAAOu8B,GAGZv8B,MAAK,GAAgB,QAGvBs6B,GAAc2B,EAAK5B,QAAQxoB,EAASoqB,EAAKn6B,MAClD,CAWA,IACE06B,EAAQ7jB,EAAYL,EAAOuF,GAC3B,IAAIY,EACJ,IAAK,IAAIlc,EAAI,EAAGA,EAAI+V,EAAMnW,SAAUI,EAAG,CAErC,GADAkc,EAAOnG,EAAM/V,GACO,IAAhBkc,EAAKtc,OACP,SAGF,IAAIgW,GAAkB,EACtB,MAAMskB,EAAUhe,EAAKyL,MAAMwS,GAAYxlB,GAAUwlB,EAAQvlB,YAClC,IAAZslB,QAC0B,IAA5BA,EAAQtkB,kBACfA,EAAkBskB,EAAQtkB,iBAE5B,MAAMwkB,EAAc,IAAI1kB,GAAY,QACpC0kB,EAAYzkB,GAAKC,EAAkB,WAAaskB,EAAQvkB,GACxDykB,EAAYxlB,IAAMF,KAClB0lB,EAAY76B,MAAQ,GACpB6W,EAAa3Y,MAAK,GAChBw8B,EAAQG,EAAahkB,EAAYkF,GAEnC,IAAK,MAAM6e,KAAWje,EACfvH,GAAUwlB,EAAQvlB,MACpBC,GAA0BslB,EAAQvlB,OACnCwB,EAAa3Y,MAAK,GAChBw8B,EAAQE,EAAS/jB,EAAYkF,IAInC,GAAI1F,EAAiB,CACnB,MAAMykB,EAAmB,IAAI3kB,GAAY,QACzC2kB,EAAiB1kB,GAAK,EACtB0kB,EAAiBzlB,IhBjUhB,IAAId,GAAI,OAAQ,QgBkUjBumB,EAAiB96B,MAAQ,GACzB6W,EAAa3Y,MAAK,GAChBw8B,EAAQI,EAAkBjkB,EAAYkF,EAC1C,CACF,CAGA,OAAOlF,CACT,CAYA,IACE6jB,EAAQ3qB,EAAS8G,EAAY7W,EAAO+b,GAEpC,MAAMzF,EAAcO,EAEpB,GAAmB,SAAf9G,EAAQ6C,SAEL,GAAI5S,aAAiBgP,WAGxB6H,EADE7W,EAAMK,SAAW,EAAI0P,EAAQqG,GAClBskB,EAAOlD,iBAAiB3gB,EAAY7W,GAEpC06B,EAAO/C,gBAAgB9gB,EAAY7W,QAE7C,GAAIA,aAAiBiX,UAC1BJ,EAAa6jB,EAAO9C,eAAe/gB,EAAY7W,QAC1C,GAAIA,aAAiB8Y,YAC1BjC,EAAa6jB,EAAO7C,iBAAiBhhB,EAAY7W,QAC5C,GAAIA,aAAiBkX,WAC1BL,EAAa6jB,EAAO5C,gBAAgBjhB,EAAY7W,QAC3C,GAAIA,aAAiBkZ,YAC1BrC,EAAa6jB,EAAO3C,iBAAiBlhB,EAAY7W,QAC5C,GAAIA,aAAiBsZ,WAC1BzC,EAAa6jB,EAAOzC,gBAAgBphB,EAAY7W,QAC3C,GAAIA,aAAiBoZ,eAC1BvC,EAAa6jB,EAAO1C,iBAAiBnhB,EAAY7W,QAC5C,GAAIA,aAAiBwZ,cAC1B3C,EAAa6jB,EAAOxC,gBAAgBrhB,EAAY7W,OAC3C,CAEL,MAAMqd,EAASjK,GAAQrD,EAAQ6C,IAC/B,QAAsB,IAAXyK,EACT,GAAe,UAAXA,EACFxG,EAAa6jB,EAAO/C,gBAAgB9gB,EAAY7W,QAC3C,GAAe,WAAXqd,EACTxG,EAAa6jB,EAAO7C,iBAAiBhhB,EAAY7W,QAC5C,GAAe,UAAXqd,EACTxG,EAAa6jB,EAAO5C,gBAAgBjhB,EAAY7W,QAC3C,GAAe,WAAXqd,EACTxG,EAAa6jB,EAAO3C,iBAAiBlhB,EAAY7W,QAC5C,GAAe,UAAXqd,EACTxG,EAAa6jB,EAAOzC,gBAAgBphB,EAAY7W,QAC3C,GAAe,WAAXqd,EACTxG,EAAa6jB,EAAO1C,iBAAiBnhB,EAAY7W,QAC5C,GAAe,UAAXqd,EACTxG,EAAa6jB,EAAOxC,gBAAgBrhB,EAAY7W,QAC3C,GAAe,YAAXqd,EACTxG,EAAa6jB,EAAOvC,kBAAkBthB,EAAY7W,QAC7C,GAAe,YAAXqd,EACTxG,EAAa6jB,EAAOtC,kBAAkBvhB,EAAY7W,OAC7C,IAAe,WAAXqd,EAGT,MAAM,IAAIjd,MAAM,oBAAsBid,GAFtCxG,EAAa6jB,EAAO/C,gBAAgB9gB,EAAY7W,EAGlD,MACK,GAAmB,OAAf+P,EAAQ6C,GACjBiE,EAAa3Y,MAAK,GAChBw8B,EAAQ7jB,EAAY7W,EAAO+b,QACxB,GAAmB,OAAfhM,EAAQ6C,GACjB,IAAK,IAAInS,EAAI,EAAGA,EAAIT,EAAMK,SAAUI,EAAG,CACrC,MAAMs6B,EAAY/6B,EAAMS,GAAK,GACvBu6B,EAAaD,EAAUjtB,UAAU,EAAG,GACpCmtB,EAAaF,EAAUjtB,UAAU,EAAG,IAGpCotB,EAAU,CAFHnmB,SAASimB,EAAY,IACrBjmB,SAASkmB,EAAY,KAElCpkB,EAAa6jB,EAAO7C,iBAAiBhhB,EAAYqkB,EACnD,KACwB,OAAfnrB,EAAQ6C,GAGfiE,EADE7W,aAAiBkX,WACNwjB,EAAO5C,gBAAgBjhB,EAAY7W,GAEnC06B,EAAO7C,iBAAiBhhB,EAAY7W,GAGnDqC,EAAOa,KAAK,eAAiB6M,EAAQ6C,GAEzC,CAEA,GAAmB,OAAf7C,EAAQ6C,IAA8B,SAAf7C,EAAQ6C,GAAe,CAChD,MAAMuoB,EAAOtkB,EAAaP,EAC1B,GAAI6kB,IAASprB,EAAQqG,GAAI,CACvB,IAAIglB,EAAU,2CACZD,EAAO,OAASprB,EAAQqG,GAC1BglB,GAAW,UACgB,IAAhBrrB,EAAQsF,MACjB+lB,GAAWrrB,EAAQsF,IAAM,MAE3B+lB,GAAW,MAAQrrB,EAAQ6C,GAAK,IAChCvQ,EAAOa,KAAKk4B,EACd,CACF,CAGA,OAAOvkB,CACT,CAYA,IACE6jB,EAAQ3qB,EAAS8G,EAAY7W,EAAO+b,GAEpC,IAAI1F,GAAkB,EAKtB,QAJuC,IAA5BtG,EAAQsG,kBACjBA,EAAkBtG,EAAQsG,iBAGvBA,EASE,CAEL,MAAMsG,EAAO,CAAC,EAEdA,EAAe,SAAI,CACjBtH,IAAKF,KACLvC,GAAI,OACJwD,GAAI,EACJpW,MAAO,IAGT,IAAK,IAAIS,EAAI,EAAGA,EAAIT,EAAMK,SAAUI,EAClCkc,EAAKlc,GAAK,CACR4U,IAAKF,KACLvC,GAAI7C,EAAQ6C,GACZwD,GAAIpW,EAAMS,GAAGJ,OACbL,MAAOA,EAAMS,IAIjBoW,EAAa3Y,MAAK,GAChBw8B,EAAQ7jB,EAAY,CAAC8F,GAAOZ,EAChC,KA/BsB,CACpB,IAAIsf,EAAar7B,EAAM,GAEnBA,EAAMK,OAAS,IACjBg7B,EArcR,SAAmCC,GACjC,MAAMC,EAAqBD,EAAaj7B,OAClCm7B,EAAcF,EAAa,GAAGj7B,OAEpC,QAA2B,IAAhBm7B,EACT,OAAOF,EAGT,MAAMG,EAAwBF,EAAqBC,EAE7CE,EAAiB,IAAIJ,EAAa,GAAGp7B,YAAYu7B,GAEvD,IAAK,IAAIh7B,EAAI,EAAGA,EAAI86B,EAAoB96B,IAAK,CAC3C,MAAMk7B,EAAsBl7B,EAAI+6B,EAChCE,EAAepqB,IAAIgqB,EAAa76B,GAAIk7B,EACtC,CACA,OAAOD,CACT,CAobqBE,CAA0B57B,IAGzC6W,EAAa3Y,MAAK,GAChBw8B,EAAQ3qB,EAAS8G,EAAYwkB,EAAYtf,EAC7C,CAyBA,OAAOlF,CACT,CAWA,IACE6jB,EAAQ3qB,EAAS8G,EAAYkF,GAC7B,MAAM8f,EAAc9rB,EAAQsF,IAAIR,WAC1BmI,KAAajB,GAAe8f,IACvBlpB,EAAY5C,EAAQ6C,IAE/BiE,EAAa6jB,EAAOnD,SAAS1gB,EAAY9G,EAAQsF,IAAIb,YAErDqC,EAAa6jB,EAAOnD,SAAS1gB,EAAY9G,EAAQsF,IAAIZ,cAErD,IAAI7B,EAAK7C,EAAQ6C,GAEb1U,MAAK,IACP6R,EAAQsF,IAAIP,aACL,OAAPlC,IACAvQ,EAAOa,KAAK,mDACZ0P,EAAK,MAEHipB,IAAgB9f,IAClBlF,EAAa6jB,EAAO/C,gBAAgB9gB,EAAY3Y,MAAK,GAAc0U,IAE/DoK,IACFnG,GAAc,IAIlB,IAAIilB,GAA0B,GACX,OAAf/rB,EAAQ6C,IACV6C,GAAe1F,EAAQsF,YACgB,IAA5BtF,EAAQsG,kBACjBylB,EAA0B/rB,EAAQsG,iBAGtC,IAAI0lB,GAAsB,EACtB3mB,GAAUrF,EAAQsF,WACmB,IAA5BtF,EAAQsG,kBACjB0lB,EAAsBhsB,EAAQsG,iBAKlC,IAAID,EAAKrG,EAAQqG,IACb0lB,GAA2BC,KAC7B3lB,EAAK,YAILS,EADEmG,EACW0d,EAAO/D,YAAY9f,EAAYT,GAE/BskB,EAAOnE,YAAY1f,EAAYT,GAI9C,IAAIpW,EAAQ+P,EAAQ/P,MAepB,QAbqB,IAAVA,IACTA,EAAQ,IAIR6W,EADEpB,GAAe1F,EAAQsF,KACZnX,MAAK,GAChBw8B,EAAQ3qB,EAAS8G,EAAY7W,EAAO+b,GAEzB7d,MAAK,GAChBw8B,EAAQ3qB,EAAS8G,EAAY7W,EAAO+b,GAIpC+f,EAAyB,CAC3B,MAAME,EAAkB,IAAI7lB,GAAY,QACxC6lB,EAAgB5lB,GAAK,EACrB4lB,EAAgB3mB,IhB3iBb,IAAId,GAAI,OAAQ,QgB4iBnBynB,EAAgBh8B,MAAQ,GACxB6W,EAAa3Y,MAAK,GAChBw8B,EAAQsB,EAAiBnlB,EAAYkF,EACzC,CAGA,OAAOlF,CACT,CAQAolB,SAAAA,CAAUnP,GAER,MAAM5R,EAAS4R,EA9hBD,YA8hBsC9sB,MAAM,GACpD+b,EAAad,GAAyBC,GACtCghB,EAAc/gB,GAA0BD,GAE9C,QAA0D,IAA/C4R,EAAa9Q,IAA+C,CACrE,MAAMmgB,EAASrP,EAAa9Q,IAA8Bhc,MAAM,QAE1C,IAAXm8B,GAAqC,aAAXA,IACnC95B,EAAOW,MAAM,+BAAiCm5B,GAC9Cj+B,KAAKo8B,wBACLxN,EAAa9Q,IAA8Bhc,MAAQ,CAAC,cAExD,CAEA,IAAIyb,OAC+C,IAAxCqR,EAAa9Q,MACtBP,EAAgBqR,EAAa9Q,IAAuBhc,MAAM,IAI5D,IAAIo8B,EAAY,IACZC,EAAY,EAChB,MAAMC,EAAe,GACfC,EAAc,GACpB,IAAIxsB,EACA0qB,EACA+B,EAAa,EAEjB,MAAMC,EhBppBD,IAAIloB,GAAI,OAAQ,QgBspBfmoB,EAAU,IAAInoB,GAAI,OAAQ,QAE1BooB,EAAW,IAAIpoB,GAAI,OAAQ,QAE3BqoB,EAAS,IAAIroB,GAAI,OAAQ,QAGzBsoB,EAAc3+B,MAAK,GAAgB0C,QAGnCoQ,EAAO5R,OAAO4R,KAAK8b,GACzB,IAAK,IAAIrsB,EAAI,EAAGO,EAAOgQ,EAAK3Q,OAAQI,EAAIO,IAAQP,EAAG,CACjD,MAAMq8B,EAAkBhQ,EAAa9b,EAAKvQ,IAG1C,GAFAq8B,EAAgBznB,IAAMH,GAAclE,EAAKvQ,IACzCsP,EAAU7R,KAAKs8B,kBAAkBsC,KACjB,OAAZ/sB,GACD0sB,EAAS17B,OAAOgP,EAAQsF,MACxBqnB,EAAQ37B,OAAOgP,EAAQsF,MACvBsnB,EAAS57B,OAAOgP,EAAQsF,MACxBunB,EAAO77B,OAAOgP,EAAQsF,MAAM,CAC7BgnB,EAAY,EAGZ,MAAM7wB,EAAQqxB,EAAYpxB,QAAQsE,EAAQsF,IAAIX,WAC/B,IAAXlJ,GACFqxB,EAAY7c,OAAOxU,EAAO,GAQxBtN,MAAK,IACP6+B,GAAqBhtB,GAAUmsB,GAIjCh+B,MAAK,GACH6R,EAASA,EAAQ/P,MAAO+b,EAAYN,GAGtCgf,EAAY1qB,EAAQsF,IAAIT,eAItBynB,GAAavgB,GAA6B/L,EAAQ6C,GADlC,iBAAd6nB,GAIY1e,GAIhBsgB,GAAatsB,EAAQqG,GAGH,iBAAdqkB,GACF6B,EAAan7B,KAAK4O,GAClBysB,GAAcH,GAEdE,EAAYp7B,KAAK4O,GAInBqsB,GAAaC,CACf,CACF,CAGA,IAAK,MAAMn9B,KAAO29B,EAAa,CAC7B,MAAMxnB,EAAMH,GAAchW,GACpB+e,EAAc,IAAI9H,GAAYd,EAAIL,uBAGxC,IAAIhV,EACJ,GAHAie,EAAY5I,IAAMA,OAGc,IAArBnX,MAAK,GAAOgB,GACrBc,EAAQ9B,MAAK,GAAOgB,GAAKc,UACpB,CACL,MAAM0H,EAAO2N,EAAIV,wBACjB3U,EAAQ9B,MAAK,GAAOwJ,GAAM1H,KAC5B,CAEA,IAAIuE,EAAOuX,GAA6BmC,EAAYrL,GAAImJ,GACxDxX,GAAQrG,MAAK,GAAiB+f,EAAa,CAACje,GAAQ+b,GACpDwgB,EAAYp7B,KAAK8c,GACjBme,GAAa73B,CACf,CAGA,MAAMy4B,EAAOC,GAAe,8BAC5B,IAAIC,EAAWphB,GAA6BkhB,EAAKpqB,IAAI,GACrDsqB,GAAYh/B,MAAK,GAAiB8+B,EAAM,CAAC,EAAG,IAAI,GAChDV,EAAan7B,KAAK67B,GAClBR,GAAcU,EACdd,GAAac,EAEb,MAAMC,EAAQF,GAAe,0BAC7B,IAAIG,EAAYthB,GAA6BqhB,EAAMvqB,IAAI,GACvD,MAAMyqB,EACJzE,GAAO,0BAA0BD,QAAQ,QAAS,OACpDyE,GAAal/B,MAAK,GAAiBi/B,EAAO,CAACE,IAAa,GACxDf,EAAan7B,KAAKg8B,GAClBX,GAAcY,EACdhB,GAAagB,EAEb,MAAME,EAAML,GAAe,6BAC3B,IAAIM,EAAUzhB,GAA6BwhB,EAAI1qB,IAAI,GACnD,MACM4qB,EAAW,Obp8BZ,gBam8B8B7E,QAAQ,QAAS,OAEpD4E,GAAWr/B,MAAK,GAAiBo/B,EAAK,CAACE,IAAW,GAClDlB,EAAan7B,KAAKm8B,GAClBd,GAAce,EACdnB,GAAamB,EAGb,MAAME,EAAe,SAAUz+B,EAAGoH,GAChC,OAAO6O,GAAmBjW,EAAEqW,IAAKjP,EAAEiP,IACrC,EACAinB,EAAaxsB,KAAK2tB,GAClBlB,EAAYzsB,KAAK2tB,GAGjB,MAAMC,EAAQT,GAAe,kCAC7B,IAAIU,EAAY7hB,GAA6B4hB,EAAM9qB,IAAI,GACvD+qB,GAAaz/B,MAAK,GAChBw/B,EAAO,IAAIxkB,YAAY,CAACsjB,KAAc,GACxCJ,GAAauB,EAGb,MAAMtsB,EAAS,IAAIusB,YAAYxB,GACzByB,EAAa,IAAI3H,GAAW7kB,GAC5BysB,EAAa,IAAI5H,GAAW7kB,GAAS6qB,GAE3C,IAAI95B,EAAS,IAEbA,EAASy7B,EAAWlG,gBAAgBv1B,EAAQlE,MAAK,GAAc,SAE/DkE,EAASlE,MAAK,GAAkB2/B,EAAYH,EAAOt7B,GAAQ,GAE3D,IAAK,IAAId,EAAI,EAAGy8B,EAAOzB,EAAaj8B,OAAQiB,EAAIy8B,IAAQz8B,EACtDc,EAASlE,MAAK,GACZ2/B,EAAYvB,EAAah7B,GAAIc,GAAQ,GAIzC,MACM47B,EADe,IACaL,EAAYnB,EAC1Cp6B,IAAW47B,GACb37B,EAAOa,KAAK,wCAA0Cd,EACpD,qBAAuB47B,EACvB,WAAa57B,EAAS47B,GAAc,KAIxC,IAAK,IAAIrzB,EAAI,EAAGszB,EAAO1B,EAAYl8B,OAAQsK,EAAIszB,IAAQtzB,EACrDvI,EAASlE,MAAK,GACZ4/B,EAAYvB,EAAY5xB,GAAIvI,EAAQ2Z,GAUxC,OANI3Z,IAAWg6B,GACb/5B,EAAOa,KAAK,yCAA2Cd,EACrD,qBAAuBg6B,EACvB,WAAah6B,EAASg6B,GAAa,KAGhC/qB,CACT,CAWA,IACEtB,EAAS/P,EAAO+b,EAAYN,GAE5B,IAAIlX,EAAO,EAEX,GAAmB,OAAfwL,EAAQ6C,IAEV,GAAc,OAAV5S,GAA4B,IAAVA,EAAa,CACjC,MAAMk+B,EAAW,GAGjB,IAAI7nB,GAAkB,OACiB,IAA5BtG,EAAQsG,kBACjBA,EAAkBtG,EAAQsG,uBACnBtG,EAAQsG,iBAIjB,IAAK,IAAI5V,EAAI,EAAGA,EAAIT,EAAMK,SAAUI,EAAG,CACrC,MAAM09B,EAAkBn+B,EAAMS,GACxB29B,EAAkB,GACxB,IAAIC,EAAU,EAGd,GAAwB,OAApBF,GAAgD,IAApBA,EAC9B,SAIF,IAAIpgB,EAAkBtC,EACtB,MAAMwC,EAAckgB,EAAgBniB,SACT,IAAhBiC,QACoB,IAAtBA,EAAYje,QACnB+d,EAAkBE,EAAYje,MAAM,IAItC,MAAMs+B,EAAWl/B,OAAO4R,KAAKmtB,GAC7B,IAAK,IAAI78B,EAAI,EAAGy8B,EAAOO,EAASj+B,OAAQiB,EAAIy8B,IAAQz8B,EAAG,CACrD,MAAMi9B,EAAUD,EAASh9B,GACnB4c,EAAaigB,EAAgBI,GACnCrgB,EAAW7I,IAAMH,GAAcqpB,GAE3BnpB,GAAU8I,EAAW7I,OAIzBgpB,GAAWngC,MAAK,GACdggB,EAAYA,EAAWle,MAAO+b,EAAYgC,GAC5CqgB,EAAgBj9B,KAAK+c,GAErBmgB,GAAWviB,GACToC,EAAWtL,GAAImJ,GACnB,CAGA,MAAM8e,EAAc,CAClBxlB,IAAKF,KACLvC,GAAI,OACJwD,GAAIioB,EACJr+B,MAAO,IAELqW,IACFwkB,EAAYxkB,gBAAkBA,GAEhC+nB,EAAgBj9B,KAAK05B,GACrBwD,GAAWviB,GACT+e,EAAYjoB,GAAImJ,GAGd1F,IACFgoB,GAAWviB,GACT,OAAQC,IAIZ,MAAM0hB,EAAe,SAAUz+B,EAAGoH,GAChC,OAAO6O,GAAmBjW,EAAEqW,IAAKjP,EAAEiP,IACrC,EACA+oB,EAAgBtuB,KAAK2tB,GAErBl5B,GAAQ85B,EACRH,EAAS/8B,KAAKi9B,EAChB,CAGI/nB,IACF9R,GAAQuX,GAA6B,OAAQC,IAI/ChM,EAAQ/P,MAAQk+B,EAChBnuB,EAAQqG,GAAK7R,EACT8R,IACFtG,EAAQsG,gBAAkBA,EAE9B,MACK,CAEL,GAv8BGijB,GADU1mB,EAw8BC7C,EAAQ6C,KAv8BM,OAAPA,EAu8BM,CACzB,MAAM4rB,EA/7Bd,SAAkB5rB,GAChB,IAAI6rB,EAAM,GAQV,OAPInF,GAAW1mB,KAEX6rB,EADS,OAAP7rB,EACI,KAEA,KAGH6rB,CACT,CAq7BuBC,CAAS3uB,EAAQ6C,IAGhC,GAAI0mB,GAAWvpB,EAAQ6C,IAAK,CAC1B,IAAI6rB,EACAtrB,GAAkBpD,EAAQ6C,KAC5B5S,EAAQ9B,MAAK,GAAqB8B,EAAM2+B,KAAK,OAC7CF,EAAMvgC,MAAK,GAAqBsgC,KAEhCx+B,EAAQ9B,MAAK,GAAc8B,EAAM2+B,KAAK,OACtCF,EAAMvgC,MAAK,GAAcsgC,IAEtBnF,GAAOr5B,EAAMK,UAChBL,EAAQu5B,GAAev5B,EAAOy+B,GAElC,KAA0B,OAAf1uB,EAAQ6C,KACjB5S,EA/6BV,SAAoBA,GAClB,GAAIA,cAEsB,IAAjBA,EAAMK,OAmBb,MAAM,IAAID,MAAM,0CAjBhB,GAAqB,IAAjBJ,EAAMK,aACmB,IAApBL,EAAM,GAAGK,OAAwB,CAExC,IAAIkE,EAAO,EACX,IAAK,IAAI9D,EAAI,EAAGA,EAAIT,EAAMK,SAAUI,EAClC8D,GAAQvE,EAAMS,GAAGJ,OAEdg5B,GAAO90B,KACVvE,EAAMA,EAAMK,OAAS,GAAKk5B,GACxBv5B,EAAMA,EAAMK,OAAS,GAAI,CAAC,IAEhC,MACOg5B,GAAOr5B,EAAMK,UAChBL,EAAQu5B,GAAev5B,EAAO,CAAC,KAQrC,OAAOA,CACT,CAo5BkB4+B,CAAW5+B,GAEvB,CAIA,GADAuE,EAAO,EACY,OAAfwL,EAAQ6C,GACVrO,EAAO,EAAIvE,EAAMK,YACZ,GAAmB,OAAf0P,EAAQ6C,GACjBrO,EAAOvE,EAAMK,OAASyY,YAAY/B,uBAC7B,GA7/Bb,SAAwBnE,GACtB,MAAMyK,EAASjK,GAAQR,GACvB,YAAyB,IAAXyK,GACD,WAAXA,CACJ,CAy/BiBwhB,CAAe9uB,EAAQ6C,KAAsB,OAAf7C,EAAQ6C,GAAa,CAC5D,GAAI6C,GAAe1F,EAAQsF,MACzBiI,MAAMwhB,QAAQ9+B,GAAQ,CACtBuE,EAAO,EACP,IAAK,IAAI6B,EAAI,EAAGA,EAAIpG,EAAMK,SAAU+F,EAClC7B,GAAQvE,EAAMoG,GAAG/F,MAErB,MACEkE,EAAOvE,EAAMK,OAIf,MAAMgd,EAASjK,GAAQrD,EAAQ6C,IAC/B,GAAI6C,GAAe1F,EAAQsF,MAAuB,OAAftF,EAAQ6C,GACzC,GAAI7C,EAAQsG,gBAAiB,CAC3B,MAAM0oB,EACJjjB,GAA6B,OAAQC,GAEvCxX,GAAQw6B,EAERx6B,GAAQw6B,EAAiB/+B,EAAMK,OAE/BkE,GAAQw6B,CACV,WAG+B,IAAlBtjB,IACa,IAAlBA,EAEFlX,GAAQ,EACmB,KAAlBkX,IACTlX,GAAQuU,YAAY/B,wBAIrB,SAAsB,IAAXsG,EAQhB,MAAM,IAAIjd,MAAM,wBAA0B2P,EAAQ6C,IARV,CACxC,MAAMkE,EA+GhB,SAAyBuG,GACvB,IAAIvG,EAoBJ,MAnBe,UAAXuG,EACFvG,EAAM9H,WAAW+H,kBACG,WAAXsG,EACTvG,EAAMgC,YAAY/B,kBACE,UAAXsG,EACTvG,EAAMI,WAAWH,kBACG,WAAXsG,EACTvG,EAAMoC,YAAYnC,kBACE,UAAXsG,EACTvG,EAAMwC,WAAWvC,kBACG,YAAXsG,EACTvG,EAAM/U,aAAagV,kBACC,YAAXsG,EACTvG,EAAM6C,aAAa5C,kBACC,WAAXsG,EACTvG,EAAMsC,eAAerC,kBACD,UAAXsG,IACTvG,EAAM0C,cAAczC,mBAEfD,CACT,CArIsBkoB,CAAgB3hB,GAC5B,QAAmB,IAARvG,EAGT,MAAM,IAAI1W,MAAM,0CAA4Cid,GAF5D9Y,GAAQuS,CAIZ,CAEA,CACF,MACEvS,EAAOvE,EAAMK,OAGf0P,EAAQ/P,MAAQA,EAChB+P,EAAQqG,GAAK7R,CACf,CAthCJ,IAAmBqO,EAyhCf,OAAOrO,CACT,EAYF,SAASw4B,GAAqBhtB,EAASqH,GACrC,GAAmB,OAAfrH,EAAQ6C,GAAa,CACvB,MAAMqsB,EAASlvB,EAAQsF,IAAIL,sBAC3B,QAAsB,IAAXiqB,GAA0BlvB,EAAQ6C,KAAOqsB,EAAQ,CAC1DlvB,EAAQ6C,GAAKqsB,EAEb,MAAM5hB,EAASjK,GAAQrD,EAAQ6C,IAC/B,QAAsB,IAAXyK,GACE,UAAXA,GACW,WAAXA,EAAqB,CACrB,MAAMlM,EAsBd,SAA2BnR,EAAO4S,EAAIwE,GACpC,IAAIjG,EACJ,QAA4B,IAAjBnR,EAAMqR,OACf,OAAOF,EAET,MAAMqL,EAAS,IAAIxF,GAAWhX,EAAMqR,OAAQ+F,GACtChV,EAASpC,EAAM6W,WACfT,EAAKpW,EAAMK,OACXgd,EAASjK,GAAQR,GAkBvB,MAjBe,WAAXyK,EACFlM,EAAOqL,EAAO3D,gBAAgBzW,EAAQgU,GAClB,WAAXiH,EACTlM,EAAOqL,EAAOvD,gBAAgB7W,EAAQgU,GAClB,WAAXiH,EACTlM,EAAOqL,EAAOrD,gBAAgB/W,EAAQgU,GAClB,UAAXiH,EACTlM,EAAOmM,MAAMC,KAAKf,EAAOxD,eAAe5W,EAAQgU,IAC5B,UAAXiH,EACTlM,EAAOmM,MAAMC,KAAKf,EAAOnD,eAAejX,EAAQgU,IAC5B,UAAXiH,EACTlM,EAAOqL,EAAOjD,eAAenX,EAAQgU,GACjB,YAAXiH,EACTlM,EAAOmM,MAAMC,KAAKf,EAAO/C,iBAAiBrX,EAAQgU,IAC9B,YAAXiH,IACTlM,EAAOmM,MAAMC,KAAKf,EAAO9C,iBAAiBtX,EAAQgU,KAE7CjF,CACT,CAjDqB+tB,CACXnvB,EAAQ/P,MAAO+P,EAAQ6C,GAAIwE,QACT,IAATjG,IACTpB,EAAQ/P,MAAQmR,EAEpB,CACA9O,EAAOY,KAAK,WAAa8M,EAAQsF,IAAIb,WACnC,IAAMzE,EAAQsF,IAAIZ,aAClB,0BAA4B1E,EAAQ6C,GACxC,CACF,CACF,CA8CA,SAASqqB,GAAetnB,GACtB,MAAMN,EAAMK,GAAqBC,GAC3B5F,EAAU,IAAIoG,GAAYd,EAAIL,uBAEpC,OADAjF,EAAQsF,IAAMA,EACPtF,CACT,CA0CO,SAASovB,GAAwBC,GACtC,MAAMpuB,EAAO5R,OAAO4R,KAAKouB,GACnBtS,EAAe,CAAC,EACtB,IAAK,IAAIniB,EAAI,EAAG+sB,EAAM1mB,EAAK3Q,OAAQsK,EAAI+sB,IAAO/sB,EAAG,CAE/C,MAAM0K,EAAMK,GAAqB1E,EAAKrG,IACtC,QAAmB,IAAR0K,EACT,SAEF,MAAMzC,EAAKyC,EAAIL,sBAEf,IAAIhV,EACAqW,GAAkB,EACtB,MAAMgpB,EAAYD,EAAWpuB,EAAKrG,IAClC,GAAW,OAAPiI,EAAa,CACf,MAAM4D,EAAQ,GAId,QAHyC,IAA9B6oB,EAAUhpB,kBACnBA,EAAkBgpB,EAAUhpB,sBAEC,IAApBgpB,EAAUr/B,OACC,OAApBq/B,EAAUr/B,MACV,IAAK,IAAIS,EAAI,EAAGA,EAAI4+B,EAAUr/B,MAAMK,SAAUI,EAC5C+V,EAAMrV,KAAKg+B,GAAwBE,EAAUr/B,MAAMS,UAGrD4B,EAAOQ,MAAM,yCAEf7C,EAAQwW,CACV,MAEIxW,EADEsd,MAAMwhB,QAAQO,GACRA,EAEA,CAACA,GAIb,MAAMphB,EAAc,IAAI9H,GAAYvD,GACpCqL,EAAY5I,IAAMA,EAClB4I,EAAYje,MAAQA,EAChBqW,IACF4H,EAAY5H,gBAAkBA,GAGhCyW,EAAazX,EAAIX,UAAYuJ,CAC/B,CAGA,OAAO6O,CACT,CCp4CA,MAAM9Q,GAAU,CACdsjB,UAAW,WACXC,uBAAwB,WACxBC,YAAa,WACbC,cAAe,WACfC,aAAc,YAQT,MAAMC,GAMXC,QAMA5/B,MAMA6/B,UAMAC,SAMAC,iBAKA7/B,WAAAA,CAAY0/B,GACV1hC,KAAK0hC,QAAUA,CACjB,CAOAl/B,QAAAA,GACE,MAAO,IAAMxC,KAAK8B,MAAQ,KACxB9B,KAAK6hC,iBAAmB,MACxB7hC,KAAK0hC,QAAU,IACnB,EAUK,SAASI,GAAYC,EAAOC,GACjC,OAAO9gC,OAAO4R,KAAKivB,GAAO5/B,SAAWjB,OAAO4R,KAAKkvB,GAAO7/B,QACxDjB,OAAO4R,KAAKivB,GAAO3/B,OAAMpB,GACvBE,OAAOM,UAAUC,eAAeC,KAAKsgC,EAAOhhC,IAC5C+gC,EAAM/gC,KAASghC,EAAMhhC,IAEzB,CAQO,SAASihC,GAAQrT,GAEtB,MAAMd,EAAO,IAAI2T,GAAU7S,EAAa9Q,GAAQwjB,aAAax/B,MAAM,IAInE,QAA+C,IAApC8sB,EAAa9Q,GAAQsjB,WAC9BtT,EAAKhsB,MAAQ8sB,EAAa9Q,GAAQsjB,WAAWt/B,MAAM,QAC9C,QAAmD,IAAxC8sB,EAAa9Q,GAAQyjB,eACrCzT,EAAK6T,UAAY/S,EAAa9Q,GAAQyjB,eAAez/B,MAAM,OACtD,SAAkD,IAAvC8sB,EAAa9Q,GAAQ0jB,cAGrC,MAAM,IAAIt/B,MACR,+DAHF4rB,EAAK8T,SAAWhT,EAAa9Q,GAAQ0jB,cAAc1/B,MAAM,EAI3D,CAEA,QAA0B,IAAfgsB,EAAKhsB,YACY,IAAnBgsB,EAAK6T,UAA2B,CACvC,QAA4D,IAAjD/S,EAAa9Q,GAAQujB,wBAI9B,MAAM,IAAIn/B,MACR,uEAJF4rB,EAAK+T,iBACHjT,EAAa9Q,GAAQujB,wBAAwBv/B,MAAM,EAKzD,CACA,OAAOgsB,CACT,CAQO,SAASoU,GAAiBpU,GAE/B,MAAMrP,EAAO,CAAC,EAgBd,YAd0B,IAAfqP,EAAKhsB,MACd2c,EAAK2iB,UAAYtT,EAAKhsB,WACa,IAAnBgsB,EAAK6T,UACrBljB,EAAK8iB,cAAgBzT,EAAK6T,eACQ,IAAlB7T,EAAK8T,WACrBnjB,EAAK+iB,aAAe1T,EAAK8T,eAGU,IAA1B9T,EAAK+T,mBACdpjB,EAAK4iB,uBAAyBvT,EAAK+T,kBAGrCpjB,EAAK6iB,YAAcxT,EAAK4T,QAEjBjjB,CACT,CAMA,MAAM0jB,GAAW,CACf,OAAQ,eACR,OAAQ,sBACR,OAAQ,6BACR,OAAQ,yBACR,OAAQ,sBACR,OAAQ,yBACR,OAAQ,qBACR,OAAQ,eACR,OAAQ,OACR,OAAQ,SACR,OAAQ,8CACR,OAAQ,eACR,OAAQ,mBACR,OAAQ,oBACR,OAAQ,cACR,OAAQ,sBAOJC,GAAW,CACf,QAAS,QACT,QAAU,OACV,UAAW,QACX,UAAW,YACX,UAAW,aACX,UAAW,SACX,UAAW,UACX,UAAW,SACX,UAAW,SAQPC,GAAY,CAChB,EAAG,WACHhzB,GAAI,aACJizB,IAAK,uBACLhzB,IAAK,oBACL,SAAU,mCACV,MAAO,iBACP,OAAQ,sBACR,cAAe,wCACf,QAAS,2BACT,UAAW,2BACX,QAAS,4BACT,YAAa,uCACb,cAAe,sCACf,WAAY,iCACZ,OAAQ,sBACR,YAAa,uCACb,QAAS,4BACT,IAAK,aACL,WAAa,kBACb,WAAY,mBACZ,WAAY,SACZ,aAAc,oBACd,eAAgB,yBAChB,iBAAkB,qCAUpB,SAASizB,GAAazgC,EAAO0gC,GAC3B,IAAId,EAQA5T,EAMJ,MAbe,QAAX0U,EACFd,EAAUS,GAASrgC,GACC,QAAX0gC,EACTd,EAAUU,GAAStgC,GACC,SAAX0gC,IACTd,EAAUW,GAAUvgC,SAGC,IAAZ4/B,IACT5T,EAAO,IAAI2T,GAAUC,GACrB5T,EAAK+T,iBAAmBW,EACxB1U,EAAKhsB,MAAQA,GAERgsB,CACT,CAOO,SAAS2U,KACd,OAAOF,GAAa,SAAU,MAChC,CAgBO,SAASG,KACd,OAAOH,GAAa,SAAU,MAChC,CAgBO,SAASI,KACd,OAAOJ,GAAa,SAAU,MAChC,CAOO,SAASK,KACd,OAAOL,GAAa,SAAU,MAChC,CAyBO,SAASM,KACd,OAAON,GAAa,SAAU,MAChC,CAOO,SAASO,KACd,OAAOP,GAAa,SAAU,MAChC,CAOO,SAASQ,KACd,OAAOR,GAAa,YAAa,MACnC,CAKA,MAAMS,GAA8B,CAClCC,MAAO,CAACjiC,IAAK,UAAWwhC,OAAQ,OAChCrgC,OAAQ,CAACnB,IAAK,YAAawhC,OAAQ,OACnCU,QAAS,CAACliC,IAAK,WAAYwhC,OAAQ,OACnCW,OAAQ,CAACniC,IAAK,SAAUwhC,OAAQ,OAChCp9B,MAAO,CAACpE,IAAK,YAAawhC,OAAQ,OAClCY,OAAQ,CAACpiC,IAAK,YAAawhC,OAAQ,OACnC1hC,EAAG,CAACE,IAAK,YAAawhC,OAAQ,OAC9Bt6B,EAAG,CAAClH,IAAK,YAAawhC,OAAQ,OAC9B7b,IAAK,CAAC3lB,IAAK,SAAUwhC,OAAQ,OAC7Bn1B,IAAK,CAACrM,IAAK,SAAUwhC,OAAQ,OAC7B5b,KAAM,CAAC5lB,IAAK,SAAUwhC,OAAQ,OAC9Ba,OAAQ,CAACriC,IAAK,SAAUwhC,OAAQ,QA4B3B,SAASc,GAAsBxV,GACpC,IAAItkB,EACJ,IAAK,MAAM+5B,KAAWP,GAA6B,CACjD,MAAMvkB,EAAOukB,GAA4BO,GACzC,GAAI9kB,EAAK+jB,SAAW1U,EAAK+T,kBACvBpjB,EAAKzd,MAAQ8sB,EAAKhsB,MAAO,CACzB0H,EAAO+5B,EACP,KACF,CACF,CACA,OAAO/5B,CACT,CAQA,MAAMg6B,GAA6B,CACjC,UAAW,KACX,WAAY,MACZ,cAAe,MAEfC,GAAI,WAEJC,KAAM,QAENC,GAAI,WAGJC,IAAK,IACLC,KAAM,WACNC,KAAM,IACNC,IAAK,MACLC,MAAO,SACPC,KAAM,IACNC,IAAK,aACLC,KAAM,QACNC,QAAS,YACTC,UAAW,cACXC,OAAQ,WACRC,IAAK,OACL,MAAO,MACPC,OAAQ,UACRC,SAAU,eACVC,QAAS,iBACTC,QAAS,YACTC,KAAM,QACNC,IAAK,OAELC,IAAK,eA2BA,SAASC,GAAsBjX,GACpC,IAAI4I,EACJ,IAAK,MAAM6M,KAAWC,GAA4B,CAChD,MAAMwB,EAAUxB,GAA2BD,GAC3C,GAA8B,SAA1BzV,EAAK+T,kBACPmD,IAAYlX,EAAKhsB,MAAO,CACxB40B,EAAO6M,EACP,KACF,CACF,CACA,OAAO7M,CACT,CCvcA,MAAM5Y,GAEU,WAFVA,GAIkB,WAJlBA,GAK8B,WAL9BA,GAM2B,WAN3BA,GAOmC,WAPnCA,GAQ+B,WAR/BA,GASQ,WASP,MAAMmnB,GAMXh0B,OAMA+P,MAMAkkB,cAMAC,cAMAC,aAMAC,gBAOAC,iBAOAC,qBAMAC,YAMAC,WAOAzjC,WAAAA,CAAYiP,EAAQ+P,EAAOkkB,GACzBllC,KAAKiR,OAASA,EACdjR,KAAKghB,MAAQA,EACbhhB,KAAKklC,cAAgBA,CACvB,EASK,SAASQ,GAAW9W,GAIzB,MAAM+W,EAAU,IAAIV,GAClBrW,EAxGa,YAwGuB9sB,MAAM,GAC1C8sB,EAAa9Q,IACT8Q,EAAa9Q,IAAsBhc,MAAM,GAAK,MAClD8sB,EAzGoB,YAyGuB9sB,MAAM,IAenD,QAZ0D,IAA/C8sB,EAAa9Q,MACtB6nB,EAAQR,cAAgBvW,EAAa9Q,IAA8Bhc,MAAM,SAYzE,IADS8sB,EAAa9Q,IAEtB6nB,EAAQP,aACNxW,EAAa9Q,IAA0Chc,MAAM,QAC1D,QACL,IADgB8sB,EAAa9Q,IAChB,CACb,MAAM8nB,EACJhX,EAAa9Q,IAAuChc,MAChD+jC,E1BiMH,SAAsBt9B,GAC3B,OAzEK,SAAsBA,GAO3B,SAASu9B,EAAUr9B,GACjB,IAAIK,EAAM,KAQV,OANEA,EADEL,GAAK,SACD,MAAQA,EAGR,MAAQ9E,KAAKC,IAAI6E,EAAG,YAAe,KAGpC9E,KAAKgjB,IAAI,EAAGhjB,KAAK0J,IAAI,EAAGvE,GACjC,CAEA,MAAML,EAAIF,EAAQE,EAAI,IAChBC,EAAIH,EAAQG,EAAI,IAChBC,EAAIJ,EAAQI,EAAI,IAEtB,MAAO,CACLhH,EAAGgC,KAAK0N,MAAM,IAAMy0B,EAAU,OAASr9B,EAAI,OAASC,EAAI,MAASC,IACjEV,EAAGtE,KAAK0N,MAAM,IAAMy0B,GAAW,MAASr9B,EAAI,OAASC,EAAI,MAASC,IAClET,EAAGvE,KAAK0N,MAAM,IAAMy0B,EAAU,MAASr9B,EAAI,KAASC,EAAI,MAASC,IAErE,CA6CSo9B,CAtJF,SAAwBx9B,GAO7B,SAASy9B,EAAWv9B,GAClB,IAAIK,EAAM,KASV,OANEA,EADEL,EAAI,WACA9E,KAAKC,IAAI6E,EAAG,GAIZ,WAAcA,EAAI,WAEnBK,CACT,CAEA,MAAMC,EAAaP,EACby9B,GAAM19B,EAAQlF,EAAI,IAAM,IAE9B,MAAO,CACLoF,EAAGM,EAAWN,EAAIu9B,EAAWC,EAAK19B,EAAQzH,EAAI,KAC9C4H,EAAGK,EAAWL,EAAIs9B,EAAWC,GAC7Bt9B,EAAGI,EAAWJ,EAAIq9B,EAAWC,EAAK19B,EAAQL,EAAI,KAElD,CA0HsBg+B,CAAe39B,GACrC,C0BnMgB49B,C1BDP,CACL9iC,EAAG,YAJsBkF,E0BIa,CACpClF,EAAGuiC,EAAc,GACjB9kC,EAAG8kC,EAAc,GACjB19B,EAAG09B,EAAc,K1BHMviC,EACzBvC,EAAG,WAAcyH,EAAQzH,EAAI,IAC7BoH,EAAG,WAAcK,EAAQL,EAAI,M0BG7By9B,EAAQN,gBAAkBQ,CAC5B,C1BVK,IAAsBt9B,E0BY3B,QACE,IADSqmB,EAAa9Q,IAOtB,MAAM,IAAI5b,MAAM,sDAGlB,GAREyjC,EAAQJ,qBACNtD,GACErT,EAAa9Q,IAA+Chc,MAAM,SAOtE,IADS8sB,EAAa9Q,IAKtB,MAAM,IAAI5b,MAAM,kDAQlB,OAXEyjC,EAAQL,iBACNrD,GAAQrT,EAAa9Q,IAA2Chc,MAAM,SAK1B,IAArC8sB,EAAa9Q,MACtB6nB,EAAQF,WAAa7W,EAAa9Q,IAAoBhc,MAAM,GAC5D6jC,EAAQH,YAAc5W,EArJX,YAqJ6C9sB,MAAM,IAGzD6jC,CACT,CAoFO,SAASS,GAAoBT,GAClC,IAAIU,EAAWV,EAAQT,mBACN1kC,IAAb6lC,IACFA,EAAW,UAGb,MAAMC,EAAc,CAClBC,cAAeZ,EAAQ10B,OACvBu1B,aAAcb,EAAQ3kB,MACtBylB,qBAAsBJ,GAOxB,GAJiB,WAAbA,QAAmD7lC,IAA1BmlC,EAAQR,gBACnCmB,EAAYI,qBAAuBf,EAAQR,eAGzCQ,EAAQN,gBAAiB,CAC3B,MAAMsB,EAASr+B,EAAaM,EAAa+8B,EAAQN,kBACjDiB,EAAYM,8BAAgC,CAC1CjjC,KAAK0N,MAAMs1B,EAAOtjC,GAClBM,KAAK0N,MAAMs1B,EAAO7lC,GAClB6C,KAAK0N,MAAMs1B,EAAOz+B,GAEtB,MACEo+B,EAAYO,iCAAmClB,EAAQP,aAoBzD,OAjBIO,EAAQJ,uBACVe,EAAYQ,sCAAwC,CAClDhlC,MAAO,CAACogC,GAAiByD,EAAQJ,yBAIjCI,EAAQL,mBACVgB,EAAYS,kCAAoC,CAC9CjlC,MAAO,CAACogC,GAAiByD,EAAQL,qBAIjCK,EAAQF,aACVa,EAAYU,WAAarB,EAAQF,WACjCa,EAAYW,YAActB,EAAQH,aAG7Bc,CACT,CCxSA,MAAMxoB,GACqB,WADrBA,GAEiB,WAFjBA,GAGmB,WAHnBA,GAIsB,WAJtBA,GAWsB,WAXtBA,GAamB,WASlB,MAAMopB,GAMXC,SAMAC,YAMAC,iBAMAC,iBAOA1T,wBAMAzL,QAQAnmB,WAAAA,CAAYmlC,EAAUC,EAAaC,EAAkBC,GACnDtnC,KAAKmnC,SAAWA,EAChBnnC,KAAKonC,YAAcA,EACnBpnC,KAAKqnC,iBAAmBA,EACxBrnC,KAAKsnC,iBAAmBA,CAC1B,EASK,SAASC,GAAoB3Y,GAElC,MAAMyY,EAAmB,GACzB,QAA6D,IAAlDzY,EAAa9Q,IAAkD,CACxE,MAAM0pB,EACJ5Y,EAAa9Q,IAAiChc,MAEhD,IAAK,IAAIS,EAAI,EAAGA,EAAIilC,EAAkBrlC,SAAUI,EAAG,CACjD,MAAMklC,EAAe,GACrB,QACE,IADSD,EAAkBjlC,GAAGub,IACjB,CACb,MAAM4pB,EACJF,EAAkBjlC,GAAGub,IAA6Bhc,MACpD,IAAK,IAAIsB,EAAI,EAAGA,EAAIskC,EAAcvlC,SAAUiB,EAAG,CAC7C,MAAMukC,EAAc,CAAC,OAGnB,IADSD,EAActkC,GAAG0a,MAE1B6pB,EAAYC,sBACVF,EAActkC,GAAG0a,IAA+Bhc,MAAM,SAIxD,IADS4lC,EAActkC,GAAG0a,MAE1B6pB,EAAYE,yBACVH,EAActkC,GAAG0a,IAAkChc,MAAM,IAE7D2lC,EAAaxkC,KAAK0kC,EACpB,CACF,CACAN,EAAiBpkC,KAAK,CACpBwkC,aAAcA,GAElB,CACF,CAEA,MAEMN,EAFiBvY,EAhHD,YAgH4C9sB,MAElC,GAjHX,YAiH2CA,MAE1DgmC,EAAclZ,EAlHW,YAkHyC9sB,MAElEwlC,EACJzwB,SAASixB,EAAY,GApHE,YAoHkChmC,MAAM,GAAI,GAI/DslC,EAFaxY,EArHI,YAqHwC9sB,MAEhC,GAtHhB,YAsH0CA,MACzD,IAAK,IAAIuK,EAAI,EAAGA,EAAI+6B,EAAYjlC,SAAUkK,EACxC+6B,EAAY/6B,GAAKyiB,WAAWsY,EAAY/6B,IAE1C,MAAM07B,EAAY,IAAIb,GACpBC,EACAC,EACAC,EACAC,GAGF,QAA8D,IAAnD1Y,EAAa9Q,IAAmD,CACzE,MAAMkqB,EACJpZ,EAAa9Q,IACf,GAA8C,IAA1CkqB,EAAyBlmC,MAAMK,OAAc,CAE/C,MAAM8lC,EACJD,EAAyBlmC,MAAM,GArInB,YAqIgDA,WACzB,IAA1BmmC,IACTF,EAAUnU,wBAA0BqU,EAExC,CACF,CAEA,QAA2D,IAAhDrZ,EAAa9Q,IAAgD,CACtE,MAAMoqB,EAAwBtZ,EAAa9Q,IAC3C,GAA2C,IAAvCoqB,EAAsBpmC,MAAMK,OAAc,CAE5C,MAAMgmC,EACJxZ,GAAsBuZ,EAAsBpmC,MAAM,SACxB,IAAjBqmC,IACTJ,EAAU5f,QAAUggB,EAExB,MACEhkC,EAAOa,KACL,2DAEN,CAEA,OAAO+iC,CACT,CAkDO,SAASK,GAA6BL,GAC3C,MAAMtpB,EAAO,CACX4pB,qBAAsB,CACpBvmC,MAAO,CACL,CACEwmC,qBAAsBP,EAAUZ,YAItCoB,sBAAuB,CACrBzmC,MAAO,CACL,CACE0mC,qBAAsBT,EAAUX,eAItCqB,8BAA+B,CAC7B3mC,MAAO,CACL,CACE4mC,wBAAyBX,EAAUT,qBAM3C,QAAmC9mC,IAA/BunC,EAAUV,iBAAgC,CAC5C,MAAMsB,EACJzG,GFoDGK,GAAa,SAAU,QEnDtBqG,EACJ1G,GFyCGK,GAAa,SAAU,QEvCtBsG,EAAuB,GAC7B,IAAK,MAAMC,KAAmBf,EAAUV,iBAAkB,CACxD,MAAMI,EAAe,GACrB,IAAK,MAAME,KAAemB,EAAgBrB,aACxCA,EAAaxkC,KAAK,CAChB8lC,+BAAgC,CAC9BjnC,MAAO,CAAC6mC,IAEVK,sBAAuBrB,EAAYC,sBACnCqB,yBAA0BtB,EAAYE,2BAI1CgB,EAAqB5lC,KAAK,CACxBimC,uBAAwB,CACtBpnC,MAAO,CAAC8mC,IAEVO,oBAAqB,CACnBrnC,MAAO2lC,IAGb,CAEAhpB,EAAK2qB,wBAA0B,CAC7BtnC,MAAO+mC,EAEX,CAEA,OAAOpqB,CACT,CCpPA,SAAS4qB,GAAYC,EAAMC,GACzB,OAAOC,KAAKC,UAAUH,KAAUE,KAAKC,UAAUF,EACjD,CAgDA,SAASta,GAASL,EAAc8a,GAC9B,MAAM73B,EAAU+c,EAAa8a,EAAcvyB,KAE3C,GAA2B,IAAvBuyB,EAAchoB,MAAqC,IAAvBgoB,EAAchoB,MAC5C,QAAuB,IAAZ7P,EACT,MAAM,IAAI3P,MAAM,oBAAsBwnC,EAAclgC,WAGtD,QAAuB,IAAZqI,EAET,OAGJ,IACI83B,EADAh5B,GAAW,EAOf,GAJEg5B,EAD2B,IAAzB93B,EAAQ/P,MAAMK,OACL0P,EAAQ/P,MAAM,GAEd+P,EAAQ/P,MAEjBsd,MAAMwhB,QAAQ+I,GAChB,IAAK,IAAIpnC,EAAI,EAAGA,EAAImnC,EAAcE,KAAKznC,SAAUI,EAAG,CAClD,IAAK6c,MAAMwhB,QAAQ8I,EAAcE,KAAKrnC,IACpC,MAAM,IAAIL,MAAM,iDAElB,GAAIsP,EAAgBk4B,EAAcE,KAAKrnC,GAAIonC,GAAW,CACpDh5B,GAAW,EACX,KACF,CACF,MAEAA,EAAW+4B,EAAcE,KAAKj5B,SAASg5B,GAEzC,IAAKh5B,EACH,MAAM,IAAIzO,MACR,eAAiBwnC,EAAclgC,KAAO,WAAamgC,EAEzD,CAUA,SAASE,GACPzmB,EACA0mB,EACAC,GAGA,MAEM3lB,EAFWhB,EAAMI,cACDC,UACCY,WAAW,GAC5B2lB,EAAU,CAAC,EACjB,IAAK,IAAI/oC,EAAI,EAAGA,EAAImjB,IAAanjB,EAAG,CAClC,MAAMgpC,EAAcF,EAAc9oC,EAC5BipC,EAAa9mB,EAAMY,iBAAiBimB,GAC1C,IAAK,MAAMtE,KAAWmE,EAAU,CAC9B,MAAMK,EAAexE,EAAQ10B,OAAS,EAClCi5B,IAAevE,EAAQ10B,cACKzQ,IAA1BwpC,EAAQG,KACVH,EAAQG,GAAgB,IAAIr5B,WAAWsT,IAEzC4lB,EAAQG,GAAclpC,GAAK,EAE/B,CACF,CACA,OAAO+oC,CACT,CAoCA,MAAMI,GAAuB,CAC3B,CACE5gC,KAAM,oBACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CACJxzB,GACAA,GACAA,KAGJ,CACE5M,KAAM,0BACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CAAC,iCAET,CACEpgC,KAAM,cACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CAAC,iCAET,CACEpgC,KAAM,WACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CAAC,QAET,CACEpgC,KAAM,mBACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CAAC,WAET,CACEpgC,KAAM,4BACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CAAC,OAET,CACEpgC,KAAM,YACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CAAC,CAAC,UAAW,aAErB,CACEpgC,KAAM,kBACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CAAC,IAET,CACEpgC,KAAM,4BACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CAAC,gBAET,CACEpgC,KAAM,sBACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CAAC,IAET,CACEpgC,KAAM,gBACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CAAC,IAET,CACEpgC,KAAM,aACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CAAC,IAET,CACEpgC,KAAM,UACN2N,IAAK,WACLuK,KAAM,IACNkoB,KAAM,CAAC,KASJ,SAASS,KACd,MAAM72B,EAAO,CAAC,EACd,IAAK,IAAIjR,EAAI,EAAGA,EAAI6nC,GAAqBjoC,SAAUI,EAAG,CACpD,MAAM+nC,EAASF,GAAqB7nC,GACpCiR,EAAK82B,EAAO9gC,MAAQ8gC,EAAOV,KAAK,EAClC,CACA,OAAOp2B,CACT,CAKO,MAAM+2B,GAOX,GAQAjb,UAAAA,GACE,OAAOtvB,MAAK,CACd,CAQAuvB,aAAAA,CAAcib,GAGd,CAWAtX,MAAAA,CAAOtE,EAAcuE,GAEnB,IAAK,IAAItyB,EAAI,EAAGA,EAAIupC,GAAqBjoC,SAAUtB,EACjDouB,GAASL,EAAcwb,GAAqBvpC,IAI9C,MAAMwyB,EAAS7E,GAAeI,GACxBvoB,EAAO,IAAIyf,GAAK,CAACuN,EAAO,GAAIA,EAAO,GAAI,IAEvCjP,EAAY/d,EAAK8f,eAGvB,IAAIskB,EAAS,EACb,MAAMC,EAAa9b,EAAa,YAKhC,QAJ0B,IAAf8b,IACTD,EAAS5zB,SAAS6zB,EAAW5oC,MAAM,GAAI,KAGrC2oC,IAAWtX,EAAYhxB,OAASiiB,EAClC,MAAM,IAAIliB,MACR,gDACAuoC,EAAS,IAAMtX,EAAYhxB,OAASiiB,GAIxC,MAAM4B,EP6FH,SAAkC4I,GAEvC,MAAM+b,EAAQ/b,EAAa,YAC3B,QAAqB,IAAV+b,GAAgD,IAAvBA,EAAM7oC,MAAMK,OAC9C,MAAM,IAAID,MAAM,sDAGlB,MAAM0oC,EAASD,EAAM7oC,MAAM,GAAG,YAAYA,MAAM,GAG1C+oC,EAAU,GACVC,EAAclc,EAAa,YACjC,QAA2B,IAAhBkc,EAA6B,CACtC,MAAMC,EAAUD,EAAYhpC,MAE5B,GAAuB,IAAnBipC,EAAQ5oC,OACV,MAAM,IAAID,MAAM,+CAElB,IAAI8oC,EACJ,IAAK,IAAIzoC,EAAI,EAAGA,EAAIwoC,EAAQ5oC,SAAUI,EAAG,CAEvC,MAAM0oC,EAAWF,EAAQxoC,GAAG,YAAYT,MAAM,GAC9C,GAAImpC,IAAaL,EACf,MAAM,IAAI1oC,MACR,sEAGJ8oC,EAAeD,EAAQxoC,GAAG,YAAYT,MAAM,GAE5C,MAAMwL,EAAQ,CACZ49B,yBAA0BD,EAC1BE,sBAAuBH,QAGa,IAA3BD,EAAQxoC,GAAG,cACpB+K,EAAM89B,0BAA4BL,EAAQxoC,GAAG,YAAYT,MAAM,IAGjE+oC,EAAQ5nC,KAAKqK,EACf,CAEA,GAAqB,gBAAjB09B,EACF,MAAM,IAAI9oC,MAAM,+CAEpB,CAEA,MAAO,CACLmpC,cAAe,CACbvpC,MAAO,CACL,CACEopC,yBAA0BN,KAIhCC,QAAS,CACP/oC,MAAO+oC,GAGb,COvJsBS,CAAyB1c,GAGrC2c,EAAc3c,EAAa,YACjC,QAA2B,IAAhB2c,EACT,MAAM,IAAIrpC,MAAM,0CAElB,MAAM4nC,EAAW,GAEX3S,EAAS,CAAC,GACVC,EAAW,CAAC,GACZC,EAAU,CAAC,GACjB,IAAK,IAAI90B,EAAI,EAAGA,EAAIgpC,EAAYzpC,MAAMK,SAAUI,EAAG,CACjD,MAAMojC,EAAUD,GAAW6F,EAAYzpC,MAAMS,SACN,IAA5BojC,EAAQN,kBAEjBlO,EAAOwO,EAAQ10B,QAAU00B,EAAQN,gBAAgB1jC,EACjDy1B,EAASuO,EAAQ10B,QAAU00B,EAAQN,gBAAgBp9B,EACnDovB,EAAQsO,EAAQ10B,QAAU00B,EAAQN,gBAAgBn9B,GAGpD4hC,EAAS7mC,KAAK0iC,EAChB,CAEA,IACI6F,EAOArjB,EACAyL,EATA6X,GAAqB,EAErBtU,EAAOh1B,OAAS,IAClBspC,GAAqB,EACrBD,EAAmB,IAAItkC,EAAUiwB,EAAQC,EAAUC,IAMrD,MAAMqU,EAA4B9c,EAAa,UAC/C,QAAyC,IAA9B8c,EAA2C,CAEpD,MAAMC,EAAaD,EAA0B5pC,MAAM,GAEnD,QAAsC,IAA3B6pC,EAAW,YAA6B,CACjD,MAAMC,EAAsBD,EAAW,YACE,IAArCC,EAAoB9pC,MAAMK,OAE5ByxB,EACEgY,EAAoB9pC,MAAM,GAAG,YAAYA,MAE3CqC,EAAOa,KACL,+DAEN,CAEA,QAAsC,IAA3B2mC,EAAW,YAA6B,CACjD,MAAME,EAAmBF,EAAW,YACE,IAAlCE,EAAiB/pC,MAAMK,OAEzBgmB,EAAUwG,GAAsBkd,EAAiB/pC,MAAM,IAEvDqC,EAAOa,KACL,2DAEN,CACF,CAEA,MAAM8mC,EAAiB,SAAUj7B,EAAKxO,GACpC,OAAOwO,EAAIk7B,MAAK,SAAUC,GACxB,OAAO3C,GAAYhnC,EAAK2pC,EAC1B,GACF,EAEMC,EAAkB,SAAUp7B,EAAKxO,GACrC,OAAOwO,EAAIq7B,WAAU,SAAUF,GAC7B,OAAO3C,GAAYhnC,EAAK2pC,EAC1B,GACF,EAGMG,EAA4Bvd,EAAa,UAC/C,QAAyC,IAA9Bud,EACT,MAAM,IAAIjqC,MAAM,kDAElB,GAAIuoC,IAAW0B,EAA0BrqC,MAAMK,OAC7C,MAAM,IAAID,MACR,oEAGJ,MAAMkqC,EAAa,GACnB,IAAK,IAAIhpC,EAAI,EAAGA,EAAI+oC,EAA0BrqC,MAAMK,SAAUiB,EAC5DgpC,EAAWnpC,KACTskC,GAAoB4E,EAA0BrqC,MAAMsB,KAIxD,MAAMipC,EAAe,GACrB,IAAK,IAAIC,EAAK,EAAGA,EAAKF,EAAWjqC,SAAUmqC,EAAI,CAK7C,GAJKR,EAAeO,EAAcD,EAAWE,GAAIlF,cAC/CiF,EAAappC,KAAKmpC,EAAWE,GAAIlF,kBAGmB,IAA3CgF,EAAWE,GAAI1Y,wBACxB,QAAuC,IAA5BA,EACTA,EAA0BwY,EAAWE,GAAI1Y,6BAEzC,IAAKpiB,EACHoiB,EAAyBwY,EAAWE,GAAI1Y,yBACxC,MAAM,IAAI1xB,MAAM,4CAKtB,QAAsC,IAA3BkqC,EAAWE,GAAInkB,QACxB,QAAuB,IAAZA,EACTA,EAAUikB,EAAWE,GAAInkB,aAEzB,IAAKA,EAAQtlB,OAAOupC,EAAWE,GAAInkB,SACjC,MAAM,IAAIjmB,MAAM,0CAIxB,CAGA,QAAuB,IAAZimB,EACT,MAAM,IAAIjmB,MAAM,kCAElB,GAAyB,IAArBimB,EAAQhmB,SACV,MAAM,IAAID,MAAM,0CAElB,QAAuC,IAA5B0xB,EACT,MAAM,IAAI1xB,MAAM,kDAElB,GAAuC,IAAnC0xB,EAAwBzxB,OAC1B,MAAM,IAAID,MAAM,0DAIlB,MAAMgsB,EAAa,IAAIhkB,EACrB4kB,WAAW8E,EAAwB,IACnC9E,WAAW8E,EAAwB,IACnC9E,WAAW8E,EAAwB,KAC/BzF,EAAa,IAAIjkB,EACrB4kB,WAAW8E,EAAwB,IACnC9E,WAAW8E,EAAwB,IACnC9E,WAAW8E,EAAwB,KAC/BxF,EAASF,EAAW1jB,aAAa2jB,GAEjCF,EAAoB,IAAI/iB,EAAS,CACrCgjB,EAAW/jB,OAAQgkB,EAAWhkB,OAAQikB,EAAOjkB,OAC7C+jB,EAAW9jB,OAAQ+jB,EAAW/jB,OAAQgkB,EAAOhkB,OAC7C8jB,EAAW7jB,OAAQ8jB,EAAW9jB,OAAQ+jB,EAAO/jB,SAK/CgiC,EAAaz6B,KA1cjB,SAA0BwW,GACxB,MAAMmkB,EAAiBnkB,EAAY/c,aACnC,OAAO,SAAUi+B,EAAMC,GACrB,MAAMiD,EAAKD,EAAe5/B,gBAAgB28B,GACpCmD,EAAKF,EAAe5/B,gBAAgB48B,GAC1C,OAAOiD,EAAG,GAAKC,EAAG,EACpB,CACF,CAmcsBC,CAAiBze,IAEnC,MAAM0e,EAAmB,SAAU97B,GACjC,OAAO,IAAI7D,EAAQ6D,EAAI,GAAIA,EAAI,GAAIA,EAAI,GACzC,EAGM+7B,EAAe,GACrB,IAAK,IAAIlsC,EAAI,EAAGA,EAAI2rC,EAAalqC,SAAUzB,EACzCksC,EAAa3pC,KAAK0pC,EAAiBN,EAAa3rC,KAIlD,MAAMmsC,EAAc,IAAI5kB,GACtB2kB,EAAa,GAAIvmC,EAAM8hB,EAAS8F,GAI5B6e,EAAiB,SAAUhrC,GAC/B,IAAIgH,EAAMhH,EAAQgJ,EAmBlB,OAlBIhC,IAEFA,EAAMhH,EAA6B,GAArBgJ,EACThC,GAMHA,EAAMhH,EAA6B,IAArBgJ,EACThC,GAEH3E,EAAOa,KACL,2DARJb,EAAOa,KACL,0DAYC8D,CACT,EAGMikC,EAAU,GAChBA,EAAQ9pC,KAAKopC,EAAa,IAC1B,IAAIW,EAAa,EACjB,IAAK,IAAI/kC,EAAI,EAAGA,EAAIokC,EAAalqC,SAAU8F,EAAG,GAC1C+kC,EACF,IAAI1/B,EAAQ,IAAIvL,EAAM,CAAC,EAAG,EAAGirC,IACzBrjB,EAAQkjB,EAAYriB,aAAald,GAAOuB,QAC5C,MAAMo+B,EAAcL,EAAa3kC,GAEjC,IAAIyG,EAAOu+B,EAAYh/B,YAAY0b,GACnC,MAAMujB,EAAex+B,EAErB,KAAOo+B,EAAep+B,IAQpB,GAPAvK,EAAOW,MAAM,iDACX6kB,EAAMnnB,YACRuqC,EAAQ9pC,KAAK,CAAC0mB,EAAMxf,OAAQwf,EAAMvf,OAAQuf,EAAMtf,WAC9C2iC,EACF1/B,EAAQ,IAAIvL,EAAM,CAAC,EAAG,EAAGirC,IACzBrjB,EAAQkjB,EAAYriB,aAAald,GAAOuB,QACxCH,EAAOu+B,EAAYh/B,YAAY0b,GAC3Bjb,EAAOw+B,EACT,MAAM,IAAIhrC,MACR,iEAIN6qC,EAAQ9pC,KAAKopC,EAAapkC,GAC5B,CAGA,MAAMklC,EAAiBJ,EAAQ5qC,OAGzB2xB,EAAW,IAAI7L,GACnB2kB,EAAa,GAAIvmC,EAAM8hB,EAAS8F,GAC5Bmf,EAAO,CAAC,KACd,IAAK,IAAI9hC,EAAI,EAAGA,EAAI6hC,IAAkB7hC,EACpCwoB,EAAS9J,aAAa2iB,EAAiBI,EAAQzhC,IAAKA,GACpD8hC,EAAKnqC,KAAKqI,EAAE9I,YAGd,MAAM6qC,EAAqB,SAAUp8B,GACnC,OAAO,SAAUwN,GACf,OAAOA,EAAKxN,SAAWA,CACzB,CACF,EAGMkC,EAEJ,IAAIggB,EAAYnxB,YAAYoiB,EAAY+oB,GAC1Ch6B,EAAOm6B,KAAK,GAEZ,IAAIvD,EAAc,KACdwD,EAAc,KAClB,IAAK,IAAIjsB,EAAI,EAAGA,EAAI8qB,EAAWjqC,SAAUmf,EAAG,CAE1C0rB,EAAaf,EAAgBc,EAASX,EAAW9qB,GAAG8lB,aACpDmG,EAAcnpB,EAAY9C,EAC1ByoB,EAAc3lB,EAAY4oB,EAE1B,MAAMQ,EAAe1D,EAAS5f,KAC5BmjB,EAAmBjB,EAAW9qB,GAAGgmB,mBAEnC,IAAK,IAAIjkC,EAAI,EAAGA,EAAI+gB,IAAa/gB,EAC/B,GAAqC,IAAjC8vB,EAAYoa,EAAclqC,GAAU,CAGpC8P,EAFa42B,EAAc1mC,GACzBooC,EACe+B,EAAav8B,OAEbu8B,EAAapI,YAElC,CAEJ,CAGA,MAAMhiB,EAAQ,IAAI8Q,GAAMJ,EAAU3gB,EAAQi6B,GACtC3B,IACFroB,EAAM+Q,6BAA6B,iBACnC/Q,EAAMwU,oBAAoB4T,IAG5B,MAAMhX,EAAO6V,KACPxV,EAAU,SAAU7zB,GACxB,IAAI8H,EACJ,MAAM+I,EAAU+c,EAAa5tB,GAI7B,YAHuB,IAAZ6Q,IACT/I,EAAM+I,EAAQ/P,MAAM,IAEfgH,CACT,EAEA0rB,EAAKe,UAAYV,EAAQ,YACzBL,EAAKgB,UAAYX,EAAQ,YACzBL,EAAKiB,iBAAmBZ,EAAQ,YAChCL,EAAKkB,QAAUb,EAAQ,YAEvBL,EAAKiZ,WAAa5Y,EAAQ,YAC1BL,EAAKkZ,WAAa7Y,EAAQ,YAC1BL,EAAKmB,kBAAoBd,EAAQ,YACjCL,EAAKoB,aAAef,EAAQ,YAE5BL,EAAKqB,uBAAyBhB,EAAQ,YAEtCL,EAAKsB,YAAcjB,EAAQ,YAC3BL,EAAKuB,UAAYlB,EAAQ,YACzBL,EAAKwB,iBAAmBnB,EAAQ,YAChCL,EAAKyB,WAAapB,EAAQ,YAE1BL,EAAK0B,aAAerB,EAAQ,YAC5BL,EAAK2B,sBAAwBtB,EAAQ,YACrCL,EAAK4B,mBAAqBvB,EAAQ,YAClCL,EAAK6B,iBAAmBxB,EAAQ,YAEhCL,EAAKmZ,8BAAgC3nB,EAAUqlB,cAC/C7W,EAAKoZ,uBAAyB5nB,EAAU6kB,QAExCrW,EAAKqZ,OAAS,CACZ/D,SAAUA,EACVsC,WAAYA,EACZ0B,eAAgBlf,EAAa,YAAY9sB,MAAM,IAKjD0yB,EAAKpB,cAAgB+Z,EAErB,MAAMY,EAAsBnf,EAAa,YACrCmf,IACFvZ,EAAK+B,oBAAsBwX,EAAoBjsC,MAAM,IAGvD,MAAMksC,EAAwBpf,EAAa,YAO3C,OANIof,IACFxZ,EAAKyZ,sBAAwBD,EAAsBlsC,MAAM,IAG3DshB,EAAM2U,QAAQvD,GAEPpR,CACT,CAWA8qB,OAAAA,CACE9qB,EACA0mB,EACAnC,EACAwG,GAGA,MAAM36B,EAAO4P,EAAMgrB,eAGF5tC,IAAbspC,IACFA,EAAWt2B,EAAKs2B,UAGlB,MAAMhW,EAAW1Q,EAAMI,cACjBnd,EAAOytB,EAASrQ,UAGtBjQ,EAAK66B,KAAOhoC,EAAKhF,IAAI,GACrBmS,EAAK86B,QAAUjoC,EAAKhF,IAAI,GAExB,MAAMktC,EAAM,IAAI1c,KAChBre,EAAKg7B,YAAcjiB,GAAaR,GAAcwiB,IAC9C/6B,EAAKi7B,YAAchiB,GAAaN,GAAcoiB,SAG1B/tC,IAAhBmnC,IACFn0B,EAAKiiB,iBAAoBkS,EAAYyG,UAAW3Y,kBAIlD,MAAMiZ,EAAe,GACrB,IAAK,MAAM/I,KAAWmE,EACpB4E,EAAazrC,KAAKmjC,GAAoBT,IPjLrC,IAA6Bxd,EAaSC,EOsKzC5U,EAAKm7B,gBAAkB,CACrB7sC,MAAO4sC,GAITl7B,EAAKo7B,+BAAiC,CACpC9sC,MAAO,CACL,CACE+sC,yBAA0B,CACxB/sC,MAAO,EP/K0BsmB,EO+KI0L,EAASrK,iBP9KjD,CACL6M,wBAAyB,CACvBlO,EAAY/mB,IAAI,EAAG,GACnB+mB,EAAY/mB,IAAI,EAAG,GACnB+mB,EAAY/mB,IAAI,EAAG,GACnB+mB,EAAY/mB,IAAI,EAAG,GACnB+mB,EAAY/mB,IAAI,EAAG,GACnB+mB,EAAY/mB,IAAI,EAAG,QOyKfytC,sBAAuB,CACrBhtC,MAAO,EP/LiBqmB,EO+LI2L,EAASxK,aP9LxC,CACLylB,qBAAsB5mB,EAAQ9mB,IAAI,GAClC2tC,aAAc,CAAC7mB,EAAQ9mB,IAAI,GAAI8mB,EAAQ9mB,IAAI,WOmM3C,MAAM4tC,EAnlBV,SAA0B7rB,EAAO0mB,GAC/B,MACMzjC,EADW+c,EAAMI,cACDC,UAGhBW,EAAY/d,EAAKge,WAAW,GAC5B4qB,EAAa,CAAC,EACpB,IAAK,IAAIxiC,EAAI,EAAGA,EAAIpG,EAAKhF,IAAI,KAAMoL,EAAG,CACpC,MAEMu9B,EAAUH,GAAsBzmB,EAAO0mB,EAFzBr9B,EAAI2X,GAIlB1M,EAAQxW,OAAO4R,KAAKk3B,GAC1B,IAAK,MAAMkF,KAAQx3B,OACQlX,IAArByuC,EAAWC,KACbD,EAAWC,GAAQ,CAAC,GAGtBD,EAAWC,GAAMziC,GAAKu9B,EAAQkF,EAElC,CACA,OAAOD,CACT,CA6jBuBE,CAAiB/rB,EAAO0mB,GAErCsC,EAAa,GAGbgD,EAAe,GACfC,EAAiB,GACvB,IAAK,MAAM1J,KAAWmE,EAAU,CAC9B,MAAMwF,EAAW3J,EAAQ10B,OACnBs+B,EAAUD,EAAW,EAE3B,QAA4B9uC,IAAxByuC,EAAWM,GACb,SAEF,MAAM53B,EAAQzW,OAAO4R,KAAKm8B,EAAWM,IAErC,IAAK,IAAIx3B,EAAKJ,EAAMxV,OAAS,EAAG4V,GAAM,IAAKA,EAAI,CAC7C,MAAMy3B,EAAO5kC,OAAOiM,SAASc,EAAMI,GAAK,IACxCq3B,EAAansC,KAAKgsC,EAAWM,GAASC,IAEtC,MAAMC,EAASrsB,EAAMI,cAAcoF,aAAa4mB,GAC1CE,EAAc,CAACD,EAAOtlC,OAAQslC,EAAOrlC,OAAQqlC,EAAOplC,QACpD09B,EAAY,CAChBZ,SAAU,CAACmI,EAAU33B,EAAMxV,OAAS4V,GACpCqvB,YAAasI,EACbpI,iBAAkBgI,GAGpB,QAAoB9uC,IAAhBmnC,EAA2B,CAC7B,MACMgI,EADiBhI,EAAYnkB,cACA+G,aACjC,IAAI3b,EAAM,CAAC6gC,EAAOtlC,OAAQslC,EAAOrlC,OAAQqlC,EAAOplC,UAElD09B,EAAUV,iBAAmB,CAC3B,CACEI,aAAc,CACZ,CACEI,yBACEF,EAAYiI,YAAYD,GAC1B/H,sBACGD,EAAYyG,UAAWne,gBAMlCof,EAAepsC,KAAK,CAClBgmC,yBACEtB,EAAYiI,YAAYD,GAC1B3G,sBACGrB,EAAYyG,UAAWne,aAE9B,CACAmc,EAAWnpC,KAAK8kC,EAClB,CACF,CAEAv0B,EAAKq8B,eAAiBT,EAAajtC,OAAOK,WAG1C,MAAMstC,EAAgB,GACtB,IAAK,MAAM/H,KAAaqE,EACtB0D,EAAc7sC,KAAKmlC,GAA6BL,IAOlD,GALAv0B,EAAKu8B,iCAAmC,CACtCjuC,MAAOguC,QAIWtvC,IAAhBmnC,EAA2B,CAC7B,MAAMqI,EAAe,GACrBA,EAAa/sC,KAAK,CAChBgtC,2BAA4B,CAC1BnuC,MAAOutC,GAET1Z,kBAAoBgS,EAAYyG,UAAWzY,oBAE7CniB,EAAK08B,yBAA2B,CAC9BpuC,MAAOkuC,EAEX,MAGkBxvC,IAAd2tC,GAtwBR,SAAmBgC,EAAOC,GACxB,MAAMC,EAAQnvC,OAAO4R,KAAKs9B,GAC1B,IAAK,MAAME,KAAYD,OACG7vC,IAApB2vC,EAAMG,IACRnsC,EAAOQ,MAAM,qBAAuB2rC,GAEtCH,EAAMG,GAAYF,EAAME,EAE5B,CA+vBMC,CAAU/8B,EAAM26B,GAIlB,MAAMqC,EAAgBvP,GAAwBztB,GAGxC4Q,EAAY/d,EAAKge,WAAW,GAC5BosB,EAASrB,EAAajtC,OAASiiB,EAAa,EAC5CssB,EAAK,IAAIz4B,GAAY,MAM3B,OALAy4B,EAAGv5B,IAAM,IAAId,GAAI,OAAQ,QACzBq6B,EAAGx4B,GAAKu4B,EACRC,EAAG5uC,MAAQstC,EACXoB,EAAc,YAAcE,EAErBF,CACT,ECxzBK,SAASG,GAAY1wB,GAE1B,OADgB,IAAIoP,IACL6D,OACbjT,EACAA,EAAS,YAAYne,MAAM,GAC3B,EAEJ,CAQO,SAAS8uC,GAAgB3wB,GAE9B,OADgB,IAAIsqB,IACLrX,OACbjT,EACAA,EAAS,YAAYne,MAAM,GAE/B,CAwCO,MAAMoyB,GAOX,IAiBA,GAOA,IAOA,GAAO,IAAIxO,GAAyB,EAAG,GAOvC,IAAQ,KAOR,KAAiB,EAOjB,KAAiB,EAOjB,IAA6B,cAO7B,IAQA,IAAuB,EAOvB,IAOA,IAAQ,CAAC,EAOT,IAAa,KAOb,IAAqB,KAOrB,IAAa,KAOb,IAAmB,IAAIjE,GAOvBzf,WAAAA,CAAY8xB,EAAU3gB,EAAQ09B,GAC5B7wC,MAAK,GAAY8zB,EACjB9zB,MAAK,EAAUmT,EACfnT,MAAK,GAAa6wC,EAElB7wC,MAAK,GAAsBA,MAAK,EAAQmC,OACtCnC,MAAK,GAAUyjB,UAAU0C,cAC7B,CAQAypB,WAAAA,CAAYtiC,GACV,IAAIutB,EAAM76B,MAAK,GAAW,GAI1B,OAH+B,IAA3BA,MAAK,GAAWmC,aAAiC,IAAVmL,IACzCutB,EAAM76B,MAAK,GAAWA,KAAK8wC,mBAAmBxjC,KAEzCutB,CACT,CAQAkW,oBAAAA,CAAqBlW,GACnB,IAAI3S,EACJ,MAAM8oB,EAAWhxC,MAAK,GAAWuN,QAAQstB,GAKzC,OAJkB,IAAdmW,IAEF9oB,EADgBloB,KAAKwjB,cAAcoF,aAClBooB,IAEZ9oB,CACT,CAQA+oB,gBAAAA,CAAiBpW,GACf,OAAO76B,MAAK,GAAW2Q,SAASkqB,EAClC,CAQAqW,iBAAAA,CAAkB9D,GAChB,OvB/NG,SAAuB37B,EAAMC,GAElC,GAAa,OAATD,GACO,OAATC,QACgB,IAATD,QACS,IAATC,EACP,OAAO,EAET,GAAoB,IAAhBD,EAAKtP,QACS,IAAhBuP,EAAKvP,QACLuP,EAAKvP,OAASsP,EAAKtP,OACnB,OAAO,EAGT,IAAK,MAAMgvC,KAAYz/B,EACrB,IAAKD,EAAKd,SAASwgC,GACjB,OAAO,EAGX,OAAO,CACT,CuB2MWC,CAAcpxC,MAAK,GAAYotC,EACxC,CAOA5pB,WAAAA,GACE,OAAOxjB,MAAK,EACd,CAQA+9B,SAAAA,GACE,OAAO/9B,MAAK,CACd,CAOAqxC,WAAAA,GACE,OAAwC,IAAjCrxC,KAAKukB,uBACd,CAQA+sB,cAAAA,GACE,OAAOtxC,KAAK+uB,cACd,CAOAA,YAAAA,GACE,OAAOA,GAAa/uB,KAAKgwB,+BAC3B,CASA9J,SAAAA,CAAU3C,GACR,MAAMld,EAAOrG,KAAKwjB,cAAcC,UAEhC,IAAI8tB,EAAS,EAIb,YAHwC,IAA7BvxC,MAAK,GAAMozB,gBACpBme,EAASvxC,MAAK,GAAMozB,eAEf/sB,EAAK6f,UAAU3C,IAA+B,IAAXguB,CAC5C,CAOA,MACE,OAAOvxC,MAAK,GAAUyjB,UAAU0C,aAAa,EAC/C,CASA2qB,kBAAAA,CAAmBxjC,GACjB,OAAOtN,MAAK,GAAUyjB,UAAUK,cAAcxW,EAAO,EACvD,CAQAkkC,2BAAAA,CAA4BlkC,GAC1B,IAAIxE,EAAM9I,MAAK,EACf,IAAKA,KAAKyxC,gBAAiB,CACzB,QAAqB,IAAVnkC,EACT,MAAM,IAAIpL,MAAM,uDAElB,MAAMgC,EAASlE,KAAK8wC,mBAAmBxjC,QACL,IAAvBtN,MAAK,GAAMkE,GACpB4E,EAAM9I,MAAK,GAAMkE,GAEjBC,EAAOa,KAAK,iCAAmCd,EAEnD,CACA,OAAO4E,CACT,CAQA,IAAqC5E,GACnC,OAAOlE,MAAK,GAAMkE,EACpB,CASA0wB,2BAAAA,CAA4B8c,EAAOxtC,GAIjC,GAFAlE,MAAK,GAAiBA,MAAK,IAAkB0xC,EAAMhuC,OAE9C1D,MAAK,IAOR,IAAKA,MAAK,EAAK6C,OAAO6uC,GACpB,QAAsB,IAAXxtC,EAETlE,MAAK,EAAO0xC,MACP,CAEL1xC,MAAK,IAAiB,EAEtBA,MAAK,GAAQ,GAEb,IAAK,IAAIuC,EAAI,EAAGO,EAAO9C,MAAK,KAA0BuC,EAAIO,IAAQP,EAChEvC,MAAK,GAAMiD,KAAKjD,MAAK,GAGvBA,MAAK,EAAO,KACZA,MAAK,GAAM8hB,OAAO5d,EAAQ,EAAGwtC,EAC/B,MAvBsB,CACxB,QAAsB,IAAXxtC,EACT,MAAM,IAAIhC,MACR,yDAEJlC,MAAK,GAAM8hB,OAAO5d,EAAQ,EAAGwtC,EAC/B,CAoBF,CAOAC,aAAAA,GACE,OAAO3xC,MAAK,EACd,CAOAyxC,aAAAA,GACE,OAAOzxC,MAAK,EACd,CAOAgwB,4BAAAA,GACE,OAAOhwB,MAAK,EACd,CAOAm0B,4BAAAA,CAA6Byd,GAC3B5xC,MAAK,GAA6B4xC,CACpC,CAOAha,mBAAAA,CAAoB/T,GAClB7jB,MAAK,GAAoB6jB,EAEzB7jB,MAAK,GAAW,CAAC0hB,KAAM,sBACzB,CAOAmwB,mBAAAA,GACE,OAAO7xC,MAAK,EACd,CAQA8xC,sBAAAA,CAAuBxkC,EAAOykC,GAC5B/xC,MAAK,GAAkBmH,IAAImG,GAASykC,EAAOpwC,EAC3C3B,MAAK,GAAkBoH,MAAMkG,GAASykC,EAAO9pC,EAC7CjI,MAAK,GAAkBqH,KAAKiG,GAASykC,EAAO7pC,EAE5ClI,MAAK,GAAW,CAAC0hB,KAAM,sBACzB,CAOA+C,sBAAAA,GACE,OAAOzkB,MAAK,EACd,CAOAq0B,sBAAAA,CAAuB2d,GACrBhyC,MAAK,GAAuBgyC,CAC9B,CAOAztB,qBAAAA,GACE,OAAOvkB,MAAK,EACd,CAOAouC,OAAAA,GACE,OAAOpuC,MAAK,EACd,CAOA+3B,OAAAA,CAAQn1B,GACN5C,MAAK,GAAQ4C,CACf,CAQAohB,gBAAAA,CAAiB9f,GACf,OAAOlE,MAAK,EAAQkE,EACtB,CASA+tC,UAAAA,CAAWnwC,GAET,IAAIowC,EACJ,GAAqB,iBAAVpwC,EAAoB,CAC7B,GAAiC,IAA7B9B,MAAK,GACP,MAAM,IAAIkC,MACR,2DAEJgwC,EAAc,CAACpwC,EACjB,MAAO,QAAuB,IAAZA,EAAMH,QACH,IAAZG,EAAMmG,QACM,IAAZnG,EAAMoG,EAAmB,CAChC,GAAiC,IAA7BlI,MAAK,GACP,MAAM,IAAIkC,MACR,wDAEJgwC,EAAc,CAACpwC,EAAMH,EAAGG,EAAMmG,EAAGnG,EAAMoG,EACzC,CAGA,MAAMiqC,EAAU,GAChB,IAAIC,EACJ,IAAK,IAAI7vC,EAAI,EAAGA,EAAIvC,MAAK,EAAQmC,OAAQI,GAAQvC,MAAK,GAAqB,CACzEoyC,GAAQ,EACR,IAAK,IAAIhvC,EAAI,EAAGA,EAAIpD,MAAK,KAAuBoD,EAC9C,GAAIpD,MAAK,EAAQuC,EAAIa,KAAO8uC,EAAY9uC,GAAI,CAC1CgvC,GAAQ,EACR,KACF,CAEEA,GACFD,EAAQlvC,KAAKV,EAEjB,CACA,OAAO4vC,CACT,CAUAE,SAAAA,CAAUpwC,GAER,QAAsB,IAAXA,GACS,IAAlBA,EAAOE,OACP,MAAO,GAGT,MAAMmwC,EAAc,GACpB,IAAK,IAAIplB,EAAK,EAAGA,EAAKjrB,EAAOE,SAAU+qB,EACJ,IAA7BltB,MAAK,GACPsyC,EAAYrvC,KAAK,CAAChB,EAAOirB,KACa,IAA7BltB,MAAK,IACdsyC,EAAYrvC,KAAK,CACfhB,EAAOirB,GAAIvrB,EACXM,EAAOirB,GAAIjlB,EACXhG,EAAOirB,GAAIhlB,IAKjB,IAAIqqC,EAC6B,IAA7BvyC,MAAK,GACPuyC,EAAY,SAAUzxC,EAAGoH,GACvB,OAAOpH,EAAE,KAAOoH,EAAE,EACpB,EACsC,IAA7BlI,MAAK,KACduyC,EAAY,SAAUzxC,EAAGoH,GACvB,OAAOpH,EAAE,KAAOoH,EAAE,IAChBpH,EAAE,KAAOoH,EAAE,IACXpH,EAAE,KAAOoH,EAAE,EACf,GAEF,MAAMsqC,EAAmB,SAAU1wC,GACjC,OAAO,SAAU2c,GACf,OAAO8zB,EAAU9zB,EAAM3c,EACzB,CACF,EAEMgH,EAAM,IAAIsW,MAAMnd,EAAOE,QAC7B2G,EAAIwkC,MAAK,GACT,MAAMmF,EAAeH,EAAY5vC,QACjC,IAAI0vC,EACAM,EACJ,IAAK,IAAInwC,EAAI,EAAGO,EAAO9C,MAAK,EAAQmC,OAClCI,EAAIO,EAAMP,GAAQvC,MAAK,GAAqB,CAC5C0yC,EAAkB,GAClB,IAAK,IAAIC,EAAI,EAAGA,EAAIF,EAAatwC,SAAUwwC,EAAG,CAC5CP,GAAQ,EAER,IAAK,IAAIhvC,EAAI,EAAGA,EAAIpD,MAAK,KAAuBoD,EAC9C,GAAIpD,MAAK,EAAQuC,EAAIa,KAAOqvC,EAAaE,GAAGvvC,GAAI,CAC9CgvC,GAAQ,EACR,KACF,CAGEA,IAGFtpC,EAFiBwpC,EAAYpG,UAC3BsG,EAAiBC,EAAaE,OAChB,EAChBD,EAAgBzvC,KAAK0vC,GAEzB,CAEA,IAAK,IAAIhxC,EAAI,EAAGA,EAAI+wC,EAAgBvwC,SAAUR,EAC5C8wC,EAAa3wB,OAAO4wB,EAAgB/wC,GAAI,GAG1C,GAA4B,IAAxB8wC,EAAatwC,OACf,KAEJ,CAEA,OAAO2G,CACT,CAOA6uB,KAAAA,GAEE,MAAMib,EAAe5yC,MAAK,EAAQ0C,MAAM,GAElC63B,EAAO,IAAIrG,GAAMl0B,KAAKwjB,cAAeovB,EAAc5yC,MAAK,IAE9D,GAAIA,KAAKyxC,gBACPlX,EAAK3F,4BAA4B50B,KAAKwxC,oCAEtC,IAAK,IAAIjvC,EAAI,EAAGA,EAAIvC,MAAK,OAA4BuC,EACnDg4B,EAAK3F,4BACH50B,MAAK,GAAqCuC,GAAIA,GAQpD,OAJAg4B,EAAKpG,6BAA6Bn0B,KAAKgwB,gCACvCuK,EAAKlG,uBAAuBr0B,KAAKykB,0BACjC8V,EAAKxC,QAAQ/3B,KAAKouC,WAEX7T,CACT,CAOA,IAASl0B,GAEP,IAAIwsC,EAAY7yC,MAAK,EAMrB,GAJAA,MAAK,EAAUsd,GACoB,EAAjCtd,MAAK,EAAQ6Y,kBACb7Y,MAAK,GAAMw2B,SAAW,EAAI,EAC1BnwB,GACmB,OAAjBrG,MAAK,EACP,MAAM,IAAIkC,MAAM,qCAGlBlC,MAAK,EAAQoT,IAAIy/B,GAEjBA,EAAY,IACd,CAQAC,WAAAA,CAAYlwC,GAEV,GAAY,OAARA,EACF,MAAM,IAAIV,MAAM,4BAElB,MAAM6wC,EAAUnwC,EAAI4gB,cAAcC,UAClC,IAAIpd,EAAOrG,MAAK,GAAUyjB,UAC1B,GAAuB,IAAnBsvB,EAAQ1xC,IAAI,GACd,MAAM,IAAIa,MAAM,qCAElB,GAAImE,EAAKhF,IAAI,KAAO0xC,EAAQ1xC,IAAI,GAC9B,MAAM,IAAIa,MAAM,0DAElB,GAAImE,EAAKhF,IAAI,KAAO0xC,EAAQ1xC,IAAI,GAC9B,MAAM,IAAIa,MAAM,uDAElB,IAAKlC,MAAK,GAAUypB,iBAAiB5mB,OACnCD,EAAI4gB,cAAciG,iBAAkB,MACpC,MAAM,IAAIvnB,MAAM,oDAElB,GAAIlC,MAAK,KACP4C,EAAIotB,+BACJ,MAAM,IAAI9tB,MACR,mEAGJ,IAAK,MAAMlB,KAAOhB,MAAK,GACrB,GAAY,kBAARgB,GAAmC,kBAARA,GACrB,WAARA,GAGEhB,MAAK,GAAMgB,KAAS4B,EAAIwrC,UAAUptC,GACpC,MAAM,IAAIkB,MAAM,wCAA0ClB,EACxD,KAAOhB,MAAK,GAAMgB,GAAO,OAAS4B,EAAIwrC,UAAUptC,IAKtD,MAAMgyC,EAAWpwC,EAAIqwC,eACf/wB,EAAQliB,KAAKizC,eACnBjzC,MAAK,GAAa,CAChB2mB,IAAKhjB,KAAKgjB,IAAIqsB,EAASrsB,IAAKzE,EAAMyE,KAClCtZ,IAAK1J,KAAK0J,IAAI2lC,EAAS3lC,IAAK6U,EAAM7U,MAEpC,MAAM6lC,EAActwC,EAAIuwC,uBAClBC,EAAWpzC,KAAKmzC,uBACtBnzC,MAAK,GAAqB,CACxB2mB,IAAKhjB,KAAKgjB,IAAIusB,EAAYvsB,IAAKysB,EAASzsB,KACxCtZ,IAAK1J,KAAK0J,IAAI6lC,EAAY7lC,IAAK+lC,EAAS/lC,MAI1C,MAAMgmC,EAASzwC,EAAI4gB,cAAc8E,iBAGjC,IAAIgrB,GAAa,OACK,IAAXD,GACRrzC,MAAK,GAAUyoB,gBAAgB4qB,KAEhCrzC,KAAKmqB,YAAYkpB,EAAQzwC,EAAI4gB,cAAcmF,aAE3CtiB,EAAOrG,MAAK,GAAUyjB,UAEtB6vB,GAAa,GAIf,MAAMhmC,EApyBV,SAAuBimC,EAAgBC,GAErC,MAAMH,EAASG,EAAclrB,iBAEvBrmB,EAAS,GAWf,OATAA,EAAOgB,KAAK,GACZhB,EAAOgB,KAAK,GAEZhB,EAAOgB,KAAKswC,EAAe7pB,cAAc8pB,EAAc7qB,YAAa0qB,SAE9C,IAAXA,GACTpxC,EAAOgB,KAAKowC,GAGP,IAAItxC,EAAME,EACnB,CAoxBkBynB,CAAc1pB,MAAK,GAAW4C,EAAI4gB,eAG1CY,EAAYpkB,MAAK,GAAsBqG,EAAKge,WAAW,GAG7D,QAAwC,IAA7BrkB,MAAK,GAAMozB,cACpB,MAAM,IAAIlxB,MAAM,oDAElB,MAAMuxC,EAAiBrvB,EAAYpkB,MAAK,GAAMozB,cAC1CpzB,MAAK,EAAQmC,SAAWsxC,GAC1BzzC,MAAK,GAASyzC,GAIhB,MAAMzG,EAAa1/B,EAAMjM,IAAI,GAG7B,IAAIqyC,EAAiB1G,OACC,IAAXqG,IACTK,GACE1zC,MAAK,GAAU0oB,mCAAmC2qB,IAGtD,MAAMM,EAAcD,EAAiBtvB,EAC/BwvB,EACJ5zC,MAAK,GAAUuoB,gCAAkCnE,EAE/CuvB,EAAcC,GAChB5zC,MAAK,EAAQoT,IACXpT,MAAK,EAAQ6zC,SAASF,EAAaC,GACnCD,EAAcvvB,GAIlBpkB,MAAK,EAAQoT,IAAIxQ,EAAIm7B,YAAa4V,GAG7BL,GACHtzC,MAAK,GAAUgqB,aACbpnB,EAAI4gB,cAAcmF,YAAaqkB,EAAYqG,GAI/CrzC,KAAK40B,4BACHhyB,EAAI4uC,8BAA+BkC,GAGrC,MAAMI,EAAiB9zC,MAAK,GAAWmC,OAMvC,GAHAnC,MAAK,GAAW8hB,OAAO4xB,EAAgB,EAAG9wC,EAAIgtC,oBAGN,IAA7B5vC,MAAK,GAAM42B,cAA+B,CACnD,MAAMA,EAAgB52B,MAAK,GAAM42B,cAC3Bmd,EAAanxC,EAAIwrC,UAAUxX,cAC3B9jB,EAAO5R,OAAO4R,KAAKihC,GACzB,IAAIC,EAAO,KACX,IAAK,IAAIzxC,EAAI,EAAGA,EAAIuQ,EAAK3Q,SAAUI,EAAG,CACpCyxC,EAAOlhC,EAAKvQ,GACZ,MAAM0xC,EAAYF,EAAWC,GACvBE,EAAetd,EAAcod,GACnC,QAA4B,IAAjBE,EAA8B,CAEvC,SAAqC,IAA1BA,EAAaC,WACI,IAA1BD,EAAaC,YAERD,EAAaruC,GAAG,GAAGhD,OAAOoxC,EAAUpuC,GAAG,IAAK,CAC/CquC,EAAaC,UAAW,EAGxB,IAAK,IAAI/wC,EAAI,EAAGA,EAAI0wC,EAAiB,IAAK1wC,EACxC8wC,EAAaruC,GAAG5C,KAAKixC,EAAaruC,GAAG,GAEzC,MAGmC,IAA1BquC,EAAaC,WACI,IAA1BD,EAAaC,UACbvd,EAAcod,GAAMnuC,GAAGic,OACrB4xB,EAAgB,EAAGO,EAAUpuC,GAAG,GAEtC,MAEE+wB,EAAcod,GAAQD,EAAWC,EAErC,CACF,CAQAh0C,MAAK,GAAW,CACd0hB,KAAM,uBAEV,CAQA0yB,iBAAAA,CAAkBC,EAAaC,GAE7B,MAAMjuC,EAAOrG,MAAK,GAAUyjB,UACtB8wB,EAAYv0C,MAAK,GAAsBqG,EAAKge,WAAW,GAC7D,QAAwC,IAA7BrkB,MAAK,GAAMozB,cACpB,MAAM,IAAIlxB,MAAM,0DAElB,MAAMuxC,EAAiBc,EAAYv0C,MAAK,GAAMozB,cAC1CpzB,MAAK,EAAQmC,SAAWsxC,GAC1BzzC,MAAK,GAASyzC,GAGZa,GAAct0C,MAAK,GAAMozB,cAC3BjvB,EAAOa,KAAK,2BAA6BsvC,EACvC,WAAat0C,MAAK,GAAMozB,cAAgB,MAI5CpzB,MAAK,EAAQoT,IAAIihC,EAAaE,EAAYD,GAE1Ct0C,KAAKmqB,YAAYmqB,EAAY,IAAItnC,EAAQ,EAAG,EAAG,IACjD,CAQAmd,WAAAA,CAAY9B,EAAMH,GAChBloB,MAAK,GAAUmqB,YAAYjC,EAAQG,GAQnCroB,MAAK,GAAW,CACd0hB,KAAM,eAGV,CAOAuxB,YAAAA,GAIE,OAHKjzC,MAAK,KACRA,MAAK,GAAaA,KAAKw0C,sBAElBx0C,MAAK,EACd,CAOAmzC,oBAAAA,GAIE,OAHKnzC,MAAK,KACRA,MAAK,GAAqBA,KAAKy0C,8BAE1Bz0C,MAAK,EACd,CAOA00C,YAAAA,GACE,IAAK10C,MAAK,GAAY,CACpB,MAAM8I,EAAM9I,KAAK20C,qBACjB30C,MAAK,GAAa8I,EAAI8rC,UACtB50C,MAAK,GAAqB8I,EAAI+rC,kBAC9B70C,MAAK,GAAa8I,EAAIgsC,SACxB,CACA,OAAO90C,MAAK,EACd,CASA+0C,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAcK,IACZhiB,MAAK,GAAiB+hB,UAAUC,EAAM,EAcxCizB,YAAAA,CAAa9C,EAASrwC,GAEpB,IAAIowC,EAiBAhuC,EAhBJ,GAAqB,iBAAVpC,EAAoB,CAC7B,GAAiC,IAA7B9B,MAAK,GACP,MAAM,IAAIkC,MACR,2DAEJgwC,EAAc,CAACpwC,EACjB,MAAO,QAAuB,IAAZA,EAAMH,QACH,IAAZG,EAAMmG,QACM,IAAZnG,EAAMoG,EAAmB,CAChC,GAAiC,IAA7BlI,MAAK,GACP,MAAM,IAAIkC,MACR,wDAEJgwC,EAAc,CAACpwC,EAAMH,EAAGG,EAAMmG,EAAGnG,EAAMoG,EACzC,CAGA,IAAK,IAAI3F,EAAI,EAAGO,EAAOqvC,EAAQhwC,OAAQI,EAAIO,IAAQP,EAAG,CACpD2B,EAASiuC,EAAQ5vC,GACjB,IAAK,IAAIa,EAAI,EAAGA,EAAIpD,MAAK,KAAuBoD,EAC9CpD,MAAK,EAAQkE,EAASd,GAAK8uC,EAAY9uC,EAE3C,CAEApD,MAAK,GAAW,CAAC0hB,KAAM,sBACzB,CAYAwzB,2BAAAA,CAA4BC,EAAcrzC,GACxC,MAAMszC,EAAsB,GAG5B,IAAK,IAAIhyC,EAAI,EAAGA,EAAI+xC,EAAahzC,SAAUiB,EAAG,CAC5C,MAAM+uC,EAAUgD,EAAa/xC,GAE7B,IAAIc,EAASiuC,EAAQ,GACjBkD,EAAgBr1C,MAAK,EAAQkE,GAEjC,MAAMoxC,EAAiB,GACvBA,EAAeryC,KAAK,CAClBqK,MAAO,EACPxL,MAAOuzC,IAET,IAAK,IAAI9yC,EAAI,EAAGA,EAAI4vC,EAAQhwC,SAAUI,EAAG,CACvC2B,EAASiuC,EAAQ5vC,GACjB,MAAMgzC,EAAev1C,MAAK,EAAQkE,GAE9BmxC,IAAkBE,IAEpBD,EAAeryC,KAAK,CAClBqK,MAAO/K,EACPT,MAAOyzC,IAETF,EAAgBE,GAGlBv1C,MAAK,EAAQkE,GAAUpC,CACzB,CACAszC,EAAoBnyC,KAAKqyC,EAC3B,CAGA,OADAt1C,MAAK,GAAW,CAAC0hB,KAAM,uBAChB0zB,CACT,CAUAI,wBAAAA,CAAyBL,EAAcrzC,GACrC,MAAM2zC,EAAer2B,MAAMwhB,QAAQ9+B,GAEnC,IAAK,IAAIsB,EAAI,EAAGA,EAAI+xC,EAAahzC,SAAUiB,EAAG,CAC5C,MAAM+uC,EAAUgD,EAAa/xC,GAC7B,IAAI6f,EAIFA,EAAWuC,GAHTiwB,EAIA3zC,EAAMsB,GAIN,CAAC,CAACkK,MAAO,EAAGxL,MAAOA,IAJTqwC,EAAQhwC,QAQtB,IAAI+gB,EAAOD,EAASH,OACpB,MAAQI,EAAKH,MAAM,CACjB,MAAM7e,EAASiuC,EAAQjvB,EAAK5V,OAC5BtN,MAAK,EAAQkE,GAAUgf,EAAKphB,MAC5BohB,EAAOD,EAASH,MAClB,CACF,CAQA9iB,MAAK,GAAW,CAAC0hB,KAAM,sBACzB,CAYAzd,QAAAA,CAAS1B,EAAGa,EAAGqJ,EAAG6U,GAChB,MACMhU,EAAQ,IAAIvL,EAAM,CAACQ,EAAGa,EAAGqJ,EADhB6U,GAAK,IAEpB,OAAOthB,KAAKgkB,iBACVhkB,KAAKwjB,cAAcC,UAAUK,cAAcxW,GAC/C,CASAooC,eAAAA,CAAgBpoC,GACd,OAAOtN,KAAKgkB,iBACVhkB,KAAKwjB,cAAcC,UAAUK,cAAcxW,GAC/C,CAYAqoC,gBAAAA,CAAiBpzC,EAAGa,EAAGqJ,EAAG6U,QACP,IAANA,IACTA,EAAI,GAEN,IAAIjf,EAAMrC,KAAKiE,SAAS1B,EAAGa,EAAGqJ,EAAG6U,GACjC,IAAKthB,KAAK2xC,gBACR,GAAI3xC,KAAKyxC,gBACPpvC,EAAMrC,KAAKwxC,8BAA8B1tC,MAAMzB,OAC1C,CACL,MACMiL,EAAQ,IAAIvL,EADH,CAACQ,EAAGa,EAAGqJ,EAAG6U,IAEzBjf,EAAMrC,KAAKwxC,4BAA4BlkC,GAAOxJ,MAAMzB,EACtD,CAEF,OAAOA,CACT,CASAuzC,uBAAAA,CAAwBtoC,GACtB,OAAOtN,KAAK+jB,yBACV/jB,KAAKwjB,cAAcC,UAAUK,cAAcxW,GAE/C,CASAyW,wBAAAA,CAAyB7f,GACvB,IAAI7B,EAAMrC,KAAKgkB,iBAAiB9f,GAChC,IAAKlE,KAAK2xC,gBACR,GAAI3xC,KAAKyxC,gBACPpvC,EAAMrC,KAAKwxC,8BAA8B1tC,MAAMzB,OAC1C,CACL,MAAMiL,EAAQtN,KAAKwjB,cAAcC,UAAU6C,cAAcpiB,GACzD7B,EAAMrC,KAAKwxC,4BAA4BlkC,GAAOxJ,MAAMzB,EACtD,CAEF,OAAOA,CACT,CAQAmyC,kBAAAA,GACE,IAAI7tB,EAAM3mB,KAAKgkB,iBAAiB,GAC5B3W,EAAMsZ,EACN7kB,EAAQ,EACZ,MAAMuE,EAAOrG,KAAKwjB,cAAcC,UAChC,IAAI3gB,EAAOuD,EAAK8f,eAEZ9f,EAAKlE,UAAY,IACnBW,EAAOuD,EAAKge,WAAW,IAEzB,IAAK,IAAI9hB,EAAI,EAAGA,EAAIO,IAAQP,EAC1BT,EAAQ9B,KAAKgkB,iBAAiBzhB,GAC1BT,EAAQuL,IACVA,EAAMvL,GAEJA,EAAQ6kB,IACVA,EAAM7kB,GAIV,MAAO,CAAC6kB,IAAKA,EAAKtZ,IAAKA,EACzB,CAQAonC,0BAAAA,GACE,GAAIz0C,KAAK2xC,gBACP,OAAO3xC,KAAKizC,eACP,GAAIjzC,KAAKyxC,gBAAiB,CAC/B,MAAMvvB,EAAQliB,KAAKizC,eACb4C,EAAS71C,KAAKwxC,8BAA8B1tC,MAAMoe,EAAMyE,KACxDmvB,EAAS91C,KAAKwxC,8BAA8B1tC,MAAMoe,EAAM7U,KAC9D,MAAO,CACLsZ,IAAOkvB,EAASC,EAAUD,EAASC,EACnCzoC,IAAOwoC,EAASC,EAAUD,EAASC,EAEvC,CAAO,CACL,IAAIC,EAAO/1C,KAAK+jB,yBAAyB,GACrCiyB,EAAOD,EACPE,EAAS,EACb,MAAM5vC,EAAOrG,KAAKwjB,cAAcC,UAChC,IAAI3gB,EAAOuD,EAAK8f,eAEM,IAAlB9f,EAAKlE,WACPW,EAAOuD,EAAKge,WAAW,IAEzB,IAAK,IAAI9hB,EAAI,EAAGA,EAAIO,IAAQP,EAC1B0zC,EAASj2C,KAAK+jB,yBAAyBxhB,GACnC0zC,EAASD,IACXA,EAAOC,GAELA,EAASF,IACXA,EAAOE,GAIX,MAAO,CAACtvB,IAAKovB,EAAM1oC,IAAK2oC,EAC1B,CACF,CAOArB,kBAAAA,GACE,MAAMtuC,EAAOrG,KAAKwjB,cAAcC,UAC1ByyB,EAAQ,GACd,IAAIvvB,EAAM3mB,KAAKgkB,iBAAiB,GAC5B3W,EAAMsZ,EACN7kB,EAAQ,EACRi0C,EAAO/1C,KAAK+jB,yBAAyB,GACrCiyB,EAAOD,EACPE,EAAS,EACb,IAAK,IAAI1zC,EAAI,EAAGO,EAAOuD,EAAK8f,eAAgB5jB,EAAIO,IAAQP,EACtDT,EAAQ9B,KAAKgkB,iBAAiBzhB,GAC1BT,EAAQuL,IACVA,EAAMvL,GAEJA,EAAQ6kB,IACVA,EAAM7kB,GAERm0C,EAASj2C,KAAK+jB,yBAAyBxhB,GACnC0zC,EAASD,IACXA,EAAOC,GAELA,EAASF,IACXA,EAAOE,GAETC,EAAMD,IAAWC,EAAMD,IAAW,GAAK,EAGzC,MAAMrB,EAAY,CAACjuB,IAAKA,EAAKtZ,IAAKA,GAC5BwnC,EAAoB,CAACluB,IAAKovB,EAAM1oC,IAAK2oC,GAErClB,EAAY,GAClB,IAAK,IAAI5sC,EAAI6tC,EAAM7tC,GAAK8tC,IAAQ9tC,EAC9B4sC,EAAU7xC,KAAK,CAACiF,EAAIguC,EAAMhuC,IAAM,IAGlC,MAAO,CACL0sC,UAAWA,EACXC,kBAAmBA,EACnBC,UAAWA,EAEf,CAUAqB,WAAAA,CAAYC,GACV,GAAuB,IAAnBA,EAAQj0C,OACV,MAAM,IAAID,MACR,8DACAk0C,EAAQj0C,QAGZ,MAAMk0C,EAAWr2C,KAAK23B,QAChBpW,EAAY80B,EAAStY,YAErBuY,EAAUt2C,KAAKwjB,cAAcC,UAC7B8yB,EAAYD,EAAQjyB,WAAW,GAAKrkB,KAAKukB,wBAC/C,IAAK,IAAI9X,EAAI,EAAGA,EAAI6pC,EAAQj1C,IAAI,KAAMoL,EACpCzM,KAAKw2C,gBAAgBJ,EAAS70B,EAAW9U,EAAI8pC,GAG/C,OAAOF,CACT,CAWAG,eAAAA,CACEJ,EAASjjC,EAAQiF,GACjB,MAAMk+B,EAAUt2C,KAAKwjB,cAAcC,UAC7BQ,EAAQqyB,EAAQj1C,IAAI,GACpB6iB,EAAQoyB,EAAQj1C,IAAI,GACpBijB,EAAQtkB,KAAKukB,wBAGnB,IAAIpT,EAAS,EACTslC,EAAkB,EACR,IAAVnyB,IACoC,IAAlCtkB,KAAKykB,yBACPtT,EAAS,EAETslC,EAAkBH,EAAQjyB,WAAW,IAQzC,MAAMqyB,EAAO,GACbA,EAAK,KAAOzyB,EAAQ,GAAK9S,EACzBulC,EAAK,IAAOzyB,EAAS9S,EACrBulC,EAAK,IAAe,EAARzyB,GAAa9S,EACzBulC,EAAK,IAAMvlC,EACXulC,EAAK,GAAK,EACVA,EAAK,GAAK,EAAIvlC,EACdulC,EAAK,IAAMzyB,EAAQ,GAAK9S,EACxBulC,EAAK,GAAMzyB,EAAS9S,EACpBulC,EAAK,IAAMzyB,EAAQ,GAAK9S,EAMxB,MAAMwlC,EAAS,GACfA,EAAO,GAAKD,EAAK,GAAIC,EAAO,GAAKD,EAAK,GAAIC,EAAO,GAAKD,EAAK,GAC3DC,EAAO,GAAKD,EAAK,GAAIC,EAAO,GAAKD,EAAK,GAAIC,EAAO,GAAKD,EAAK,GAC3DC,EAAO,GAAKD,EAAK,GAAIC,EAAO,GAAKD,EAAK,GAAIC,EAAO,GAAKD,EAAK,GAE3D,MAAME,EAAS,GACfA,EAAO,GAAKF,EAAK,GAAIE,EAAO,GAAKF,EAAK,GAAIE,EAAO,GAAKF,EAAK,GAC3DE,EAAO,GAAKF,EAAK,GAAIE,EAAO,GAAKF,EAAK,GAAIE,EAAO,GAAKF,EAAK,GAC3DE,EAAO,GAAKF,EAAK,GAAIE,EAAO,GAAKF,EAAK,GAAIE,EAAO,GAAKF,EAAK,GAE3D,MAAMG,EAAS,GACfA,EAAO,GAAKH,EAAK,GAAIG,EAAO,GAAKH,EAAK,GAAIG,EAAO,GAAKH,EAAK,GAC3DG,EAAO,GAAKH,EAAK,GAAIG,EAAO,GAAKH,EAAK,GAAIG,EAAO,GAAKH,EAAK,GAC3DG,EAAO,GAAKH,EAAK,GAAIG,EAAO,GAAKH,EAAK,GAAIG,EAAO,GAAKH,EAAK,GAG3D,MAAMI,EAAS,GACfA,EAAO,GAAKJ,EAAK,GAAII,EAAO,GAAKJ,EAAK,GAAII,EAAO,GAAKJ,EAAK,GAC3DI,EAAO,GAAKJ,EAAK,GAAII,EAAO,GAAKJ,EAAK,GAAII,EAAO,GAAKJ,EAAK,GAC3DI,EAAO,GAAKJ,EAAK,GAAII,EAAO,GAAKJ,EAAK,GAAII,EAAO,GAAKJ,EAAK,GAG3D,MAAMK,EAAS,GACfA,EAAO,GAAKL,EAAK,GAAIK,EAAO,GAAKL,EAAK,GAAIK,EAAO,GAAKL,EAAK,GAC3DK,EAAO,GAAKL,EAAK,GAAIK,EAAO,GAAKL,EAAK,GAAIK,EAAO,GAAKL,EAAK,GAC3DK,EAAO,GAAKL,EAAK,GAAIK,EAAO,GAAKL,EAAK,GAAIK,EAAO,GAAKL,EAAK,GAG3D,MAAMM,EAAS,GACfA,EAAO,GAAKN,EAAK,GAAIM,EAAO,GAAKN,EAAK,GAAIM,EAAO,GAAKN,EAAK,GAC3DM,EAAO,GAAKN,EAAK,GAAIM,EAAO,GAAKN,EAAK,GAAIM,EAAO,GAAKN,EAAK,GAC3DM,EAAO,GAAKN,EAAK,GAAIM,EAAO,GAAKN,EAAK,GAAIM,EAAO,GAAKN,EAAK,GAE3D,MAAMO,EAAS,GACfA,EAAO,GAAKP,EAAK,GAAIO,EAAO,GAAKP,EAAK,GAAIO,EAAO,GAAKP,EAAK,GAC3DO,EAAO,GAAKP,EAAK,GAAIO,EAAO,GAAKP,EAAK,GAAIO,EAAO,GAAKP,EAAK,GAC3DO,EAAO,GAAKP,EAAK,GAAIO,EAAO,GAAKP,EAAK,GAAIO,EAAO,GAAKP,EAAK,GAE3D,MAAMQ,EAAS,GACfA,EAAO,GAAKR,EAAK,GAAIQ,EAAO,GAAKR,EAAK,GAAIQ,EAAO,GAAKR,EAAK,GAC3DQ,EAAO,GAAKR,EAAK,GAAIQ,EAAO,GAAKR,EAAK,GAAIQ,EAAO,GAAKR,EAAK,GAC3DQ,EAAO,GAAKR,EAAK,GAAIQ,EAAO,GAAKR,EAAK,GAAIQ,EAAO,GAAKR,EAAK,GAM3D,IAAIS,EAAc/+B,EACdg/B,EAAW,EACXC,EAAY,GAChB,IAAK,IAAItxC,EAAI,EAAGA,EAAIue,IAASve,EAAG,CAE9BoxC,GAAepxC,EAAI0wC,EACnB,IAAK,IAAIrzC,EAAI,EAAGA,EAAI8gB,IAAS9gB,EAC3B,IAAK,IAAIb,EAAI,EAAGA,EAAI0hB,IAAS1hB,EAAG,CAC9B80C,EAAYX,EAEF,IAANn0C,GAAiB,IAANa,EACbi0C,EAAYV,EACG,IAANp0C,GAAWa,IAAO8gB,EAAQ,EACnCmzB,EAAYR,EACHt0C,IAAO0hB,EAAQ,GAAY,IAAN7gB,EAC9Bi0C,EAAYL,EACHz0C,IAAO0hB,EAAQ,GAAM7gB,IAAO8gB,EAAQ,EAC7CmzB,EAAYH,EACG,IAAN30C,GAAWa,IAAO8gB,EAAQ,GAAY,IAAN9gB,EACzCi0C,EAAYT,EACHr0C,IAAO0hB,EAAQ,GAAM7gB,IAAO8gB,EAAQ,GAAY,IAAN9gB,EACnDi0C,EAAYJ,EACG,IAAN10C,GAAWA,IAAO0hB,EAAQ,GAAY,IAAN7gB,EACzCi0C,EAAYP,EACG,IAANv0C,GAAWA,IAAO0hB,EAAQ,GAAM7gB,IAAO8gB,EAAQ,IACxDmzB,EAAYN,GAIdK,EAAW,EACX,IAAK,IAAIE,EAAK,EAAGA,EAAK,IAAKA,EACzBF,GAAYp3C,KAAKgkB,iBACfmzB,EAAcE,EAAUC,IAAOlB,EAAQkB,GAE3CnkC,EAAOgkC,GAAeC,EAEtBD,GAAehmC,CACjB,CAEJ,CACF,CAUAomC,SAAAA,CAAUC,GACR,MAAMnB,EAAWr2C,KAAK23B,QAChBpW,EAAY80B,EAAStY,YAC3B,IAAK,IAAIx7B,EAAI,EAAGO,EAAOye,EAAUpf,OAAQI,EAAIO,IAAQP,EACnDgf,EAAUhf,GAAKi1C,EAASnB,EAASryB,iBAAiBzhB,IAEpD,OAAO8zC,CACT,CAWAoB,OAAAA,CAAQ70C,EAAK40C,GACX,MAAMnB,EAAWr2C,KAAK23B,QAChBpW,EAAY80B,EAAStY,YAC3B,IAAK,IAAIx7B,EAAI,EAAGO,EAAOye,EAAUpf,OAAQI,EAAIO,IAAQP,EAGnDgf,EAAUhf,GAAKoB,KAAKiD,MAClB4wC,EAASx3C,KAAKgkB,iBAAiBzhB,GAAIK,EAAIohB,iBAAiBzhB,KAG5D,OAAO8zC,CACT,ECviDK,MAAMqB,GASXxkB,MAAAA,CAAOtE,EAAcxL,GAEnB,MAAMu0B,EAAO,IAAIC,GAAKx0B,GAGuB,gBAAzCA,EAAM4M,gCACR2nB,EAAKE,aAAa,YAIpB,IAAIjhB,EAAgB,CAAC,EAYrB,QAV6C,IAAlCxT,EAAMgrB,UAAUxX,gBACzBA,EAAgBxT,EAAMgrB,UAAUxX,eAOlCA,EAAckhB,OAAS,CAACtuC,KAAM,eAEA,IAAnBnE,EAAgC,CACzC,MAAMmqB,EAAWpM,EAAMgrB,UAAU3Z,SACjC,IAAK,MAAMzzB,KAAOqE,EAAemqB,GAAW,CAC1C,MAAMuoB,EAAS1yC,EAAemqB,GAAUxuB,GACxC41B,EAAc51B,GAAO,CACnB6E,GAAI,CAAC,IAAIX,EAAY6yC,EAAO5yC,OAAQ4yC,EAAO3yC,QAC3CoE,KAAMxI,EAEV,CACF,CAQA,OALA22C,EAAKK,iBAAiBphB,GAGtB+gB,EAAKM,OAEEN,CACT,EC9BK,MAAMO,GAAiB,CAC5B,WACA,cACA,kBACA,iBACA,gBACA,mBAUK,SAASC,GAAWl4B,EAAUmD,GAEnC,OADgB,IAAIs0B,IACLxkB,OAAOjT,EAAUmD,EAClC,CAuCO,MAAMw0B,GAOX,IAOA,IAOA,IAQA,IAAiB,CAACE,OAAQ,CAACtuC,KAAM,WAOjC,IAAqB,KAOrB,IAOA,IAAiB,QAQjB,IAAmB,KAOnB,GAOA,IAAmB,IAAIiY,GAKvBzf,WAAAA,CAAYohB,GACVpjB,MAAK,GAASojB,EAIdpjB,MAAK,GAAO+0C,iBAAiB,eAAe,KAE1C,MAAMznC,EAAQtN,KAAKo4C,kBACnB,GAAuB,IAAnB9qC,EAAMnL,SAAgB,CAExB,MAAMF,EAASqL,EAAM7K,YACrBR,EAAOgB,KAAK,GACZjD,KAAKq4C,gBAAgB,IAAIt2C,EAAME,GACjC,IAEJ,CAOAq2C,QAAAA,GACE,OAAOt4C,MAAK,EACd,CAOAu4C,QAAAA,CAASC,GACPx4C,MAAK,GAASw4C,CAChB,CAOA/uB,cAAAA,GACE,OAAOzpB,MAAK,CACd,CAOAy4C,cAAAA,CAAe3qC,GACb9N,MAAK,EAAe8N,CACtB,CAKAmqC,IAAAA,GACEj4C,KAAK04C,iBACP,CAKAA,eAAAA,GACE,MACMryC,EADWrG,MAAK,GAAOwjB,cACPC,UAChBxhB,EAAS,IAAImd,MAAM/Y,EAAKlE,UAC9BF,EAAOqrC,KAAK,GAEZrrC,EAAO,GAAK0B,KAAKiD,MAAMP,EAAKhF,IAAI,GAAK,GACrCY,EAAO,GAAK0B,KAAKiD,MAAMP,EAAKhF,IAAI,GAAK,GACrCY,EAAO,GAAK0B,KAAKiD,MAAMP,EAAKhF,IAAI,GAAK,GACrCrB,KAAKq4C,gBAAgB,IAAIt2C,EAAME,IAAS,EAC1C,CAQA02C,uBAAAA,CAAwB9gB,GAMtB,OALKA,IAEHA,EAA8B,IAGzBl0B,KAAK0N,MAAM,IAAOwmB,EAC3B,CAUA,IAAiB,SAAU+gB,EAAQC,GAEjC,OAAO,GACT,EAcAC,gBAAAA,GACE,OAAO94C,MAAK,EACd,CAQA+4C,gBAAAA,CAAiBjyC,GACf9G,MAAK,GAAiB8G,EAQtB9G,MAAK,GAAW,CACd0hB,KAAM,mBAEV,CASA,MAEE,GAAI1hB,MAAK,SACiD,IAAjDA,MAAK,GAAeA,MAAK,UAE9B,IADKA,MAAK,GAAeA,MAAK,IAAoBm0C,WAEM,IAA1Dn0C,MAAK,GAAeA,MAAK,IAAoBm0C,SAAmB,CAE3Dn0C,KAAKo4C,mBACRp4C,KAAK04C,kBAGP,MAAMM,EAAeh5C,KAAKo4C,kBACpBl0C,EAASlE,MAAK,GAAO8wC,mBAAmBkI,GAExCC,EADgBj5C,MAAK,GAAeA,MAAK,IACjB6F,GAAG3B,GAGjClE,KAAKk5C,eAAeD,EAASj5C,MAAK,IAAoB,EACxD,CAQA,QAL+B,IAApBA,MAAK,IACdA,KAAKm5C,yBAAyB,GAAG,QAIA,IAAxBn5C,MAAK,IACdA,MAAK,GAAOyxC,kBAAoBzxC,MAAK,GAAgB,CAKrD,IAAIwD,EACA4C,EALJpG,MAAK,GAAiBA,MAAK,GAAOyxC,gBAM9BzxC,MAAK,IACPwD,EAAMxD,MAAK,GAAOwxC,8BAClBprC,GAAa,IAEb5C,EAAM,IAAIkiB,GAAyB,EAAG,GACtCtf,GAAa,GAGf,MAAMF,EAAc,IAAI3C,EACtBC,EACAxD,MAAK,GAAOouC,UAAU/Y,YAExBr1B,MAAK,GAAa,IAAIiG,EACpBC,EACAlG,MAAK,GAAOouC,UAAU5X,SACtBpwB,EACJ,CAIA,MAAMgzC,EAASp5C,MAAK,GAAWsG,YAC/B,IAAI+yC,EAIJ,QAHsB,IAAXD,IACTC,EAAWD,EAAOtzC,uBAEE,IAAXszC,IACRp5C,MAAK,GAAW6C,OAAOw2C,GAAW,CAEnC,MAAMD,EAAS,IAAIxzC,EAAO5F,MAAK,IAC/BA,MAAK,GAAWwG,UAAU4yC,EAC5B,CAGA,OAAOp5C,MAAK,EACd,CAOAs5C,gBAAAA,GACE,OAAOt5C,MAAK,EACd,CAOAu5C,qBAAAA,GACE,OAAOr4C,OAAO4R,KAAK9S,MAAK,GAC1B,CAOAg4C,gBAAAA,CAAiBwB,GACfx5C,MAAK,GAAiBw5C,CACxB,CAOAC,gBAAAA,CAAiBD,GACf,MAAM1mC,EAAO5R,OAAO4R,KAAK0mC,GACzB,IAAIx4C,EAAM,KACV,IAAK,IAAIuB,EAAI,EAAGA,EAAIuQ,EAAK3Q,SAAUI,EAEjC,GADAvB,EAAM8R,EAAKvQ,QAC6B,IAA7BvC,MAAK,GAAegB,GAAsB,CACnD,QAAiD,IAAtChB,MAAK,GAAegB,GAAKmzC,WACI,IAAtCn0C,MAAK,GAAegB,GAAKmzC,SACzB,MAAM,IAAIjyC,MAAM,8BAGhBlC,MAAK,GAAegB,GAAOw4C,EAAQx4C,EAEvC,MAEEhB,MAAK,GAAegB,GAAOw4C,EAAQx4C,GAUnChB,MAAK,GAAW,CACd0hB,KAAM,cACNlY,KAAMxI,GAId,CAOA04C,0BAAAA,GACE,OAAO15C,MAAK,EACd,CAOA25C,YAAAA,GACE,OAAO35C,MAAK,EACd,CAOA,MACE,OAAOsH,EAAKtH,MAAK,GACnB,CAQA63C,YAAAA,CAAaruC,GAEX,IAAKlC,EAAKkC,GACR,MAAM,IAAItH,MAAM,wBAA2BsH,EAAO,KAGpDxJ,MAAK,GAAiBwJ,EAUtBxJ,MAAK,GAAW,CACd0hB,KAAM,kBACN5f,MAAO,CAAC0H,IAEZ,CAOAowC,kBAAAA,GACE,OAAO55C,MAAK,EACd,CAOAo4C,eAAAA,GACE,MAAM/0B,EAAWrjB,KAAK45C,qBACtB,OAAKv2B,EAGYrjB,KAAKs4C,WAAW90B,cACjB+G,aAAalH,GAHpB,IAIX,CAOAw2B,kBAAAA,GACE,OAAO75C,MAAK,GAAO4vC,YAAY5vC,KAAKo4C,kBACtC,CAQArH,oBAAAA,CAAqBlW,GACnB,OAAO76B,MAAK,GAAO+wC,qBAAqBlW,EAC1C,CAQAoW,gBAAAA,CAAiBpW,GACf,OAAO76B,MAAK,GAAOixC,iBAAiBpW,EACtC,CASAif,kBAAAA,CAAmBz2B,QACO,IAAbA,IACTA,EAAWrjB,MAAK,IAElB,MAAM8zB,EAAW9zB,MAAK,GAAOwjB,cACvBlW,EAAQwmB,EAASvJ,aAAalH,GAC9BgD,EAAO,CAACrmB,KAAK+5C,kBAInB,OAHuB,IAAnBzsC,EAAMnL,UACRkkB,EAAKpjB,KAAK,GAEL6wB,EAASxJ,gBAAgBhd,EAAO+Y,EACzC,CAQAsC,SAAAA,CAAUtF,GACR,MAAMyQ,EAAW9zB,MAAK,GAAOwjB,cAC7B,IAAIw2B,EAAc,EAMlB,YALwB,IAAb32B,IAGT22B,EAFclmB,EAASvJ,aAAalH,GAEhBhiB,IAAI,IAEnByyB,EAASlL,aAAaoxB,EAC/B,CAUAC,kBAAAA,CAAmB52B,EAAU62B,GAE3B,MAAMpmB,EAAW9zB,MAAK,GAAOwjB,cACvBlW,EAAQwmB,EAASvJ,aAAalH,GAC9BgD,EAAO,CAACrmB,KAAK+5C,kBAInB,OAHuB,IAAnBzsC,EAAMnL,UACRkkB,EAAKpjB,KAAK,GAEP6wB,EAASxJ,gBAAgBhd,EAAO+Y,GAe9BrmB,KAAKq4C,gBAAgB/qC,EAAO4sC,IAd5BA,IACHl6C,MAAK,GAAmBqjB,EAExBrjB,MAAK,GAAW,CACd0hB,KAAM,iBACN5f,MAAO,CACLwL,EAAM7K,YACN4gB,EAAS5gB,aAEX03C,OAAO,MAGJ,EAGX,CAUA9B,eAAAA,CAAgB/qC,EAAO4sC,QAEC,IAAXA,IACTA,GAAS,GAGX,MAAMpmB,EAAW9zB,MAAK,GAAOwjB,cACvBH,EAAWyQ,EAAStJ,aAAald,GAGjC+Y,EAAO,CAACrmB,KAAK+5C,kBAInB,GAHuB,IAAnBzsC,EAAMnL,UACRkkB,EAAKpjB,KAAK,IAEP6wB,EAASxJ,gBAAgBhd,EAAO+Y,GAenC,OAdK6zB,IACHl6C,MAAK,GAAmBqjB,EAExBrjB,MAAK,GAAW,CACd0hB,KAAM,iBACN5f,MAAO,CACLwL,EAAM7K,YACN4gB,EAAS5gB,aAEX03C,OAAO,MAKJ,EAIT,IAAIn3C,EAAW,KACXg2C,EAAe,KAInB,GAHIh5C,KAAK45C,uBACPZ,EAAeh5C,KAAKo4C,mBAElBY,EACF,GAAIA,EAAar2C,WAAW2K,GAC1BtK,EAAWg2C,EAAaj2C,QAAQuK,OAC3B,CACLtK,EAAW,GACX,MAAMo3C,EAASz2C,KAAKgjB,IAAIqyB,EAAa72C,SAAUmL,EAAMnL,UACrD,IAAK,IAAII,EAAI,EAAGA,EAAI63C,IAAU73C,EACxBy2C,EAAa33C,IAAIkB,KAAO+K,EAAMjM,IAAIkB,IACpCS,EAASC,KAAKV,GAGlB,MAAM83C,EAAS12C,KAAK0J,IAAI2rC,EAAa72C,SAAUmL,EAAMnL,UACrD,IAAK,IAAIiB,EAAIg3C,EAAQh3C,EAAIi3C,IAAUj3C,EACjCJ,EAASC,KAAKG,EAElB,KACK,CACLJ,EAAW,GACX,IAAK,IAAIyJ,EAAI,EAAGA,EAAIa,EAAMnL,WAAYsK,EACpCzJ,EAASC,KAAKwJ,EAElB,CAKA,GAFAzM,MAAK,GAAmBqjB,GAEnB62B,EAAQ,CASX,MAAMI,EAAW,CACf54B,KAAM,iBACN5f,MAAO,CACLwL,EAAM7K,YACN4gB,EAAS5gB,aAEXO,SAAUA,EACViQ,KAAM,CACJsnC,SAAUv6C,MAAK,GAAO4vC,YAAYtiC,KAKtC,GAAItN,MAAK,GAAOqxC,cAAe,CAC7B,MAAMmJ,EAAWx6C,MAAK,GAAO41C,wBAAwBtoC,GACrDgtC,EAASx4C,MAAMmB,KAAKu3C,EACtB,CAGAx6C,MAAK,GAAWs6C,EAClB,CAGA,OAAO,CACT,CAWApB,cAAAA,CAAerzC,EAAI2D,EAAM0wC,GAKvB,QAHoB,IAAT1wC,IACTA,EAAO,UAEI,WAATA,QACmC,IAA9BxJ,MAAK,GAAewJ,GAC3B,MAAM,IAAItH,MAAM,iCAAoCsH,EAAO,UAEvC,IAAX0wC,IACTA,GAAS,GAIX,MAAMO,GAAW50C,EAAGhD,OAAO7C,MAAK,IAE1B06C,EAAY16C,MAAK,KAAuBwJ,GAG1CixC,GAAWC,KAEb16C,MAAK,GAAa6F,EAClB7F,MAAK,GAAqBwJ,EAGb,WAATA,SACuC,IAA9BxJ,MAAK,GAAewJ,GAC7BxJ,MAAK,GAAewJ,GAAM3D,GAAG,GAAKA,EAGlC7F,KAAKy5C,iBAAiB,CACpBkB,OAAQ,CACN90C,GAAI,CAACA,GACL2D,KAAM,aAiBdxJ,MAAK,GAAW,CACd0hB,KAAM,WACN5f,MAAO,CAAC+D,EAAGV,OAAQU,EAAGT,MAAOoE,GAC7BoxC,GAAI/0C,EAAGV,OACP01C,GAAIh1C,EAAGT,MACP01C,aAAcZ,IAGpB,CAOAp0C,cAAAA,GAGE,OADkB9F,MAAK,KACNsG,YAAYR,gBAC/B,CAQAi1C,oBAAAA,CAAqBvxC,EAAM0wC,GACzB,MAAMnC,EAAS/3C,KAAKs5C,mBAAmB9vC,GACvC,QAAsB,IAAXuuC,EACT,MAAM,IAAI71C,MAAM,iCAAoCsH,EAAO,KAGhD,WAATA,QAA0C,IAAduuC,EAAOlyC,KACrCkyC,EAAOlyC,GAAK,CAAC7F,KAAKg7C,yBAGpB,IAAIn1C,EAAKkyC,EAAOlyC,GAAG,GAEnB,QAA+B,IAApBkyC,EAAO5D,WACI,IAApB4D,EAAO5D,SAAmB,CAC1B,MAAMjwC,EAASlE,MAAK,GAAO8wC,mBAAmB9wC,KAAKo4C,mBACnDvyC,EAAKkyC,EAAOlyC,GAAG3B,EACjB,CAEAlE,KAAKk5C,eAAerzC,EAAI2D,EAAM0wC,EAChC,CAQAf,wBAAAA,CAAyBpyC,EAAImzC,GAC3B,MAAMpnC,EAAO5R,OAAO4R,KAAK9S,KAAKs5C,oBAC9Bt5C,KAAK+6C,qBAAqBjoC,EAAK/L,GAAKmzC,EACtC,CASAnF,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAcK,IACZhiB,MAAK,GAAiB+hB,UAAUC,EAAM,EASxCg5B,oBAAAA,GACE,MAAM94B,EAAQliB,KAAKs4C,WAAWnF,uBACxBxsB,EAAMzE,EAAMyE,IAElB,IAAIvhB,EADQ8c,EAAM7U,IACAsZ,EAOlB,OALIvhB,EAAQ,IACVjB,EAAOa,KAAK,qDACZI,EAAQ,GAGH,IAAIF,EADIyhB,EAAMvhB,EAAQ,EACEA,EACjC,CAMA61C,oBAAAA,GAEE,MAAMp1C,EAAK7F,KAAKg7C,uBAEhBh7C,KAAKk5C,eAAerzC,EAAI,SAC1B,CASAq1C,iBAAAA,CAAkBjoC,EAAM3F,QAED,IAAVA,IACJtN,KAAKo4C,mBACRp4C,KAAK04C,kBAEPprC,EAAQtN,KAAKo4C,mBAGf,MAAMh1B,EAAQpjB,KAAKs4C,WACbh1B,GAAcF,EAAMquB,gBACpBxuB,EAAWE,GACfC,EAAO9V,EAAOgW,EAAYtjB,KAAKypB,kBAE3B0xB,EAAsB/3B,EAAM4M,+BAClC,OAAQmrB,GACR,IAAK,cACL,IAAK,eC75BF,SACL3iC,EACAyK,EACAm4B,EACAC,EACAC,GACA,IAAIhuC,EAAQ,EACRiuC,EAAU,EACVr4B,EAAOD,EAASH,OACpB,MAAQI,EAAKH,MAEXw4B,EAAUF,EAAUp3C,SAASif,EAAKphB,OAElC0W,EAAMvF,KAAK3F,GAASguC,EAAUn0C,IAAIo0C,GAClC/iC,EAAMvF,KAAK3F,EAAQ,GAAKguC,EAAUl0C,MAAMm0C,GACxC/iC,EAAMvF,KAAK3F,EAAQ,GAAKguC,EAAUj0C,KAAKk0C,GACvC/iC,EAAMvF,KAAK3F,EAAQ,GAAK8tC,EAAUl4B,EAAKphB,MAAOohB,EAAK5V,OAEnDA,GAAS,EACT4V,EAAOD,EAASH,MAEpB,CDy4BM04B,CACEvoC,EACAgQ,EACAjjB,KAAK84C,mBACL94C,MAAK,KACLA,MAAK,MAEP,MAEF,IAAK,iBEt6BF,SACLwY,EACAyK,EACAm4B,EACAE,EACAG,GAEA,MAAMC,EAAM,SAAU55C,GACpB,OAAOA,GAAS,CAClB,EAEI25C,GACFt3C,EAAOY,KAAK,iCAGd,IAAIuI,EAAQ,EACRiuC,EAAU,EACVr4B,EAAOD,EAASH,OACpB,MAAQI,EAAKH,MAEXw4B,EAAUr4B,EAAKphB,MAGX25C,GACFjjC,EAAMvF,KAAK3F,GAASouC,EAAIJ,EAAUn0C,IAAIo0C,IACtC/iC,EAAMvF,KAAK3F,EAAQ,GAAKouC,EAAIJ,EAAUl0C,MAAMm0C,IAC5C/iC,EAAMvF,KAAK3F,EAAQ,GAAKouC,EAAIJ,EAAUj0C,KAAKk0C,MAE3C/iC,EAAMvF,KAAK3F,GAASguC,EAAUn0C,IAAIo0C,GAClC/iC,EAAMvF,KAAK3F,EAAQ,GAAKguC,EAAUl0C,MAAMm0C,GACxC/iC,EAAMvF,KAAK3F,EAAQ,GAAKguC,EAAUj0C,KAAKk0C,IAEzC/iC,EAAMvF,KAAK3F,EAAQ,GAAK8tC,EAAUG,EAASr4B,EAAK5V,OAEhDA,GAAS,EACT4V,EAAOD,EAASH,MAEpB,CFk4BM64B,CACE1oC,EACAgQ,EACAjjB,KAAK84C,mBACL11B,EAAMyuB,sBACyB,KAA/BzuB,EAAMgrB,UAAU/Y,YAElB,MAEF,IAAK,OGz7BF,SACL7c,EACAyK,EACAm4B,GACA,IAAI9tC,EAAQ,EACR4V,EAAOD,EAASH,OACpB,MAAQI,EAAKH,MAEXvK,EAAMvF,KAAK3F,GAAS4V,EAAKphB,MAAM,GAC/B0W,EAAMvF,KAAK3F,EAAQ,GAAK4V,EAAKphB,MAAM,GACnC0W,EAAMvF,KAAK3F,EAAQ,GAAK4V,EAAKphB,MAAM,GACnC0W,EAAMvF,KAAK3F,EAAQ,GAAK8tC,EAAUl4B,EAAKphB,MAAOohB,EAAK5V,OAEnDA,GAAS,EACT4V,EAAOD,EAASH,MAEpB,CH06BM84B,CACE3oC,EACAgQ,EACAjjB,KAAK84C,oBAEP,MAEF,IAAK,YI/7BF,SACLtgC,EACAyK,EACAm4B,GACA,IAAI9tC,EAAQ,EACRu4B,EAAM,KACN3iB,EAAOD,EAASH,OACpB,MAAQI,EAAKH,MnCuDUra,EmCrDNwa,EAAKphB,MAAM,GnCqDF+5C,EmCrDM34B,EAAKphB,MAAM,GAAzC+jC,EnCsDK,CACLlkC,EAAG+G,EAAI,QAFqBozC,EmCrDiB54B,EAAKphB,MAAM,InCuDnC,KACrBmG,EAAGS,EAAI,QAAWmzC,EAAK,KAAO,QAAWC,EAAK,KAC9C5zC,EAAGQ,EAAI,OAASmzC,EAAK,MmCvDrBrjC,EAAMvF,KAAK3F,GAASu4B,EAAIlkC,EACxB6W,EAAMvF,KAAK3F,EAAQ,GAAKu4B,EAAI59B,EAC5BuQ,EAAMvF,KAAK3F,EAAQ,GAAKu4B,EAAI39B,EAC5BsQ,EAAMvF,KAAK3F,EAAQ,GAAK8tC,EAAUl4B,EAAKphB,MAAOohB,EAAK5V,OAEnDA,GAAS,EACT4V,EAAOD,EAASH,OnC6Cb,IAAkBpa,EAAGmzC,EAAIC,CmC3ChC,CJ66BMC,CACE9oC,EACAgQ,EACAjjB,KAAK84C,oBAEP,MAEF,QACE,MAAM,IAAI52C,MACR,2CAA6Ci5C,GAEnD,CAOApB,cAAAA,GACE,IAAIzsC,EAAQ,KACZ,MAAM8a,EAAcpoB,KAAKypB,iBAMzB,OAJEnc,OADyB,IAAhB8a,EACDA,EAAYza,4BAEZ,EAEHL,CACT,CAOA0uC,uBAAAA,GACE,OAAOnuC,EAAgB7N,MAAK,EAC9B,EKv9BK,MAAMi8C,GAOX,IAOA,GAOA,IAOA,IAOA,IAMAj6C,WAAAA,CAAYk6C,EAAe34B,GACzBvjB,MAAK,GAAiBk8C,EACtBl8C,MAAK,EAAWk8C,EAAc1yB,iBAC9BxpB,MAAK,GAAoBk8C,EAAczyB,iBACvCzpB,MAAK,GAAmBujB,EAExBvjB,MAAK,GhBkMF,SAA8BsuB,EAAkB/K,GAMrD,IAAIgL,EACFD,EAAiB7gB,gBAAgBlB,SAASgX,GAQ5C,OAL+B+K,EAAiB7gB,gBAAgBf,SACrC7J,OAAO6pB,KAAkBhgB,YAClD6hB,EAAoBA,EAAkB7hB,UAGjC6hB,CACT,CgBlN8B4tB,CACxBn8C,MAAK,GAAmBujB,EAC5B,CAOA8K,kBAAAA,GACE,OAAOruB,MAAK,EACd,CAOAm8C,oBAAAA,GACE,OAAOn8C,MAAK,EACd,CAQAo8C,0BAAAA,CAA2BC,GAEzB,MAAMC,EAAc,IAAIpyC,EACtBmyC,EAAS5zC,EAAG4zC,EAAS3zC,EAAG,GAEpByuC,EAAcn3C,KAAKu8C,4BAA4BD,GAErD,OAAO,IAAIpyC,EACTitC,EAAYhtC,OAASnK,MAAK,EAASqB,IAAI,GACvC81C,EAAY/sC,OAASpK,MAAK,EAASqB,IAAI,GACvC81C,EAAY9sC,OAASrK,MAAK,EAASqB,IAAI,GAC3C,CAQAm7C,0BAAAA,CAA2BC,GAEzB,MAAMtF,EAAc,IAAIjtC,EACtBuyC,EAASh0C,EAAIzI,MAAK,EAASqB,IAAI,GAC/Bo7C,EAAS/zC,EAAI1I,MAAK,EAASqB,IAAI,GAC/Bo7C,EAAS9zC,EAAI3I,MAAK,EAASqB,IAAI,IAE3Bi7C,EAAct8C,KAAK08C,0BAA0BvF,GAEnD,MAAO,CACL1uC,EAAG6zC,EAAYnyC,OACfzB,EAAG4zC,EAAYlyC,OAEnB,CAQAsyC,yBAAAA,CAA0BrvB,GACxB,IAAIsvB,EAActvB,EAKlB,YAJuC,IAA5BrtB,MAAK,KACd28C,EACE38C,MAAK,GAAmBqL,aAAawB,iBAAiBwgB,IAEnDsvB,CACT,CAQAJ,2BAAAA,CAA4BI,GAC1B,IAAItvB,EAASsvB,EAIb,YAHuC,IAA5B38C,MAAK,KACdqtB,EAASrtB,MAAK,GAAmB6M,iBAAiB8vC,IAE7CtvB,CACT,CAQAuvB,0BAAAA,CAA2BC,GACzB,IAAIlzB,EAAQkzB,EAIZ,YAHuC,IAA5B78C,MAAK,KACd2pB,EAAQ3pB,MAAK,GAAmB8M,gBAAgB+vC,IAE3ClzB,CACT,CAQAmzB,wBAAAA,CAAyBH,GACvB,IAAItvB,EAASsvB,EACb,QAAqC,IAA1B38C,MAAK,GAAkC,CAEhD,MAAMiC,EAAS2oB,GACb,CACE+xB,EAAYxyC,OACZwyC,EAAYvyC,OACZuyC,EAAYtyC,QAEdrK,MAAK,IACPqtB,EAAS,IAAInjB,EACXjI,EAAO,GACPA,EAAO,GACPA,EAAO,GAEX,CACA,OAAOorB,CACT,CAQA0vB,uBAAAA,CAAwBF,GACtB,IAAIlzB,EAAQkzB,EACZ,QAAqC,IAA1B78C,MAAK,GAAkC,CAEhD,MAAMiC,EAAS2oB,GACb,CACEiyB,EAAW1yC,OACX0yC,EAAWzyC,OACXyyC,EAAWxyC,QAEbrK,MAAK,IACP2pB,EAAQ,IAAI3c,EACV/K,EAAO,GACPA,EAAO,GACPA,EAAO,GAEX,CACA,OAAO0nB,CACT,CAQAqzB,0BAAAA,CAA2B3vB,GACzB,IAAIsvB,EAActvB,EAClB,QAAqC,IAA1BrtB,MAAK,GAAkC,CAEhD,MAAMupB,EAAiBT,GACrB,CACEuE,EAAOljB,OACPkjB,EAAOjjB,OACPijB,EAAOhjB,QAETrK,MAAK,IACP28C,EAAc,IAAIzyC,EAChBqf,EAAe,GACfA,EAAe,GACfA,EAAe,GAEnB,CACA,OAAOozB,CACT,CAQAM,yBAAAA,CAA0BtzB,GACxB,IAAIkzB,EAAalzB,EACjB,QAAqC,IAA1B3pB,MAAK,GAAkC,CAEhD,MAAMupB,EAAiBT,GACrB,CACEa,EAAMxf,OACNwf,EAAMvf,OACNuf,EAAMtf,QAERrK,MAAK,IACP68C,EAAa,IAAI7vC,EACfuc,EAAe,GACfA,EAAe,GACfA,EAAe,GAEnB,CACA,OAAOszB,CACT,CASAK,yBAAAA,CAA0BhvC,EAASzB,GACjC,MAAMowC,EAAa,IAAI7vC,EAAQkB,EAAQ/D,OAAQ+D,EAAQ9D,OAAQqC,GAEzDkd,EAAQ3pB,KAAK+8C,wBAAwBF,GAE3C,OAAO78C,MAAK,GAAe0qB,aAAaf,EAC1C,CAQAwzB,yBAAAA,CAA0BxzB,GACxB,MAAM5c,EAAU/M,MAAK,GAAe2qB,aAAahB,GACjD,OAAO3pB,KAAKi9C,0BAA0BlwC,EACxC,CAOAqwC,UAAAA,GACE,MhBxFK,EADiCpwB,EgByFLhtB,MAAK,IhBvF/BqB,IAAI,EAAG,GACd2rB,EAAO3rB,IAAI,EAAG,GACd2rB,EAAO3rB,IAAI,EAAG,GACd2rB,EAAO3rB,IAAI,EAAG,GACd2rB,EAAO3rB,IAAI,EAAG,GACd2rB,EAAO3rB,IAAI,EAAG,IAPX,IAAmC2rB,CgB0FxC,CASAqwB,cAAAA,CAAeh6B,GAEb,MAAMw5B,EAAa78C,KAAKm9C,0BAA0B95B,GAE5Ci6B,EAAct9C,KAAKk9C,0BACvB,IAAInvC,EAAQ,EAAG,GAAI8uC,EAAWxyC,QAG1BsjB,EAAU3tB,KAAKo9C,aAErB,MAAO,CACLE,EACA,IAAItwC,EAAQ2gB,EAAQ,GAAIA,EAAQ,GAAIA,EAAQ,IAC5C,IAAI3gB,EAAQ2gB,EAAQ,GAAIA,EAAQ,GAAIA,EAAQ,IAEhD,CAQApD,YAAAA,CAAaZ,GACX,OAAO3pB,MAAK,GAAeuqB,aAAaZ,EAC1C,CAOAqyB,uBAAAA,GACE,OAAOnuC,EAAgB7N,MAAK,GAC9B,CAQAu9C,4BAAAA,CAA6Bt7C,GAC3B,MAAMsnB,EAAiBT,GACrB,CACE7mB,EAAOwG,EACPxG,EAAOyG,EACPzG,EAAO0G,GAET3I,MAAK,IACP,MAAO,CACLyI,EAAG8gB,EAAe,GAClB7gB,EAAG6gB,EAAe,GAClB5gB,EAAG4gB,EAAe,GAEtB,CAOAwwB,cAAAA,GACE,IAAIzsC,EAAQ,KAMZ,OAJEA,OADmC,IAA1BtN,MAAK,GACNA,MAAK,GAAiB2N,4BAEtB,EAEHL,CACT,CAOAkwC,oBAAAA,GACE,IAAIlwC,EAAQ,KAMZ,OAJEA,OADoC,IAA3BtN,MAAK,GACNA,MAAK,GAAkB2N,4BAEvB,EAEHL,CACT,ECxXK,MAAMmwC,GAOX,GAOA,IAOA,IAOA,KAAU,EAKVz7C,WAAAA,CAAY21C,GAEV,QAA+B,IAApBA,EAAKW,WACd,MAAM,IAAIp2C,MAAM,wDAGlBlC,MAAK,EAAQ23C,EAGb33C,MAAK,GAAe,IAAIi8C,GACtBtE,EAAKW,WAAW90B,cAChBm0B,EAAKluB,kBAIoC,QAAvCkuB,EAAKW,WAAWlK,UAAU3Z,WAC5Bz0B,MAAK,IAAU,EAEnB,CAOA09C,cAAAA,GACE,OAAO19C,MAAK,EACd,CAOA29C,MAAAA,GACE,OAAO39C,MAAK,EACd,CAKA49C,UAAAA,GAEE59C,KAAKm5C,yBAAyB,GAE9Bn5C,KAAKi6C,mBAAmBj6C,KAAKk9C,0BAC3B,IAAInvC,EAAQ,EAAG,IAEnB,CAOA8vC,WAAAA,GACE,OAAO79C,MAAK,EAAMs4C,WAAWlK,UAAU3Z,QACzC,CAOAqpB,0BAAAA,GACE,OAAO99C,MAAK,EAAMu5C,uBACpB,CAQAwE,qBAAAA,CAAsBvE,GACpB,OAAOx5C,MAAK,EAAMy5C,iBAAiBD,EACrC,CAOAuB,oBAAAA,CAAqBvxC,GACnBxJ,MAAK,EAAM+6C,qBAAqBvxC,EAClC,CAOA2vC,wBAAAA,CAAyBpyC,GACvB/G,MAAK,EAAMm5C,yBAAyBpyC,EACtC,CAOAi3C,SAAAA,GACE,YAAkC,IAAnBh+C,MAAK,EACtB,CAOA45C,kBAAAA,GACE,OAAO55C,MAAK,EAAM45C,oBACpB,CAOAxB,eAAAA,GACE,OAAOp4C,MAAK,EAAMo4C,iBACpB,CAOAyB,kBAAAA,GACE,OAAO75C,MAAK,EAAM65C,oBACpB,CAQA9I,oBAAAA,CAAqBlW,GACnB,OAAO76B,MAAK,EAAM+wC,qBAAqBlW,EACzC,CAQAoW,gBAAAA,CAAiBpW,GACf,OAAO76B,MAAK,EAAMixC,iBAAiBpW,EACrC,CAOAojB,uBAAAA,GACE,IAAIn1C,EAAM9I,MAAK,EAAMo4C,kBACrB,QAA2C,IAAhCp4C,MAAK,EAAMypB,iBAAkC,CAEtD,MAAM4D,EAASrtB,MAAK,GAAag9C,2BAC/B,IAAI9yC,EAASpB,EAAIzH,IAAI,GAAIyH,EAAIzH,IAAI,GAAIyH,EAAIzH,IAAI,KAE/CyH,EAAM,IAAI/G,EAAM,CACdsrB,EAAOljB,OAAQkjB,EAAOjjB,OAAQijB,EAAOhjB,QAEzC,CACA,OAAOvB,CACT,CAOAixC,cAAAA,GACE,OAAO/5C,MAAK,EAAM+5C,gBACpB,CAOAmE,0BAAAA,GACE,OAAOl+C,MAAK,EAAMo4C,kBAAkB/2C,IAAIrB,MAAK,EAAM+5C,iBACrD,CAQApxB,SAAAA,CAAUtF,GACR,OAAOrjB,MAAK,EAAM2oB,UAAUtF,EAC9B,CAOA24B,uBAAAA,GACE,OAAOh8C,MAAK,EAAMg8C,yBACpB,CASAqB,cAAAA,CAAeh6B,GACb,OAAOrjB,MAAK,GAAaq9C,eAAeh6B,EAC1C,CAOA86B,wBAAAA,GACE,MAAMC,EAAcp+C,MAAK,EAAM+5C,iBAC/B,OAAO/5C,MAAK,EAAM45C,qBAAqBv4C,IAAI+8C,EAC7C,CASAlD,iBAAAA,CAAkB1iC,EAAOlL,GACvBtN,MAAK,EAAMk7C,kBAAkB1iC,EAAOlL,EACtC,CAOAirC,QAAAA,CAAS8F,GACPr+C,MAAK,EAAMu4C,SAAS8F,EACtB,CAOAC,YAAAA,GAGE,OAFgBt+C,MAAK,EAAMs4C,WAAW90B,cAAc8F,WAClDtpB,MAAK,EAAMypB,kBACEhD,OACjB,CASA83B,qBAAAA,CAAsBl7B,GACpB,MAAMD,EAAQpjB,MAAK,EAAMs4C,WACzB,IAAKl1B,EAAMiuB,cACT,OAEF,MAAMvd,EAAW1Q,EAAMI,cACjBlW,EAAQwmB,EAASvJ,aAAalH,GACpC,IAAIvhB,EAIJ,OAHIgyB,EAASxJ,gBAAgBhd,KAC3BxL,EAAQshB,EAAMwyB,wBAAwBtoC,IAEjCxL,CACT,CAOA60B,YAAAA,GACE,OAAO32B,MAAK,EAAMs4C,WAAWlK,UAAU3X,SACzC,CAWA,IAAUrT,EAAO9V,EAAOgW,EAAY8E,GAElC,MAMMo2B,EAAcx7B,GANFG,GAChBC,EACA9V,EACAgW,EACA8E,IAKIgC,EADehH,EAAMI,cAAcC,QAAQ2E,GACjB3lB,YAChC2nB,EAAW,GAAK,EAChB,MAAMhG,EAAY,IAAI0B,GAAKsE,GAErBC,EADkBjH,EAAMI,cAAc8F,WAAWlB,GACjB3lB,YACtC4nB,EAAc,GAAK,EACnB,MAAMjB,EAAe,IAAIpB,GAAQqC,GAC3Bo0B,EAAc,IAAIzxC,EAAQ,EAAG,EAAG,GAChCwmC,EACJ,IAAIvrB,GAASw2B,EAAar6B,EAAWgF,GAGvC,OAAO,IAAI8K,GAAMsf,EAAegL,EAClC,CASAE,oBAAAA,CAAqB/3B,EAAKtZ,GACxB,IAAI+V,EAAQpjB,MAAK,EAAMs4C,WACvB,MAAMlwB,EAAcpoB,MAAK,EAAMypB,iBAC/B,IAAIuvB,EAAeh5C,KAAKo4C,kBACpBuG,GAAW,EAGV9wC,EAAgBua,KACnBhF,EAAQpjB,MAAK,GAAUojB,EAAO41B,EAAc2F,EAAUv2B,GAEtD4wB,EAAe,IAAIj3C,EAAM,CAAC,EAAG,EAAG,IAChC48C,GAAW,GAIb,MAAMC,ExBkGH,SACLx7B,EAAO9V,EAAOgW,EAAYqD,EAAKtZ,GAC/B,GAAsC,IAAlC+V,EAAMmB,wBACR,MAAM,IAAIriB,MAAM,yDACdkhB,EAAMmB,8BAIgB,IAAfjB,IACTA,GAAa,GAEf,IAAInB,EAAe,KAEjBA,EADEmB,EACa,SAAUpf,GACvB,OAAOkf,EAAMW,yBAAyB7f,EACxC,EAEe,SAAUA,GACvB,OAAOkf,EAAMY,iBAAiB9f,EAChC,EAGF,MAAMmC,EAAO+c,EAAMI,cAAcC,eACd,IAARkD,IACTA,EAAM,IAAI5Y,EAAQ,EAAG,SAEJ,IAARV,IACTA,EAAM,IAAIU,EACR1H,EAAKhF,IAAI,GAAK,EACdgF,EAAKhF,IAAI,KAIb,MAAM+W,EAAc/R,EAAKyd,cAAcxW,EAAMnK,aAC3CwjB,EAAIxc,OAAQwc,EAAIvc,SAEZiO,EAAYhS,EAAKyd,cAAcxW,EAAMnK,aACzCkK,EAAIlD,OAAQkD,EAAIjD,OAAS,IAIrBy0C,EAAuBl7C,KAAK0J,IAAI,EAAGA,EAAIlD,OAASwc,EAAIxc,QAG1D,OA/ZK,SACLgY,EAAchQ,EAAOC,EAAKiQ,EAAWy8B,EAAYC,GACjD,IAAIr8B,EAAYvQ,EACZ6sC,EAAqB,EAEzB,MAAO,CACLl8B,KAAM,WACJ,GAAIJ,EAAYtQ,EAAK,CACnB,MAAMgK,EAAS,CACbta,MAAOqgB,EAAaO,GACpBK,MAAM,EACNzV,MAAOoV,GAQT,OANAs8B,GAAsB,EACtBt8B,GAmZJ,EAlZQs8B,IAAuBF,IACzBE,EAAqB,EACrBt8B,GAAaq8B,GAER3iC,CACT,CACA,MAAO,CACL2G,MAAM,EACNzV,MAAO8E,EAEX,EAEJ,CAoYS6sC,CACL98B,EAAc/J,EAAaC,EAAY,EACvC,EAAGwmC,EAJgBx4C,EAAKhF,IAAI,GAAKw9C,EAKrC,CwBjJiBK,CACX97B,EAAO41B,EAAc2F,EAAUh4B,EAAKtZ,GACtC,IAAIpL,EAAS,GAIb,OAHI28C,IACF38C,EAAS+gB,GAAkB47B,IAEtB38C,CACT,CAQAk9C,4BAAAA,CAA6BC,GAC3B,IAAIh8B,EAAQpjB,MAAK,EAAMs4C,WACvB,MAAMlwB,EAAcpoB,MAAK,EAAMypB,iBAC/B,IAAIuvB,EAAeh5C,KAAKo4C,kBACpBuG,GAAW,EAGV9wC,EAAgBua,KACnBhF,EAAQpjB,MAAK,GAAUojB,EAAO41B,EAAc2F,EAAUv2B,GAEtD4wB,EAAe,IAAIj3C,EAAM,CAAC,EAAG,EAAG,IAChC48C,GAAW,GAIb,MAAMC,ExB8HH,SACLx7B,EAAO9V,EAAOgW,EAAY87B,GAC1B,GAAsC,IAAlCh8B,EAAMmB,wBACR,MAAM,IAAIriB,MAAM,yDACdkhB,EAAMmB,8BAIgB,IAAfjB,IACTA,GAAa,GAEf,IAAInB,EAAe,KAEjBA,EADEmB,EACa,SAAUpf,GACvB,OAAOkf,EAAMW,yBAAyB7f,EACxC,EAEe,SAAUA,GACvB,OAAOkf,EAAMY,iBAAiB9f,EAChC,EAGF,MAAMmC,EAAO+c,EAAMI,cAAcC,UAE3B47B,EAAgB,GACtB,IAAIC,EACA34B,EAAM,KACNtZ,EAAM,KACNkyC,EAAc,KAClB,IAAK,IAAIh9C,EAAI,EAAGA,EAAI68C,EAAQj9C,SAAUI,EAAG,CACvC+8C,EAASF,EAAQ78C,GACjB,MAAM6C,EAAQk6C,EAAO,GAAG,GAAKA,EAAO,GAAG,GACzB,IAAVl6C,IACFm6C,EAAch9C,EACTokB,IACHA,EAAM24B,EAAO,IAEfD,EAAcp8C,KAAK,CACjBq8C,EAAO,GAAG,GACVl6C,EACAiB,EAAKhF,IAAI,GAAKi+C,EAAO,GAAG,KAG9B,CAMA,GALoB,OAAhBC,IACFlyC,EAAM+xC,EAAQG,GAAa,IAIA,IAAzBF,EAAcl9C,OAWlB,OAhcK,SACLggB,EAAchQ,EAAOC,EAAKiQ,EAAW+8B,GACrC,IAAI18B,EAAYvQ,EACZqtC,EAAc,EACdR,EAAqB,EAEzB,MAAO,CACLl8B,KAAM,WACJ,GAAIJ,EAAYtQ,EAAK,CACnB,MAAMgK,EAAS,CACbta,MAAOqgB,EAAaO,GACpBK,MAAM,EACNzV,MAAOoV,GAcT,OAZAs8B,GAAsB,EACtBt8B,GAmbJ,EAlbQs8B,IAAuBI,EAAQI,GAAa,KAC9CR,EAAqB,EAErBt8B,GAAa08B,EAAQI,GAAa,GAClCA,GAAe,EAEXA,EAAcJ,EAAQj9C,SACxBugB,GAAa08B,EAAQI,GAAa,KAG/BpjC,CACT,CACA,MAAO,CACL2G,MAAM,EACNzV,MAAO8E,EAEX,EAEJ,CA8ZSqtC,CACLt9B,EARkB9b,EAAKyd,cAAcxW,EAAMnK,aAC3CwjB,EAAI,GAAIA,EAAI,KAEItgB,EAAKyd,cAAcxW,EAAMnK,aACzCkK,EAAI,GAAIA,EAAI,KAI2B,EACvC,EAAGgyC,EACP,CwB7LiBK,CACXt8B,EAAO41B,EAAc2F,EAAUS,GACjC,IAAIn9C,EAAS,GAIb,OAHI28C,IACF38C,EAAS+gB,GAAkB47B,IAEtB38C,CACT,CAOA09C,gBAAAA,GACE,OAAO3/C,MAAK,EAAMs4C,WAAWjH,aAC/B,CAQAC,cAAAA,GACE,OAAOtxC,KAAK+uB,cACd,CAOAA,YAAAA,GACE,OAAO/uB,MAAK,EAAMs4C,WAAWvpB,cAC/B,CAQA7I,SAAAA,GACE,OAAOlmB,MAAK,EAAMs4C,WAAWpyB,UAAUlmB,MAAK,EAAMypB,iBACpD,CAOAm2B,YAAAA,GACE,OAAO5/C,MAAK,EAAMs4C,WAAW90B,cAAcC,QACzCzjB,MAAK,EAAMypB,iBACf,CAUA1D,WAAAA,CAAY85B,GACV,OAAO7/C,KAAK4/C,eAAe75B,YAAY85B,EACzC,CAOAC,iBAAAA,GACE,MAAMhsB,EAAW9zB,MAAK,EAAMs4C,WAAW90B,cACjCnd,EAAOytB,EAASrQ,QAAQzjB,MAAK,EAAMypB,kBAAkBhD,QACrD0B,EAAU2L,EAASxK,WAAWtpB,MAAK,EAAMypB,kBAAkBhD,QACjE,MAAO,CACLhe,EAAGpC,EAAKoC,EAAI0f,EAAQ1f,EACpBC,EAAGrC,EAAKqC,EAAIyf,EAAQzf,EAExB,CAOAq3C,yBAAAA,GACE,OAAO//C,MAAK,EAAMs4C,WAAWnF,sBAC/B,CAQA6M,cAAAA,CAAexrB,GACb,MAAMyrB,EAAYjgD,MAAK,EAAMs4C,WAAWlK,UAElC8R,EAAWh/C,OAAO4R,KAAK0hB,GAC7B,IAAK,IAAIjyB,EAAI,EAAGA,EAAI29C,EAAS/9C,SAAUI,EAAG,CACxC,MAAM49C,EAAUD,EAAS39C,GACzB,QAAkC,IAAvB09C,EAAUE,GACnB,OAAO,EAET,GAAIF,EAAUE,KAAa3rB,EAAK2rB,GAC9B,OAAO,CAEX,CACA,OAAO,CACT,CASArG,kBAAAA,CAAmBz2B,GACjB,OAAOrjB,MAAK,EAAM85C,mBAAmBz2B,EACvC,CAUA42B,kBAAAA,CAAmBtqC,EAAKuqC,GACtB,OAAOl6C,MAAK,EAAMi6C,mBAAmBtqC,EAAKuqC,EAC5C,CAUAgD,yBAAAA,CAA0BhvC,EAASzB,QAEhB,IAANA,IACTA,EAAIzM,KAAKk+C,8BAEX,MAAMrB,EAAa,IAAI7vC,EAAQkB,EAAQ/D,OAAQ+D,EAAQ9D,OAAQqC,GAEzDkd,EAAQ3pB,MAAK,GAAa+8C,wBAAwBF,GAGlD9vC,EADW/M,MAAK,EAAMs4C,WAAW90B,cACdkH,aAAaf,GAEtC,OAAO3pB,KAAK45C,qBAAqB5qC,YAAYjC,EAC/C,CAQAqzC,4BAAAA,CAA6Bz2B,GAE3B,MAEM5c,EAFW/M,MAAK,EAAMs4C,WAAW90B,cAEdmH,aAAahB,GAChCkzB,EAAa78C,MAAK,GAAai9C,0BAA0BlwC,GAE/D,OAAO,IAAIgB,EACT8uC,EAAW1yC,OACX0yC,EAAWzyC,OAEf,CAQAi2C,oBAAAA,CAAqB12B,GAInB,OAFiB3pB,MAAK,EAAMs4C,WAAW90B,cAEvB+G,aAAaZ,EAC/B,CASA0uB,eAAAA,CAAgB/qC,EAAO4sC,GACrB,OAAOl6C,MAAK,EAAMq4C,gBAAgB/qC,EAAO4sC,EAC3C,CASAoG,8BAAAA,CAA+BpyC,GAE7B,MAAMzB,EAAIzM,KAAKk+C,6BACTrB,EAAa,IAAI7vC,EAAQkB,EAAQ/D,OAAQ+D,EAAQ9D,OAAQqC,GAEzDkd,EAAQ3pB,MAAK,GAAa48C,2BAA2BC,GAGrD10B,EADWnoB,MAAK,EAAMs4C,WAAW90B,cACdgG,iBACzB,OAAO,IAAIxc,EACT2c,EAAMxf,OAASge,EAAQ9mB,IAAI,GAC3BsoB,EAAMvf,OAAS+d,EAAQ9mB,IAAI,GAC3BsoB,EAAMtf,OAAS8d,EAAQ9mB,IAAI,GAC/B,CAQA+6C,0BAAAA,CAA2BC,GACzB,OAAOr8C,MAAK,GAAao8C,2BAA2BC,EACtD,CAQA,IAAmBwD,GACjB,MAAMvyC,EAAQtN,KAAKo4C,kBACbn2C,EAAS,IAAImd,MAAM9R,EAAMnL,UAC/BF,EAAOqrC,KAAK,GACRuS,EAAM59C,EAAOE,OACfF,EAAO49C,GAAO,EAEdh7C,QAAQG,KAAK,iCAAkC66C,EAAK59C,EAAOE,QAE7D,MAAMo+C,EAAO,IAAIx+C,EAAME,GACvB,OAAOqL,EAAMpK,IAAIq9C,EACnB,CAQA,IAAmBV,GACjB,MAAMvyC,EAAQtN,KAAKo4C,kBACbn2C,EAAS,IAAImd,MAAM9R,EAAMnL,UAC/BF,EAAOqrC,KAAK,GACRuS,EAAM59C,EAAOE,OACfF,EAAO49C,IAAQ,EAEfh7C,QAAQG,KAAK,iCAAkC66C,EAAK59C,EAAOE,QAE7D,MAAMo+C,EAAO,IAAIx+C,EAAME,GACvB,OAAOqL,EAAMpK,IAAIq9C,EACnB,CAOA,MACE,OAAOvgD,MAAK,GAAmBA,KAAK+5C,iBACtC,CAOA,MACE,OAAO/5C,MAAK,GAAmBA,KAAK+5C,iBACtC,CAQAyG,oBAAAA,CAAqBX,GAEnB,OADiB7/C,MAAK,EAAMs4C,WAAW90B,cACvBgH,aAAaxqB,MAAK,GAAmB6/C,GACvD,CAQAY,oBAAAA,CAAqBZ,GAEnB,OADiB7/C,MAAK,EAAMs4C,WAAW90B,cACvBgH,aAAaxqB,MAAK,GAAmB6/C,GACvD,CAOAa,0BAAAA,GAEE,OADiB1gD,MAAK,EAAMs4C,WAAW90B,cACvBgH,aAAaxqB,MAAK,KACpC,CAOA2gD,0BAAAA,GAEE,OADiB3gD,MAAK,EAAMs4C,WAAW90B,cACvBgH,aAAaxqB,MAAK,KACpC,CASA4gD,cAAAA,CAAef,EAAK3F,GAClB,OAAOl6C,KAAKq4C,gBAAgBr4C,MAAK,GAAmB6/C,GAAM3F,EAC5D,CASA2G,cAAAA,CAAehB,EAAK3F,GAClB,OAAOl6C,KAAKq4C,gBAAgBr4C,MAAK,GAAmB6/C,GAAM3F,EAC5D,CAQA4G,oBAAAA,CAAqB5G,GACnB,OAAOl6C,KAAKq4C,gBAAgBr4C,MAAK,KAA4Bk6C,EAC/D,CAQA6G,oBAAAA,CAAqB7G,GACnB,OAAOl6C,KAAKq4C,gBAAgBr4C,MAAK,KAA4Bk6C,EAC/D,CAKA8G,IAAAA,GAEE,GAAKhhD,KAAKkmB,YAGV,QAA8B,IAAnBlmB,MAAK,GAA2B,CACzC,MAAMojB,EAAQpjB,MAAK,EAAMs4C,WACnBzgB,EACJzU,EAAMgrB,UAAUtW,4BACZhM,EAAe9rB,MAAK,EAAM24C,wBAC9B9gB,GAEI5R,EADO7C,EAAMI,cAAcC,UACRwC,cAEzBjmB,MAAK,GAAYihD,OAAOC,aAAY,KAClC,IAAIC,GAAY,EAOhB,GALEA,EADEl7B,EACUjmB,KAAK+gD,uBAEL/gD,KAAK4gD,eAAe,IAG7BO,EAAW,CACd,MACMl/C,EADOjC,KAAKo4C,kBACE31C,YACd2lB,EAAcpoB,MAAK,EAAMypB,iBAC3BxD,EACFhkB,EAAOmmB,EAAYza,6BAA+B,EAElD1L,EAAO,GAAK,EAEd,MAAMqL,EAAQ,IAAIvL,EAAME,GAClB6xB,EAAW9zB,MAAK,EAAMs4C,WAAW90B,cACvCxjB,KAAKi6C,mBAAmBnmB,EAAStJ,aAAald,GAChD,IACCwe,EACL,MACE9rB,KAAKohD,MAET,CAKAA,IAAAA,QACgC,IAAnBphD,MAAK,KACdqhD,cAAcrhD,MAAK,IACnBA,MAAK,QAAYQ,EAErB,CAOAsF,cAAAA,GACE,OAAO9F,MAAK,EAAM8F,gBACpB,CAOA4zC,0BAAAA,GACE,OAAO15C,MAAK,EAAM05C,4BACpB,CAOAR,cAAAA,CAAerzC,GACb7F,MAAK,EAAMk5C,eAAerzC,EAC5B,CAOA8zC,YAAAA,GACE,OAAO35C,MAAK,EAAM25C,cACpB,CAOA9B,YAAAA,CAAaruC,GACXxJ,MAAK,EAAM63C,aAAaruC,EAC1B,CAcA83C,oBAAAA,CAAqBx6C,GACnB9G,MAAK,EAAM+4C,iBAAiBjyC,EAC9B,CAOAy6C,iBAAAA,CAAkBC,GAChB,MAAMp+B,EAAQpjB,MAAK,EAAMs4C,WACzBl1B,EAAM2xB,iBAAiB,qBACrByM,EAAUC,sBAEZr+B,EAAM2xB,iBAAiB,sBACrByM,EAAUE,sBAEd,CAOAC,mBAAAA,CAAoBH,GAClB,MAAMp+B,EAAQpjB,MAAK,EAAMs4C,WACzBl1B,EAAM4xB,oBAAoB,qBACxBwM,EAAUC,sBAEZr+B,EAAM4xB,oBAAoB,sBACxBwM,EAAUE,sBAEd,ECx4BF,MAAME,GAMJ,IAAO,EAOPC,MAAAA,GACE,OAAO7hD,MAAK,EACd,CAOAkD,GAAAA,CAAI8e,GACFhiB,MAAK,IA9DT,SAAkBgiB,GAoBhB,QAAiC,IAAtBA,EAAM8/B,YAEf,OAAQ9/B,EAAM+/B,OACT,CACL,MAAMt0B,EAAY,GAClB,OAAIzL,EAAM8/B,YAAcr0B,EACf,EACEzL,EAAM8/B,aAAer0B,GACtB,GAEAzL,EAAM+/B,OAAS,EAE3B,CACF,CA6BiBC,CAAShgC,EACxB,CAKAwY,KAAAA,GACEx6B,MAAK,GAAO,CACd,CAOAiiD,MAAAA,GACE,OAAOt+C,KAAKsH,IAAIjL,MAAK,KAAS,CAChC,EAOK,MAAMkiD,GAMX,IAOA,IAAa,IAAIN,GAKjB5/C,WAAAA,CAAYmgD,GACVniD,MAAK,GAAOmiD,CACd,CAOAC,KAAAA,CAAMpgC,GACJhiB,MAAK,GAAWkD,IAAI8e,GACpB,MAAMqgC,EAAKriD,MAAK,GAAW6hD,UAAY,EAGvC,IAAK7hD,MAAK,GAAWiiD,SACnB,OAEAjiD,MAAK,GAAWw6B,QAIlBxY,EAAMsgC,iBAEN,MAAMC,EAAeC,GAAyBxgC,GACxCygC,EAAaziD,MAAK,GAAK0iD,qBAAqBH,EAAaI,YACzDC,EACJH,EAAWI,qBAAqBC,oBAClC,IAAIC,EACAN,EAAWv8B,YAEX68B,EADEV,EACYO,EAAelC,6BAEfkC,EAAejC,6BAEtB8B,EAAW18B,YAAY,KAE9Bg9B,EADEV,EACYO,EAAepC,qBAAqB,GAEpCoC,EAAenC,qBAAqB,SAK3B,IAAhBsC,GACTN,EAAW3I,mBAAmBiJ,IAC9BH,EAAe3I,mBAAmB8I,EAEtC,ECvJK,MAAMC,GAOX,IAOA,IAOAhhD,WAAAA,CAAYihD,EAAO7wC,GACjBpS,MAAK,GAASijD,EACdjjD,MAAK,GAAOoS,CACd,CAOA8wC,QAAAA,GACE,OAAOljD,MAAK,EACd,CAOAmjD,MAAAA,GACE,OAAOnjD,MAAK,EACd,CAQA6C,MAAAA,CAAOD,GACL,OAAe,OAARA,GACL5C,KAAKkjD,WAAWrgD,OAAOD,EAAIsgD,aAC3BljD,KAAKmjD,SAAStgD,OAAOD,EAAIugD,SAC7B,CAOAC,SAAAA,GACE,OAAOpjD,KAAKmjD,SAASh5C,OAASnK,KAAKkjD,WAAW/4C,MAChD,CAOAk5C,SAAAA,GACE,OAAOrjD,KAAKmjD,SAAS/4C,OAASpK,KAAKkjD,WAAW94C,MAChD,CAOApG,SAAAA,GACE,OAAOL,KAAK4G,KACVvK,KAAKojD,YAAcpjD,KAAKojD,YACxBpjD,KAAKqjD,YAAcrjD,KAAKqjD,YAE5B,CASAC,cAAAA,CAAeC,GACb,IAAIC,EAAO,KACX,GAAkB,OAAdD,EAAoB,CACtB,MAAME,EAAMzjD,KAAKojD,YAAcG,EAAU96C,EACnCi7C,EAAM1jD,KAAKqjD,YAAcE,EAAU76C,EACzC86C,EAAO7/C,KAAK4G,KAAKk5C,EAAMA,EAAMC,EAAMA,EACrC,CACA,OAAOF,CACT,CAOAG,WAAAA,GACE,OAAO,IAAI51C,GACR/N,KAAKkjD,WAAW/4C,OAASnK,KAAKmjD,SAASh5C,QAAU,GACjDnK,KAAKkjD,WAAW94C,OAASpK,KAAKmjD,SAAS/4C,QAAU,EAEtD,CAOA4D,WAAAA,GACE,OAAOhO,KAAK2jD,aACd,CAOAj9C,QAAAA,GACE,OAAO1G,KAAKqjD,YAAcrjD,KAAKojD,WACjC,CAOAv9B,YAAAA,GACE,OACE7lB,KAAKmjD,SAASh5C,OAASnK,KAAKkjD,WAAW94C,OACvCpK,KAAKkjD,WAAW/4C,OAASnK,KAAKmjD,SAAS/4C,QACrCpK,KAAKojD,WACX,CAOAQ,cAAAA,GAKE,OAAO,IAF4C,IAAjDjgD,KAAKkgD,MAAM7jD,KAAKqjD,YAAarjD,KAAKojD,aAAqBz/C,KAAKmgD,EAGhE,CAQAC,QAAAA,CAASnB,GACP,MAAMoB,EAAQ,CAAC,EAETT,EAAYX,EAAetE,eAC3Bn8C,EAASnC,KAAKsjD,eAAeC,GAKnC,OAJe,OAAXphD,IACF6hD,EAAM7hD,OAAS,CAACL,MAAOK,EAAQu0B,KAAM,YAGhCstB,CACT,EAWK,SAASC,GAASC,EAAOC,GAC9B,MAAMC,EAAMF,EAAMd,YACZiB,EAAMH,EAAMb,YACZiB,EAAMH,EAAMf,YACZmB,EAAMJ,EAAMd,YAEZmB,EAAMJ,EAAME,EAAMD,EAAME,EAExBp4C,EAAMi4C,EAAMG,EAAMF,EAAMC,EAK9B,OAAO,KAAO,IAHuB,IAAvB3gD,KAAKkgD,MAAM13C,EAAKq4C,GAAa7gD,KAAKmgD,GAIlD,CASO,SAASW,GAAcP,EAAOC,GACnC,MAAMC,EAAMF,EAAMd,YACZiB,EAAMH,EAAMb,YAIlB,OAAQe,EAHID,EAAMf,YAGEiB,EAFRF,EAAMd,aAEiB,CACrC,CA6BO,SAASqB,GAAqBC,EAAMh7B,EAAOxnB,EAAQgmB,QACjC,IAAZA,IACTA,EAAU,CAAC1f,EAAG,EAAGC,EAAG,IAEtB,MAGMk8C,GAHMz8B,EAAQ1f,EAAI0f,EAAQ1f,GACpB0f,EAAQzf,EAAIyf,EAAQzf,EAEAi8C,EAAKj+C,YAIrC,OAAOm+C,GAAoBD,EAFLj7B,EAAMvf,OAASw6C,EAAYj7B,EAAMxf,OAEFwf,EAAOxnB,EAAQgmB,EACtE,CAYO,SAAS28B,GACdH,EAAMI,EAAU5iD,EAAQgmB,GAExB,MAAM68B,EAAaH,GACjBF,EAAKj+C,WACLi+C,EAAK9+B,eACL8+B,EAAKzB,WACL6B,EACA58B,GAGF,IAAI88B,EAOJ,OAHEA,EA3DG,SAA4Bt7B,EAAOg7B,GACxC,MAAMO,EAAOvhD,KAAKgjB,IAAIg+B,EAAKzB,WAAW/4C,OAAQw6C,EAAKxB,SAASh5C,QACtDg7C,EAAOxhD,KAAK0J,IAAIs3C,EAAKzB,WAAW/4C,OAAQw6C,EAAKxB,SAASh5C,QACtDi7C,EAAOzhD,KAAKgjB,IAAIg+B,EAAKzB,WAAW94C,OAAQu6C,EAAKxB,SAAS/4C,QACtDi7C,EAAO1hD,KAAK0J,IAAIs3C,EAAKzB,WAAW94C,OAAQu6C,EAAKxB,SAAS/4C,QAC5D,OAAOuf,EAAMxf,QAAU+6C,GACrBv7B,EAAMxf,QAAUg7C,GAChBx7B,EAAMvf,QAAUg7C,GAChBz7B,EAAMvf,QAAUi7C,CACpB,CA+CMC,CAAmBN,EAAW9B,WAAYyB,GAC/BK,EAAW9B,WAEX8B,EAAW7B,SAGnBuB,GAAqBC,EAAMM,EAAY9iD,EAAQgmB,EACxD,CAYO,SAAS08B,GAAoBl/B,EAAOC,EAAW+D,EAAOxnB,EAAQgmB,QAC5C,IAAZA,IACTA,EAAU,CAAC1f,EAAG,EAAGC,EAAG,IAGtB,IAAI68C,EAAS,EACTC,EAAS,EAETC,EAAO,EACPC,EAAO,EAEX,GAAI36C,EAAU4a,EAAO,EAAG7a,GAEtBy6C,EAAS57B,EAAMxf,OAAShI,GAAU,EAAIgmB,EAAQ1f,GAC9C+8C,EAAS77B,EAAMvf,OACfq7C,EAAO97B,EAAMxf,OAAShI,GAAU,EAAIgmB,EAAQ1f,GAC5Ci9C,EAAO/7B,EAAMvf,YACR,GAAIzG,KAAKsH,IAAI0a,GAAS,IAE3B4/B,EAAS57B,EAAMxf,OACfq7C,EAAS77B,EAAMvf,OAASjI,GAAU,EAAIgmB,EAAQzf,GAC9C+8C,EAAO97B,EAAMxf,OACbu7C,EAAO/7B,EAAMvf,OAASjI,GAAU,EAAIgmB,EAAQzf,OACvC,CACL,MAAMi9C,EAAMx9B,EAAQ1f,EAAI0f,EAAQ1f,EAC1Bm9C,EAAMz9B,EAAQzf,EAAIyf,EAAQzf,EAU1ByF,EAAKhM,GAAU,EAAIwB,KAAK4G,KAAKo7C,EAAMC,EAAMjgC,EAAQA,IAGvD4/B,EAAS57B,EAAMxf,OAASgE,EACxBq3C,EAAS7/B,EAAQ4/B,EAAS3/B,EAE1B6/B,EAAO97B,EAAMxf,OAASgE,EACtBu3C,EAAO//B,EAAQ8/B,EAAO7/B,CACxB,CACA,OAAO,IAAIo9B,GACT,IAAIj1C,EAAQw3C,EAAQC,GACpB,IAAIz3C,EAAQ03C,EAAMC,GACtB,C,yBC7VO,MAAMG,GAIX,IAOA,IAAQ,CAAC,EAOT,IAAmB,IAAIpkC,GAOvB,IAQA,IAMAzf,WAAAA,CAAY8jD,GAER9lD,MAAK,QADa,IAAT8lD,EACIA,EAEA,GAEf9lD,MAAK,IAAY,CACnB,CAOA+lD,OAAAA,GACE,OAAO/lD,MAAK,EACd,CAOAgE,SAAAA,GACE,OAAOhE,MAAK,GAAMmC,MACpB,CAOA6jD,UAAAA,GACE,OAAOhmD,MAAK,EACd,CAOAimD,WAAAA,CAAYrqB,GACV57B,MAAK,GAAY47B,EASjB57B,MAAK,GAAW,CACd0hB,KAAM,gCACNzO,KAAM2oB,GAEV,CAOAsqB,SAAAA,GACE,OAAOlmD,MAAK,EACd,CAOAmmD,SAAAA,CAAUpU,GACR/xC,MAAK,GAAU+xC,CACjB,CAOA7uC,GAAAA,CAAIkjD,GACFpmD,MAAK,GAAMiD,KAAKmjD,GAShBpmD,MAAK,GAAW,CACd0hB,KAAM,gBACNzO,KAAMmzC,GAEV,CAQAC,MAAAA,CAAOD,EAAYE,GACjB,MAAMh5C,EAAQtN,MAAK,GAAMksC,WAAWztB,GAASA,EAAK1X,KAAOq/C,EAAWr/C,MACrD,IAAXuG,GACFtN,MAAK,GAAMsN,GAAS84C,EAUpBpmD,MAAK,GAAW,CACd0hB,KAAM,mBACNzO,KAAMmzC,EACNtzC,KAAMwzC,KAGRniD,EAAOa,KAAK,mCAEhB,CAOA4c,MAAAA,CAAO7a,GACL,MAAMuG,EAAQtN,MAAK,GAAMksC,WAAWztB,GAASA,EAAK1X,KAAOA,IACzD,IAAe,IAAXuG,EAAc,CAChB,MAAM84C,EAAapmD,MAAK,GAAM8hB,OAAOxU,EAAO,GAAG,GAU/CtN,MAAK,GAAW,CACd0hB,KAAM,mBACNzO,KAAMmzC,GAEV,MACEjiD,EAAOa,KAAK,mCAEhB,CAOAuhD,iBAAAA,CAAkB3D,GAChB,IAAK,MAAMnkC,KAAQze,MAAK,GACtBye,EAAK8nC,kBAAkB3D,GACvBnkC,EAAK+nC,sBAET,CAQAt8B,IAAAA,CAAKnjB,GACH,OAAO/G,MAAK,GAAMkqB,MAAMzL,GAASA,EAAK1X,KAAOA,GAC/C,CAOAqnC,OAAAA,GACE,OAAOpuC,MAAK,EACd,CAQAymD,OAAAA,CAAQzlD,GACN,YAAkC,IAApBhB,MAAK,GAAMgB,EAC3B,CAQA0lD,YAAAA,CAAa1lD,GACX,OAAOhB,MAAK,GAAMgB,EACpB,CAQA2lD,YAAAA,CAAa3lD,EAAKc,GAChB9B,MAAK,GAAMgB,GAAOc,CACpB,CASAizC,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAcK,IACZhiB,MAAK,GAAiB+hB,UAAUC,EAAM,ECrRnC,MAAM4kC,GAOX,IAQAC,aAAAA,CAAc9/C,GACZ,OAAO/G,MAAK,GAAiBkqB,KAAKnjB,EACpC,CAOA+/C,kBAAAA,GACE,OAAO9mD,MAAK,EACd,CAOA+mD,yBAAAA,GACE,OAAO/mD,MAAK,GAAiBgmD,YAC/B,CAOAgB,0BAAAA,CAA2BprB,GACzB57B,MAAK,GAAiBimD,YAAYrqB,EACpC,CAOAqrB,aAAAA,CAAcb,GACZpmD,MAAK,GAAiBkD,IAAIkjD,EAC5B,CAQAc,gBAAAA,CAAiBd,EAAYE,GAC3BtmD,MAAK,GAAiBqmD,OAAOD,EAAYE,EAC3C,CAOAa,gBAAAA,CAAiBpgD,GACf/G,MAAK,GAAiB4hB,OAAO7a,EAC/B,CAQAqgD,2BAAAA,CAA4BrgD,EAAIsgD,GAC9B,MAAMjB,EAAapmD,KAAK6mD,cAAc9/C,GACtC,QAA0B,IAAfq/C,EAGT,YAFAjiD,EAAOa,KACL,0DAA4D+B,GAIhE,MAAMugD,EAAU,IAAIC,GAAwBnB,EAAYpmD,MAExDqnD,EAAYC,GAEZA,EAAQE,SACV,CAYAC,2BAAAA,CAA4B1gD,EAAI2gD,EAAeC,EAAUN,GACvD,MAAMjB,EAAapmD,KAAK6mD,cAAc9/C,GACtC,QAA0B,IAAfq/C,EAGT,YAFAjiD,EAAOa,KACL,0DAA4D+B,GAIhE,MAAMugD,EAAU,IAAIM,GAClBxB,EAAYsB,EAAeC,EAAU3nD,MAEvCqnD,EAAYC,GAEZA,EAAQE,SACV,CAOAK,+BAAAA,CAAgCR,GAC9B,IAAK,MAAMjB,KAAcpmD,MAAK,GAAiB+lD,UAC7C/lD,KAAKonD,4BAA4BhB,EAAWr/C,GAAIsgD,EAEpD,CAKArlD,WAAAA,CAAYuR,GAERvT,MAAK,QADc,IAAVuT,EACeA,EAEA,IAAIsyC,EAEhC,CAQAiC,iBAAAA,CAAkB9mD,GAChB,OAAOhB,MAAK,GAAiBymD,QAAQzlD,EACvC,CAQA+mD,iBAAAA,CAAkB/mD,EAAKc,GACrB9B,MAAK,GAAiB2mD,aAAa3lD,EAAKc,EAC1C,ECtKK,MAAMkmD,GAMX,IAAY,GAOZ,IAAc,UAOd,IAAc,OAOd,IAAc,UAOd,IAAa,CAACv/C,EAAG,EAAGC,EAAG,GAOvB,IAAa,CAACD,EAAG,EAAGC,EAAG,GAOvB,IAAe,EAOf,IAAgB,CAACD,EAAG,IAAMC,EAAG,KAO7B,IAAc,GAOd,IAAe,EAOfu/C,aAAAA,GACE,OAAOjoD,MAAK,EACd,CAOAkoD,WAAAA,GACE,OAAOloD,MAAK,EACd,CAOAmoD,cAAAA,GACE,OAAOnoD,MAAK,EACd,CAOAooD,aAAAA,GACE,OAAOpoD,MAAK,EACd,CAOAqoD,aAAAA,GACE,OAAOroD,MAAK,EACd,CAOAsoD,aAAAA,CAAcvW,GACZ/xC,MAAK,GAAc+xC,CACrB,CAOAwW,YAAAA,CAAaC,GACXxoD,MAAK,GAAawoD,CACpB,CAOAC,YAAAA,CAAaD,GACXxoD,MAAK,GAAawoD,CACpB,CAOAE,YAAAA,GACE,OAAO1oD,MAAK,EACd,CAOA2oD,YAAAA,GACE,OAAO3oD,MAAK,EACd,CAQAwoD,KAAAA,CAAM1mD,GAEJ,OAAOA,EAAQ9B,MAAK,GAAWyI,CACjC,CAQAmgD,cAAAA,CAAe9mD,GACb,MAAO,CACL2G,EAAG3G,EAAQ9B,MAAK,GAAWyI,EAC3BC,EAAG5G,EAAQ9B,MAAK,GAAW0I,EAE/B,CAQAmgD,cAAAA,CAAe/mD,GACb,OAAOA,EAAQ9B,MAAK,GAAWyI,EAAIzI,MAAK,GAAW0I,CACrD,CAOAogD,eAAAA,GACE,OAAO9oD,MAAK,EACd,CAOA+oD,aAAAA,GACE,OAAO/oD,MAAK,EACd,CAOAgpD,cAAAA,GACE,OAAOhpD,MAAK,EACd,CAOAipD,UAAAA,GACE,MAAQ,UAAYjpD,KAAKkoD,cAAgB,eAC3C,CAOAgB,aAAAA,GACE,OAAQlpD,KAAKkoD,cAAgBloD,KAAKkoD,cAAgB,CACpD,CAOAiB,iBAAAA,GACE,OAAOnpD,KAAKwoD,MAAMxoD,KAAKkoD,cACzB,CAOAkB,oBAAAA,GACE,OAAOppD,KAAKwoD,MAAMxoD,KAAKmoD,iBACzB,CAOAkB,mBAAAA,GACE,O1ClJyBC,E0CkJFtpD,KAAKqoD,gB1C7LPkB,EA4COD,EAZf,YAJazjB,EA3BrB,CACLlkC,EAAGkV,SAAS0yC,EAAO35C,UAAU,EAAG,GAAI,IACpC3H,EAAG4O,SAAS0yC,EAAO35C,UAAU,EAAG,GAAI,IACpC1H,EAAG2O,SAAS0yC,EAAO35C,UAAU,EAAG,GAAI,MA4B3BjO,EACD,WAARkkC,EAAI59B,EACI,UAAR49B,EAAI39B,EAUsC,GAUX,OAAS,OAXrC,IAAsBohD,EAfCzjB,EA5BL0jB,C0C8LvB,ECnQK,SAASC,GAAgBC,GAC9B,MAAuB,UAAhBA,EAAKjgD,MACd,CAQO,SAASkgD,GAAgBD,GAC9B,MAAuB,UAAhBA,EAAKjgD,MACd,CAQO,SAASmgD,GAAeF,GAC7B,MAAuB,mBAAhBA,EAAKjgD,MACd,CAQO,SAASogD,GAAar2C,GAC3B,MAAMs2C,EAASt2C,EAAMu2C,YAAYJ,IAAiB,GAClD,GAAMG,aAAkBE,KAAAA,KAGxB,OAAOF,CACT,CASO,SAASG,GAAez2C,EAAOjG,GACpC,MAAMu8C,EAASt2C,EAAMu2C,aAAY,SAAUL,GACzC,OAAOA,EAAK1iD,OAAS,SAAWuG,CAClC,IAAG,GACH,GAAMu8C,aAAkBE,KAAAA,QAGxB,OAAOF,CACT,CAcO,SAASI,GAAaljD,GAC3B,OAAO,SAAU0iD,GACf,OAAOA,EAAK1iD,OAASA,CACvB,CACF,CAgBO,SAASmjD,GAAiBzhD,EAAGC,EAAG3B,EAAIojD,GACzC,MAAM/mB,EAAS+mB,EAAMvB,eAAe,GAC9BwB,EAAY,CAChB3hD,EAAG9E,KAAKsH,IAAIm4B,EAAO36B,GACnBC,EAAG/E,KAAKsH,IAAIm4B,EAAO16B,IAErB,OAAO,IAAIqhD,KAAAA,SAAc,CACvBthD,EAAGA,EACHC,EAAGA,EACH2hD,OAAQ,OACR/c,KAAM,uBACNgd,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpBnnB,OAAQgnB,EACRI,QAASJ,EAAU3hD,EACnBgiD,QAASL,EAAU1hD,EACnBc,KAAM,SACNzC,GAAIA,EAAGvE,WACPkoD,WAAW,EACXC,WAAW,EACXC,SAAS,GAEb,CAQO,SAASC,GAAe9jD,GAE7B,OAAO8P,SAAS9P,EAAG6I,UAAU,GAAI,GACnC,CC1GO,MAAMk7C,GAOX,IAOA,IAQA9oD,WAAAA,CAAYihD,EAAO7wC,GACjBpS,MAAK,GAAS,IAAI+N,EAChBpK,KAAKgjB,IAAIs8B,EAAM94C,OAAQiI,EAAIjI,QAC3BxG,KAAKgjB,IAAIs8B,EAAM74C,OAAQgI,EAAIhI,SAE7BpK,MAAK,GAAO,IAAI+N,EACdpK,KAAK0J,IAAI41C,EAAM94C,OAAQiI,EAAIjI,QAC3BxG,KAAK0J,IAAI41C,EAAM74C,OAAQgI,EAAIhI,QAE/B,CAOA84C,QAAAA,GACE,OAAOljD,MAAK,EACd,CAOAmjD,MAAAA,GACE,OAAOnjD,MAAK,EACd,CAQA6C,MAAAA,CAAOD,GACL,OAAe,OAARA,GACL5C,KAAKkjD,WAAWrgD,OAAOD,EAAIsgD,aAC3BljD,KAAKmjD,SAAStgD,OAAOD,EAAIugD,SAC7B,CAOA4H,UAAAA,GACE,MAAM9H,EAAQjjD,KAAKkjD,WACb9wC,EAAMpS,KAAKmjD,SACjB,OAAOx/C,KAAKsH,IAAImH,EAAIjI,OAAS84C,EAAM94C,QACjCxG,KAAKsH,IAAImH,EAAIhI,OAAS64C,EAAM74C,OAChC,CASA4gD,eAAAA,CAAgBzH,GACd,OA9FJ,SAAgBziD,EAAGoH,EAAGnC,GACpB,IAAI+C,EAAM,KAIV,OAHU,OAANZ,GAAoB,OAANnC,IAChB+C,EAAMhI,EAAIoH,EAAInC,GAET+C,CACT,CAwFWmiD,CAAOjrD,KAAK+qD,aAAcxH,EAAU96C,EAAG86C,EAAU76C,EAC1D,CAOAwiD,YAAAA,GACE,OAAOlrD,KAAKmjD,SAASh5C,OAASnK,KAAKkjD,WAAW/4C,MAChD,CAOAghD,aAAAA,GACE,OAAOnrD,KAAKmjD,SAAS/4C,OAASpK,KAAKkjD,WAAW94C,MAChD,CAOAghD,QAAAA,GACE,OAAOznD,KAAKsH,IAAIjL,KAAKkrD,eACvB,CAOAG,SAAAA,GACE,OAAO1nD,KAAKsH,IAAIjL,KAAKmrD,gBACvB,CAOAG,QAAAA,GASE,MAAO,CACL3kC,IATiB,IAAI5Y,EACrBpK,KAAK0N,MAAMrR,KAAKkjD,WAAW/4C,QAC3BxG,KAAK0N,MAAMrR,KAAKkjD,WAAW94C,SAQ3BiD,IANe,IAAIU,EACnBpK,KAAK0N,MAAMrR,KAAKmjD,SAASh5C,QACzBxG,KAAK0N,MAAMrR,KAAKmjD,SAAS/4C,SAM7B,CAOA4D,WAAAA,GACE,OAAO,IAAID,EACT/N,KAAKkjD,WAAW/4C,OAASnK,KAAKorD,WAAa,EAC3CprD,KAAKkjD,WAAW94C,OAASpK,KAAKqrD,YAAc,EAEhD,CASAtH,QAAAA,CAASnB,EAAgB5yC,GACvB,MAAMg0C,EAAQ,CAAC,EAETT,EAAYX,EAAetE,eACjC0F,EAAM5+C,MAAQ,CACZtD,MAAO9B,KAAKorD,WAAa7H,EAAU96C,EACnCiuB,KAAM,WAERstB,EAAM7gB,OAAS,CACbrhC,MAAO9B,KAAKqrD,YAAc9H,EAAU76C,EACpCguB,KAAM,WAER,MAAMwM,EAAUljC,KAAKgrD,gBAAgBzH,GASrC,GARgB,OAAZrgB,IACF8gB,EAAM9gB,QAAU,CACdphC,MAAOohC,EAAU,IACjBxM,KAAM,aAKNksB,EAAejD,mBAAoB,CACrC,MAAMtuC,EAAQrR,KAAKsrD,WACbrpD,EAAS2gD,EAAelE,qBAAqBrtC,EAAMsV,IAAKtV,EAAMhE,KAC9DqpB,EAAOksB,EAAejsB,eACtB40B,EAAUtkC,GAAShlB,EAAQ+N,GACjCg0C,EAAMr9B,IAAM,CAAC7kB,MAAOypD,EAAQ5kC,IAAK+P,KAAMA,GACvCstB,EAAM32C,IAAM,CAACvL,MAAOypD,EAAQl+C,IAAKqpB,KAAMA,GACvCstB,EAAMp9B,KAAO,CAAC9kB,MAAOypD,EAAQ3kC,KAAM8P,KAAMA,GACzCstB,EAAMn9B,OAAS,CAAC/kB,MAAOypD,EAAQ1kC,OAAQ6P,KAAMA,QACf,IAAnB60B,EAAQzkC,SACjBk9B,EAAMl9B,OAAS,CAAChlB,MAAOypD,EAAQzkC,OAAQ4P,KAAMA,SAEpB,IAAhB60B,EAAQxkC,MACjBi9B,EAAMj9B,IAAM,CAACjlB,MAAOypD,EAAQxkC,IAAK2P,KAAMA,SAEd,IAAhB60B,EAAQvkC,MACjBg9B,EAAMh9B,IAAM,CAACllB,MAAOypD,EAAQvkC,IAAK0P,KAAMA,GAE3C,CAGA,OAAOstB,CACT,EAYK,SAASwH,GAAoBrmD,EAAQkB,EAAMolD,GAChD,MAAMC,EAAevmD,EAAO1C,YAEtBR,EAASypD,EAAahpD,QACtBmoC,EAAU,GACV8gB,EAAQtlD,EAAK,GACbulD,EAAYjoD,KAAKiD,MAAM+kD,EAAQ,GAC/BE,EAAQxlD,EAAK,GACbylD,EAAYnoD,KAAKiD,MAAMilD,EAAQ,GAC/BE,EAAKN,EAAI,GACTO,EAAKP,EAAI,GACf,IAAK,IAAIroD,EAAI,EAAGA,EAAIyoD,IAASzoD,EAAG,CAC9BnB,EAAO+pD,GAAMN,EAAaM,GAAMF,EAAY1oD,EAC5C,IAAK,IAAIb,EAAI,EAAGA,EAAIopD,IAASppD,EAC3BN,EAAO8pD,GAAML,EAAaK,GAAMH,EAAYrpD,EAC5CsoC,EAAQ5nC,KAAK,IAAIlB,EAAME,EAAOS,SAElC,CACA,OAAOmoC,CACT,CCnQO,MAAMohB,GAOX,IAAU,GAKVjqD,WAAAA,CAAYkqD,QACY,IAAXA,IACTlsD,MAAK,GAAUksD,EAEnB,CASAC,QAAAA,CAAS7+C,GACP,OAAOtN,MAAK,GAAQsN,EACtB,CAOA8+C,SAAAA,GACE,OAAOpsD,MAAK,EACd,CAOAgE,SAAAA,GACE,OAAOhE,MAAK,GAAQmC,MACtB,CAOAkqD,QAAAA,CAAS1iC,GACP3pB,MAAK,GAAQiD,KAAK0mB,EACpB,CAOA2iC,SAAAA,CAAU1pD,GACR5C,MAAK,GAAUA,MAAK,GAAQ+e,OAAOnc,EACrC,CASAoL,WAAAA,GACE,IAAIlN,EAAI,EACJyrD,EAAK,EACLC,EAAK,EACT,IAAK,IAAIjqD,EAAI,EAAGA,EAAIvC,MAAK,GAAQmC,SAAUI,EAAG,CAC5C,MAAMkqD,EAAKzsD,MAAK,GAAQuC,GACxB,IAAImqD,EAEFA,EADEnqD,IAAMvC,MAAK,GAAQmC,OAAS,EACxBnC,MAAK,GAAQ,GAEbA,MAAK,GAAQuC,EAAI,GAEzB,MAAMoqD,EAAKF,EAAGtiD,OAASuiD,EAAItiD,OAASsiD,EAAIviD,OAASsiD,EAAGriD,OACpDtJ,GAAK6rD,EACLJ,IAAOE,EAAGtiD,OAASuiD,EAAIviD,QAAUwiD,EACjCH,IAAOC,EAAGriD,OAASsiD,EAAItiD,QAAUuiD,CACnC,CACA7rD,GAAK,GACL,MAAM8rD,EAAK,GAAK,EAAI9rD,GAIpB,OAHAyrD,GAAMK,EACNJ,GAAMI,EAEC,IAAI7+C,EAAQw+C,EAAIC,EACzB,EC1FK,MAAMK,GAOX,IAMA7qD,WAAAA,CAAYkqD,GACV,GAAIA,EAAO/pD,OAAS,EAClB,MAAM,IAAID,MAAM,oCAElBlC,MAAK,GAAUksD,EAAOxpD,MAAM,EAAG,EACjC,CASAypD,QAAAA,CAAS7+C,GACP,OAAOtN,MAAK,GAAQsN,EACtB,CAOAtJ,SAAAA,GACE,OAAOhE,MAAK,GAAQmC,MACtB,CAOA6L,WAAAA,GACE,OAAOhO,MAAK,GAAQ,EACtB,CASA+jD,QAAAA,CAAS+I,EAAiBC,GACxB,MAAM/I,EAAQ,CAAC,EACf,GAA4B,IAAxBhkD,MAAK,GAAQmC,OAAc,CAG7B,IAAI8gC,EAAQghB,GAFE,IAAIjB,GAAKhjD,MAAK,GAAQ,GAAIA,MAAK,GAAQ,IACvC,IAAIgjD,GAAKhjD,MAAK,GAAQ,GAAIA,MAAK,GAAQ,KAEjDijC,EAAQ,MACVA,EAAQ,IAAMA,GAEhB+gB,EAAM/gB,MAAQ,CACZnhC,MAAOmhC,EACPvM,KAAM,cAEV,CACA,OAAOstB,CACT,ECpDK,MAAMgJ,GAOX,IAOA,IAOA,IAQAhrD,WAAAA,CAAYirD,EAAQnsD,EAAGoH,GACrBlI,MAAK,GAAUitD,EACfjtD,MAAK,GAAKc,EACVd,MAAK,GAAKkI,CACZ,CAOAglD,SAAAA,GACE,OAAOltD,MAAK,EACd,CAOAgO,WAAAA,GACE,OAAOhO,MAAK,EACd,CAOAmtD,IAAAA,GACE,OAAOntD,MAAK,EACd,CAOAotD,IAAAA,GACE,OAAOptD,MAAK,EACd,CAQA6C,MAAAA,CAAOD,GACL,OAAe,OAARA,GACL5C,KAAKktD,YAAYrqD,OAAOD,EAAIsqD,cAC5BltD,KAAKmtD,SAAWvqD,EAAIuqD,QACpBntD,KAAKotD,SAAWxqD,EAAIwqD,MACxB,CAOArC,UAAAA,GACE,OAAOpnD,KAAKmgD,GAAK9jD,KAAKmtD,OAASntD,KAAKotD,MACtC,CASApC,eAAAA,CAAgBzH,GACd,OAhHJ,SAAgBziD,EAAGoH,EAAGnC,GACpB,IAAI+C,EAAM,KAIV,OAHU,OAANZ,GAAoB,OAANnC,IAChB+C,EAAMhI,EAAIoH,EAAInC,GAET+C,CACT,CA0GWmiD,CAAOjrD,KAAK+qD,aAAcxH,EAAU96C,EAAG86C,EAAU76C,EAC1D,CAcA4iD,QAAAA,GACE,MAAM+B,EAAUrtD,KAAKktD,YAAY/iD,OAC3BmjD,EAAUttD,KAAKktD,YAAY9iD,OAC3BogD,EAAUxqD,KAAKmtD,OACf1C,EAAUzqD,KAAKotD,OACfG,EAAc/C,EAAUC,EACxB+C,EAAW7pD,KAAKC,IAAI6mD,EAAS,GAG7BpF,EAAOiI,EAAU7C,EACjBrL,EAAU,GAEhB,IAAK,IAAI12C,EAJI4kD,EAAU7C,EAIJ/hD,EAAI28C,IAAQ38C,EAAG,CAChC,MAAMu0B,EAAOuwB,EAAW7pD,KAAKC,IAAI8E,EAAI4kD,EAAS,GAE9C,GAAI3pD,KAAKsH,IAAIgyB,GAAQ,KACnB,SAEF,MAAMwwB,EAASF,EAAc5pD,KAAK4G,KAAK0yB,GAEnCwwB,EAAS,IAGbrO,EAAQn8C,KAAK,CACX,CAACU,KAAK0N,MAAMg8C,EAAUI,GAAS9pD,KAAK0N,MAAM3I,IAC1C,CAAC/E,KAAK0N,MAAMg8C,EAAUI,GAAS9pD,KAAK0N,MAAM3I,KAE9C,CACA,OAAO02C,CACT,CASA2E,QAAAA,CAASnB,EAAgB5yC,GACvB,MAAMg0C,EAAQ,CAAC,EAETT,EAAYX,EAAetE,eACjC0F,EAAMljD,EAAI,CACRgB,MAAO9B,KAAKmtD,OAAS5J,EAAU96C,EAC/BiuB,KAAM,WAERstB,EAAM97C,EAAI,CACRpG,MAAO9B,KAAKotD,OAAS7J,EAAU76C,EAC/BguB,KAAM,WAER,MAAMwM,EAAUljC,KAAKgrD,gBAAgBzH,GASrC,GARgB,OAAZrgB,IACF8gB,EAAM9gB,QAAU,CACdphC,MAAOohC,EAAU,IACjBxM,KAAM,aAKNksB,EAAejD,mBAAoB,CACrC,MAAMP,EAAUp/C,KAAKsrD,WACrB,GAAuB,IAAnBlM,EAAQj9C,OAAc,CACxB,MAAMF,EAAS2gD,EAAezD,6BAA6BC,GACrD1oB,EAAOksB,EAAejsB,eACtB40B,EAAUtkC,GAAShlB,EAAQ+N,GACjCg0C,EAAMr9B,IAAM,CAAC7kB,MAAOypD,EAAQ5kC,IAAK+P,KAAMA,GACvCstB,EAAM32C,IAAM,CAACvL,MAAOypD,EAAQl+C,IAAKqpB,KAAMA,GACvCstB,EAAMp9B,KAAO,CAAC9kB,MAAOypD,EAAQ3kC,KAAM8P,KAAMA,GACzCstB,EAAMn9B,OAAS,CAAC/kB,MAAOypD,EAAQ1kC,OAAQ6P,KAAMA,QACf,IAAnB60B,EAAQzkC,SACjBk9B,EAAMl9B,OAAS,CAAChlB,MAAOypD,EAAQzkC,OAAQ4P,KAAMA,SAEpB,IAAhB60B,EAAQxkC,MACjBi9B,EAAMj9B,IAAM,CAACjlB,MAAOypD,EAAQxkC,IAAK2P,KAAMA,SAEd,IAAhB60B,EAAQvkC,MACjBg9B,EAAMh9B,IAAM,CAACllB,MAAOypD,EAAQvkC,IAAK0P,KAAMA,GAE3C,CACF,CAGA,OAAOstB,CACT,EAYK,SAAS0J,GAAkBvoD,EAAQi+B,EAAQqoB,GAChD,MAAMC,EAAevmD,EAAO1C,YAEtBR,EAASypD,EAAahpD,QACtBmoC,EAAU,GACV8iB,EAAUvqB,EAAO,GACjBwqB,EAAUxqB,EAAO,GACjBmqB,EAAcI,EAAUC,EACxBC,EAAWlqD,KAAKC,IAAIgqD,EAAS,GAC7B7B,EAAKN,EAAI,GACTO,EAAKP,EAAI,GAEf,IAAK,IAAIroD,EAAI,EAAGA,EAAIwqD,IAAWxqD,EAAG,CAIhC,MAAMo2B,EAAM71B,KAAK0N,MACfk8C,EAAc5pD,KAAK4G,KAAKsjD,EAAWlqD,KAAKC,IAAIR,EAAG,KAC3C0qD,EAAOpC,EAAaM,GAAM5oD,EAC1B2qD,EAAOrC,EAAaM,GAAM5oD,EAChC,IAAK,IAAIb,EAAI,EAAGA,EAAIi3B,IAAOj3B,EAAG,CAC5B,MAAMyrD,EAAOtC,EAAaK,GAAMxpD,EAC1B0rD,EAAOvC,EAAaK,GAAMxpD,EAGhCN,EAAO8pD,GAAMiC,EAEb/rD,EAAO+pD,GAAM8B,EACbjjB,EAAQ5nC,KAAK,IAAIlB,EAAME,EAAOS,UAE1BqrD,IAASD,IACX7rD,EAAO+pD,GAAM+B,EACbljB,EAAQ5nC,KAAK,IAAIlB,EAAME,EAAOS,WAI5BurD,IAASD,IACX/rD,EAAO8pD,GAAMkC,EAEbhsD,EAAO+pD,GAAM8B,EACbjjB,EAAQ5nC,KAAK,IAAIlB,EAAME,EAAOS,UAE1BqrD,IAASD,IACX7rD,EAAO+pD,GAAM+B,EACbljB,EAAQ5nC,KAAK,IAAIlB,EAAME,EAAOS,WAGpC,CACF,CACA,OAAOmoC,CACT,CCtQO,MAAMqjB,GAOX,IAOA,IAOAlsD,WAAAA,CAAYirD,EAAQ7pB,GAClBpjC,MAAK,GAAUitD,EACfjtD,MAAK,GAAUojC,CACjB,CAOA8pB,SAAAA,GACE,OAAOltD,MAAK,EACd,CAOAgO,WAAAA,GACE,OAAOhO,MAAK,EACd,CAOAmuD,SAAAA,GACE,OAAOnuD,MAAK,EACd,CASA6C,MAAAA,CAAOD,GACL,OAAe,OAARA,GACL5C,KAAKktD,YAAYrqD,OAAOD,EAAIsqD,cAC5BltD,KAAKmuD,cAAgBvrD,EAAIurD,WAC7B,CAOApD,UAAAA,GACE,OAAOpnD,KAAKmgD,GAAK9jD,KAAKmuD,YAAcnuD,KAAKmuD,WAC3C,CASAnD,eAAAA,CAAgBzH,GACd,OA9FJ,SAAgBziD,EAAGoH,EAAGnC,GACpB,IAAI+C,EAAM,KAIV,OAHU,OAANZ,GAAoB,OAANnC,IAChB+C,EAAMhI,EAAIoH,EAAInC,GAET+C,CACT,CAwFWmiD,CAAOjrD,KAAK+qD,aAAcxH,EAAU96C,EAAG86C,EAAU76C,EAC1D,CAcA4iD,QAAAA,GACE,MAAM+B,EAAUrtD,KAAKktD,YAAY/iD,OAC3BmjD,EAAUttD,KAAKktD,YAAY9iD,OAC3Bg5B,EAASpjC,KAAKmuD,YACdC,EAAUzqD,KAAKC,IAAIw/B,EAAQ,GAG3BiiB,EAAOiI,EAAUlqB,EACjBgc,EAAU,GAEhB,IAAK,IAAI12C,EAJI4kD,EAAUlqB,EAIJ16B,EAAI28C,IAAQ38C,EAAG,CAChC,MAAMu0B,EAAOmxB,EAAUzqD,KAAKC,IAAI8E,EAAI4kD,EAAS,GAE7C,GAAI3pD,KAAKsH,IAAIgyB,GAAQ,KACnB,SAEF,MAAMwwB,EAAS9pD,KAAK4G,KAAK0yB,GAErBwwB,EAAS,IAGbrO,EAAQn8C,KAAK,CACX,CAACU,KAAK0N,MAAMg8C,EAAUI,GAAS9pD,KAAK0N,MAAM3I,IAC1C,CAAC/E,KAAK0N,MAAMg8C,EAAUI,GAAS9pD,KAAK0N,MAAM3I,KAE9C,CACA,OAAO02C,CACT,CASA2E,QAAAA,CAASnB,EAAgB5yC,GACvB,MAAMg0C,EAAQ,CAAC,EAETT,EAAYX,EAAetE,eACjC0F,EAAM5gB,OAAS,CACbthC,MAAO9B,KAAKmuD,YAAc5K,EAAU96C,EACpCiuB,KAAM,WAER,MAAMwM,EAAUljC,KAAKgrD,gBAAgBzH,GASrC,GARgB,OAAZrgB,IACF8gB,EAAM9gB,QAAU,CACdphC,MAAOohC,EAAU,IACjBxM,KAAM,aAKNksB,EAAejD,mBAAoB,CACrC,MAAMP,EAAUp/C,KAAKsrD,WACrB,GAAuB,IAAnBlM,EAAQj9C,OAAc,CACxB,MAAMF,EAAS2gD,EAAezD,6BAA6BC,GACrD1oB,EAAOksB,EAAejsB,eACtB40B,EAAUtkC,GAAShlB,EAAQ+N,GACjCg0C,EAAMr9B,IAAM,CAAC7kB,MAAOypD,EAAQ5kC,IAAK+P,KAAMA,GACvCstB,EAAM32C,IAAM,CAACvL,MAAOypD,EAAQl+C,IAAKqpB,KAAMA,GACvCstB,EAAMp9B,KAAO,CAAC9kB,MAAOypD,EAAQ3kC,KAAM8P,KAAMA,GACzCstB,EAAMn9B,OAAS,CAAC/kB,MAAOypD,EAAQ1kC,OAAQ6P,KAAMA,QACf,IAAnB60B,EAAQzkC,SACjBk9B,EAAMl9B,OAAS,CAAChlB,MAAOypD,EAAQzkC,OAAQ4P,KAAMA,SAEpB,IAAhB60B,EAAQxkC,MACjBi9B,EAAMj9B,IAAM,CAACjlB,MAAOypD,EAAQxkC,IAAK2P,KAAMA,SAEd,IAAhB60B,EAAQvkC,MACjBg9B,EAAMh9B,IAAM,CAACllB,MAAOypD,EAAQvkC,IAAK0P,KAAMA,GAE3C,CACF,CAGA,OAAOstB,CACT,EC5LK,MAAMqK,GAOX,IAOA,IAMArsD,WAAAA,CAAYmgD,EAAKmM,GACftuD,MAAK,GAAOmiD,EACZniD,MAAK,GAAiBsuD,CACxB,CAOA,IAAkB,KAOlB,IAAS,KAOT,IAOA,IAOA,KAAY,EAcZC,QAAAA,CAASC,EAASC,EAAWrI,GAK3B,GAJApmD,MAAK,GAASwuD,EACdxuD,MAAK,GAAayuD,EAClBzuD,MAAK,GAAcomD,EAEfpmD,MAAK,GAAQ,CAKf,GAHAA,MAAK,KAELA,MAAK,GAAkBomD,EAAWsI,aACL,OAAzB1uD,MAAK,GACP,MAAM,IAAIkC,MAAM,6CAIlBlC,MAAK,IACP,CACF,CAOA2uD,QAAAA,GACE,OAAO3uD,MAAK,EACd,CAOA6mD,aAAAA,GACE,OAAO7mD,MAAK,EACd,CAOA4uD,QAAAA,GACE,OAAO5uD,MAAK,EACd,CAKA6uD,MAAAA,GACE7uD,MAAK,IAAY,EACbA,MAAK,KACPA,MAAK,IAAmB,GACpBA,MAAK,GAAO8uD,YACd9uD,MAAK,GAAO8uD,WAAWC,OAG7B,CAKAC,OAAAA,GACEhvD,MAAK,IAAY,EACbA,MAAK,KACPA,MAAK,IAAmB,GACpBA,MAAK,GAAO8uD,YACd9uD,MAAK,GAAO8uD,WAAWC,OAG7B,CAKAE,KAAAA,GACEjvD,MAAK,QAASQ,EACdR,MAAK,QAAaQ,EAClBR,MAAK,QAAcQ,CACrB,CAKA0uD,YAAAA,GAEElvD,MAAK,KAELA,MAAK,KAELA,MAAK,IAAmB,EAC1B,CAOA,IAAoB8G,GACd9G,MAAK,IAAUA,MAAK,GAAOmvD,aACbnvD,MAAK,GAAOmvD,YAAYjlC,KAAK,WACrCklC,QAAQtoD,EAEpB,CAOA,IAAmB80B,GACjB57B,MAAK,IAAoB,SAAUqvD,GACjCA,EAAOzE,QAAQhvB,EACjB,GACF,CAOA0zB,gBAAAA,CAAiB1zB,GACf,IAAI90B,EAAO,KAETA,EADE80B,EACMyzB,IACNrvD,MAAK,GAAaqvD,EAAO,EAGnBA,IACNrvD,MAAK,GAAcqvD,EAAO,EAG9BrvD,MAAK,GAAoB8G,EAC3B,CAKA,MACE9G,MAAK,IAAoB,SAAUqvD,GACjCA,EAAOztC,QACT,GACF,CAKA,MAEE,IAAK5hB,MAAK,KAAWA,MAAK,GAAO8uD,WAC/B,OAGF,MAAMv7C,EAAQvT,MAAK,GAAOmvD,YAGpBI,EACJvvD,MAAK,GAAgBwvD,WAAWxvD,MAAK,GAAQA,MAAK,GAAKyvD,YACzD,IAAK,IAAIltD,EAAI,EAAGA,EAAIgtD,EAAQptD,SAAUI,EAEpCvC,MAAK,GAAauvD,EAAQhtD,IAE1BgR,EAAMrQ,IAAIqsD,EAAQhtD,GAEtB,CAOA,IAAa8sD,GACX,IAAI3H,EAGJ2H,EAAOK,GAAG,kBAAmB1tC,IAE3BA,EAAM2tC,cAAe,EAErBjI,EAAgB,CACdkI,UAAW5vD,MAAK,GAAY4vD,UAC5BC,gBAAiB7vD,MAAK,GAAY6vD,gBACnC,IAGHR,EAAOK,GAAG,iBAAkB1tC,IAC1B,MAAMqtC,EAASrtC,EAAM8tC,OACfT,aAAkBtF,KAAAA,QNrEvB,SAAgCgG,EAAWV,GAChD,MAAM97C,EAAQ87C,EAAOF,aA7DvB,SAA2B1F,EAAM9iC,EAAKtZ,GACpC,IAAI2iD,GAAU,EACVvG,EAAKhhD,IAAMke,EAAIxc,QACjBs/C,EAAKhhD,EAAEke,EAAIxc,QACX6lD,GAAU,GACDvG,EAAKhhD,IAAM4E,EAAIlD,SACxBs/C,EAAKhhD,EAAE4E,EAAIlD,QACX6lD,GAAU,GAERvG,EAAK/gD,IAAMie,EAAIvc,QACjBq/C,EAAK/gD,EAAEie,EAAIvc,QACX4lD,GAAU,GACDvG,EAAK/gD,IAAM2E,EAAIjD,SACxBq/C,EAAK/gD,EAAE2E,EAAIjD,QACX4lD,GAAU,EAGd,CAuDSC,CAAkBZ,EATb,IAAIthD,GACbwF,EAAM9K,KACN8K,EAAM7K,KAEG,IAAIqF,EACdgiD,EAAUtnD,EAAI8K,EAAM9K,IACpBsnD,EAAUrnD,EAAI6K,EAAM7K,KAIxB,CM4DMwnD,CAAuBlwD,MAAK,GAAWmwD,cAAed,QACE,IAA7CrvD,MAAK,GAAgBowD,qBAC9BpwD,MAAK,GAAgBowD,oBAAoBf,GAI3CrvD,MAAK,GAAgBqwD,6BACnBrwD,MAAK,GAAaqvD,GAEpBrvD,MAAK,GAAgBswD,6BACnBtwD,MAAK,GAAaqvD,EAAQrvD,MAAK,GAAKyvD,YAGlCJ,EAAOP,WACTO,EAAOP,WAAWC,OAElB5qD,EAAOa,KAAK,gCAGdgd,EAAM2tC,cAAe,EAAI,IAG3BN,EAAOK,GAAG,gBAAiB1tC,IAEzB,MAAM2lC,EAAW,CACfiI,UAAW5vD,MAAK,GAAY4vD,UAC5BC,gBAAiB7vD,MAAK,GAAY6vD,iBAE9BvI,EAAU,IAAIM,GAClB5nD,MAAK,GACL0nD,EACAC,EACA3nD,MAAK,GAAWuwD,qBAGlBvwD,MAAK,GAAKwwD,eAAelJ,GAEzBtnD,MAAK,GAAe,CAClB0hB,KAAM,mBACNzO,KAAMjT,MAAK,GACXywD,OAAQzwD,MAAK,GAAW0wD,YACxB59C,KAAM5R,OAAO4R,KAAK60C,KAGpBD,EAAgB,CACdkI,UAAWjI,EAASiI,UACpBC,gBAAiBlI,EAASkI,iBAI5B7tC,EAAM2tC,cAAe,CAAI,IAG3BN,EAAOK,GAAG,wBAAyB1tC,IAClBA,EAAM8tC,OACda,WAAW,IAGpBtB,EAAOK,GAAG,kBAAmB1tC,IAC3B,MAAMqtC,EAASrtC,EAAM8tC,OACfT,aAAkBtF,KAAAA,QAIxBsF,EAAOhF,OAAO,QACVgF,EAAOP,WACTO,EAAOP,WAAWC,OAElB5qD,EAAOa,KAAK,gCACd,IAGFqqD,EAAOK,GAAG,iBAAkB1tC,IAC1B,MAAMqtC,EAASrtC,EAAM8tC,OACfT,aAAkBtF,KAAAA,QAIxBsF,EAAOhF,OAAO,QACVgF,EAAOP,WACTO,EAAOP,WAAWC,OAElB5qD,EAAOa,KAAK,gCACd,GAEJ,CAOA,IAAcqqD,GACZA,EAAO9oC,IAAI,kBACX8oC,EAAO9oC,IAAI,iBACX8oC,EAAO9oC,IAAI,gBACX8oC,EAAO9oC,IAAI,wBACX8oC,EAAO9oC,IAAI,kBACX8oC,EAAO9oC,IAAI,gBACb,ECnXK,MAAMqqC,GAMX,IAEA5uD,WAAAA,GACEhC,KAAK6wD,iBAEP,CAKAA,eAAAA,GACE7wD,MAAK,GAAS,IAAI+pD,KAAAA,OAElB,MAAM+G,EAAa,IAAI/G,KAAAA,MAAW,CAChCmC,OAAQ,EAAE,IAAK,GAAI,GAAI,IACvB7B,OAAQ,QAGJ0G,EAAa,IAAIhH,KAAAA,MAAW,CAChCmC,OAAQ,CAAC,IAAK,IAAK,GAAI,IACvB7B,OAAQ,QAEVrqD,MAAK,GAAOoF,MAAM,IAClBpF,MAAK,GAAOmjC,OAAO,IACnBnjC,MAAK,GAAOkD,IAAI4tD,GAChB9wD,MAAK,GAAOkD,IAAI6tD,EAClB,CAQAC,QAAAA,CAASvC,GACP,MAAMwC,EAAQxC,EAAUyC,gBAClB1I,EAAQyI,EAAMzI,QACd2I,EAAa1C,EAAU2C,gBACvBC,EAAW,CAAC5oD,EAAG,EAAI+/C,EAAM//C,EAAGC,EAAG,EAAI8/C,EAAM9/C,GAC/C1I,MAAK,GAAOyI,EAAEwoD,EAAM/sD,SAASuE,EAAKwoD,EAAM7rD,SAAW,EAAIojD,EAAM//C,IAC7DzI,MAAK,GAAO0I,EAAEuoD,EAAM/sD,SAASwE,EAAKuoD,EAAM9tB,UAAY,GAAKqlB,EAAM9/C,IAC/D1I,MAAK,GAAOwoD,MAAM6I,GAClBF,EAAWjuD,IAAIlD,MAAK,IAEpBmxD,EAAWpC,MACb,CAWAuC,gCAAAA,CAAiCC,EAC/BC,EAAYC,GACZ,GAAIzxD,KAAK0xD,YAAYH,GAGnB,OAFAvxD,KAAK2xD,0BAA0B3xD,MAAK,GAAQ,eAC5CA,KAAK2xD,0BAA0BH,EAAY,OAI7CxxD,KAAK2xD,0BAA0B3xD,MAAK,GAAQ,OAC5CA,KAAK2xD,0BAA0BH,EAAYC,EAC7C,CAQAE,yBAAAA,CAA0Bp+C,EAAOw+B,GAC/Bx+B,EAAMu2C,cAAcsF,SAAQ,SAAUwC,GAChCA,aAAkB7H,KAAAA,YACK,IAAlB6H,EAAOvH,QACduH,EAAOvH,OAAOtY,EAElB,GACF,CAKAnwB,MAAAA,GACE5hB,MAAK,GAAO4hB,QACd,CAQA8vC,WAAAA,CAAYH,GACV,MAAMM,EACF7xD,MAAK,GAAOoF,QAAUzB,KAAKsH,IAAIjL,MAAK,GAAO8xD,UAAY,EACrDC,EACF/xD,MAAK,GAAOmjC,SAAWx/B,KAAKsH,IAAIjL,MAAK,GAAOgyD,UAAY,EAC5D,OAAOruD,KAAKsH,IAAIsmD,EAAc9oD,EAAIzI,MAAK,GAAOyI,KAAOopD,GACjDluD,KAAKsH,IAAIsmD,EAAc7oD,EAAI1I,MAAK,GAAO0I,KAAOqpD,CACpD,ECpFK,MAAME,GAOX,IAOA,IAOA,IAOA,IAAmB,UAOnB,IAOA,IAOA,IAWAjwD,WAAAA,CAAYmgD,EAAKmM,GACftuD,MAAK,GAAOmiD,EACZniD,MAAK,GAAiBsuD,EACtBtuD,MAAK,GAAe,IAAIquD,GAAgBlM,EAAKmM,GAC7CtuD,MAAK,GAAS,IAAI4wD,EACpB,CAQAsB,cAAAA,CAAeC,EAAO1D,GACpB,MAAM2D,EAAiB3D,EAAU8B,oBAC7B4B,GACFA,aAAiBpI,KAAAA,OACjBoI,IAAUnyD,MAAK,GAAa2uD,YAC5ByD,EAAerL,8BAEf/mD,MAAK,GAAagvD,UAElBhvD,MAAK,GAAauuD,SAChB4D,EACA1D,EACAA,EAAU8B,oBAAoB1J,cAAcsL,EAAMhD,YAAYpoD,OAEhE/G,MAAK,GAAa6uD,SAEtB,CAOAwD,mBAAAA,GACE,IAAIvpD,EACJ,IAAI9I,MAAK,GAAa4uD,aACpB9lD,EAAM9I,MAAK,GAAa2uD,WAAWQ,YAC7BrmD,aAAeihD,KAAAA,OAIvB,OAAOjhD,CACT,CAOAwpD,mBAAAA,GACE,IAAIxpD,EAIJ,OAHI9I,MAAK,GAAa4uD,aACpB9lD,EAAM9I,MAAK,GAAa6mD,iBAEnB/9C,CACT,CAKAypD,qBAAAA,GACEvyD,MAAK,GAAagvD,UAClBhvD,MAAK,GAAaivD,OACpB,CAUA,IAAiB3hD,EAAOmhD,GACtB,MAAMwC,EAAQxC,EAAUyC,gBACxB,MAAO,CACLzoD,EAAGwoD,EAAM/sD,SAASuE,EAAI6E,EAAM7E,EAAIwoD,EAAMzI,QAAQ//C,EAC9CC,EAAGuoD,EAAM/sD,SAASwE,EAAI4E,EAAM5E,EAAIuoD,EAAMzI,QAAQ9/C,EAElD,CAOA8pD,oBAAAA,CAAqBC,GACnBzyD,MAAK,GAAmByyD,CAC1B,CAKA,MAEEzyD,MAAK,GAAkB0yD,SAASC,KAAKxI,MAAMsI,OAC3CC,SAASC,KAAKxI,MAAMsI,OAASzyD,MAAK,GAElCA,MAAK,GAAqB4yD,QAAQ,IACpC,CAKAC,oBAAAA,QAEsC,IAAzB7yD,MAAK,KACd0yD,SAASC,KAAKxI,MAAMsI,OAASzyD,MAAK,GAClCA,MAAK,QAAkBQ,QAGgB,IAA9BR,MAAK,IACdA,MAAK,GAAqB4yD,QAAQ,EAEtC,CAQA,IAAuBpB,GAErBA,EAAW9B,GAAG,aAAa,KACzB1vD,MAAK,GAAuBwxD,EAC5BxxD,MAAK,IAAwB,IAI/BwxD,EAAW9B,GAAG,YAAY,KACxB1vD,KAAK6yD,uBACL7yD,MAAK,QAAuBQ,CAAS,GAEzC,CAOA,IAA0BgxD,GACxBA,EAAWjrC,IAAI,aACfirC,EAAWjrC,IAAI,WACjB,CASAusC,sBAAAA,CAAuBtB,EAAYpL,EAAYqI,GAE7CzuD,MAAK,GAAuBwxD,GAG5BxxD,MAAK,GAAmBwxD,EAAYpL,EAAYqI,GAGhDzuD,MAAK,GAAmBwxD,EAAYpL,EAAYqI,GAGhD+C,EAAW9B,GAAG,YAAY,KAExB,MAAMqD,EAAmB3M,EAAW4M,SAmBpCC,GAASC,cAAc9M,GAjBCA,IAEtB,MAAM+M,EAAc/M,EAAW4M,SAEzB1L,EAAU,IAAIM,GAClBxB,EACA,CAAC4M,SAAUD,GACX,CAACC,SAAUG,GACX1E,EAAU8B,qBAGZvwD,MAAK,GAAKwwD,eAAelJ,GAEzBA,EAAQE,SAAS,GAI+B,GAEtD,CASA,IAAmBgK,EAAYpL,EAAYqI,GACzC,MAAM0C,EAAa1C,EAAU2C,gBAEvBe,EAAQX,EAAW1H,YAAYJ,IAAiB,GACtD,KAAMyI,aAAiBpI,KAAAA,OACrB,OAKF,IAAIqJ,EACAC,EACA3L,EACA3V,EANJogB,EAAMxH,WAAU,GAShBwH,EAAMzC,GAAG,kBAAmB1tC,IAE1B+vB,EAASogB,EAAM9H,SAEf+I,EAAe,CACb3qD,EAAG0pD,EAAM1pD,IACTC,EAAGypD,EAAMzpD,KAEX2qD,EAAc,CACZ5qD,EAAGuZ,EAAM8tC,OAAOrnD,IAChBC,EAAGsZ,EAAM8tC,OAAOpnD,KAGlBg/C,EAAgB,CACdkI,UAAWxJ,EAAWwJ,UACtBC,gBAAiBzJ,EAAWyJ,iBAI9B7vD,MAAK,GAAOgxD,SAASvC,GAErBzuD,MAAK,GAAasvD,kBAAiB,GAEnC6B,EAAWpC,MAAM,IAInBoD,EAAMzC,GAAG,iBAAkB1tC,IAEzB,MAAME,ERpKL,SAA+B6tC,EAAWoC,GAO/C,MAAO,CAACxrC,IANI,IAAI5Y,EAAQ,EAAG,GAMTV,IALN,IAAIU,EACdgiD,EAAUtnD,EAAI9E,KAAKsH,IAAIknD,EAAM/sD,SAC7B2qD,EAAUrnD,EAAI/E,KAAKsH,IAAIknD,EAAMhvB,WAIjC,CQ4JoBmwB,CAAsB7E,EAAU0B,cAAegC,GAC7D,GAAIjwC,IRnJH,SAAwBiwC,EAAOxrC,EAAKtZ,GAEzC,MAAMkmD,EAAYpB,EAAMqB,cAAc,CAACC,WAAYtB,EAAMhD,cACzD,OAAOoE,EAAU9qD,EAAIke,EAAIxc,QACvBopD,EAAU9qD,EAAI4E,EAAIlD,QAClBopD,EAAU7qD,EAAIie,EAAIvc,QAClBmpD,EAAU7qD,EAAI2E,EAAIjD,MACtB,CQ4IoBspD,CAAevB,EAAOjwC,EAAMyE,IAAKzE,EAAM7U,KAGnD,OAFA8kD,EAAM1pD,EAAE4qD,EAAY5qD,QACpB0pD,EAAMzpD,EAAE2qD,EAAY3qD,GAKtB,MAAMu0B,EAAO,CACXx0B,EAAGuZ,EAAM8tC,OAAOrnD,IAAM4qD,EAAY5qD,EAClCC,EAAGsZ,EAAM8tC,OAAOpnD,IAAM2qD,EAAY3qD,GAE9BirD,EAAWnC,EAAW1H,cACtB8J,OACgC,IAA7BxN,EAAWyN,cACpB,IAAK,MAAMC,KAASH,EAEdG,IAAU9xC,EAAM8tC,QACA,UAAjBgE,EAAMtqD,SAAuBoqD,GACb,cAAjBE,EAAMtqD,QAKRsqD,EAAMC,KAAK92B,GAIbo2B,EAAc,CACZ5qD,EAAGuZ,EAAM8tC,OAAOrnD,IAChBC,EAAGsZ,EAAM8tC,OAAOpnD,KAIlB,MAAMhJ,EAAU0mD,EAAWsI,aAE3BhvD,EAAQs0D,8BAA8B5N,EAAYnpB,GAElDv9B,EAAQu0D,mBAAmB7N,EAAYoL,EAAYxxD,MAAK,GAAKyvD,YAE7D/vD,EAAQw0D,gBAAgB1C,GAExB,MAAM2C,EAAaC,GAAcpyC,EAAMqyC,KACjCnwD,EAAS,CACbuE,EAAG0rD,EAAWhqD,OACdzB,EAAGyrD,EAAW/pD,QAEVkqD,EAAWt0D,MAAK,GAAiBkE,EAAQuqD,GAC/CzuD,MAAK,GAAOsxD,iCAAiCgD,EAC3C9C,EAAYzf,GAEdof,EAAWpC,MAAM,IAInBoD,EAAMzC,GAAG,gBAAiB1tC,IAIxB,GAFAhiB,MAAK,GAAO4hB,cAES,IAAVI,QACY,IAAdA,EAAMqyC,IACb,OAEF,MAAM1kD,EAAUwiD,EAAM1pD,IAAhBkH,EAAwBwiD,EAAMzpD,IAE9ByrD,EAAaC,GAAcpyC,EAAMqyC,KACjCnwD,EAAS,CACbuE,EAAG0rD,EAAWhqD,OACdzB,EAAGyrD,EAAW/pD,QAEVkqD,EAAWt0D,MAAK,GAAiBkE,EAAQuqD,GAC/C,GAAIzuD,MAAK,GAAO0xD,YAAY4C,GAAW,CAErC9C,EAAW/oD,EAAE2qD,EAAa3qD,GAC1B+oD,EAAW9oD,EAAE0qD,EAAa1qD,GAE1B1I,MAAK,GAAagvD,UAClBhvD,MAAK,GAAaivD,QAClBjvD,MAAK,GAAO2xD,0BAA0BH,EAAYzf,GAElDqU,EAAWwJ,UAAYlI,EAAckI,UACrCxJ,EAAWyJ,gBAAkBnI,EAAcmI,gBAG3C,MAAMvI,EAAU,IAAIC,GAClBnB,EACAqI,EAAU8B,qBAGZvwD,MAAK,GAAKwwD,eAAelJ,GAEzBA,EAAQE,UAGRxnD,KAAK6yD,sBACP,KAAO,CACL,MAAM0B,EAAc,CAClB9rD,EAAGkH,EAAQyjD,EAAa3qD,EACxBC,EAAGiH,EAAQyjD,EAAa1qD,GAE1B,GAAsB,IAAlB6rD,EAAY9rD,GAA6B,IAAlB8rD,EAAY7rD,EAAS,CAE9C,MAAMi/C,EAAW,CACfiI,UAAWxJ,EAAWwJ,UACtBC,gBAAiBzJ,EAAWyJ,iBAExBvI,EAAU,IAAIM,GAClBxB,EACAsB,EACAC,EACA8G,EAAU8B,qBAGZvwD,MAAK,GAAKwwD,eAAelJ,GAEzBtnD,MAAK,GAAe,CAClB0hB,KAAM,mBACNzO,KAAMmzC,EACNqK,OAAQhC,EAAUiC,YAClB59C,KAAM5R,OAAO4R,KAAK60C,KAGpBD,EAAgB,CACdkI,UAAWjI,EAASiI,UACpBC,gBAAiBlI,EAASkI,gBAE9B,CAEA7vD,MAAK,GAAasvD,kBAAiB,GACnCtvD,MAAK,GAAakvD,cACpB,CAEAiC,EAAWpC,OAEXqE,EAAe,CACb3qD,EAAG0pD,EAAM1pD,IACTC,EAAGypD,EAAMzpD,IACV,GAEL,CASA,IAAmB8oD,EAAYpL,EAAYqI,GACzC,MAAMztC,EAAQwwC,EAAW1H,YAAYN,IAAiB,GACtD,KAAMxoC,aAAiB+oC,KAAAA,OACrB,OAKF,IAAIqJ,EACAoB,EAJJxzC,EAAM2pC,WAAU,GAOhB3pC,EAAM0uC,GAAG,kBAAkB,KAEzB0D,EAAe,CACb3qD,EAAGuY,EAAMvY,IACTC,EAAGsY,EAAMtY,KAGX8rD,EAAwBpO,EAAWyN,aAAa,IAIlD7yC,EAAM0uC,GAAG,iBAAiB,KAERtJ,EAAWsI,aAEnBwF,gBAAgB1C,EAAW,IAIrCxwC,EAAM0uC,GAAG,gBAAgB,KACvB,MAAM6E,EACDvzC,EAAMvY,IAAM2qD,EAAa3qD,EADxB8rD,EAEDvzC,EAAMtY,IAAM0qD,EAAa1qD,EAE9B,GAAsB,IAAlB6rD,GAAyC,IAAlBA,EAAqB,CAC9C,MAAME,EAAmB,IAAI1mD,EAAQiT,EAAMvY,IAAKuY,EAAMtY,KAEtD09C,EAAWyN,cAAgBY,EAE3B,MAAMnN,EAAU,IAAIM,GAClBxB,EACA,CAACyN,cAAeW,GAChB,CAACX,cAAeY,GAChBhG,EAAU8B,qBAGZvwD,MAAK,GAAKwwD,eAAelJ,GAEzBtnD,MAAK,GAAe,CAClB0hB,KAAM,mBACNzO,KAAMmzC,EACNqK,OAAQhC,EAAUiC,YAClB59C,KAAM,CAAC,mBAGT0hD,EAAwBC,CAC1B,CACArB,EAAe,CAAC3qD,EAAGuY,EAAMvY,IAAKC,EAAGsY,EAAMtY,IAAI,GAE/C,CAOAgsD,oBAAAA,CAAqBlD,GAEnBxxD,MAAK,GAA0BwxD,GAE/BA,EAAWjrC,IAAI,YAEf,MAAM4rC,EAAQX,EAAW1H,YAAYJ,IAAiB,GAClDyI,aAAiBpI,KAAAA,QACnBoI,EAAMxH,WAAU,GAChBwH,EAAM5rC,IAAI,kBACV4rC,EAAM5rC,IAAI,iBACV4rC,EAAM5rC,IAAI,iBAGZ,MAAMvF,EAAQwwC,EAAW1H,YAAYN,IAAiB,GAClDxoC,aAAiB+oC,KAAAA,QACnB/oC,EAAM2pC,WAAU,GAChB3pC,EAAMuF,IAAI,kBACVvF,EAAMuF,IAAI,gBAEd,EChgBK,MAAMouC,GAOX,IAOA,IAAc,KAOd,IAOA,IAOA,IAAY,CAAClsD,EAAG,EAAGC,EAAG,GAOtB,IAAa,CAACD,EAAG,EAAGC,EAAG,EAAGC,EAAG,GAO7B,IAAc,CAACF,EAAG,EAAGC,EAAG,GAOxB,IAAc,CAACD,EAAG,EAAGC,EAAG,GAOxB,IAAc,CAACD,EAAG,EAAGC,EAAG,GAOxB,IAAc,CAACD,EAAG,EAAGC,EAAG,GAOxB,IAOA,IAOA,IAOA,IAOA,IAOA,IAOA,KAAiB,EAMjB1G,WAAAA,CAAY4yD,GACV50D,MAAK,GAAgB40D,EAErB50D,MAAK,GAAc60D,WAAa,YAClC,CAOAC,eAAAA,CAAgBC,GACd/0D,MAAK,GAAgB+0D,CACvB,CAOArE,SAAAA,GACE,OAAO1wD,MAAK,EACd,CAOAg1D,mBAAAA,GACE,OAAOh1D,MAAK,EACd,CAOA,IAAmB,IAAIyhB,GAOvByvC,aAAAA,GACE,OAAOlxD,MAAK,EACd,CAOAoxD,aAAAA,GAEE,OAAOpxD,MAAK,GAAYi1D,YAAY,EACtC,CAOA1E,iBAAAA,GACE,OAAOvwD,MAAK,EACd,CAOAk1D,cAAAA,CAAeC,GACbn1D,MAAK,GAAem1D,CACtB,CASAC,KAAAA,GACE,OAAOp1D,MAAK,GAAc+G,EAC5B,CAKAsuD,aAAAA,GACEr1D,MAAK,GAAc4hB,QACrB,CAOAuuC,WAAAA,GACE,OAAOnwD,MAAK,EACd,CAOAs1D,UAAAA,GACE,OAAOt1D,MAAK,GAAY4yD,SAC1B,CAOA2C,UAAAA,CAAWC,GACTx1D,MAAK,GAAY4yD,QAAQjvD,KAAKgjB,IAAIhjB,KAAK0J,IAAImoD,EAAO,GAAI,GACxD,CAKAC,cAAAA,GAEE,MAAMjN,EAAQxoD,MAAK,GAAYwoD,QACzBniD,EAAOrG,MAAK,GAAYqG,OAC9BrG,MAAK,GAAYyI,GAAKpC,EAAKjB,MAAQojD,EAAM//C,EAEzC,MAAMvE,EAASlE,MAAK,GAAYkE,SAChCA,EAAOuE,GAAKzI,MAAK,GAAYyI,EAC7BzI,MAAK,GAAYkE,OAAOA,EAC1B,CAKAwxD,cAAAA,GAEE,MAAMlN,EAAQxoD,MAAK,GAAYwoD,QACzBniD,EAAOrG,MAAK,GAAYqG,OAC9BrG,MAAK,GAAY0I,GAAKrC,EAAK88B,OAASqlB,EAAM9/C,EAE1C,MAAMxE,EAASlE,MAAK,GAAYkE,SAChCA,EAAOwE,GAAK1I,MAAK,GAAY0I,EAC7B1I,MAAK,GAAYkE,OAAOA,EAC1B,CAKAyxD,UAAAA,GACE31D,MAAK,GAAWyI,IAAM,CACxB,CAKAmtD,UAAAA,GACE51D,MAAK,GAAW0I,IAAM,CACxB,CAKAmtD,UAAAA,GACE71D,MAAK,GAAW2I,IAAM,CACxB,CAQAmtD,QAAAA,CAASC,EAAU5wD,GACjB,MAAM6wD,EACJh2D,MAAK,GAAau9C,6BAA6B,CAC7C90C,EAAGstD,EAASttD,EAAIzI,MAAK,GAAWyI,EAChCC,EAAGqtD,EAASrtD,EAAI1I,MAAK,GAAW0I,EAChCC,EAAGotD,EAASptD,EAAI3I,MAAK,GAAW2I,IAE9BstD,EAAgB,CACpBxtD,EAAGzI,MAAK,GAAUyI,EAAIutD,EAAiBvtD,EACvCC,EAAG1I,MAAK,GAAU0I,EAAIstD,EAAiBttD,GAGnCxE,EAASlE,MAAK,GAAYkE,SAEhC,GAA6B,IAAzBP,KAAKsH,IAAI8qD,EAASttD,IACK,IAAzB9E,KAAKsH,IAAI8qD,EAASrtD,IACO,IAAzB/E,KAAKsH,IAAI8qD,EAASptD,GAAU,CAE5B,MAAMutD,EAAc,CAClBztD,EAAGvE,EAAOuE,EAAIzI,MAAK,GAAYyI,EAC/BC,EAAGxE,EAAOwE,EAAI1I,MAAK,GAAY0I,GAGjC1I,MAAK,GAAc,CAACyI,EAAG,EAAGC,EAAG,GAC7B1I,MAAK,GAAYkE,OAAOgyD,EAC1B,MACE,QAAsB,IAAX/wD,EAAwB,CACjC,IAAIgxD,EAAcn2D,MAAK,GAAaw8C,2BAA2B,CAC7D/zC,EAAGtD,EAAOgF,OACVzB,EAAGvD,EAAOiF,OACVzB,EAAGxD,EAAOkF,SAKZ8rD,EAAc,CACZ1tD,EAAG0tD,EAAY1tD,EAAIzI,MAAK,GAAYyI,EACpCC,EAAGytD,EAAYztD,EAAI1I,MAAK,GAAY0I,GAGtC,MAAM0tD,EAAYC,GAChBnyD,EAAQlE,MAAK,GAAYwoD,QAASyN,EAAeE,GAE7CG,EAAgB,CACpB7tD,EAAGzI,MAAK,GAAYyI,EAAI2tD,EAAU3tD,EAAIvE,EAAOuE,EAC7CC,EAAG1I,MAAK,GAAY0I,EAAI0tD,EAAU1tD,EAAIxE,EAAOwE,GAG/C1I,MAAK,GAAcs2D,EACnBt2D,MAAK,GAAYkE,OAAOkyD,EAC1B,CAGFp2D,MAAK,GAAYwoD,MAAMyN,GAEvBj2D,MAAK,GAAkBi2D,EACzB,CASAM,SAAAA,CAAUR,EAAUS,GAClB,MAAMR,EAAmBh2D,MAAK,GAAau9C,6BAA6B,CACtE90C,EAAGstD,EAASttD,EAAIzI,MAAK,GAAWyI,EAChCC,EAAGqtD,EAASrtD,EAAI1I,MAAK,GAAW0I,EAChCC,EAAGotD,EAASptD,EAAI3I,MAAK,GAAW2I,IAE5BstD,EAAgB,CACpBxtD,EAAGzI,MAAK,GAAUyI,EAAIutD,EAAiBvtD,EACvCC,EAAG1I,MAAK,GAAU0I,EAAIstD,EAAiBttD,GAEzC1I,MAAK,GAAYwoD,MAAMyN,GAEvBj2D,MAAK,GAAc,CACjByI,EAAG+tD,EAAmB/tD,EAAIzI,MAAK,GAAUyI,EACzCC,EAAG8tD,EAAmB9tD,EAAI1I,MAAK,GAAU0I,GAE3C,MAAMxE,EAASlE,MAAK,GAAYkE,SAChClE,MAAK,GAAYkE,OAAO,CACtBuE,EAAGvE,EAAOuE,EAAIzI,MAAK,GAAYyI,EAC/BC,EAAGxE,EAAOwE,EAAI1I,MAAK,GAAY0I,GAEnC,CAOA+tD,SAAAA,CAAUL,GACR,MAAMM,EACJ12D,MAAK,GAAaw8C,2BAA2B4Z,GAC/Cp2D,MAAK,GAAYkE,OAAO,CACtBuE,EAAGiuD,EAAejuD,EAChBzI,MAAK,GAAYyI,EACjBzI,MAAK,GAAYyI,EACjBzI,MAAK,GAAYyI,EACjBzI,MAAK,GAAYyI,EACnBC,EAAGguD,EAAehuD,EAChB1I,MAAK,GAAY0I,EACjB1I,MAAK,GAAY0I,EACjB1I,MAAK,GAAY0I,EACjB1I,MAAK,GAAY0I,GAEvB,CASAiuD,aAAAA,CAAcC,EAActa,GAC1B,MAAM8B,EAAcp+C,MAAK,GAAaw9C,uBAChC4Y,EAAYp2D,MAAK,GAAaw8C,2BAA2B,CAC7D/zC,EAAmB,IAAhB21C,EAAoBwY,EAAazsD,OAASmyC,EAAYnyC,OACzDzB,EAAmB,IAAhB01C,EAAoBwY,EAAaxsD,OAASkyC,EAAYlyC,OACzDzB,EAAmB,IAAhBy1C,EAAoBwY,EAAavsD,OAASiyC,EAAYjyC,SAErDwsD,EAAc72D,MAAK,GAAYyI,IAAM2tD,EAAU3tD,GACnDzI,MAAK,GAAY0I,IAAM0tD,EAAU1tD,EAEnC,GAAImuD,EAAa,CACf,MAAM3yD,EAASlE,MAAK,GAAYkE,SAChClE,MAAK,GAAYkE,OAAO,CACtBuE,EAAGvE,EAAOuE,EAAIzI,MAAK,GAAYyI,EAAI2tD,EAAU3tD,EAC7CC,EAAGxE,EAAOwE,EAAI1I,MAAK,GAAY0I,EAAI0tD,EAAU1tD,IAE/C1I,MAAK,GAAco2D,CACrB,CACA,OAAOS,CACT,CAOAC,OAAAA,CAAQl7B,GACN57B,MAAK,GAAcmqD,MAAM2M,QAAUl7B,EAAO,GAAK,MACjD,CAOAm7B,SAAAA,GACE,MAA4C,KAArC/2D,MAAK,GAAcmqD,MAAM2M,OAClC,CAMA/H,IAAAA,GACE/uD,MAAK,GAAY+uD,MACnB,CASAnR,UAAAA,CAAWv3C,EAAM8hB,EAAS6uC,GAExBh3D,MAAK,GAAYqG,EACjBrG,MAAK,GAAemoB,EACpBnoB,MAAK,GAAoBg3D,EAGzBh3D,MAAK,GAAc,IAAI+pD,KAAAA,OAAY,CACjCkN,UAAWj3D,MAAK,GAChBoF,MAAOpF,MAAK,GAAUyI,EACtB06B,OAAQnjC,MAAK,GAAU0I,EACvBwuD,WAAW,IAIbl3D,MAAK,GAAYm3D,aAAaC,aAAa,QAAS,IAGpD,MAAMjG,EAAa,IAAIpH,KAAAA,OAAY,CACjCmN,WAAW,EACXtM,SAAS,IAEX5qD,MAAK,GAAYkD,IAAIiuD,EACvB,CASAkG,kBAAAA,CAAmBC,EAAiBC,EAAQlQ,GA8B1C,GA7BArnD,MAAK,GAAUu3D,EAEfD,EAAgBviB,iBAAiB,iBAAkB/yB,IAEjDhiB,MAAK,GAAmBgiB,EAAM/O,MAAM,GACpCjT,KAAKoxD,gBAAgBrC,MAAM,IAE7BuI,EAAgBviB,iBAAiB,oBAAqB/yB,IAEpDhiB,MAAK,GAAsBgiB,EAAM/O,MACjCjT,KAAKoxD,gBAAgBrC,MAAM,IAE7BuI,EAAgBviB,iBAAiB,oBAAqB/yB,IAEpDhiB,MAAK,GAAsBgiB,EAAM/O,MACjCjT,KAAKoxD,gBAAgBrC,MAAM,IAE7BuI,EAAgBviB,iBACd,iCACC/yB,IACChiB,KAAKw3D,8BAA8Bx1C,EAAM/O,KAAK,IAKlDjT,MAAK,GAAkB,IAAI4mD,GAAe0Q,GAIN,IAAhCA,EAAgBtzD,YAClB,IAAK,MAAMoiD,KAAckR,EAAgBvR,UAEvC/lD,MAAK,GAAmBomD,GAAY,GAKpCiB,EAHgB,IAAIoQ,GAClBrR,EAAYpmD,KAAKuwD,qBAKzB,CAOAiH,6BAAAA,CAA8B57B,GAC5B,MAAMu1B,EAAanxD,KAAKoxD,gBAKxB,GAFApxD,MAAK,GAAYk3D,WAAU,QAEO,IAAvBl3D,MAAK,GAA+B,CAE7CA,MAAK,GAAcuyD,wBAEnB,MAAMmF,EAAevG,EAAWrH,cAChC,IAAK,MAAM6N,KAAYD,EACjBC,aAAoB5N,KAAAA,OACtB4N,EAAS7N,cAAcsF,SAAS77C,IAC1BA,aAAiBw2C,KAAAA,OACnB/pD,MAAK,GAAc00D,qBAAqBnhD,EAC1C,GAIR,CAGA,MAAM6+C,EAAiBpyD,KAAKuwD,oBAC5B,GAAI30B,GACFw2B,EAAetL,qBAAqBd,aAAc,CAElD,MAAM4R,EACJ53D,KAAK63D,qBAAqB/N,cAED,IAAvB8N,EAAYz1D,SACdnC,MAAK,GAAYk3D,WAAU,GAC3B/F,EAAW+F,WAAU,SAGW,IAAvBl3D,MAAK,IACd43D,EAAYxI,SAAS77C,IACnB,GAAIA,aAAiBw2C,KAAAA,MAAa,CAChC,MAAM3D,EAAagM,EAAevL,cAActzC,EAAMxM,MACtD/G,MAAK,GAAc8yD,uBAAuBv/C,EAAO6yC,EAAYpmD,KAC/D,IAGN,CAEAmxD,EAAWpC,MACb,CAQA,IAAyB3I,GACvB,IAAI8F,EAUJ,OALEA,OAFoC,IAA3B9F,EAAW0R,YAEX1R,EAAW0R,YAGX,CAAC1R,EAAW9I,aAEhBt9C,MAAK,GAAeksD,EAC7B,CAQA,IAAeA,GACb,IAAIpjD,EAAM,GACV,IAAK,MAAM6gB,KAASuiC,EACC,IAAfpjD,EAAI3G,SACN2G,GAAO,KAOTA,GAAOwI,EALW,CAChBN,EAAe2Y,EAAMxf,OAAQ,GAC7B6G,EAAe2Y,EAAMvf,OAAQ,GAC7B4G,EAAe2Y,EAAMtf,OAAQ,KAIjC,OAAOvB,CACT,CAQA,IAAgBs9C,GACd,IAAIt9C,EAEJ,MAAMivD,EAAa/3D,MAAK,GAAyBomD,GAC3C4R,EAAgBh4D,KAAKoxD,gBAAgBtH,YACzCG,GAAa8N,IACf,GAA6B,IAAzBC,EAAc71D,OAAc,CAC9B,MAAMw1D,EAAWK,EAAc,GAC/B,KAAML,aAAoB5N,KAAAA,OACxB,OAEF,MAAMkO,EAAcN,EAAS7N,YAC3BG,GAAa7D,EAAWr/C,KACC,IAAvBkxD,EAAY91D,QACd81D,EAAY,aAAclO,KAAAA,QAC1BjhD,EAAMmvD,EAAY,GAEtB,CACA,OAAOnvD,CACT,CASA,IAAmBs9C,EAAYwE,GAE7B,IAAKxE,EAAW8R,iBAAiBl4D,MAAK,IACpC,OAEF,MAAM+3D,EAAa/3D,MAAK,GAAyBomD,GAGjD,IAAIuR,EAAW33D,KAAKoxD,gBAAgBtH,YAClCG,GAAa8N,IAAa,GAS5B,QARwB,IAAbJ,IACTA,EAAW,IAAI5N,KAAAA,OAAY,CACzBhjD,GAAIgxD,EACJvuD,KAAM,iBACNohD,QAASA,IAEX5qD,KAAKoxD,gBAAgBluD,IAAIy0D,MAErBA,aAAoB5N,KAAAA,OACxB,OAGF,MAAMI,EAAQ,IAAInC,GACZiJ,EAAQjxD,KAAKkxD,gBACnB/G,EAAM1B,aAAawI,EAAMzI,SAIzB,MACMgJ,EADUpL,EAAWsI,aACAyJ,iBAAiB/R,EAAY+D,GAExDwN,EAASz0D,IAAIsuD,GAGT5G,QAC4B,IAAvB5qD,MAAK,IAEZA,MAAK,GAAc8yD,uBAAuBtB,EAAYpL,EAAYpmD,MAGpEA,KAAKo4D,mBAAmB5G,EAC1B,CAQA,IAAsBpL,GACpB,MAAMoL,EAAaxxD,MAAK,GAAgBomD,GACxC,OAAMoL,aAAsBzH,KAAAA,OAI5ByH,EAAW5vC,UACJ,IAJLzd,EAAOW,MAAM,6BACN,EAIX,CAOA,IAAsBshD,GAEpBA,EAAWI,uBAEPxmD,MAAK,GAAsBomD,IAC7BpmD,MAAK,GAAmBomD,GAAY,EAExC,CASAiS,cAAAA,CAAeC,EAAeC,EAAqBC,GAEjDx4D,MAAK,GAAYoF,MAAMkzD,EAAc7vD,GACrCzI,MAAK,GAAYmjC,OAAOm1B,EAAc5vD,GAGtC,MAAM+vD,EAAsB,CAC1BhwD,EAAG8vD,EAAsBv4D,MAAK,GAAayI,EAC3CC,EAAG6vD,EAAsBv4D,MAAK,GAAa0I,GAKvCqtD,EAAW,CACfttD,EAAGzI,MAAK,GAAYwoD,QAAQ//C,EAAIgwD,EAAoBhwD,EAAIzI,MAAK,GAAUyI,EACvEC,EAAG1I,MAAK,GAAYwoD,QAAQ9/C,EAAI+vD,EAAoB/vD,EAAI1I,MAAK,GAAU0I,GAIrE1I,MAAK,GAAYwoD,QAAQ//C,IAAMstD,EAASttD,GAC1CzI,MAAK,GAAYwoD,QAAQ9/C,IAAMqtD,EAASrtD,IACxC1I,MAAK,GAAYy4D,EACjBz4D,MAAK,GAAYwoD,MAAMuN,IAIzB,MAAM2C,EAAgB,CACpBjwD,EAAG+vD,EAAU/vD,EAAIgwD,EAAoBhwD,EACrCC,EAAG8vD,EAAU9vD,EAAI+vD,EAAoB/vD,GAGjCiwD,EAAkB,CACtBlwD,EAAG6vD,EAAc7vD,EAAIgwD,EAAoBhwD,EACzCC,EAAG4vD,EAAc5vD,EAAI+vD,EAAoB/vD,GAErCkwD,EAAgB,CACpBnwD,EAA0B,IAAvBzI,MAAK,GAAYyI,EAAUkwD,EAAgBlwD,EAAI,EAClDC,EAA0B,IAAvB1I,MAAK,GAAY0I,EAAUiwD,EAAgBjwD,EAAI,GAIhD1I,MAAK,GAAYyI,IAAMiwD,EAAcjwD,GACvCzI,MAAK,GAAY0I,IAAMgwD,EAAchwD,GACrC1I,MAAK,GAAYyI,IAAMmwD,EAAcnwD,GACrCzI,MAAK,GAAY0I,IAAMkwD,EAAclwD,IAErC1I,MAAK,GAAYkE,OAAO,CACtBuE,EAAGzI,MAAK,GAAYkE,SAASuE,EAC3BiwD,EAAcjwD,EAAIzI,MAAK,GAAYyI,EACnCmwD,EAAcnwD,EAAIzI,MAAK,GAAYyI,EACrCC,EAAG1I,MAAK,GAAYkE,SAASwE,EAC3BgwD,EAAchwD,EAAI1I,MAAK,GAAY0I,EACnCkwD,EAAclwD,EAAI1I,MAAK,GAAY0I,IAGvC1I,MAAK,GAAc44D,EACnB54D,MAAK,GAAc04D,EAEvB,CAQAG,mBAAAA,CAAoB9xD,GAElB,MAAMwM,EAAQvT,KAAKsW,SAASvP,GAC5B,YAAqB,IAAVwM,GAIJA,EAAMwjD,WACf,CAUA+B,uBAAAA,CAAwB/xD,EAAI6jD,GAE1B,MAAMr3C,EAAQvT,KAAKsW,SAASvP,GAC5B,YAAqB,IAAVwM,SAIY,IAAZq3C,IACTA,GAAWr3C,EAAMwjD,aAEnBxjD,EAAMq3C,QAAQA,GAGd5qD,KAAK+uD,QAEE,EACT,CAQAgK,mBAAAA,CAAoBnO,GAClB5qD,MAAK,GAAiB4qD,EAEtB,MAAMoO,EAAYh5D,KAAKoxD,gBAAgBtH,cACvC,IAAK,MAAM6N,KAAYqB,EACrB,GAAIrB,aAAoB5N,KAAAA,MAAa,CACnC,MAAM6N,EAAcD,EAAS7N,cAC7B,IAAK,MAAM0H,KAAcoG,EACnBpG,aAAsBzH,KAAAA,OACxB/pD,MAAK,GAAoBwxD,EAAY5G,EAG3C,CAEJ,CASA,IAAoB4G,EAAY5G,GAC9B,MAAM5pC,EAAQwwC,EAAW1H,YAAYN,IAAiB,GACtD,GAAMxoC,aAAiB+oC,KAAAA,aAIA,IAAZa,IACTA,GAAW5pC,EAAM+1C,kBAGY,IAApB/1C,EAAMi4C,WACmB,IAAlCj4C,EAAMi4C,UAAUC,OAAO/2D,QAAc,CACrC6e,EAAM4pC,QAAQA,GACd,MAAMuO,EAAY3H,EAAW1H,aAAYL,GACnB,SAAnBA,EAAKoL,WAAyC,cAAhBpL,EAAKjgD,SAAwB,GAC1D2vD,GACFA,EAAUvO,QAAQA,EAEtB,CACF,CAQAwN,kBAAAA,CAAmB5G,GACjBxxD,MAAK,GAAoBwxD,EAAYxxD,MAAK,GAC5C,CAUAo5D,UAAAA,CAAWC,EAAKC,GACd,CAUFC,WAAAA,CAAYD,GACV,CASFE,gBAAAA,GACE,MAAMR,EAAYh5D,KAAKoxD,gBAAgBtH,cACvC,IAAIthC,EAAQ,EACZ,IAAK,MAAMmvC,KAAYqB,EACjBrB,aAAoB5N,KAAAA,QACtBvhC,GAASmvC,EAAS7N,cAAc3nD,QAGpC,OAAOqmB,CACT,CAKAixC,eAAAA,GACEz5D,MAAK,GAAYk3D,WAAU,GAE3Bl3D,MAAK,GAAcmqD,MAAMuP,cAAgB,OAEzC,MAAMC,EAAQC,GACd,IAAK,IAAIr3D,EAAI,EAAGA,EAAIo3D,EAAMx3D,SAAUI,EAClCvC,MAAK,GAAc+0C,iBAAiB4kB,EAAMp3D,GAAIvC,MAAK,GAEvD,CAKA65D,iBAAAA,GACE75D,MAAK,GAAYk3D,WAAU,GAE3Bl3D,MAAK,GAAcmqD,MAAMuP,cAAgB,OAEzC,MAAMC,EAAQC,GACd,IAAK,IAAIr3D,EAAI,EAAGA,EAAIo3D,EAAMx3D,SAAUI,EAClCvC,MAAK,GAAcg1C,oBAAoB2kB,EAAMp3D,GAAIvC,MAAK,GAE1D,CASAi6C,kBAAAA,CAAmB52B,EAAU/V,QACN,IAAVA,IACTA,EAAQtN,MAAK,GAAauqB,aAAalH,IAEzC,MAAMy0C,EAAc93D,MAAK,GAAaq9C,eAAeh6B,GACrD,IAAI6oC,EAGFA,EAFElsD,MAAK,GAAag8C,0BAEX,CAAC8b,EAAY,IAGbA,EAEX,MAAMC,EAAa/3D,MAAK,GAAeksD,GAavC,OAXAlsD,MAAK,GAAmB+3D,GAExB/3D,MAAK,GAAW,CACd0hB,KAAM,iBACN5f,MAAO,CACLwL,EAAM7K,YACN4gB,EAAS5gB,aAEX03C,OAAO,KAGF,CACT,CAOA,IAAmB4d,GACjB/3D,MAAK,GAAqB+3D,EAG1B,MAAMiB,EAAYh5D,KAAKoxD,gBAAgBtH,YAAYH,IAEnD,IAAIiB,EACJ,IAAK,IAAIroD,EAAI,EAAGO,EAAOk2D,EAAU72D,OAAQI,EAAIO,IAAQP,EACnDqoD,GAAU,OACgB,IAAfmN,GACTiB,EAAUz2D,GAAGwE,OAASgxD,IACtBnN,GAAU,GAGZoO,EAAUz2D,GAAGqoD,QAAQA,GAIvB5qD,KAAKoxD,gBAAgBrC,MACvB,CAOA8I,kBAAAA,GACE,QAAuC,IAA5B73D,MAAK,GACd,OAGF,MAAMg5D,EAAYh5D,KAAKoxD,gBAAgBtH,aAAaL,GAC3CA,EAAK1iD,OAAS/G,MAAK,KAI5B,IAAI23D,EAgBJ,OAfyB,IAArBqB,EAAU72D,OACR62D,EAAU,aAAcjP,KAAAA,QAC1B4N,EAAWqB,EAAU,IAEO,IAArBA,EAAU72D,QACnBw1D,EAAW,IAAI5N,KAAAA,OACf4N,EAASnuD,KAAK,kBACdmuD,EAAS5wD,GAAG/G,MAAK,IACjB23D,EAAS/M,SAAQ,GAEjB5qD,KAAKoxD,gBAAgBluD,IAAIy0D,IAEzBxzD,EAAOa,KAAK,6CAGP2yD,CACT,CAQArhD,QAAAA,CAASvP,GACP,MAAMwM,EAAQvT,KAAKoxD,gBAAgB0I,QAAQ,IAAM/yD,GAIjD,YAHqB,IAAVwM,GACTpP,EAAOa,KAAK,6BAA+B+B,GAEtCwM,CACT,CASAwhC,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAcK,IACZA,EAAM+3C,WAAa/5D,KAAKo1D,QACxBpzC,EAAMyuC,OAASzwD,MAAK,GACpBA,MAAK,GAAiB+hB,UAAUC,EAAM,EAWxC,IAAkBwmC,GAGhB,MAAMwR,EAAS,EAAIxR,EAAM//C,EACnBwxD,EAAS,EAAIzR,EAAM9/C,EAEnBwxD,EAASl6D,MAAK,GAAYkqB,KAAK,SACrC,IAAK,IAAI3nB,EAAI,EAAGA,EAAI23D,EAAO/3D,SAAUI,EACnC23D,EAAO33D,GAAGimD,MAAM,CAAC//C,EAAGuxD,EAAQtxD,EAAGuxD,GAEnC,EClpCK,MAAMxC,GAIX,IAKA,IAMAz1D,WAAAA,CAAYokD,EAAYgM,GACtBpyD,MAAK,GAAcomD,EACnBpmD,MAAK,GAAkBoyD,CACzB,CAOA+H,OAAAA,GACE,MAAO,iBAAmBn6D,MAAK,GAAY+G,EAC7C,CAKAygD,OAAAA,GACExnD,MAAK,GAAgBinD,cAAcjnD,MAAK,GAC1C,CAKAo6D,IAAAA,GACEp6D,MAAK,GAAgBmnD,iBAAiBnnD,MAAK,GAAY+G,GACzD,EAMK,MAAMwgD,GAIX,IAKA,IAMAvlD,WAAAA,CAAYokD,EAAYgM,GACtBpyD,MAAK,GAAcomD,EACnBpmD,MAAK,GAAkBoyD,CACzB,CAOA+H,OAAAA,GACE,MAAO,oBAAsBn6D,MAAK,GAAY+G,EAChD,CAKAygD,OAAAA,GACExnD,MAAK,GAAgBmnD,iBAAiBnnD,MAAK,GAAY+G,GACzD,CAKAqzD,IAAAA,GACEp6D,MAAK,GAAgBinD,cAAcjnD,MAAK,GAC1C,EAMK,MAAM4nD,GAIX,IAKA,IAOA,IAOA,IAQA5lD,WAAAA,CAAYokD,EAAYiU,EAAc1S,EAAUyK,GAC9CpyD,MAAK,GAAcomD,EACnBpmD,MAAK,GAAkBoyD,EACvBpyD,MAAK,GAAiBq6D,EACtBr6D,MAAK,GAAY2nD,CACnB,CAOAwS,OAAAA,GACE,MAAO,oBAAsBn6D,MAAK,GAAY+G,EAChD,CAKAygD,OAAAA,GACE,MAAM10C,EAAO5R,OAAO4R,KAAK9S,MAAK,IAC9B,IAAK,MAAMgB,KAAO8R,EAChB9S,MAAK,GAAYgB,GAAOhB,MAAK,GAAUgB,GAEzChB,MAAK,GAAgBknD,iBAAiBlnD,MAAK,GAAa8S,EAC1D,CAKAsnD,IAAAA,GACE,MAAMtnD,EAAO5R,OAAO4R,KAAK9S,MAAK,IAC9B,IAAK,MAAMgB,KAAO8R,EAChB9S,MAAK,GAAYgB,GAAOhB,MAAK,GAAegB,GAE9ChB,MAAK,GAAgBknD,iBAAiBlnD,MAAK,GAAa8S,EAC1D,E,yBC/LK,MAAMwnD,GASXt4D,WAAAA,CAAYu4D,EAAiBC,GAM3Bx6D,KAAKy6D,WAAaF,EAAkBA,EAAgB73D,QAAU,GAM9D1C,KAAK06D,uBAAyBF,EAC1BA,EAA4B93D,QAAU,EAC5C,CASAypD,QAAAA,CAAS7+C,GACP,OAAOtN,KAAKy6D,WAAWntD,EACzB,CAQAqtD,cAAAA,CAAehxC,GACb,MAAMrc,EAAQtN,KAAKy6D,WAAWltD,QAAQoc,GACtC,IAAe,IAAXrc,EACF,OAAuD,IAAhDtN,KAAK06D,uBAAuBntD,QAAQD,GAE3C,MAAM,IAAIpL,MAAM,uDAEpB,CAOA8B,SAAAA,GACE,OAAOhE,KAAKy6D,WAAWt4D,MACzB,CAOAkqD,QAAAA,CAAS1iC,GACP3pB,KAAKy6D,WAAWx3D,KAAK0mB,EACvB,CAOAixC,eAAAA,CAAgBjxC,GACd,MAAMrc,EAAQtN,KAAKy6D,WAAWltD,QAAQoc,GACtC,IAAe,IAAXrc,EAGF,MAAM,IAAIpL,MACR,wDAHFlC,KAAK06D,uBAAuBz3D,KAAKqK,EAKrC,CAOAg/C,SAAAA,CAAUuO,GACR76D,KAAKy6D,WAAaz6D,KAAKy6D,WAAW17C,OAAO87C,EAC3C,CAOAC,SAAAA,CAAUC,GACR,MAAMC,EAAUh7D,KAAKy6D,WAAWt4D,OAChCnC,KAAKy6D,WAAaz6D,KAAKy6D,WAAW17C,OAAOg8C,EAAMN,YAC/C,MAAMQ,EAAa,GACnB,IAAK,IAAI14D,EAAI,EAAGA,EAAIw4D,EAAML,uBAAuBv4D,SAAUI,EACzD04D,EAAW14D,GAAKw4D,EAAML,uBAAuBn4D,GAAKy4D,EAEpDh7D,KAAK06D,uBACH16D,KAAK06D,uBAAuB37C,OAAOk8C,EACvC,EC1GK,MAAMC,GAMXl5D,WAAAA,CAAYm5D,EAAMC,GAChBp7D,KAAKq7D,YAAc,GAAKF,EACxBn7D,KAAKs7D,KAAOt7D,KAAKq7D,YAAc,EAC/Br7D,KAAKqG,KAAO,EAEZrG,KAAKu7D,IAAM,EAEXv7D,KAAKw7D,UAAkC,IAAlBJ,EACjBA,EAAe,SAAU38C,GACzB,OAAOA,CACT,EACFze,KAAKy7D,QAAUz7D,KAAK07D,WAAW17D,KAAKq7D,YACtC,CAEAp4D,IAAAA,CAAKwb,GAEH,MAAMk9C,EAAS37D,KAAK47D,UAAUn9C,GAC9BA,EAAKqE,KAAO9iB,KAAKy7D,QAAQE,GACzB37D,KAAKy7D,QAAQE,GAAUl9C,EAEvBze,KAAKqG,MACP,CAEAoK,GAAAA,GACE,GAAkB,IAAdzQ,KAAKqG,KACP,MAAM,IAAInE,MAAM,qCAIlB,KAAkC,OAA3BlC,KAAKy7D,QAAQz7D,KAAKu7D,MACvBv7D,KAAKu7D,KAAOv7D,KAAKu7D,IAAM,GAAKv7D,KAAKq7D,YAInC,MAAMQ,EAAM77D,KAAKy7D,QAAQz7D,KAAKu7D,KAK9B,OAJAv7D,KAAKy7D,QAAQz7D,KAAKu7D,KAAOM,EAAI/4C,KAC7B+4C,EAAI/4C,KAAO,KAEX9iB,KAAKqG,OACEw1D,CACT,CAGAj6C,MAAAA,CAAOnD,GAEL,IAAKA,EACH,OAAO,EAIT,MAAMk9C,EAAS37D,KAAK47D,UAAUn9C,GAC9B,IAAIgrC,EAAOzpD,KAAKy7D,QAAQE,GAExB,KAAgB,OAATlS,IACW,OAAdA,EAAK3mC,MACPrE,EAAKhW,IAAMghD,EAAK3mC,KAAKra,GACrBgW,EAAK/V,IAAM+gD,EAAK3mC,KAAKpa,IACrB+gD,EAAOA,EAAK3mC,KAGd,OAAa,OAAT2mC,IAKFA,EAAK3mC,KAAO2mC,EAAK3mC,KAAKA,KAEtB9iB,KAAKqG,QACE,EAEX,CAEAy1D,OAAAA,GACE,OAAqB,IAAd97D,KAAKqG,IACd,CAEAu1D,SAAAA,CAAUn9C,GAER,OAAOze,KAAKw7D,KAAK/8C,GAAQze,KAAKs7D,IAChC,CAEAI,UAAAA,CAAWK,GAET,MAAMN,EAAU,IAAIr8C,MAAM28C,GAE1B,IAAK,IAAIx5D,EAAI,EAAGA,EAAIk5D,EAAQt5D,OAAQI,IAClCk5D,EAAQl5D,GAAK,KAGf,OAAOk5D,CACT,ECtGF,MAAMO,GAAgB,GAAK,EAAIr4D,KAAKmgD,IA+NpC,SAASmY,GAAeC,EAAOC,EAAOC,EAAIC,EAAIC,GAE5C,MAAM9nD,EAAK0nD,EAAMG,GAAID,GACfG,EAAKJ,EAAME,GAAID,GAErB,IAAII,EAAM74D,KAAK4G,KAAKiK,EAAKA,EAAK+nD,EAAKA,GACnCC,EAAM74D,KAAK0J,IAAImvD,EAAK,QAEpBF,EAAI7zD,EAAI+L,EAAKgoD,EACbF,EAAI5zD,EAAI6zD,EAAKC,CACf,CA0HO,MAAMC,GAEXz6D,WAAAA,GACEhC,KAAKoF,OAAS,EACdpF,KAAKmjC,QAAU,EAEfnjC,KAAK08D,SAAW,KAChB18D,KAAK28D,eAAiB,EACtB38D,KAAK48D,WAAa,GAAK58D,KAAK28D,eAC5B38D,KAAK68D,cAAgB,IAIrB78D,KAAK88D,UAAY,KACjB98D,KAAK+8D,QAAU,KACf/8D,KAAKg9D,SAAW,KAChBh9D,KAAKk8D,MAAQ,KACbl8D,KAAKm8D,MAAQ,KAGbn8D,KAAKi9D,QAAU,KAEfj9D,KAAKk9D,SAAU,EAGfl9D,KAAKm9D,SAAU,EACfn9D,KAAKo9D,eAAiB,KAEtBp9D,KAAKq9D,UAAY,EACjBr9D,KAAKs9D,eAAiB,GAEtBt9D,KAAKu9D,SAAW,IAChBv9D,KAAKw9D,aAAe,KAEpBx9D,KAAKy9D,iBAAmB,GACxBz9D,KAAK09D,SAAW,KAChB19D,KAAK29D,aAAe,KAEpB39D,KAAK49D,WAAa,IAClB59D,KAAK69D,eAAiB,KAEtB79D,KAAK89D,YAAc,IACnB99D,KAAK+9D,gBAAkB,IACzB,CAKAC,cAAAA,CAAeC,EAAan8D,GAC1B,OAAO6B,KAAK0N,OAAO4sD,EAAc,GAAKn8D,EACxC,CAEAo8D,cAAAA,CAAeC,GACb,OAAOn+D,KAAKw9D,aAAax9D,KAAKg+D,eAAeh+D,KAAKu9D,SAAUY,GAC9D,CAEAC,cAAAA,CAAeC,GACb,OAAOr+D,KAAK29D,aAAa39D,KAAKg+D,eAAeh+D,KAAK09D,SAAUW,GAC9D,CAEAC,gBAAAA,CAAiBC,GACf,OAAOv+D,KAAK69D,eAAe79D,KAAKg+D,eAAeh+D,KAAK49D,WAAYW,GAClE,CAEAC,iBAAAA,CAAkBC,GAChB,OAAOz+D,KAAK+9D,gBAAgB/9D,KAAKg+D,eAAeh+D,KAAK89D,YAAaW,GACpE,CAGAC,UAAAA,CAAWxB,GAETl9D,KAAKk9D,QAAUA,CACjB,CAEAyB,aAAAA,CAAcv5D,EAAO+9B,GACnBnjC,KAAKoF,MAAQA,EACbpF,KAAKmjC,OAASA,CAChB,CAEAy7B,OAAAA,CAAQ3rD,GACN,IAAoB,IAAhBjT,KAAKoF,QAAiC,IAAjBpF,KAAKmjC,OAE5B,MAAM,IAAIjhC,MAAM,iCAGlBlC,KAAK88D,UA9aT,SAA0B7pD,EAAM7N,EAAO+9B,GAIrC,MAAM25B,EAAY,CAChB7pD,KAAM,IAIR,IAAK,IAAIvK,EAAI,EAAGA,EAAIy6B,EAAQz6B,IAAK,CAC/Bo0D,EAAU7pD,KAAKvK,GAAK,GAEpB,IAAK,IAAID,EAAI,EAAGA,EAAIrD,EAAOqD,IAAK,CAC9B,MAAM4D,EAAsB,GAAjB3D,EAAItD,EAAQqD,GACvBq0D,EAAU7pD,KAAKvK,GAAGD,IAAMwK,EAAK5G,GAAK4G,EAAK5G,EAAI,GAAK4G,EAAK5G,EAAI,IAAM,GACjE,CACF,CA4CA,OAzCAywD,EAAU3uD,GAAK,SAAU1F,EAAGC,GAK1B,OAJID,EAAI,IAAMzI,KAAKiT,KAAKvK,GAAGvG,QAEzBsG,IAEKzI,KAAKiT,KAAKvK,GAAGD,EAAI,GAAKzI,KAAKiT,KAAKvK,GAAGD,EAC5C,EAEAq0D,EAAU1uD,GAAK,SAAU3F,EAAGC,GAK1B,OAJIA,EAAI,IAAM1I,KAAKiT,KAAK9Q,QAEtBuG,IAEK1I,KAAKiT,KAAKvK,GAAGD,GAAKzI,KAAKiT,KAAKvK,EAAI,GAAGD,EAC5C,EAEAq0D,EAAU+B,cAAgB,SAAUp2D,EAAGC,GACrC,MAAMyF,EAAKnO,KAAKmO,GAAG1F,EAAGC,GAChB0F,EAAKpO,KAAKoO,GAAG3F,EAAGC,GACtB,OAAO/E,KAAK4G,KAAK4D,EAAKA,EAAKC,EAAKA,EAClC,EAEA0uD,EAAUC,QAAU,SAAUt0D,EAAGC,GAE/B,IAAIo2D,GAAO,GAAK9+D,KAAKiT,KAAKvK,GAAGD,GAc7B,OAbAq2D,GAAO9+D,KAAKiT,KAAKvK,EAAI,GAAGD,GACxBq2D,GAAO9+D,KAAKiT,KAAKvK,EAAI,GAAGD,EAAI,GAC1B,EAAIzI,KAAKiT,KAAKvK,EAAI,GAAGD,GACrBzI,KAAKiT,KAAKvK,EAAI,GAAGD,EAAI,GACvBq2D,GAAO9+D,KAAKiT,KAAKvK,GAAGD,EAAI,GACtB,EAAIzI,KAAKiT,KAAKvK,GAAGD,EAAI,GACrB,EAAIzI,KAAKiT,KAAKvK,GAAGD,EAAI,GACrBzI,KAAKiT,KAAKvK,GAAGD,EAAI,GACnBq2D,GAAO9+D,KAAKiT,KAAKvK,EAAI,GAAGD,EAAI,GAC1B,EAAIzI,KAAKiT,KAAKvK,EAAI,GAAGD,GACrBzI,KAAKiT,KAAKvK,EAAI,GAAGD,EAAI,GACvBq2D,GAAO9+D,KAAKiT,KAAKvK,EAAI,GAAGD,GAEjBq2D,CACT,EAEOhC,CACT,CAiXqBiC,CAAiB9rD,EAAMjT,KAAKoF,MAAOpF,KAAKmjC,QACzDnjC,KAAK+8D,QA9TT,SAAwBD,GAEtB,MAAMC,EAAU,GAIhBA,EAAQ,GAAK,GACbA,EAAQ,GAAK,GACb,IAAK,IAAIx6D,EAAI,EAAGA,EAAIu6D,EAAU7pD,KAAK9Q,OAAQI,IAEzCw6D,EAAQ,GAAGx6D,GAAK,EAChBw6D,EAAQ,GAAGx6D,GAAK,EAGlB,IAAK,IAAImG,EAAI,EAAGA,EAAIo0D,EAAU7pD,KAAK9Q,OAAS,EAAGuG,IAAK,CAClDq0D,EAAQr0D,GAAK,GAEbq0D,EAAQr0D,GAAG,GAAK,EAChBq0D,EAAQr0D,GAAG,GAAK,EAEhB,IAAK,IAAID,EAAI,EAAGA,EAAIq0D,EAAU7pD,KAAKvK,GAAGvG,OAAS,EAAGsG,IAEhDs0D,EAAQr0D,GAAGD,GAAMq0D,EAAUC,QAAQt0D,EAAGC,GAAK,IAAQ,EAAI,EAIzDq0D,EAAQr0D,GAAGo0D,EAAU7pD,KAAKvK,GAAGvG,OAAS,GAAK,EAC3C46D,EAAQr0D,GAAGo0D,EAAU7pD,KAAKvK,GAAGvG,OAAS,GAAK,CAC7C,CAEA46D,EAAQD,EAAU7pD,KAAK9Q,OAAS,GAAK,GACrC46D,EAAQD,EAAU7pD,KAAK9Q,OAAS,GAAK,GACrC,IAAK,IAAIiB,EAAI,EAAGA,EAAI05D,EAAU7pD,KAAK9Q,OAAQiB,IAEzC25D,EAAQD,EAAU7pD,KAAK9Q,OAAS,GAAGiB,GAAK,EACxC25D,EAAQD,EAAU7pD,KAAK9Q,OAAS,GAAGiB,GAAK,EAG1C,OAAO25D,CACT,CAuRmBiC,CAAeh/D,KAAK88D,WACnC98D,KAAKg9D,SA3WT,SAAyBF,GAIvB,MAAME,EAAW,GAEjB,IAAI3vD,EAAM,EAEN5E,EAAI,EACJC,EAAI,EAER,IAAKA,EAAI,EAAGA,EAAIo0D,EAAU7pD,KAAK9Q,OAAS,EAAGuG,IAAK,CAG9C,IAFAs0D,EAASt0D,GAAK,GAETD,EAAI,EAAGA,EAAIq0D,EAAU7pD,KAAKvK,GAAGvG,OAAS,EAAGsG,IAC5Cu0D,EAASt0D,GAAGD,GAAKq0D,EAAU+B,cAAcp2D,EAAGC,GAC5C2E,EAAM1J,KAAK0J,IAAI2vD,EAASt0D,GAAGD,GAAI4E,GAGjC2vD,EAASt0D,GAAGo0D,EAAU7pD,KAAKvK,GAAGvG,OAAS,GACrC66D,EAASt0D,GAAGo0D,EAAU7pD,KAAK9Q,OAAS,EACxC,CAEA66D,EAASF,EAAU7pD,KAAK9Q,OAAS,GAAK,GACtC,IAAK,IAAII,EAAI,EAAGA,EAAIy6D,EAAS,GAAG76D,OAAQI,IACtCy6D,EAASF,EAAU7pD,KAAK9Q,OAAS,GAAGI,GAClCy6D,EAASF,EAAU7pD,KAAK9Q,OAAS,GAAGI,GAIxC,IAAKmG,EAAI,EAAGA,EAAIs0D,EAAS76D,OAAQuG,IAC/B,IAAKD,EAAI,EAAGA,EAAIu0D,EAASt0D,GAAGvG,OAAQsG,IAElCu0D,EAASt0D,GAAGD,GAAK,EAAKu0D,EAASt0D,GAAGD,GAAK4E,EAI3C,OAAO2vD,CACT,CAqUoBiC,CAAgBj/D,KAAK88D,WACrC98D,KAAKk8D,MAjRT,SAAsBY,GAEpB,MAAMZ,EAAQ,GAEd,IAAK,IAAIxzD,EAAI,EAAGA,EAAIo0D,EAAU7pD,KAAK9Q,OAAQuG,IAAK,CAC9CwzD,EAAMxzD,GAAK,GAEX,IAAK,IAAID,EAAI,EAAGA,EAAIq0D,EAAU7pD,KAAKvK,GAAGvG,OAAS,EAAGsG,IAChDyzD,EAAMxzD,GAAGD,GAAKq0D,EAAU3uD,GAAG1F,EAAGC,GAGhCwzD,EAAMxzD,GAAGo0D,EAAU7pD,KAAKvK,GAAGvG,OAAS,GAClC+5D,EAAMxzD,GAAGo0D,EAAU7pD,KAAKvK,GAAGvG,OAAS,EACxC,CAEA,OAAO+5D,CACT,CAiQiBgD,CAAal/D,KAAK88D,WAC/B98D,KAAKm8D,MA1PT,SAAsBW,GAEpB,MAAMX,EAAQ,GAEd,IAAK,IAAIzzD,EAAI,EAAGA,EAAIo0D,EAAU7pD,KAAK9Q,OAAS,EAAGuG,IAAK,CAClDyzD,EAAMzzD,GAAK,GAEX,IAAK,IAAID,EAAI,EAAGA,EAAIq0D,EAAU7pD,KAAKvK,GAAGvG,OAAQsG,IAC5C0zD,EAAMzzD,GAAGD,GAAKq0D,EAAU1uD,GAAG3F,EAAGC,EAElC,CAEAyzD,EAAMW,EAAU7pD,KAAK9Q,OAAS,GAAK,GACnC,IAAK,IAAII,EAAI,EAAGA,EAAIu6D,EAAU7pD,KAAK,GAAG9Q,OAAQI,IAC5C45D,EAAMW,EAAU7pD,KAAK9Q,OAAS,GAAGI,GAAK45D,EAAMW,EAAU7pD,KAAK9Q,OAAS,GAAGI,GAGzE,OAAO45D,CACT,CAwOiBgD,CAAan/D,KAAK88D,WAE/B,MAAMsC,EAtKV,SAAsB1wD,EAAMwtD,EAAOC,EAAOW,GAMxC,MAAMsC,EAAQ,CACdA,OAAe,GACfA,QAAgB,IAEVC,EAAM,CAAC52D,GAAI,EAAGC,GAAI,GAExB,IAAK,IAAIA,EAAI,EAAGA,EAAIwzD,EAAM/5D,OAAQuG,IAAK,CACrC02D,EAAMb,OAAO71D,GAAK,GAClB02D,EAAMX,QAAQ/1D,GAAK,GAEnB,IAAK,IAAID,EAAI,EAAGA,EAAIyzD,EAAMxzD,GAAGvG,OAAQsG,IAAK,CACxCwzD,GAAeC,EAAOC,EAAO1zD,EAAGC,EAAG22D,GAInC,IAAIC,EAAK37D,KAAK0N,MAAM5I,EAAIiG,EAAO2wD,EAAI32D,GAC/B62D,EAAK57D,KAAK0N,MAAM3I,EAAIgG,EAAO2wD,EAAI52D,GAC/B+L,EAAK7Q,KAAK0N,MAAM5I,EAAIiG,EAAO2wD,EAAI32D,GAC/B6zD,EAAK54D,KAAK0N,MAAM3I,EAAIgG,EAAO2wD,EAAI52D,GAEnC62D,EAAK37D,KAAK0J,IAAI1J,KAAKgjB,IAAI24C,EAAIpD,EAAMxzD,GAAGvG,OAAS,GAAI,GACjDqS,EAAK7Q,KAAK0J,IAAI1J,KAAKgjB,IAAInS,EAAI0nD,EAAMxzD,GAAGvG,OAAS,GAAI,GACjDo9D,EAAK57D,KAAK0J,IAAI1J,KAAKgjB,IAAI44C,EAAIrD,EAAM/5D,OAAS,GAAI,GAC9Co6D,EAAK54D,KAAK0J,IAAI1J,KAAKgjB,IAAI41C,EAAIL,EAAM/5D,OAAS,GAAI,GAE9Ci9D,EAAMb,OAAO71D,GAAGD,GAAKq0D,EAAU7pD,KAAKssD,GAAID,GACxCF,EAAMX,QAAQ/1D,GAAGD,GAAKq0D,EAAU7pD,KAAKspD,GAAI/nD,EAC3C,CACF,CAEA,OAAO4qD,CACT,CAiIkBI,CACZx/D,KAAKq9D,UAAWr9D,KAAKk8D,MAAOl8D,KAAKm8D,MAAOn8D,KAAK88D,WAC/C98D,KAAKu+D,OAASa,EAAMb,OACpBv+D,KAAKy+D,QAAUW,EAAMX,QACrBz+D,KAAKw9D,aAAe,GACpBx9D,KAAK29D,aAAe,GACpB39D,KAAK69D,eAAiB,GACtB79D,KAAK+9D,gBAAkB,EACzB,CAEA0B,kBAAAA,CAAmBpzD,GAEjB,MAAM6/C,EAAS,GAEf,GAAqB,OAAjBlsD,KAAKi9D,QACP,IAAK,IAAI16D,EAAI,EAAGA,EAAIvC,KAAKs9D,gBAAkBjxD,EAAG9J,IAC5C2pD,EAAOjpD,KAAKoJ,GACZA,EAAIrM,KAAKi9D,QAAQ5wD,EAAE3D,GAAG2D,EAAE5D,GAI5B,OAAOyjD,CACT,CAEAwT,aAAAA,GACE1/D,KAAKm9D,SAAU,CACjB,CAEAwC,UAAAA,CAAWtzD,GAIT,GAFArM,KAAKo9D,eAAiBp9D,KAAKy/D,mBAAmBpzD,GAE1CrM,KAAKo9D,eAAej7D,OAAS,EAC/B,OAGF,MAAMgR,EAAS,GACfnT,KAAK4/D,kBACHzsD,EAAQnT,KAAKu9D,SAAUv9D,KAAK88D,UAAW98D,KAAKw9D,cAC9Cx9D,KAAK4/D,kBACHzsD,EAAQnT,KAAK09D,SAAU19D,KAAKg9D,SAAUh9D,KAAK29D,cAC7C39D,KAAK4/D,kBACHzsD,EAAQnT,KAAK49D,WAAY59D,KAAKu+D,OAAQv+D,KAAK69D,gBAC7C79D,KAAK4/D,kBACHzsD,EAAQnT,KAAK89D,YAAa99D,KAAKy+D,QAASz+D,KAAK+9D,iBAE3C/9D,KAAKo9D,eAAej7D,OAASnC,KAAKy9D,kBAGpCz9D,KAAK6/D,gBAAgB7/D,KAAKo9D,eAAej7D,OAAQnC,KAAKy9D,kBAGxDz9D,KAAKm9D,SAAU,CACjB,CAEAyC,iBAAAA,CACEzsD,EAAQ8qD,EAAa6B,EAAOC,GAC5B,IAAIx9D,EAAI,EAGR,IADA4Q,EAAOhR,OAAS87D,EACX17D,EAAI,EAAGA,EAAI07D,EAAa17D,IAC3B4Q,EAAO5Q,GAAK,EAGd,IAAIy9D,EAAS,EACb,IAAKz9D,EAAI,EAAGA,EAAIvC,KAAKo9D,eAAej7D,OAAQI,IAAK,CAC/C,MAAM8J,EAAIrM,KAAKo9D,eAAe76D,GACxB09D,EAAMjgE,KAAKg+D,eAAeC,EAAa6B,EAAMzzD,EAAE3D,GAAG2D,EAAE5D,IAC1D0K,EAAO8sD,IAAQ,EAEfD,EAASr8D,KAAK0J,IAAI2yD,EAAQ7sD,EAAO8sD,GACnC,CAGA,IAAK19D,EAAI,EAAGA,EAAI07D,EAAa17D,IAC3B4Q,EAAO5Q,GAAK,EAAI4Q,EAAO5Q,GAAKy9D,GApMlC,SAAsB7sD,EAAQmpD,GAE5BA,EAAI,GAAK,GAAMnpD,EAAO,GAAK,GAAMA,EAAO,GAAK,GAAMA,EAAO,GAC1DmpD,EAAI,GAAK,IAAOnpD,EAAO,GAAK,GAAMA,EAAO,GAAK,IAAOA,EAAO,GAC1D,GAAMA,EAAO,GAEf,IAAK,IAAI5Q,EAAI,EAAGA,EAAI4Q,EAAOhR,OAAS,EAAGI,IACrC+5D,EAAI/5D,GAAK,IAAO4Q,EAAO5Q,EAAI,GAAK,IAAO4Q,EAAO5Q,EAAI,GAChD,GAAM4Q,EAAO5Q,GAAK,IAAO4Q,EAAO5Q,EAAI,GAAK,IAAO4Q,EAAO5Q,EAAI,GAG/D,MAAMi3B,EAAMrmB,EAAOhR,OACnBm6D,EAAI9iC,EAAM,GAAK,IAAOrmB,EAAOqmB,EAAM,GAAK,GAAMrmB,EAAOqmB,EAAM,GACzD,IAAOrmB,EAAOqmB,EAAM,GAAK,GAAMrmB,EAAOqmB,EAAM,GAC9C8iC,EAAI9iC,EAAM,GAAK,GAAMrmB,EAAOqmB,EAAM,GAAK,GAAMrmB,EAAOqmB,EAAM,GACxD,GAAMrmB,EAAOqmB,EAAM,EACvB,CAwLI0mC,CAAa/sD,EAAQ4sD,EACvB,CAEAF,eAAAA,CAAgBM,EAAMC,GAGpB,IAAK,IAAI79D,EAAI,EAAGA,EAAIvC,KAAK09D,SAAUn7D,IACjCvC,KAAK29D,aAAap7D,GAAKoB,KAAKgjB,IAC1B3mB,KAAK29D,aAAap7D,GAClB,EAAIA,GAAK69D,EAAOD,IAASC,EAAOpgE,KAAK09D,UAG3C,CAEA2C,aAAAA,CAAcjE,EAAIC,EAAIiE,EAAIC,GACxB,OAtSJ,SAAuBrE,EAAOC,EAAOC,EAAIC,EAAIiE,EAAIC,GAC/C,MAAMC,EAAU,CAAC/3D,GAAI,EAAGC,GAAI,GACtB+3D,EAAU,CAACh4D,GAAI,EAAGC,GAAI,GAE5BuzD,GAAeC,EAAOC,EAAOC,EAAIC,EAAImE,GACrCvE,GAAeC,EAAOC,EAAOmE,EAAIC,EAAIE,GAErC,IAAIC,EAAKF,EAAQ93D,GAAK43D,EAAKlE,GAAMoE,EAAQ/3D,GAAK83D,EAAKlE,GAC/CsE,EAAKF,EAAQ/3D,GAAK43D,EAAKlE,GAAMqE,EAAQh4D,GAAK83D,EAAKlE,GAcnD,OAXIqE,EAAK,IACPA,GAAMA,EACNC,GAAMA,GAGJvE,IAAOkE,GAAMjE,IAAOkE,IAEtBG,GAAM/8D,KAAKi9D,QACXD,GAAMh9D,KAAKi9D,SAGN5E,IAAgBr4D,KAAKk9D,KAAKH,GAAM/8D,KAAKk9D,KAAKF,GACnD,CA+QWN,CAAcrgE,KAAKk8D,MAAOl8D,KAAKm8D,MAAOC,EAAIC,EAAIiE,EAAIC,EAC3D,CAEA7xD,IAAAA,CAAK0tD,EAAIC,EAAIiE,EAAIC,GAEf,IAAIlC,EAAOr+D,KAAKg9D,SAASuD,GAAID,GAEzBlE,IAAOkE,GAAMjE,IAAOkE,IAEtBlC,GAAQ16D,KAAKi9D,SAGf,MAAM9B,EAAM9+D,KAAK+8D,QAAQwD,GAAID,GACvB7U,EAAMzrD,KAAKqgE,cAAcjE,EAAIC,EAAIiE,EAAIC,GAE3C,OAAIvgE,KAAKm9D,QAOA,GALOn9D,KAAKo+D,eAAeC,GAKb,GAAMS,EAAM,IAAOrT,EAJ1BzrD,KAAKk+D,eAAel+D,KAAK88D,UAAU7pD,KAAKopD,GAAID,IAC1Cp8D,KAAKs+D,iBAAiBt+D,KAAKu+D,OAAOlC,GAAID,IACrCp8D,KAAKw+D,kBAAkBx+D,KAAKy+D,QAAQpC,GAAID,KAKlD,IAAOiC,EAAO,IAAOS,EAAM,IAAOrT,CAE7C,CAEAqV,GAAAA,CAAIz0D,GACF,MAAMy5C,EAAO,GAEPib,EAAKp9D,KAAK0J,IAAIhB,EAAE5D,EAAI,EAAG,GACvBu4D,EAAKr9D,KAAK0J,IAAIhB,EAAE3D,EAAI,EAAG,GACvBu4D,EAAKt9D,KAAKgjB,IAAIta,EAAE5D,EAAI,EAAGzI,KAAK88D,UAAU7pD,KAAK,GAAG9Q,OAAS,GACvD++D,EAAKv9D,KAAKgjB,IAAIta,EAAE3D,EAAI,EAAG1I,KAAK88D,UAAU7pD,KAAK9Q,OAAS,GAE1D,IAAI89D,EAAM,EACV,IAAK,IAAIv3D,EAAIs4D,EAAIt4D,GAAKw4D,EAAIx4D,IACxB,IAAK,IAAID,EAAIs4D,EAAIt4D,GAAKw4D,EAAIx4D,IACpBA,IAAM4D,EAAE5D,GAAKC,IAAM2D,EAAE3D,IACvBo9C,EAAKma,KAAS,CAACx3D,EAAGA,EAAGC,EAAGA,IAK9B,OAAOo9C,CACT,CAEA,IAAiBz5C,GACR1I,KAAK0N,MAAMrR,KAAK48D,WAAa58D,KAAKw7D,KAAKnvD,EAAE3D,GAAG2D,EAAE5D,IAGvD04D,QAAAA,CAASC,GACPphE,KAAK0+D,YAAW,GAEhB1+D,KAAK08D,SAAW0E,EAEhB,IAAI34D,EAAI,EACJC,EAAI,EAGR,IADA1I,KAAKqhE,QAAU,GACV34D,EAAI,EAAGA,EAAI1I,KAAKmjC,OAAQz6B,IAE3B,IADA1I,KAAKqhE,QAAQ34D,GAAK,GACbD,EAAI,EAAGA,EAAIzI,KAAKoF,MAAOqD,IAC1BzI,KAAKqhE,QAAQ34D,GAAGD,IAAK,EAKzB,IADAzI,KAAKi9D,QAAU,GACVv0D,EAAI,EAAGA,EAAI1I,KAAKmjC,OAAQz6B,IAC3B1I,KAAKi9D,QAAQv0D,GAAK,GAIpB,IADA1I,KAAKw7D,KAAO,GACP9yD,EAAI,EAAGA,EAAI1I,KAAKmjC,OAAQz6B,IAE3B,IADA1I,KAAKw7D,KAAK9yD,GAAK,GACVD,EAAI,EAAGA,EAAIzI,KAAKoF,MAAOqD,IAC1BzI,KAAKw7D,KAAK9yD,GAAGD,GAAKmC,OAAO02D,UAG7BthE,KAAKw7D,KAAK4F,EAAG14D,GAAG04D,EAAG34D,GAAK,EAExBzI,KAAKuhE,GAAK,IAAIrG,GAAYl7D,KAAK28D,eAAgB38D,MAAK,IACpDA,KAAKuhE,GAAGt+D,KAAKm+D,EACf,CAEAI,MAAAA,GACE,IAAKxhE,KAAKk9D,QACR,OAGFl9D,KAAKyhE,QAAU,KAEf,IAAIC,EAAa,EACjB,MAAMC,EAAY,GAClB,MAAQ3hE,KAAKuhE,GAAGzF,WAAa4F,EAAa1hE,KAAK68D,eAAe,CAC5D,MAAMxwD,EAAIrM,KAAKuhE,GAAG9wD,MAClBkxD,EAAU1+D,KAAKoJ,GACfs1D,EAAU1+D,KAAKjD,KAAKi9D,QAAQ5wD,EAAE3D,GAAG2D,EAAE5D,IAEnCzI,KAAKqhE,QAAQh1D,EAAE3D,GAAG2D,EAAE5D,IAAK,EAEzB,MAAMm5D,EAAU5hE,KAAK8gE,IAAIz0D,GACzB,IAAK,IAAI9J,EAAI,EAAGA,EAAIq/D,EAAQz/D,OAAQI,IAAK,CACvC,MAAMs/D,EAAID,EAAQr/D,GAEZu/D,EAAS9hE,KAAKw7D,KAAKnvD,EAAE3D,GAAG2D,EAAE5D,GAAKzI,KAAK0O,KAAKrC,EAAE5D,EAAG4D,EAAE3D,EAAGm5D,EAAEp5D,EAAGo5D,EAAEn5D,GAE5Do5D,EAAS9hE,KAAKw7D,KAAKqG,EAAEn5D,GAAGm5D,EAAEp5D,KACxBzI,KAAKw7D,KAAKqG,EAAEn5D,GAAGm5D,EAAEp5D,KAAOmC,OAAO02D,WAEjCthE,KAAKuhE,GAAG3/C,OAAOigD,GAGjB7hE,KAAKw7D,KAAKqG,EAAEn5D,GAAGm5D,EAAEp5D,GAAKq5D,EACtB9hE,KAAKi9D,QAAQ4E,EAAEn5D,GAAGm5D,EAAEp5D,GAAK4D,EACzBrM,KAAKuhE,GAAGt+D,KAAK4+D,GAEjB,CAEAH,GACF,CAEA,OAAOC,CACT,ECppBK,MAAMI,GAAW,CAMtBC,UAAW,CACTC,MAAO,CACL,IAAK,IAEPC,OAAQ,CACN,IAAK,aAEPC,QAAS,CACP,IAAK,aAEPC,WAAY,CACV,IAAK,WAEPC,UAAW,CACT,IAAK,aAEPC,IAAK,CACH,IAAK,IAEPC,MAAO,CACL,IAAK,cCrBJ,MAAMC,GAOX,IAKAxgE,WAAAA,CAAYygE,GACVziE,MAAK,GAAyByiE,CAChC,CAQAC,WAAAA,CAAYtc,GACV,IAAI/iC,EAAW+iC,EAAWyN,cAI1B,YAHwB,IAAbxwC,IACTA,EAAWrjB,MAAK,GAAuBomD,IAElC/iC,CACT,CASA6P,MAAAA,CAAOkzB,EAAY+D,GAEjB,MAAMwY,EAAQ,IAAI5Y,KAAAA,MAAW,CAC3B6Y,SAAUzY,EAAMjC,cAChB2a,WAAY1Y,EAAMlC,gBAClB3a,KAAM8Y,EAAWrU,OACjB+wB,QAAS3Y,EAAMnB,iBACf+Z,YAAa5Y,EAAMd,sBACnB2Z,aAAc7Y,EAAMrB,kBACpBt/C,KAAM,SAEFw4D,EAAY5b,EAAW6S,UAC7B0J,EAAMM,QAAQjB,GAId,MAAMkB,EAAY/Y,EAAMvB,eAAe,GACjCua,EAAa,CACjB16D,EAAG,EAAIy6D,EAAUz6D,EACjBC,EAAG,EAAIw6D,EAAUx6D,GAIbmrD,EAAgB7zD,KAAK0iE,YAAYtc,GACjCgd,EAAS,IAAIrZ,KAAAA,OAAY,CAC7BthD,EAAGorD,EAAc1pD,OACjBzB,EAAGmrD,EAAczpD,OACjBo+C,MAAO2a,EACPvY,QAA8B,IAArBoX,EAAU7/D,OACnBqH,KAAM,UAQR,OANA45D,EAAOlgE,IAAIy/D,GACXS,EAAOlgE,IAAI,IAAI6mD,KAAAA,KAAU,CACvBzc,KAAM8Y,EAAWrU,OACjB6gB,QAASzI,EAAMpB,mBAGVqa,CACT,CAQAC,cAAAA,CAAejd,EAAY7yC,GAEzB,MAAM6vD,EAAS7vD,EAAMu2C,aAAY,SAAUL,GACzC,MAAuB,UAAhBA,EAAKjgD,MACd,IAAG,GACH,KAAM45D,aAAkBrZ,KAAAA,OACtB,OAGF,MAAM8J,EAAgB7zD,KAAK0iE,YAAYtc,GACvCgd,EAAO//C,SAAS,CACd5a,EAAGorD,EAAc1pD,OACjBzB,EAAGmrD,EAAczpD,QAErB,CAQAk5D,uBAAAA,CAAwBtiD,GACtB,MAAMuiD,EAAKviD,EAAMvY,IACX+6D,EAAKxiD,EAAMtY,IACXyF,EAAK6S,EAAM5b,QAAU4b,EAAMwnC,QAAQ//C,EACnC2F,EAAK4S,EAAMmiB,SAAWniB,EAAMwnC,QAAQ9/C,EAC1C,MAAO,CACL,IAAIqF,EAAQw1D,EAAKp1D,EAAK,EAAGq1D,GACzB,IAAIz1D,EAAQw1D,EAAIC,EAAKp1D,EAAK,GAC1B,IAAIL,EAAQw1D,EAAKp1D,EAAK,EAAGq1D,EAAKp1D,GAC9B,IAAIL,EAAQw1D,EAAKp1D,EAAIq1D,EAAKp1D,EAAK,GAEnC,CASAq1D,gBAAAA,CAAiBC,EAASC,GACxB,IAAIl1D,EAAUi1D,EAAQ,GAAGz1D,YAAY01D,EAAQ,IACzCn3B,EAAKk3B,EAAQ,GACbj3B,EAAKk3B,EAAQ,GACjB,IAAK,MAAMC,KAAUF,EACnB,IAAK,MAAMG,KAAUF,EAAS,CAC5B,MAAMj1D,EAAOk1D,EAAO31D,YAAY41D,GAC5Bn1D,EAAOD,IACTA,EAAUC,EACV89B,EAAKo3B,EACLn3B,EAAKo3B,EAET,CAEF,MAAO,CAACr3B,EAAIC,EACd,CAUAq3B,YAAAA,CAAaC,EAAe/iD,EAAOmpC,GACjC,MAAM6Z,EAAkBhkE,KAAKsjE,wBAAwBtiD,GAC/CijD,EAAejkE,KAAKyjE,iBACxBM,EAAeC,GACjB,OAAO,IAAIja,KAAAA,MAAW,CACpBmC,OAAQ,CACN+X,EAAa,GAAG95D,OAChB85D,EAAa,GAAG75D,OAChB65D,EAAa,GAAG95D,OAChB85D,EAAa,GAAG75D,QAElBigD,OAAQrpC,EAAMi4C,UAAU3rB,OACxBgd,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpBK,QAAS5pC,EAAM4pC,UACfsZ,KAAM,CAAC,GAAI,GACX16D,KAAM,aAEV,CAQA0qD,eAAAA,CAAgB3gD,EAAOwwD,GAErB,MAAMX,EAAS7vD,EAAMu2C,aAAY,SAAUL,GACzC,MAAuB,UAAhBA,EAAKjgD,MACd,IAAG,GACH,KAAM45D,aAAkBrZ,KAAAA,OACtB,OAGF,MAAMia,EAAkBhkE,KAAKsjE,wBAAwBF,GAE/C7T,EAAUvvD,KAAKyjE,iBAAiBM,EAAeC,GAE/CG,EAAW5wD,EAAMu2C,aAAY,SAAUL,GAC3C,MAAuB,cAAhBA,EAAKjgD,MACd,IAAG,GACG26D,aAAoBpa,KAAAA,MAI1Boa,EAASjY,OAAO,CACdqD,EAAQ,GAAGplD,OACXolD,EAAQ,GAAGnlD,OACXmlD,EAAQ,GAAGplD,OACXolD,EAAQ,GAAGnlD,QAEf,CAQAg6D,aAAAA,CAAche,EAAY7yC,GAExB,MAAM6vD,EAAS7vD,EAAMu2C,aAAY,SAAUL,GACzC,MAAuB,UAAhBA,EAAKjgD,MACd,IAAG,GACH,KAAM45D,aAAkBrZ,KAAAA,OACtB,OAGF,MAAMmP,EAAO9S,EAAW6S,UACVmK,EAAOnK,UACfgK,QAAQ/J,GAEVkK,EAAOxY,WACTwY,EAAOxY,QAAwB,IAAhBsO,EAAK/2D,OAExB,ECvOK,MAAMkiE,GAMX,IAAO,EAOP,IAAO,EAOPC,MAAAA,GACE,OAAOtkE,MAAK,EACd,CAOAukE,MAAAA,CAAOliE,GACLrC,MAAK,GAAOqC,CACd,CAOAmiE,MAAAA,GACE,OAAOxkE,MAAK,EACd,CAOAykE,MAAAA,CAAOpiE,GACLrC,MAAK,GAAOqC,CACd,CAOA83D,OAAAA,GACE,MAAO,WACT,CAOA,IAAiB,KAOjBuK,gBAAAA,CAAiBthD,GACfpjB,MAAK,GAAiBojB,CACxB,CAOAuhD,gBAAAA,GACE,OAAO3kE,MAAK,EACd,CAOAqmD,MAAAA,GACE,MAAMjjC,EAAQpjB,KAAK2kE,mBACbC,EAAWxhD,EAAM6vB,eAAetsB,IAQtC,OAAOvD,EAAMm0B,WAPWz1C,GAClBA,EAAQ9B,KAAKskE,UAAYxiE,EAAQ9B,KAAKwkE,SACjCI,EAEA9iE,GAIb,EAOK,MAAM+iE,GAMX1K,OAAAA,GACE,MAAO,SACT,CAOA,IAAiB,KAOjBuK,gBAAAA,CAAiBthD,GACfpjB,MAAK,GAAiBojB,CACxB,CAOAuhD,gBAAAA,GACE,OAAO3kE,MAAK,EACd,CAOAqmD,MAAAA,GAGE,OAFcrmD,KAAK2kE,mBAENxuB,YAAY,CACvB,GAAI,EAAG,GACN,EAAG,GAAI,EACR,GAAI,EAAG,GAGX,EAOK,MAAM2uB,GAMX3K,OAAAA,GACE,MAAO,OACT,CAOA,IAAiB,KAOjBuK,gBAAAA,CAAiBthD,GACfpjB,MAAK,GAAiBojB,CACxB,CAOAuhD,gBAAAA,GACE,OAAO3kE,MAAK,EACd,CAOAqmD,MAAAA,GACE,MAAMjjC,EAAQpjB,KAAK2kE,mBAEbzI,EAAQ94C,EAAM+yB,YAAY,CAC9B,EAAG,GAAI,EACP,EAAG,GAAI,EACP,EAAG,GAAI,IAEHgmB,EAAQ/4C,EAAM+yB,YAAY,CAC9B,EAAG,EAAG,EACN,EAAG,EAAG,GACL,GAAI,GAAI,IAGX,OAAO+lB,EAAMzkB,QAAQ0kB,GAAO,SAAU1zD,EAAGC,GACvC,OAAO/E,KAAK4G,KAAK9B,EAAIA,EAAIC,EAAIA,EAC/B,GACF,ECoSK,MAAMq8D,GAOX,IAOA,IAOA,IAOA/iE,WAAAA,CAAYgjE,EAAQzN,EAAQpV,GAC1BniD,MAAK,GAAUglE,EACfhlE,MAAK,GAAUu3D,EACfv3D,MAAK,GAAOmiD,CACd,CAOAgY,OAAAA,GACE,MAAO,UAAYn6D,MAAK,GAAQm6D,SAClC,CAOA3S,OAAAA,GAEExnD,MAAK,GAAKu4C,SAASv4C,MAAK,GAASA,MAAK,GAAQqmD,UAE9CrmD,MAAK,GAAKilE,OAAOjlE,MAAK,IAStB,MAAMgiB,EAAQ,CACZN,KAAM,YACN3a,GAAI/G,KAAKm6D,UACT5C,OAAQv3D,MAAK,IAGfA,KAAKklE,UAAUljD,EACjB,CAOAo4C,IAAAA,GAEEp6D,MAAK,GAAKu4C,SAASv4C,MAAK,GAASA,MAAK,GAAQ2kE,oBAE9C3kE,MAAK,GAAKilE,OAAOjlE,MAAK,IAStB,MAAMgiB,EAAQ,CACZN,KAAM,aACN3a,GAAI/G,KAAKm6D,UACT1J,OAAQzwD,MAAK,IAEfA,KAAKmlE,OAAOnjD,EACd,CAOAkjD,SAAAA,CAAUE,GACR,CAQFD,MAAAA,CAAOC,GACL,ECtkBG,MAAMC,GAAW,CAAC,EAmEZC,GAAc,CAAC,EAOfC,GAAkB,CAC7BrgE,YCvFK,MAOL,IAOA,KAAW,EAOX,IAOA,IAKAlD,WAAAA,CAAYmgD,GACVniD,MAAK,GAAOmiD,EACZniD,MAAK,GAAe,IAAIkiD,GAAYC,EACtC,CAQA,IAAOx4B,EAAO67C,GAEOxlE,MAAK,GAAK0iD,qBAAqB8iB,GAErC3iB,qBAAqBC,oBACd/zB,iBAIpB/uB,MAAK,IAAW,EAChBA,MAAK,GAAc2pB,EACrB,CAQA,IAAQA,EAAO67C,GAEb,IAAKxlE,MAAK,GACR,OAGF,MACM4iD,EADa5iD,MAAK,GAAK0iD,qBAAqB8iB,GAErC3iB,qBAAqBC,oBAG5B2iB,EAAQ97C,EAAMxf,OAASnK,MAAK,GAAYmK,OACxCu7D,EAAQ1lE,MAAK,GAAYoK,OAASuf,EAAMvf,OAExC8X,EAAQ0gC,EAAe7C,4BAEvB4lB,EAA6C,KAAzBzjD,EAAM7U,IAAM6U,EAAMyE,KAGtCxhB,EAASy9C,EAAe98C,iBAAiBX,OACzCC,EAAQw9C,EAAe98C,iBAAiBV,MACxCyxB,EAAe1xB,EAASxB,KAAK0N,MAAMq0D,EAAQC,GACjD,IAAI7uC,EAAc1xB,EAAQzB,KAAK0N,MAAMo0D,EAAQE,GlE5G1C,IAA6B7jE,EkE8GhCg1B,GlE9GgCh1B,EkE8GEg1B,GlEtHf,IAS4Bh1B,EkE+G/C,MAAM+D,EAAK,IAAI+/D,EAAkB/uC,EAAcC,GAC/C8rB,EAAe1J,eAAerzC,GAG9B7F,MAAK,GAAc2pB,CACrB,CAKA,MACM3pB,MAAK,KACPA,MAAK,IAAW,EAEpB,CAOA6lE,UAAa7jD,IACX,MAAMmyC,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAOm0D,EAAY5R,EAAaI,WAAW,EAQlDmjB,UAAa9jD,IACX,MAAMmyC,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAQm0D,EAAY5R,EAAaI,WAAW,EAQnDojB,QAAWX,IACTplE,MAAK,IAAS,EAQhBgmE,SAAYZ,IACVplE,MAAK,IAAS,EAQhBimE,WAAcjkD,IACZ,MAAMkkD,EAAcC,GAAenkD,GAC7BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAOkmE,EAAY,GAAI3jB,EAAaI,WAAW,EAQtDyjB,UAAapkD,IACX,MAAMkkD,EAAcC,GAAenkD,GAC7BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAQkmE,EAAY,GAAI3jB,EAAaI,WAAW,EAQvD0jB,SAAYjB,IACVplE,MAAK,IAAS,EAQhBsmE,SAAYtkD,IACV,MAAMugC,EAAeC,GAAyBxgC,GACxCmyC,EAAaC,GAAcpyC,GAG3Bw/B,EADaxhD,MAAK,GAAK0iD,qBAAqBH,EAAaI,YAClCE,qBACvBv1C,EAAQk0C,EAAU+kB,oBAAoBpS,GACtCvR,EAAiBpB,EAAUsB,oBAEjC,IAAKF,EAAe7zB,eAClB,OAIF,MAAM3L,EAAQpjB,MAAK,GAAKwmE,QAAQhlB,EAAUkP,aAAattC,MACjDvd,EAAK,IAAI+/D,EACbxiD,EAAMwyB,wBACJgN,EAAexK,kBAAkBj1C,aAC/BmK,EAAMjM,IAAI,GACViM,EAAMjM,IAAI,KAGduhD,EAAe98C,iBAAiBV,OAElCw9C,EAAe1J,eAAerzC,EAAG,EAQnCu8C,MAASpgC,IACPhiB,MAAK,GAAaoiD,MAAMpgC,EAAM,EAQhCykD,QAAWzkD,IACTA,EAAM0kD,QAAU,cAChB1mE,MAAK,GAAK2mE,UAAU3kD,EAAM,EAQ5BgvC,QAAAA,CAAS4V,GACP,CAMF3uB,IAAAA,GACE,CAQF4uB,WAAAA,CAAYC,GACV,GDjKFC,OEhDK,MAML,IAOA,KAAW,EAOX,IAOA,IAOA,IAOA,KAAkB,EAOlB,IAKA/kE,WAAAA,CAAYmgD,GACVniD,MAAK,GAAOmiD,EACZniD,MAAK,GAAe,IAAIkiD,GAAYC,EACtC,CAQA,IAAOx4B,EAAO67C,GAEZxlE,MAAK,KAGL,MACMwhD,EADaxhD,MAAK,GAAK0iD,qBAAqB8iB,GACrB3iB,qBACvBD,EAAiBpB,EAAUsB,oBAC7BF,EAAe5E,aACjB4E,EAAexB,OAIjBphD,MAAK,IAAW,EAChBA,MAAK,GAAc2pB,EAGnB,MAAMq9C,EAAWxlB,EAAUylB,kBAAkBt9C,GACvCtG,EAAWu/B,EAAe1F,0BAA0B8pB,GAC1DpkB,EAAe3I,mBAAmB52B,EACpC,CAQA,IAAQsG,EAAO67C,GACb,IAAKxlE,MAAK,GAKR,YAHIA,MAAK,IACPA,MAAK,GAAa2pB,EAAO67C,IAK7B,MAAM/iB,EAAaziD,MAAK,GAAK0iD,qBAAqB8iB,GAE5C5iB,EADYH,EAAWI,qBACIC,oBAEjC,IAAIC,EAGJ,MAAM2iB,EAAQ/7C,EAAMvf,OAASpK,MAAK,GAAYoK,OACxC88D,EAASvjE,KAAKsH,IAAIy6D,GAAS,GAE7BwB,GAASzkB,EAAWv8B,cAGpB68B,EADE2iB,EAAQ,EACI9iB,EAAejC,6BAEfiC,EAAelC,8BAKjC,MAAM+kB,EAAQ97C,EAAMxf,OAASnK,MAAK,GAAYmK,OACxCg9D,EAASxjE,KAAKsH,IAAIw6D,GAAS,GAE7B0B,GAAS1kB,EAAW18B,YAAY,KAGhCg9B,EADE0iB,EAAQ,EACI7iB,EAAepC,qBAAqB,GAEpCoC,EAAenC,qBAAqB,SAK3B,IAAhBsC,GACTN,EAAW3I,mBAAmBiJ,IAC9BH,EAAe3I,mBAAmB8I,IAIhCokB,GAASD,KACXlnE,MAAK,GAAc2pB,EAEvB,CAKA,MACM3pB,MAAK,KACPA,MAAK,IAAW,EAEpB,CAOA6lE,UAAa7jD,IACX,MAAMmyC,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAOm0D,EAAY5R,EAAaI,WAAW,EAQlDmjB,UAAa9jD,IACX,MAAMmyC,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAQm0D,EAAY5R,EAAaI,WAAW,EAQnDojB,QAAWX,IACTplE,MAAK,IAAS,EAQhBgmE,SAAYZ,IACVplE,MAAK,KAELA,MAAK,IAAmB,EAQ1BimE,WAAcjkD,IAGZhiB,MAAK,GAAgBonE,YAAW,KAC9BpnE,KAAKsmE,SAAStkD,EAAM,GACnB,KAEH,MAAMkkD,EAAcC,GAAenkD,GAC7BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAOkmE,EAAY,GAAI3jB,EAAaI,WAAW,EAQtDyjB,UAAapkD,IAEgB,OAAvBhiB,MAAK,KACPqnE,aAAarnE,MAAK,IAClBA,MAAK,GAAgB,MAGvB,MAAMkmE,EAAcC,GAAenkD,GAC7BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAQkmE,EAAY,GAAI3jB,EAAaI,WAAW,EAQvD0jB,SAAYjB,IAEiB,OAAvBplE,MAAK,KACPqnE,aAAarnE,MAAK,IAClBA,MAAK,GAAgB,MAGvBA,MAAK,IAAS,EAQhBoiD,MAASpgC,IACPhiB,MAAK,GAAaoiD,MAAMpgC,EAAM,EAQhCykD,QAAWzkD,IACTA,EAAM0kD,QAAU,SAChB1mE,MAAK,GAAK2mE,UAAU3kD,EAAM,EAQ5BskD,SAAYtkD,IACV,MAAMugC,EAAeC,GAAyBxgC,GAE3BhiB,MAAK,GAAK0iD,qBAAqBH,EAAaI,YAElDE,qBAAqBC,oBACnB9B,MAAM,EASvB,IAAar3B,EAAO67C,GAElB,MAAM/iB,EAAaziD,MAAK,GAAK0iD,qBAAqB8iB,GAClDxlE,MAAK,GAAgBwlE,EAErB/iB,EAAW6kB,YAAY39C,EACzB,CAKA,WACoC,IAAvB3pB,MAAK,KACKA,MAAK,GAAK0iD,qBAAqB1iD,MAAK,IAC5CunE,mBACXvnE,MAAK,QAAgBQ,EAEzB,CAOAwwD,QAAAA,CAAS4V,GAEFA,GACH5mE,MAAK,IAET,CAOA6mE,WAAAA,CAAYW,QAC6B,IAA5BA,EAASC,iBAClBznE,MAAK,GAAkBwnE,EAASC,eAEpC,CAKAxvB,IAAAA,GACE,GFzRFyvB,WG7FK,MAOL,IAOA,KAAW,EAOX,IAOA,IAOA,IAOA,IAKA1lE,WAAAA,CAAYmgD,GACVniD,MAAK,GAAOmiD,CACd,CAOA,IAAOx4B,GACL3pB,MAAK,IAAW,EAChBA,MAAK,GAAc2pB,EACnB3pB,MAAK,IAAY,CACnB,CAOA,IAAkBksD,IAChBlsD,MAAK,IAAW,EAChBA,MAAK,GAAcksD,EAAO,GAC1BlsD,MAAK,IAAY,EAEjBA,MAAK,GAAc,IAAIgjD,GAAKkJ,EAAO,GAAIA,EAAO,IAC9ClsD,MAAK,GAAYA,MAAK,GAAY2jD,aAAa,EASjD,IAAQh6B,EAAO67C,GACb,IAAKxlE,MAAK,GACR,OAEFA,MAAK,IAAY,EAGjB,MAAM2nE,EAAKh+C,EAAMxf,OAASnK,MAAK,GAAYmK,OACrCy9D,EAAKj+C,EAAMvf,OAASpK,MAAK,GAAYoK,OAErCq4C,EAAaziD,MAAK,GAAK0iD,qBAAqB8iB,GAC5ChkB,EAAYiB,EAAWI,qBACvBD,EAAiBpB,EAAUsB,oBAC3BxG,EAAckF,EAAUqmB,oBAC5B,IAAI95D,EAAQ45D,EAAIC,IAEZnrB,EAAWmG,EAAexG,2BAA2B,CACzD3zC,EAAG6zC,EAAYnyC,OACfzB,EAAG4zC,EAAYlyC,SAEjBq4C,EAAWqlB,eAAe,CACxBr/D,EAAGg0C,EAAStyC,OACZzB,EAAG+zC,EAASryC,OACZzB,EAAG8zC,EAASpyC,SAEdo4C,EAAWsM,OAEX/uD,MAAK,GAAc2pB,CACrB,CAQA,IAAkBo+C,CAAC7b,EAAQsZ,KACzB,IAAKxlE,MAAK,GACR,OAEFA,MAAK,IAAY,EAEjB,MACMgoE,EADU,IAAIhlB,GAAKkJ,EAAO,GAAIA,EAAO,IACjBloD,YAAchE,MAAK,GAAYgE,YAEnDy+C,EAAaziD,MAAK,GAAK0iD,qBAAqB8iB,GAC5ChkB,EAAYiB,EAAWI,qBACvBD,EAAiBpB,EAAUsB,oBAEjC,GAAkB,IAAdklB,EAAiB,CAGnB,MAAMtC,EAAQxZ,EAAO,GAAG9hD,OAASpK,MAAK,GAAYoK,OAElD,GAAIzG,KAAKsH,IAAIy6D,GAAS,GACpB,OAGF,GAAIjjB,EAAWv8B,YAAa,CAC1B,IAAI68B,EAEFA,EADE2iB,EAAQ,EACI9iB,EAAelC,6BAEfkC,EAAejC,kCAGJ,IAAhBoC,GACTN,EAAW3I,mBAAmBiJ,IAC9BH,EAAe3I,mBAAmB8I,EAEtC,CACF,KAAO,CAEL,MAAMklB,GAAQD,EAAY,GAAK,GAC/B,GAAIrkE,KAAKsH,IAAIg9D,GAAQ,IAAO,UACA,IAAnBjoE,MAAK,GAA2B,CACvC,MAAMgnE,EAAWxlB,EAAU0mB,sBAAsBloE,MAAK,IAChDmF,EAASy9C,EAAetC,+BAA+B0mB,GAC7DvkB,EAAW0lB,SAASF,EAAM9iE,GAC1Bs9C,EAAWsM,MACb,CACF,GASF,IAAoBplC,EAAO67C,GACzB,MACMhkB,EADaxhD,MAAK,GAAK0iD,qBAAqB8iB,GACrB3iB,qBACvBD,EAAiBpB,EAAUsB,oBAC3BkkB,EAAWxlB,EAAUylB,kBAAkBt9C,GACvCtG,EAAWu/B,EAAe1F,0BAA0B8pB,GAC1DpkB,EAAe3I,mBAAmB52B,EACpC,CAKA,MACMrjB,MAAK,KACPA,MAAK,IAAW,EAEpB,CAOA6lE,UAAa7jD,IACX,MAAMmyC,EAAaC,GAAcpyC,GACjChiB,MAAK,GAAOm0D,EAAW,EAQzB2R,UAAa9jD,IACX,MAAMmyC,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAQm0D,EAAY5R,EAAaI,WAAW,EAQnDojB,QAAW/jD,IAET,IAAKhiB,MAAK,GAAW,CACnB,MAAMm0D,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAoBm0D,EAAY5R,EAAaI,WACpD,CACA3iD,MAAK,IAAS,EAQhBgmE,SAAYZ,IACVplE,MAAK,IAAS,EAQhBimE,WAAcjkD,IACZ,MAAMkkD,EAAcC,GAAenkD,GACR,IAAvBkkD,EAAY/jE,OACdnC,MAAK,GAAOkmE,EAAY,IACQ,IAAvBA,EAAY/jE,QACrBnC,MAAK,GAAekmE,EACtB,EAQFE,UAAapkD,IACX,MAAMkkD,EAAcC,GAAenkD,GAC7BugC,EAAeC,GAAyBxgC,GACnB,IAAvBkkD,EAAY/jE,OACdnC,MAAK,GAAQkmE,EAAY,GAAI3jB,EAAaI,YACV,IAAvBujB,EAAY/jE,QACrBnC,MAAK,GAAgBkmE,EAAa3jB,EAAaI,WACjD,EAQF0jB,SAAYrkD,IAEV,IAAKhiB,MAAK,GAAW,CACnB,MAAMm0D,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAoBm0D,EAAY5R,EAAaI,WACpD,CACA3iD,MAAK,IAAS,EAQhBoiD,MAASpgC,IAEPA,EAAMsgC,iBAEN,MAAM8lB,GAAQpmD,EAAM+/B,OAAS,IAEvBQ,EAAeC,GAAyBxgC,GACxCmyC,EAAaC,GAAcpyC,GAE3BygC,EAAaziD,MAAK,GAAK0iD,qBAAqBH,EAAaI,YACzDnB,EAAYiB,EAAWI,qBACvBD,EAAiBpB,EAAUsB,oBAC3BkkB,EAAWxlB,EAAU0mB,sBAAsB/T,GAC3ChvD,EAASy9C,EAAetC,+BAA+B0mB,GAC7DvkB,EAAW0lB,SAASC,EAAMjjE,GAC1Bs9C,EAAWsM,MAAM,EAQnB0X,QAAWzkD,IACTA,EAAM0kD,QAAU,aAChB1mE,MAAK,GAAK2mE,UAAU3kD,EAAM,EAQ5BgvC,QAAAA,CAAS4V,GACP,CAMF3uB,IAAAA,GACE,CAQF4uB,WAAAA,CAAYC,GACV,GHhPFuB,QI9FK,MAML,IAOA,KAAW,EAOX,IAOA,IAKArmE,WAAAA,CAAYmgD,GACVniD,MAAK,GAAOmiD,EACZniD,MAAK,GAAe,IAAIkiD,GAAYC,EACtC,CAOA,IAAOx4B,GACL3pB,MAAK,IAAW,EAChBA,MAAK,GAAc2pB,CACrB,CAQA,IAAQA,EAAO67C,GACb,IAAKxlE,MAAK,GACR,OAIF,MAAMylE,EAAQ97C,EAAMxf,OAASnK,MAAK,GAAYmK,OAG9C,GAFexG,KAAKsH,IAAIw6D,GAAS,GAEtB,CACT,MACMjkB,EADaxhD,MAAK,GAAK0iD,qBAAqB8iB,GACrB3iB,qBACvBylB,EAAK9mB,EAAU8T,aACrB9T,EAAU+T,WAAW+S,EAAM7C,EAAQ,KACnCjkB,EAAUuN,OAGV/uD,MAAK,GAAc2pB,CACrB,CACF,CAKA,MACM3pB,MAAK,KACPA,MAAK,IAAW,EAEpB,CAOA6lE,UAAa7jD,IACX,MAAMmyC,EAAaC,GAAcpyC,GACjChiB,MAAK,GAAOm0D,EAAW,EAQzB2R,UAAa9jD,IACX,MAAMmyC,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAQm0D,EAAY5R,EAAaI,WAAW,EAQnDojB,QAAWX,IACTplE,MAAK,IAAS,EAQhBgmE,SAAYZ,IACVplE,MAAK,IAAS,EAQhBimE,WAAcjkD,IACZ,MAAMkkD,EAAcC,GAAenkD,GACnChiB,MAAK,GAAOkmE,EAAY,GAAG,EAQ7BE,UAAapkD,IACX,MAAMkkD,EAAcC,GAAenkD,GAC7BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAQkmE,EAAY,GAAI3jB,EAAaI,WAAW,EAQvD0jB,SAAYjB,IACVplE,MAAK,IAAS,EAQhBoiD,MAASpgC,IACPhiB,MAAK,GAAaoiD,MAAMpgC,EAAM,EAQhCykD,QAAWzkD,IACTA,EAAM0kD,QAAU,UAChB1mE,MAAK,GAAK2mE,UAAU3kD,EAAM,EAQ5BgvC,QAAAA,CAAS4V,GACP,CAMF3uB,IAAAA,GACE,CAQF4uB,WAAAA,CAAYC,GACV,GJlGFyB,KK7EK,MAOL,IAOA,IAOA,IAOA,KAAa,EAOb,IAAoB,KAOpB,IAAkB,KAOlB,IAAiB,KAOjB,IAOA,IAAU,GAOV,IAAa,KAOb,KAAc,EAMd,IAAa,GAOb,IAQA,KAAmB,EAKnB,GAAa,CAAC,EAOd,KAAwB,EAOxB,IAAiB,GAKjBvmE,WAAAA,CAAYmgD,GACVniD,MAAK,GAAOmiD,EACZniD,MAAK,GAAe,IAAIkiD,GAAYC,GACpCniD,MAAK,GAAgB,IAAIiyD,GAAiB9P,EAAKniD,MAAK,IAEpDA,MAAK,GAASmiD,EAAIsN,UACpB,CASA,IAA8B9lC,EAAO67C,GACnC,MAAM/iB,EAAaziD,MAAK,GAAK0iD,qBAAqB8iB,GAClD,IAAI/W,EAAYhM,EAAW+lB,qBAE3B,QAAyB,IAAd/Z,EAA2B,CACpC,MACMga,EADYhmB,EAAWI,qBACD6N,YAGtBgY,EAFU1oE,MAAK,GAAKwmE,QAAQiC,GACVrlD,MAAMgrB,UACIzY,kBAElC,GAAI31B,MAAK,GAAW2Q,SAAS+3D,GAa3B,YAJA1oE,MAAK,GAAW,CACd0hB,KAAM,OACNwb,QAAS,oDAKb,MAAMjqB,EAAOjT,MAAK,GAAK2oE,qBAAqBF,GAE5CzoE,MAAK,GAAK4oE,2BAA2B31D,EAAMuyD,EAAOiD,GAElDha,EAAYhM,EAAW+lB,qBAEvB/Z,EAAUqG,gBAAgB90D,MAAK,IAE/ByiD,EAAWomB,2BAA2Bpa,EAAUiC,YAClD,CAGA,MAAMz9C,EAAOw7C,EAAU8B,oBAAoBzJ,qBAErCmK,EAAQxC,EAAUyC,gBAKxB,GAFAlxD,MAAK,GAAOyoD,aAAawI,EAAMzI,SAE3Bv1C,EAAK+yC,aAAc,CAErB,MAAM6D,EAASoH,EAAM6X,gBAAgB,CACnCrgE,EAAGkhB,EAAMxf,OACTzB,EAAGihB,EAAMvf,SAEPy/C,EAEF7pD,MAAK,GAAkByuD,EAAW5E,GAGlC7pD,MAAK,GAAyByiD,EAAY94B,EAE9C,CACF,CAWA,IAAyB84B,EAAY94B,GAEnC3pB,MAAK,GAAcuyD,wBACnBvyD,MAAK,KAEL,MAAMwhD,EAAYiB,EAAWI,qBAC7B7iD,MAAK,GAAawhD,EAAUylB,kBAAkBt9C,GAC9C3pB,MAAK,GAAQiD,KAAKjD,MAAK,GACzB,CAQA,MAEEA,MAAK,IAAa,EAElBA,MAAK,GAAkB,IAAIA,MAAK,GAAkBA,MAAK,IAEvDA,MAAK,GAAU,EACjB,CAQA,MACEA,MAAK,IAAa,EAClBA,MAAK,GAAU,EACjB,CAQA,IAAkByuD,EAAW5E,GAC3B,IAAIt2C,EAAQs2C,EAAOsF,YAEftF,aAAkBE,KAAAA,MACpBx2C,EAAQA,EAAM47C,aAEhB,MAAM4Z,EAAgBx1D,EAAM2W,KAAK,UAAU,GACrC6+C,aAAyBhf,KAAAA,QAY/B/pD,MAAK,GAAW,CACd0hB,KAAM,mBACNsnD,aAAcz1D,EAAMxM,KACpB0pD,OAAQhC,EAAUiC,cAEpB1wD,MAAK,GAAckyD,eAAe6W,EAAeta,GACnD,CAQA,IAA0B9kC,EAAO67C,GAC/B,MAAM/iB,EAAaziD,MAAK,GAAK0iD,qBAAqB8iB,GAE5C71D,EADY8yC,EAAWI,qBACPokB,kBAAkBt9C,IAGpChmB,KAAKsH,IAAI0E,EAAIxF,OAASnK,MAAK,GAAWmK,QAAU,GAClDxG,KAAKsH,IAAI0E,EAAIvF,OAASpK,MAAK,GAAWoK,QAAU,KAE5CpK,MAAK,IACPA,MAAK,GAAQyQ,MAGfzQ,MAAK,GAAa2P,EAElB3P,MAAK,IAAwB,EAE7BA,MAAK,GAAQiD,KAAKjD,MAAK,IAEvBA,MAAK,GAAaA,MAAK,GAASyiD,GAEpC,CAOA,IAA0B+iB,GAExB,GAA4B,IAAxBxlE,MAAK,GAAQmC,OAAjB,CAMA,GAAInC,MAAK,GAAQmC,SAAWnC,MAAK,GAAgBipE,aAAc,CAE7D,MAAMxmB,EACJziD,MAAK,GAAK0iD,qBAAqB8iB,GACjCxlE,MAAK,GAAeA,MAAK,GAASyiD,GAClCziD,MAAK,IACP,CAGAA,MAAK,IAAwB,CAZ7B,MAFEmE,EAAOa,KAAK,gCAehB,CAOA6gE,UAAa7jD,IAEX,GAAIhiB,MAAK,GACP,OAEF,MAAMm0D,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAA8Bm0D,EAAY5R,EAAaI,WAAW,EAQzEmjB,UAAa9jD,IAEX,IAAKhiB,MAAK,GACR,OAEF,MAAMm0D,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAA0Bm0D,EAAY5R,EAAaI,WAAW,EAQrEojB,QAAW/jD,IAET,IAAKhiB,MAAK,GACR,OAEF,MAAMuiD,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAA0BuiD,EAAaI,WAAW,EAQzD2jB,SAAYtkD,IAEV,GAAIhiB,MAAK,SACsC,IAAtCA,MAAK,GAAgBipE,aAC5B,OAGF,IAAKjpE,MAAK,GACR,OAGF,GAA4B,IAAxBA,MAAK,GAAQmC,OAEf,YADAgC,EAAOa,KAAK,kCAKd,MAAMu9C,EAAeC,GAAyBxgC,GACxCygC,EAAaziD,MAAK,GAAK0iD,qBAAqBH,EAAaI,YAC/D3iD,MAAK,GAAeA,MAAK,GAASyiD,GAClCziD,MAAK,IAAuB,EAQ9BgmE,SAAYhkD,IAEV,IAAKhiB,MAAK,GACR,OAEF,MAAMuiD,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAA0BuiD,EAAaI,WAAW,EAQzDsjB,WAAcjkD,IAEZ,GAAIhiB,MAAK,GACP,OAEF,MAAMkmE,EAAcC,GAAenkD,GAC7BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAA8BkmE,EAAY,GAAI3jB,EAAaI,WAAW,EAQ7EyjB,UAAapkD,IAEX,IAAKhiB,MAAK,GACR,OAGF,MAAMuiD,EAAeC,GAAyBxgC,GACxCkkD,EAAcC,GAAenkD,GAE7BygC,EAAaziD,MAAK,GAAK0iD,qBAAqBH,EAAaI,YAEzDhzC,EADY8yC,EAAWI,qBACPokB,kBAAkBf,EAAY,KAEhDviE,KAAKsH,IAAI0E,EAAIxF,OAASnK,MAAK,GAAWmK,QAAU,GAClDxG,KAAKsH,IAAI0E,EAAIvF,OAASpK,MAAK,GAAWoK,QAAU,KAEpB,IAAxBpK,MAAK,GAAQmC,QACfnC,MAAK,GAAQyQ,MAGfzQ,MAAK,GAAa2P,EAElB3P,MAAK,GAAQiD,KAAKjD,MAAK,IAEnBA,MAAK,GAAQmC,OAASnC,MAAK,GAAgBipE,eAC7C5B,aAAarnE,KAAKkpE,OAClBlpE,KAAKkpE,MAAQ9B,YAAW,KACtBpnE,MAAK,GAAQiD,KAAKjD,MAAK,GAAW,GACjCA,MAAK,GAAgBmpE,eAG1BnpE,MAAK,GAAaA,MAAK,GAASyiD,GAClC,EAQF4jB,SAAYrkD,IACVhiB,KAAKsmE,SAAStkD,EAAM,EAQtBogC,MAASpgC,IACHhiB,MAAK,IACPA,MAAK,GAAaoiD,MAAMpgC,EAC1B,EAQFykD,QAAWzkD,IAEJhiB,MAAK,KACRgiB,EAAM0kD,QAAU,OAChB1mE,MAAK,GAAK2mE,UAAU3kD,IAItB,MAAMokC,EAAapmD,MAAK,GAAcsyD,sBACtC,IAAmB,WAAdtwC,EAAMhhB,KACK,cAAdghB,EAAMhhB,WACgB,IAAfolD,EAA4B,CACnC,MAEMgM,EAFapyD,MAAK,GAAKopE,sBACAZ,qBACIjY,oBAG3BjJ,EAAU,IAAIC,GAAwBnB,EAAYgM,GAExDpyD,MAAK,GAAKwwD,eAAelJ,GAEzBA,EAAQE,UAGRxnD,MAAK,GAAc6yD,sBACrB,CAGA,GAAkB,WAAd7wC,EAAMhhB,KAA4C,OAAxBhB,MAAK,GAAyB,CAC1D,MAAMmxD,EAAanxD,MAAK,GAAe8uD,WAEvC9uD,MAAK,GAAeqpE,UACpBrpE,MAAK,GAAiB,KAEtBA,MAAK,KAELmxD,EAAWpC,MACb,GASF,IAAaua,EAAW7mB,GAElBziD,MAAK,KACPA,MAAK,GAAeqpE,UACpBrpE,MAAK,GAAiB,MAGxB,MAAMyuD,EAAYhM,EAAW+lB,qBACvBpW,EAAiB3D,EAAU8B,oBAC3BY,EAAa1C,EAAU2C,gBAEvBxO,EADYH,EAAWI,qBACIC,oBAGjC,GAAI9iD,MAAK,GAAkB,CACzB,MAAMupE,EAAU,CACd,UAAW,UAAW,UAAW,UAAW,SAAU,UAGlDC,EAAc/a,EAAU2G,QACxBqU,EAAUD,EAAY55D,UAAU45D,EAAYrnE,OAAS,GAErD4vC,EAASw3B,EADI1yD,SAAS4yD,EAAS,IAAM,QAErB,IAAX13B,GACT/xC,MAAK,GAAOsoD,cAAcvW,EAE9B,CAGA,MAAMqU,EAAa,IAAIsjB,GAEjBC,EAAcvX,EAAetL,qBAAqBZ,YAEtDE,EAAWrU,YADc,IAAhB43B,EACWA,EAEA3pE,MAAK,GAAOqoD,gBAElCjC,EAAWnO,KAAK2K,GAEhB5iD,MAAK,GAAgB4pE,uBAAuBxjB,EAAYkjB,GAExDtpE,MAAK,GACHA,MAAK,GAAgBm4D,iBAAiB/R,EAAYpmD,MAAK,IAEzDyuD,EAAU2J,mBAAmBp4D,MAAK,IAGpBA,MAAK,GAAe8pD,YAAYJ,IAAiB,GACzDwN,WAAU,GAChB/F,EAAW+F,WAAU,GAErB/F,EAAWjuD,IAAIlD,MAAK,IACpBmxD,EAAWpC,MACb,CAQA,IAAe8a,EAAapnB,GAGtBziD,MAAK,KACPA,MAAK,GAAeqpE,UACpBrpE,MAAK,GAAiB,MAGxB,MAAMyuD,EAAYhM,EAAW+lB,qBACvBrX,EAAa1C,EAAU2C,gBACvBgB,EAAiB3D,EAAU8B,oBAE3B3N,EADYH,EAAWI,qBACIC,oBAG3BsD,EAAa,IAAIsjB,GAEjBC,EAAcvX,EAAetL,qBAAqBZ,YAEtDE,EAAWrU,YADc,IAAhB43B,EACWA,EAEA3pE,MAAK,GAAOqoD,gBAElCjC,EAAWr/C,GAAK8gB,KAChBu+B,EAAWnO,KAAK2K,GAEhB5iD,MAAK,GAAgB4pE,uBAAuBxjB,EAAYyjB,GAGxD,MAAMviB,EAAU,IAAImQ,GAAqBrR,EAAYgM,GAErDpyD,MAAK,GAAKwwD,eAAelJ,GAEzBA,EAAQE,UAGR2J,EAAW+F,WAAU,EACvB,CAUA,IAAqB4S,GACnB,MAAML,EAAUK,EAAM1U,QAMtB,YAL4C,IAAjCp1D,MAAK,GAAeypE,KAC7BzpE,MAAK,GAAeypE,GAAW,KAC7BK,EAAMtS,+BAA8B,EAAK,GAGtCx3D,MAAK,GAAeypE,EAC7B,CAQA,IAAehb,EAAW7yB,GACxB6yB,EAAUqG,gBAAgB90D,MAAK,IAC/ByuD,EAAU+I,8BAA8B57B,GAEpCA,EACF57B,MAAK,GAAK+0C,iBAAiB,iBACzB/0C,MAAK,GAAqByuD,IAG5BzuD,MAAK,GAAKg1C,oBAAoB,iBAC5Bh1C,MAAK,GAAqByuD,GAGhC,CAOAuC,QAAAA,CAASp1B,GAEFA,GACH57B,MAAK,GAAc6yD,uBAGrB,MAAMkX,EAAa/pE,MAAK,GAAKgqE,gBAC7B,IAAK,MAAMvb,KAAasb,OACG,IAAdtb,GACTzuD,MAAK,GAAeyuD,EAAW7yB,GAInC57B,MAAK,GAAK+0C,iBAAiB,gBAAiB/yB,IAC1C,MAAM+nD,EAAa/pE,MAAK,GAAKgqE,eAAc,SAAUvrD,GACnD,OAAOA,EAAK22C,UAAYpzC,EAAMioD,OAChC,IAE0B,IAAtBF,EAAW5nE,QACbnC,MAAK,GAAe+pE,EAAW,GAAInuC,EACrC,GAGJ,CAOAsuC,UAAAA,CAAWC,GAETnqE,MAAK,GAAoBmqE,CAC3B,CAQAC,cAAAA,GACE,MAAO,SACT,CAOAvD,WAAAA,CAAYW,GAQV,QAPwC,IAA7BA,EAAS6C,kBAClBrqE,MAAK,GAAmBwnE,EAAS6C,sBAEC,IAAzB7C,EAAS8C,cAClBtqE,MAAK,GAAOsoD,cAAckf,EAAS8C,aACnCtqE,MAAK,IAAmB,QAEQ,IAAvBwnE,EAAS+C,UAA2B,CAE7C,IAAKvqE,KAAKwqE,SAAShD,EAAS+C,WAC1B,MAAM,IAAIroE,MAAM,mBAAsBslE,EAAS+C,UAAY,KAE7DvqE,MAAK,GAAawnE,EAAS+C,SAC7B,MACwC,IAA7B/C,EAASiD,iBAClBzqE,MAAK,GAAcwyD,qBAAqBgV,EAASiD,sBAEhB,IAAxBjD,EAASkD,aAClB1qE,MAAK,GAAcwnE,EAASkD,iBAEI,IAAvBlD,EAASmD,YAClB3qE,MAAK,GAAawnE,EAASmD,UAE/B,CAKA1yB,IAAAA,GACE,CAQF2yB,aAAAA,GACE,MAAO,CACL,mBAAoB,mBAAoB,OAE5C,CASA71B,gBAAAA,CAAiBrzB,EAAMmpD,QACgB,IAA1B7qE,MAAK,EAAW0hB,KACzB1hB,MAAK,EAAW0hB,GAAQ,IAE1B1hB,MAAK,EAAW0hB,GAAMze,KAAK4nE,EAC7B,CASA71B,mBAAAA,CAAoBtzB,EAAMmpD,GACxB,QAAqC,IAA1B7qE,MAAK,EAAW0hB,GAG3B,IAAK,IAAInf,EAAI,EAAGA,EAAIvC,MAAK,EAAW0hB,GAAMvf,SAAUI,EAC9CvC,MAAK,EAAW0hB,GAAMnf,KAAOsoE,GAC/B7qE,MAAK,EAAW0hB,GAAMI,OAAOvf,EAAG,EAGtC,CASA,IAAcyf,IACZ,QAA2C,IAAhChiB,MAAK,EAAWgiB,EAAMN,MAGjC,IAAK,IAAInf,EAAI,EAAGA,EAAIvC,MAAK,EAAWgiB,EAAMN,MAAMvf,SAAUI,EACxDvC,MAAK,EAAWgiB,EAAMN,MAAMnf,GAAGyf,EACjC,EASFwoD,QAAAA,CAAShhE,GACP,YAA+C,IAAjCxJ,MAAK,GAAkBwJ,EACvC,GLvvBAshE,ODnHK,MAOL,IAKA9oE,WAAAA,CAAYmgD,GACVniD,MAAK,GAAOmiD,CACd,CAOA,IAAc,KAOd,IAAkB,EAOlB,IAAmB,IAAI1gC,GAOvBuvC,QAAAA,CAAS+Z,GAEP,IAAK,MAAM/pE,KAAOhB,MAAK,GACjB+qE,GACF/qE,MAAK,GAAYgB,GAAK+zC,iBAAiB,YAAa/0C,MAAK,IACzDA,MAAK,GAAYgB,GAAK+zC,iBAAiB,cAAe/0C,MAAK,MAE3DA,MAAK,GAAYgB,GAAKg0C,oBACpB,YAAah1C,MAAK,IACpBA,MAAK,GAAYgB,GAAKg0C,oBACpB,cAAeh1C,MAAK,IAG5B,CAOAkqE,UAAAA,CAAWC,GACTnqE,MAAK,GAAc,CAAC,EAEpB,IAAK,MAAMgB,KAAOmpE,EAChBnqE,MAAK,GAAYgB,GAAO,IAAImpE,EAAQnpE,GAAKhB,MAAK,GAElD,CAQAoqE,cAAAA,GACE,MAAO,UACT,CAKAnyB,IAAAA,GAEE,IAAK,MAAMj3C,KAAOhB,MAAK,GACrBA,MAAK,GAAYgB,GAAKi3C,MAE1B,CAOAwuB,QAAWzkD,IACTA,EAAM0kD,QAAU,SAChB1mE,MAAK,GAAK2mE,UAAU3kD,EAAM,EAQ5B4oD,aAAAA,GACE,MAAO,CAAC,YAAa,aACvB,CASA71B,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAcK,IACZhiB,MAAK,GAAiB+hB,UAAUC,EAAM,EAQxCgpD,iBAAAA,GACE,OAAOhrE,MAAK,EACd,CAOA6mE,WAAAA,CAAYW,GACV,QAAmC,IAAxBA,EAASyD,WAA4B,CAE9C,IAAKjrE,KAAKkrE,UAAU1D,EAASyD,YAC3B,MAAM,IAAI/oE,MAAM,oBAAuBslE,EAASyD,WAAa,KAG3DjrE,MAAK,IACPA,MAAK,GAAgBgxD,UAAS,GAGhChxD,MAAK,GAAkBA,MAAK,GAAYwnE,EAASyD,YAEjDjrE,MAAK,GAAgBgxD,UAAS,EAChC,CACA,QAA4B,IAAjBwW,EAAS2D,KAAuB3D,EAAS2D,IAAK,CACvD,IAAIC,EAAO,CAAC,OACoB,IAArB5D,EAAS6D,UAClBD,EAAO5D,EAAS6D,SAElBrrE,KAAKgrE,oBAAoBG,IAAIC,EAC/B,CACF,CAOAE,aAAAA,GACE,OAAOtrE,MAAK,EACd,CAQAkrE,SAAAA,CAAU1hE,GACR,OAAOxJ,MAAK,GAAYwJ,EAC1B,GC/EA+hE,UM9FK,MAML,IAKAvpE,WAAAA,CAAYmgD,GACVniD,MAAK,GAAOmiD,CACd,CAOA,IAAc,EAMd,IAAoB,EAOpB,IAAiB,IAOjB,IAAa,KAOb,IAAQ,KAOR,IAAoB,GAOpB,IAAoB,KAOpB,KAAW,EAOX,IAOA,IAOA,IAAU,KAOV,IAAgB,GAOhB,KAAY,EAOZ,IAAS,IAAI6F,GAOb,IAAmB,IAAIvmC,GAOvB+pD,SAAAA,CAAUT,GACR/qE,MAAK,GAAY+qE,CACnB,CAQAU,SAAAA,GACE,OAAOzrE,MAAK,EACd,CASA,IAAY0rE,CAAC/hD,EAAO67C,KAClB,MAEMl4D,EAFatN,MAAK,GAAK0iD,qBAAqB8iB,GACrB3iB,qBACL0jB,oBAAoB58C,GAC5C,MAAO,CACLlhB,EAAG6E,EAAMjM,IAAI,GACbqH,EAAG4E,EAAMjM,IAAI,GACd,EAWH,IAAY6qD,EAAQz+B,EAAWk+C,GAE7B3rE,MAAK,GAAgB,GACrB,MAAMojB,EAAQ,CACZnQ,KAAMjT,MAAK,GAAWiT,KACtB7N,MAAOpF,MAAK,GAAWoF,MACvB+9B,OAAQnjC,MAAK,GAAWmjC,OACxByoC,MAAO,GAGT5rE,MAAK,GAAQ6rE,KAAAA,UAAoBzoD,EAAO8oC,EAAOzjD,EAAGyjD,EAAOxjD,EAAG+kB,GAC5DztB,MAAK,GAAQ6rE,KAAAA,oBAA8B7rE,MAAK,GAAOA,MAAK,IAE5D,IAAI8rE,EAAKD,KAAAA,cAAwB7rE,MAAK,IAItC,GAHA8rE,EAAKD,KAAAA,iBACHC,EAAI9rE,MAAK,GAAmBA,MAAK,IAE/B8rE,EAAG3pE,OAAS,GAAK2pE,EAAG,GAAG5f,OAAO,GAAGzjD,EAAG,CACtC,GAAIkjE,EACF,OAAOG,EAAG,GAAG5f,OAEf,IAAK,IAAI9oD,EAAI,EAAG2oE,EAAOD,EAAG,GAAG5f,OAAO/pD,OAAQiB,EAAI2oE,EAAM3oE,IACpDpD,MAAK,GAAciD,KAAK,IAAI8K,EAC1B+9D,EAAG,GAAG5f,OAAO9oD,GAAGqF,EAChBqjE,EAAG,GAAG5f,OAAO9oD,GAAGsF,IAGpB,OAAO1I,MAAK,EACd,CACE,MAAO,EAEX,CAUA,IAAa2pB,EAAO8D,EAAWg1B,GAI7B,GAFAziD,MAAK,GAAUA,MAAK,GAAY2pB,EAAO8D,GAAW,GAEtB,IAAxBztB,MAAK,GAAQmC,OAAc,CAC7B,MACMiwD,EADY3P,EAAW+lB,qBACIjY,oBAE3Byb,EAAe,IAAI/f,GAAIjsD,MAAK,IAElC,IAAIsnD,EACJ,QAAgC,IAArBtnD,MAAK,GAA6B,CAE3CA,MAAK,GAAc,IAAI0pE,GACvB1pE,MAAK,GAAY+xC,OAAS/xC,MAAK,GAAOqoD,gBACtCroD,MAAK,GAAY+G,GAAK8gB,KAEtB,MACM+6B,EADYH,EAAWI,qBACIC,oBACjC9iD,MAAK,GAAYi4C,KAAK2K,GAEtB5iD,MAAK,GAAY4vD,UAAYoc,EAC7B1kB,EAAU,IAAImQ,GACZz3D,MAAK,GACLoyD,EAEJ,KAAO,CAEL,MAAM6Z,EAAoBjsE,MAAK,GAAY4vD,UAC3CtI,EAAU,IAAIM,GACZ5nD,MAAK,GACL,CAAC4vD,UAAWqc,GACZ,CAACrc,UAAWoc,GACZ5Z,EAEJ,CAGApyD,MAAK,GAAKwwD,eAAelJ,GAEzBA,EAAQE,SACV,CAEA,OAA+B,IAAxBxnD,MAAK,GAAQmC,MACtB,CASA+pE,MAAAA,CAAOC,EAAK/5D,EAAKqwC,GAEf,IAAKziD,MAAK,GACR,KAAM,+DAGR,MAAM4iD,EACJH,EAAWI,qBAAqBC,oBAE5BnzC,EAAMizC,EAAexK,kBACrBg0B,EAAYxpB,EAAehD,eAC3BnyB,EAAYztB,MAAK,IAAqBA,MAAK,GAGjD,IAAK,IAAIuC,EAAIoN,EAAItO,IAAI,GACnBm4B,EAAMpnB,GACIg6D,EAAU/qE,IAAI,GACxBkB,EAAIi3B,GACCx5B,MAAK,GAAaA,MAAK,GAAeytB,EAAWg1B,GAD7ClgD,IAITqgD,EAAehC,eAAe,GAEhCgC,EAAe3I,mBAAmBtqC,GAGlC,IAAK,IAAIvM,EAAIuM,EAAItO,IAAI,GAAIgrE,EAAKF,GAAY,EAAG/oE,EAAIipE,GAC1CrsE,MAAK,GAAaA,MAAK,GAAeytB,EAAWg1B,GADHr/C,IAInDw/C,EAAe/B,eAAe,GAEhC+B,EAAe3I,mBAAmBtqC,EACpC,CAOA28D,iBAAAA,CAAkB1zB,GAChB,CASF,IAAOjvB,EAAO67C,GACZ,MAAM/iB,EAAaziD,MAAK,GAAK0iD,qBAAqB8iB,GAC5ChkB,EAAYiB,EAAWI,qBAC7B,IAAI4L,EAAYhM,EAAW+lB,qBAE3B,QAAyB,IAAd/Z,EAA2B,CACpC,MACMga,EADYhmB,EAAWI,qBACD6N,YAEtBz9C,EAAOjT,MAAK,GAAK2oE,qBAAqBF,GAE5CzoE,MAAK,GAAK4oE,2BAA2B31D,EAAMuyD,EAAOiD,GAElDha,EAAYhM,EAAW+lB,qBAEvB/lB,EAAWomB,2BAA2Bpa,EAAUiC,YAClD,CAEA1wD,MAAK,GAAawhD,EAAU+qB,eACvBvsE,MAAK,IAMVA,MAAK,GAAOyoD,aACVgG,EAAU2C,gBAAgBob,oBAE5BxsE,MAAK,IAAW,EAChBA,MAAK,GAAgBA,MAAK,GAAU2pB,EAAO67C,GAC3CxlE,MAAK,GAAaA,MAAK,GAAeA,MAAK,GAAmByiD,GAC9DziD,KAAKssE,kBAAkBtsE,MAAK,KAX1BmE,EAAOc,MAAM,iBAYjB,CAQA,IAAQ0kB,EAAO67C,GACb,IAAKxlE,MAAK,GACR,OAGF,MAAMysE,EAAazsE,MAAK,GAAU2pB,EAAO67C,GACzCxlE,MAAK,GAAoB2D,KAAK0N,MAAM1N,KAAK4G,KACvC5G,KAAKC,IAAK5D,MAAK,GAAcyI,EAAIgkE,EAAWhkE,EAAI,GAChD9E,KAAKC,IAAK5D,MAAK,GAAc0I,EAAI+jE,EAAW/jE,EAAI,IAAM,GACxD1I,MAAK,GAAoBA,MAAK,GAAoBA,MAAK,GACnDA,MAAK,GACLA,MAAK,GAAoBA,MAAK,GAElCA,MAAK,GACHA,MAAK,GACLA,MAAK,GACLA,MAAK,GAAK0iD,qBAAqB8iB,IAGjCxlE,KAAKssE,kBAAkBtsE,MAAK,GAC9B,CAKA,MACMA,MAAK,KACPA,MAAK,IAAW,EAEpB,CAOA6lE,UAAa7jD,IACX,MAAMmyC,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAOm0D,EAAY5R,EAAaI,WAAW,EAQlDmjB,UAAa9jD,IACX,MAAMmyC,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAQm0D,EAAY5R,EAAaI,WAAW,EAQnDojB,QAAWX,IACTplE,MAAK,IAAS,EAehBgmE,SAAYZ,IACVplE,MAAK,IAAS,EAQhBimE,WAAcjkD,IACZ,MAAMkkD,EAAcC,GAAenkD,GAC7BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAOkmE,EAAY,GAAI3jB,EAAaI,WAAW,EAQtDyjB,UAAapkD,IACX,MAAMkkD,EAAcC,GAAenkD,GAC7BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAQkmE,EAAY,GAAI3jB,EAAaI,WAAW,EAQvD0jB,SAAYjB,IACVplE,MAAK,IAAS,EAQhBymE,QAAWzkD,IACTA,EAAM0kD,QAAU,YAChB1mE,MAAK,GAAK2mE,UAAU3kD,EAAM,EAQ5BgvC,QAAAA,CAAS+Z,GACHA,IAEF/qE,MAAK,GAAOuoD,aAAavoD,MAAK,GAAK0oD,gBAEnC1oD,KAAK6mE,YAAY,CAACyD,YAAatqE,MAAK,GAAOqoD,kBAE/C,CAKApQ,IAAAA,GACE,CAQF2yB,aAAAA,GACE,MAAO,CAAC,aAAc,aAAc,WAAY,aAClD,CASA71B,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAgBAklD,WAAAA,CAAYW,QAC0B,IAAzBA,EAAS8C,aAClBtqE,MAAK,GAAOsoD,cAAckf,EAAS8C,YAEvC,GNzbAoC,SO1GK,MAML,IAKA1qE,WAAAA,CAAYmgD,GACVniD,MAAK,GAAOmiD,CACd,CAOA,KAAW,EAOX,IAOA,IAOA,IAAS,IAAI6F,GAOb,IAAQ,IAAIsS,GAOZ,IAAe,IAAIA,GAOnB,IAAgB,GAOhB,IAAa,EAOb,IAAmB,IAAI74C,GAOvB,IAAmB2qD,GACjB,MAAMloD,EAAQkoD,EAAU/qE,IAAI,GAC5B,IAAK,IAAIkB,EAAI,EAAGA,EAAI2hB,IAAS3hB,EAC3BvC,MAAK,GAAcuC,GAAK,EAE5B,CAKA,MACEvC,MAAK,GAAQ,IAAIs6D,GACjBt6D,MAAK,GAAe,IAAIs6D,EAC1B,CAOA,IAAY,IAAImC,GAQhB,IAAO9yC,EAAO67C,GACZ,MAAM/iB,EAAaziD,MAAK,GAAK0iD,qBAAqB8iB,GAC5ChkB,EAAYiB,EAAWI,qBACvBupB,EAAY5qB,EAAUsB,oBAAoBlD,eAC1CtyC,EAAQk0C,EAAU+kB,oBAAoB58C,GAG5C,GAAK3pB,MAAK,GA8BH,CACL,MAAMylE,EAAQ9hE,KAAKsH,IAAIqC,EAAMjM,IAAI,GAAKrB,MAAK,GAAYmK,QACjDu7D,EAAQ/hE,KAAKsH,IAAIqC,EAAMjM,IAAI,GAAKrB,MAAK,GAAYoK,QAEvD,GAAIq7D,EAAQzlE,MAAK,IACf0lE,EAAQ1lE,MAAK,GAEbA,MAAK,SACA,CAELA,MAAK,GAAQA,MAAK,GAClBA,MAAK,GAAmBosE,GACxB,MAAMO,EAAK,CAAClkE,EAAG6E,EAAMjM,IAAI,GAAIqH,EAAG4E,EAAMjM,IAAI,IAC1CrB,MAAK,GAAU2/D,WAAWgN,GAC1B3sE,MAAK,GAAM46D,gBAAgB56D,MAAK,GAAamsD,SAAS,GACxD,CACF,KA9CoB,CAClBnsD,MAAK,IAAW,EAChBA,MAAK,GAAc,IAAI+N,EAAQT,EAAMjM,IAAI,GAAIiM,EAAMjM,IAAI,IAEvDrB,MAAK,KACLA,MAAK,GAAmBosE,GAExB,IAAI3d,EAAYhM,EAAW+lB,qBAC3B,QAAyB,IAAd/Z,EAA2B,CACpC,MACMga,EADYhmB,EAAWI,qBACD6N,YAEtBz9C,EAAOjT,MAAK,GAAK2oE,qBAAqBF,GAE5CzoE,MAAK,GAAK4oE,2BAA2B31D,EAAMuyD,EAAOiD,GAElDha,EAAYhM,EAAW+lB,qBAEvB/lB,EAAWomB,2BAA2Bpa,EAAUiC,YAClD,CAEA1wD,MAAK,GAAOyoD,aACVgG,EAAU2C,gBAAgBob,oBAE5B,MAAMngE,EAAI,CAAC5D,EAAG6E,EAAMjM,IAAI,GAAIqH,EAAG4E,EAAMjM,IAAI,IACzCrB,MAAK,GAAU2/D,WAAWtzD,GAE1B,MAAMugE,EAAK,IAAI7+D,EAAQT,EAAMjM,IAAI,GAAIiM,EAAMjM,IAAI,IAC/CrB,MAAK,GAAMqsD,SAASugB,GACpB5sE,MAAK,GAAM46D,gBAAgBgS,EAC7B,CAiBF,CAQA,IAAQjjD,EAAO67C,GACb,IAAKxlE,MAAK,GACR,OAEF,MAAMyiD,EAAaziD,MAAK,GAAK0iD,qBAAqB8iB,GAE5Cl4D,EADYm1C,EAAWI,qBACL0jB,oBAAoB58C,GAG5C,IAAItd,EAAI,CAAC5D,EAAG6E,EAAMjM,IAAI,GAAIqH,EAAG4E,EAAMjM,IAAI,IACvCrB,MAAK,GAAUmhE,SAAS90D,GAExB,IAAIwgE,EAAU,GACVzrB,GAAO,EACX,MAAQphD,MAAK,GAAcqM,EAAE3D,GAAG2D,EAAE5D,KAAO24C,GAGvC,GAFAyrB,EAAU7sE,MAAK,GAAUwhE,SAEF,IAAnBqL,EAAQ1qE,OACVi/C,GAAO,OAGP,IAAK,IAAI7+C,EAAI,EAAGA,EAAIsqE,EAAQ1qE,OAAS,EAAGI,GAAK,EAAG,CAC9C,MAAMuqE,EAAKD,EAAQtqE,GACbwqE,EAAKF,EAAQtqE,EAAI,GACvBvC,MAAK,GAAc8sE,EAAGpkE,GAAGokE,EAAGrkE,GAAKskE,CACnC,CAOJ,IAFA/sE,MAAK,GAAe,IAAIs6D,GACxBlZ,GAAO,EACA/0C,IAAM+0C,GACXphD,MAAK,GAAaqsD,SAAS,IAAIt+C,EAAQ1B,EAAE5D,EAAG4D,EAAE3D,IACzC1I,MAAK,GAAcqM,EAAE3D,IAGnB1I,MAAK,GAAcqM,EAAE3D,GAAG2D,EAAE5D,GAG7B4D,EAAIrM,MAAK,GAAcqM,EAAE3D,GAAG2D,EAAE5D,GALhC24C,GAAO,EASXphD,MAAK,GAAa86D,UAAU96D,MAAK,IAEjC,MACMoyD,EADY3P,EAAW+lB,qBACIjY,oBAE3Byb,EAAe,IAAI/f,GAAIjsD,MAAK,GAAay6D,YAE/C,IAAInT,EACJ,QAAgC,IAArBtnD,MAAK,GAA6B,CAE3CA,MAAK,GAAc,IAAI0pE,GACvB1pE,MAAK,GAAY+xC,OAAS/xC,MAAK,GAAOqoD,gBACtCroD,MAAK,GAAY+G,GAAK8gB,KAEtB,MACM+6B,EADYH,EAAWI,qBACIC,oBACjC9iD,MAAK,GAAYi4C,KAAK2K,GAEtB5iD,MAAK,GAAY4vD,UAAYoc,EAC7B1kB,EAAU,IAAImQ,GACZz3D,MAAK,GACLoyD,EAEJ,KAAO,CAEL,MAAM6Z,EAAoBjsE,MAAK,GAAY4vD,UAC3CtI,EAAU,IAAIM,GACZ5nD,MAAK,GACL,CAAC4vD,UAAWqc,GACZ,CAACrc,UAAWoc,GACZ5Z,EAEJ,CAGApyD,MAAK,GAAKwwD,eAAelJ,GAEzBA,EAAQE,SACV,CAKA,MAEExnD,MAAK,IAAW,CAClB,CAOA6lE,UAAa7jD,IACX,MAAMmyC,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAOm0D,EAAY5R,EAAaI,WAAW,EAQlDmjB,UAAa9jD,IACX,MAAMmyC,EAAaC,GAAcpyC,GAC3BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAQm0D,EAAY5R,EAAaI,WAAW,EAQnDojB,OAAAA,CAAQX,GACN,CAQFY,SAAYZ,MASZkB,SAAYlB,IACVplE,MAAK,IAAc,EAQrBimE,WAAcjkD,IACZ,MAAMkkD,EAAcC,GAAenkD,GAC7BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAOkmE,EAAY,GAAI3jB,EAAaI,WAAW,EAQtDyjB,UAAapkD,IACX,MAAMkkD,EAAcC,GAAenkD,GAC7BugC,EAAeC,GAAyBxgC,GAC9ChiB,MAAK,GAAQkmE,EAAY,GAAI3jB,EAAaI,WAAW,EAQvD0jB,SAAYjB,MASZqB,QAAWzkD,IACTA,EAAM0kD,QAAU,WAChB1mE,MAAK,GAAK2mE,UAAU3kD,EAAM,EAQ5BgvC,QAAAA,CAAS+Z,GAEP,GAAIA,EAAM,CACR,MACMvpB,EADaxhD,MAAK,GAAKopE,sBACAvmB,qBAGvBupB,EAAY5qB,EAAUsB,oBAAoBlD,eAChD5/C,MAAK,GAAU2+D,cACbyN,EAAU/qE,IAAI,GACd+qE,EAAU/qE,IAAI,IAChBrB,MAAK,GAAU4+D,QAAQpd,EAAU+qB,eAAet5D,MAGhDjT,MAAK,GAAOuoD,aAAavoD,MAAK,GAAK0oD,gBAEnC1oD,KAAK6mE,YAAY,CAACyD,YAAatqE,MAAK,GAAOqoD,iBAC7C,CACF,CAKApQ,IAAAA,GACE,CAQF2yB,aAAAA,GACE,MAAO,CAAC,aAAc,aAAc,WAAY,aAClD,CASA71B,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAgBAklD,WAAAA,CAAYW,QAC0B,IAAzBA,EAAS8C,aAClBtqE,MAAK,GAAOsoD,cAAckf,EAAS8C,YAEvC,IPlUW0C,GAAqB,CAChCje,KAAM,CACJke,aQlHG,MAOL,IAAQ,QAOR,IAAgB,IAAIzK,GAAaxiE,MAAK,IAQtC,eAAOktE,CAAStd,GACd,OAAOA,aAAqB7hD,CAC9B,CAOAosD,OAAAA,GACE,OAAOn6D,MAAK,EACd,CAOA0W,YAAAA,GACE,OAAO1W,MAAK,GAAQ,QACtB,CAOAipE,UAAAA,GACE,OAAO,CACT,CAOAE,UAAAA,GACE,OAAO,CACT,CAQAS,sBAAAA,CAAuBxjB,EAAY8F,GACjC9F,EAAWwJ,UAAY5vD,MAAK,GAAoBksD,GAChD9F,EAAWyJ,gBAAkB,CAAC3D,EAAO,IACrC9F,EAAW+mB,YAAYntE,MAAK,MAC5BomD,EAAWI,sBACb,CASA2R,gBAAAA,CAAiB/R,EAAY+D,GAE3B,MAAM52C,EAAQ,IAAIw2C,KAAAA,OAClBx2C,EAAM/J,KAAKxJ,KAAK0W,gBAChBnD,EAAMq3C,SAAQ,GACdr3C,EAAMxM,GAAGq/C,EAAWr/C,IAEpB,MAAMorD,EAAQnyD,MAAK,GAAaomD,EAAY+D,GAC5C52C,EAAMrQ,IAAIivD,GAEV,MAAMib,EAASptE,MAAK,GAAmBomD,EAAY+D,GACnD,IAAK,MAAMkjB,KAASD,EAClB75D,EAAMrQ,IAAImqE,GAGZ,MAAMrsD,EAAQhhB,MAAK,GAAckzB,OAAOkzB,EAAY+D,GACpD52C,EAAMrQ,IAAI8d,GAEV,MAAM+iD,EAAgB/jE,MAAK,GAAwBmyD,GAMnD,OALA5+C,EAAMrQ,IAAIlD,MAAK,GAAc8jE,aAAaC,EAAe/iD,EAAOmpC,IAKzD52C,CACT,CAQA,IAAwB4+C,GACtB,MAAMjG,EAASiG,EAAMjG,SACf6U,EAAK5O,EAAM1pD,IACXu4D,EAAK7O,EAAMzpD,IACX2kD,GAAWnB,EAAO,GAAKA,EAAO,IAAM,EAAI6U,EACxCzT,GAAWpB,EAAO,GAAKA,EAAO,IAAM,EAAI8U,EAC9C,MAAO,CAAC,IAAIjzD,EAAQs/C,EAASC,GAC/B,CAQA,IAAqB6E,GACnB,MAAMjG,EAASiG,EAAMjG,SACf6U,EAAK5O,EAAM1pD,IACXu4D,EAAK7O,EAAMzpD,IACjB,MAAO,CACL,IAAIqF,EAAQm+C,EAAO,GAAK6U,EAAI7U,EAAO,GAAK8U,GACxC,IAAIjzD,EAAQm+C,EAAO,GAAK6U,EAAI7U,EAAO,GAAK8U,GAE5C,CASAxR,UAAAA,CAAW2C,EAAOhI,GAChB,MAAMmjB,EAAYttE,MAAK,GAAqBmyD,GACtC5C,EAAU,GAChB,IAAK,IAAIhtD,EAAI,EAAGA,EAAI+qE,EAAUnrE,SAAUI,EACtCgtD,EAAQtsD,KAAKinD,GACXojB,EAAU/qE,GAAG4H,OACbmjE,EAAU/qE,GAAG6H,OACb,SAAW7H,EACX4nD,IAGJ,OAAOoF,CACT,CAOAa,mBAAAA,CAAoBmd,GAClB,CAWFjd,4BAAAA,CAA6BlK,EAAYiJ,EAAQlF,GAE/C,MAAM52C,EAAQ87C,EAAOF,YACf57C,aAAiBw2C,KAAAA,QAKvB/pD,MAAK,GAAaomD,EAAYiJ,EAAQlF,GAEtCnqD,KAAKi0D,mBAAmB7N,EAAY7yC,EAAO42C,QAEH,IAA7B/D,EAAWyN,cAEpB7zD,MAAK,GAAcqjE,eAAejd,EAAY7yC,GAG9CvT,KAAKk0D,gBAAgB3gD,GAMzB,CAQA88C,4BAAAA,CAA6BjK,EAAYiJ,GAEvC,MAAM97C,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAGF,MAAMyjB,EAAQxtE,MAAK,GAAUuT,GAEvB0vC,EAAQ+G,GAAez2C,EAAO,GAC9BnB,EAAM43C,GAAez2C,EAAO,GAI5Bk6D,EAAa,IAAI1/D,EACrBk1C,EAAMx6C,IAAM+kE,EAAM/kE,IAClBw6C,EAAMv6C,IAAM8kE,EAAM9kE,KAEdglE,EAAW,IAAI3/D,EACnBqE,EAAI3J,IAAM+kE,EAAM/kE,IAChB2J,EAAI1J,IAAM8kE,EAAM9kE,KAElB09C,EAAWwJ,UAAY6d,EACvBrnB,EAAWyJ,gBAAkB,CAAC6d,GAE9BtnB,EAAWI,sBACb,CAQAwN,6BAAAA,CAA8B5N,EAAYmO,GAExC,MAAM5qC,EAAQy8B,EAAWwJ,UACnB+d,EAAWvnB,EAAWyJ,gBAAgB,GACtClL,EAAO,IAAI3B,GAAKr5B,EAAOgkD,GAEvB1qB,EAAQ0B,EAAKzB,WACb0qB,EAAW,IAAI7/D,EACnBk1C,EAAM94C,OAASoqD,EAAY9rD,EAC3Bw6C,EAAM74C,OAASmqD,EAAY7rD,GAEvB0J,EAAMuyC,EAAKxB,SACX0qB,EAAS,IAAI9/D,EACjBqE,EAAIjI,OAASoqD,EAAY9rD,EACzB2J,EAAIhI,OAASmqD,EAAY7rD,GAE3B09C,EAAWwJ,UAAYge,EACvBxnB,EAAWyJ,gBAAkB,CAACge,GAE9BznB,EAAWI,sBACb,CASAyN,kBAAAA,CAAmB7N,EAAY7yC,EAAOu6D,GACpC9tE,MAAK,GAAcokE,cAAche,EAAY7yC,EAC/C,CAOA2gD,eAAAA,CAAgB3gD,GACd,MAAMs2C,EAAS7pD,MAAK,GAAUuT,GACxBwwD,EAAgB/jE,MAAK,GAAwB6pD,GACnD7pD,MAAK,GAAck0D,gBAAgB3gD,EAAOwwD,EAC5C,CAQA,IAAoB7X,GAClB,OAAOA,EAAO,EAChB,CAOA,MACE,OAAO6V,GAASC,UAAUC,KAC5B,CASA,IAAa7b,EAAY+D,GACvB,MAAMxgC,EAAQy8B,EAAWwJ,UACnB+d,EAAWvnB,EAAWyJ,gBAAgB,GACtClL,EAAO,IAAI3B,GAAKr5B,EAAOgkD,GAGvB9jB,EAAS,IAAIE,KAAAA,MAAW,CAC5BmC,OAAQ,CACNviC,EAAMxf,OACNwf,EAAMvf,OACNujE,EAASxjE,OACTwjE,EAASvjE,QAEXigD,OAAQjE,EAAWrU,OACnBuY,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpB/gD,KAAM,UAKFukE,EAAYrpB,GAChBC,EAAMh7B,EAFQ,GAEQwgC,EAAMxB,gBACxBqlB,EAAYtpB,GAChBC,EAAMgpB,EAJQ,GAIWxjB,EAAMxB,gBAWjC,OAVAkB,EAAOokB,SAAQ,SAAUvH,GACvBA,EAAQwH,YACRxH,EAAQyH,OAAOJ,EAAU7qB,WAAW/4C,OAAQ4jE,EAAU7qB,WAAW94C,QACjEs8D,EAAQ0H,OAAOL,EAAU5qB,SAASh5C,OAAQ4jE,EAAU5qB,SAAS/4C,QAC7Ds8D,EAAQ0H,OAAOJ,EAAU7qB,SAASh5C,OAAQ6jE,EAAU7qB,SAAS/4C,QAC7Ds8D,EAAQ0H,OAAOJ,EAAU9qB,WAAW/4C,OAAQ6jE,EAAU9qB,WAAW94C,QACjEs8D,EAAQ2H,YACR3H,EAAQ4H,gBAAgBzkB,EAC1B,IAEOA,CACT,CAQA,IAAUt2C,GACR,OAAOq2C,GAAar2C,EACtB,CASA,IAAmB6yC,EAAY+D,GAC7B,MAAMxgC,EAAQy8B,EAAWwJ,UACnB+d,EAAWvnB,EAAWyJ,gBAAgB,GACtClL,EAAO,IAAI3B,GAAKr5B,EAAOgkD,GAIvBY,EAAWzpB,GACfH,EAAM,GAHQ,GAGcwF,EAAMxB,gBAmBpC,MAAO,CAhBW,IAAIoB,KAAAA,MAAW,CAC/BmC,OAAQ,CACNvH,EAAKzB,WAAW/4C,OAChBw6C,EAAKzB,WAAW94C,OAChBmkE,EAASrrB,WAAW/4C,OACpBokE,EAASrrB,WAAW94C,OACpBmkE,EAASprB,SAASh5C,OAClBokE,EAASprB,SAAS/4C,QAEpBkjC,KAAM8Y,EAAWrU,OACjBuY,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpBikB,QAAQ,EACRhlE,KAAM,mBAIV,CAQA,IAAyB48C,GAEvB,OADcA,EAAWwJ,SAE3B,CAUA,IAAaxJ,EAAYiJ,EAAQlF,GAC/B,MAAMxgC,EAAQy8B,EAAWwJ,UACnB+d,EAAWvnB,EAAWyJ,gBAAgB,GACtClL,EAAO,IAAI3B,GAAKr5B,EAAOgkD,GAGvBp6D,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAGF,MAAMyjB,EAAQxtE,MAAK,GAAUuT,GAG7Bi6D,EAAMnqD,SAAS,CAAC5a,EAAG,EAAGC,EAAG,IAEzB8kE,EAAMthB,OAAO,CACXviC,EAAMxf,OACNwf,EAAMvf,OACNujE,EAASxjE,OACTwjE,EAASvjE,SAIX,MAAMqkE,EAAYl7D,EAAMu2C,aAAY,SAAUL,GAC5C,MAAuB,mBAAhBA,EAAKjgD,MACd,IAAG,GACH,KAAMilE,aAAqB1kB,KAAAA,MACzB,OAGF,MAAM9G,EAAQ+G,GAAez2C,EAAO,GAC9BnB,EAAM43C,GAAez2C,EAAO,GAGlC,OAAQ87C,EAAOtoD,MACf,IAAK,UACHk8C,EAAMx6C,EAAE4mD,EAAO5mD,KACfw6C,EAAMv6C,EAAE2mD,EAAO3mD,KACf,MACF,IAAK,UACH0J,EAAI3J,EAAE4mD,EAAO5mD,KACb2J,EAAI1J,EAAE2mD,EAAO3mD,KACb,MACF,QACEvE,EAAOc,MAAM,wBAA0BoqD,EAAOtoD,MAIhD,MAGMwnE,EAAWzpB,GACfH,EAAM,GAJQ,GAIcwF,EAAMxB,gBACpC8lB,EAAUprD,SAAS,CAAC5a,EAAG,EAAGC,EAAG,IAC7B+lE,EAAUviB,OAAO,CACfvH,EAAKzB,WAAW/4C,OAChBw6C,EAAKzB,WAAW94C,OAChBmkE,EAASrrB,WAAW/4C,OACpBokE,EAASrrB,WAAW94C,OACpBmkE,EAASprB,SAASh5C,OAClBokE,EAASprB,SAAS/4C,SAIpB,MAAM2jE,EAAYrpB,GAChBC,EAAMh7B,EAjBQ,GAiBQwgC,EAAMxB,gBACxBqlB,EAAYtpB,GAChBC,EAAMgpB,EAnBQ,GAmBWxjB,EAAMxB,gBACjC6kB,EAAMS,SAAQ,SAAUvH,GACtBA,EAAQwH,YACRxH,EAAQyH,OAAOJ,EAAU7qB,WAAW/4C,OAAQ4jE,EAAU7qB,WAAW94C,QACjEs8D,EAAQ0H,OAAOL,EAAU5qB,SAASh5C,OAAQ4jE,EAAU5qB,SAAS/4C,QAC7Ds8D,EAAQ0H,OAAOJ,EAAU7qB,SAASh5C,OAAQ6jE,EAAU7qB,SAAS/4C,QAC7Ds8D,EAAQ0H,OAAOJ,EAAU9qB,WAAW/4C,OAAQ6jE,EAAU9qB,WAAW94C,QACjEs8D,EAAQ2H,YACR3H,EAAQ4H,gBAAgBd,EAC1B,GACF,CASA,IAAgBkB,EAAaC,GAE7B,CAQA,IAAmBD,EAAaC,GAC9B,GRhZAC,cSvHG,MAOL,IAAQ,SAOR,IAAgB,IAAIpM,GAAaxiE,MAAK,IAQtC,eAAOktE,CAAStd,GACd,OAAOA,aAAqB1B,EAC9B,CAOAiM,OAAAA,GACE,OAAOn6D,MAAK,EACd,CAOA0W,YAAAA,GACE,OAAO1W,MAAK,GAAQ,QACtB,CAOAipE,UAAAA,GACE,OAAO,CACT,CAOAE,UAAAA,GACE,OAAO,CACT,CAQAS,sBAAAA,CAAuBxjB,EAAY8F,GACjC9F,EAAWwJ,UAAY5vD,MAAK,GAAoBksD,GAChD9F,EAAW+mB,YAAYntE,MAAK,MAC5BomD,EAAWI,sBACb,CASA2R,gBAAAA,CAAiB/R,EAAY+D,GAE3B,MAAM52C,EAAQ,IAAIw2C,KAAAA,OAClBx2C,EAAM/J,KAAKxJ,KAAK0W,gBAChBnD,EAAMq3C,SAAQ,GACdr3C,EAAMxM,GAAGq/C,EAAWr/C,IAEpB,MAAMorD,EAAQnyD,MAAK,GAAaomD,EAAY+D,GAC5C52C,EAAMrQ,IAAIlD,MAAK,GAAaomD,EAAY+D,IAExC,MAAMnpC,EAAQhhB,MAAK,GAAckzB,OAAOkzB,EAAY+D,GACpD52C,EAAMrQ,IAAIlD,MAAK,GAAckzB,OAAOkzB,EAAY+D,IAEhD,MAAM4Z,EAAgB/jE,MAAK,GAAwBmyD,GAMnD,OALA5+C,EAAMrQ,IAAIlD,MAAK,GAAc8jE,aAAaC,EAAe/iD,EAAOmpC,IAKzD52C,CACT,CAQA,IAAwB4+C,GACtB,MAAM9E,EAAU8E,EAAM1pD,IAChB6kD,EAAU6E,EAAMzpD,IAChB06B,EAAS+uB,EAAM/uB,SAAWz/B,KAAK4G,KAAK,GAAK,EAC/C,MAAO,CACL,IAAIwD,EAAQs/C,EAAUjqB,EAAQkqB,EAAUlqB,GACxC,IAAIr1B,EAAQs/C,EAAUjqB,EAAQkqB,EAAUlqB,GACxC,IAAIr1B,EAAQs/C,EAAUjqB,EAAQkqB,EAAUlqB,GACxC,IAAIr1B,EAAQs/C,EAAUjqB,EAAQkqB,EAAUlqB,GAE5C,CAQA,IAAqB+uB,GACnB,MAAM9E,EAAU8E,EAAM1pD,IAChB6kD,EAAU6E,EAAMzpD,IAChB06B,EAAS+uB,EAAM/uB,SACrB,MAAO,CACL,IAAIr1B,EAAQs/C,EAAUjqB,EAAQkqB,GAC9B,IAAIv/C,EAAQs/C,EAAUjqB,EAAQkqB,GAC9B,IAAIv/C,EAAQs/C,EAASC,EAAUlqB,GAC/B,IAAIr1B,EAAQs/C,EAASC,EAAUlqB,GAEnC,CASAosB,UAAAA,CAAW2C,EAAOhI,GAChB,MAAMmjB,EAAYttE,MAAK,GAAqBmyD,GACtC5C,EAAU,GAChB,IAAK,IAAIhtD,EAAI,EAAGA,EAAI+qE,EAAUnrE,SAAUI,EACtCgtD,EAAQtsD,KAAKinD,GACXojB,EAAU/qE,GAAG4H,OACbmjE,EAAU/qE,GAAG6H,OACb,SAAW7H,EACX4nD,IAGJ,OAAOoF,CACT,CAOAa,mBAAAA,CAAoBf,GAElB,MAAM97C,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAIF,MAAM8kB,EAAO7kB,GAAez2C,EAAO,GAC7Bu7D,EAAQ9kB,GAAez2C,EAAO,GAC9Bw7D,EAAS/kB,GAAez2C,EAAO,GAC/By7D,EAAMhlB,GAAez2C,EAAO,GAGlC,OAAQ87C,EAAOtoD,MACf,IAAK,UAEH8nE,EAAKnmE,EAAEomE,EAAMpmE,KACb,MACF,IAAK,UAEHomE,EAAMpmE,EAAEmmE,EAAKnmE,KACb,MACF,IAAK,UAEHqmE,EAAOtmE,EAAEumE,EAAIvmE,KACb,MACF,IAAK,UAEHumE,EAAIvmE,EAAEsmE,EAAOtmE,KACb,MACF,QACEtE,EAAOc,MAAM,wBAA0BoqD,EAAOtoD,MAGlD,CAUAupD,4BAAAA,CAA6BlK,EAAYiJ,EAAQlF,GAE/C,MAAM52C,EAAQ87C,EAAOF,YACf57C,aAAiBw2C,KAAAA,QAKvB/pD,MAAK,GAAaomD,EAAYiJ,EAAQlF,GAEtCnqD,KAAKi0D,mBAAmB7N,EAAY7yC,EAAO42C,QAEH,IAA7B/D,EAAWyN,cAEpB7zD,MAAK,GAAcqjE,eAAejd,EAAY7yC,GAG9CvT,KAAKk0D,gBAAgB3gD,GAMzB,CAQA88C,4BAAAA,CAA6BjK,EAAYiJ,GAEvC,MAAM6S,EAAS9b,EAAWwJ,UACpBzqD,EAAS,IAAI4I,EACjBm0D,EAAOhV,YAAY/iD,OACnB+3D,EAAOhV,YAAY9iD,QAEf6kE,EAAc,IAAIlhE,EAAQshD,EAAO5mD,IAAK4mD,EAAO3mD,KAC7CwmE,EAAY/pE,EAAO8I,YAAYghE,GACrC7oB,EAAWwJ,UAAY,IAAI1B,GAAO/oD,EAAQ+pE,GAE1C9oB,EAAWI,sBACb,CAQAwN,6BAAAA,CAA8B5N,EAAYmO,GAExC,MAAM2N,EAAS9b,EAAWwJ,UACpBzqD,EAAS+8D,EAAOhV,YAChBiiB,EAAY,IAAIphE,EACpB5I,EAAOgF,OAASoqD,EAAY9rD,EAC5BtD,EAAOiF,OAASmqD,EAAY7rD,GAE9B09C,EAAWwJ,UAAY,IAAI1B,GAAOihB,EAAWjN,EAAO/T,aAEpD/H,EAAWI,sBACb,CASAyN,kBAAAA,CAAmB7N,EAAY7yC,EAAOu6D,GACpC9tE,MAAK,GAAcokE,cAAche,EAAY7yC,EAC/C,CAOA2gD,eAAAA,CAAgB3gD,GACd,MAAMs2C,EAAS7pD,MAAK,GAAUuT,GACxBwwD,EAAgB/jE,MAAK,GAAwB6pD,GACnD7pD,MAAK,GAAck0D,gBAAgB3gD,EAAOwwD,EAC5C,CASA,IAAoB7X,GAElB,MAAMprD,EAAI6C,KAAKsH,IAAIihD,EAAO,GAAG/hD,OAAS+hD,EAAO,GAAG/hD,QAC1CjC,EAAIvE,KAAKsH,IAAIihD,EAAO,GAAG9hD,OAAS8hD,EAAO,GAAG9hD,QAC1Cg5B,EAASz/B,KAAK0N,MAAM1N,KAAK4G,KAAKzJ,EAAIA,EAAIoH,EAAIA,IAEhD,OAAO,IAAIgmD,GAAOhC,EAAO,GAAI9oB,EAC/B,CAOA,MACE,OAAO2+B,GAASC,UAAUE,MAC5B,CASA,IAAa9b,EAAY+D,GACvB,MAAM+X,EAAS9b,EAAWwJ,UAE1B,OAAO,IAAI7F,KAAAA,QAAa,CACtBthD,EAAGy5D,EAAOhV,YAAY/iD,OACtBzB,EAAGw5D,EAAOhV,YAAY9iD,OACtBg5B,OAAQ8+B,EAAO/T,YACf9D,OAAQjE,EAAWrU,OACnBuY,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpB/gD,KAAM,SAEV,CAQA,IAAU+J,GACR,MAAMs2C,EAASt2C,EAAMu2C,YAAYJ,IAAiB,GAClD,GAAMG,aAAkBE,KAAAA,OAGxB,OAAOF,CACT,CAQA,IAAyBzD,GACvB,MAAM8b,EAAS9b,EAAWwJ,UACpBzqD,EAAS+8D,EAAOhV,YAChB9pB,EAAS8+B,EAAO/T,YACtB,OAAO,IAAIpgD,EACT5I,EAAOgF,OAASi5B,EAChBj+B,EAAOiF,OAASg5B,EAEpB,CAUA,IAAagjB,EAAYiJ,EAAQye,GAC/B,MAAM5L,EAAS9b,EAAWwJ,UACpBzqD,EAAS+8D,EAAOhV,YAChB9pB,EAAS8+B,EAAO/T,YAGhB56C,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAGc/pD,MAAK,GAAUuT,GAEvB6vB,OAAOA,GAGf,MAAMyrC,EAAO7kB,GAAez2C,EAAO,GAC7Bu7D,EAAQ9kB,GAAez2C,EAAO,GAC9Bw7D,EAAS/kB,GAAez2C,EAAO,GAC/By7D,EAAMhlB,GAAez2C,EAAO,GAE5B67D,EAAQN,EAAMrmE,IAAMomE,EAAKpmE,KAAO,EAAI,EACpC4mE,EAAQL,EAAItmE,IAAMqmE,EAAOrmE,IAAM,GAAK,EAG1C,OAAQ2mD,EAAOtoD,MACf,IAAK,UAEH8nE,EAAKpmE,EAAE4mD,EAAO5mD,KAEdqmE,EAAMrmE,EAAEtD,EAAOgF,OAASilE,EAAQhsC,GAChC2rC,EAAOrmE,EAAEvD,EAAOiF,OAASg5B,GACzB4rC,EAAItmE,EAAEvD,EAAOiF,OAASg5B,GACtB,MACF,IAAK,UAEH0rC,EAAMrmE,EAAE4mD,EAAO5mD,KAEfomE,EAAKpmE,EAAEtD,EAAOgF,OAASilE,EAAQhsC,GAC/B2rC,EAAOrmE,EAAEvD,EAAOiF,OAASg5B,GACzB4rC,EAAItmE,EAAEvD,EAAOiF,OAASg5B,GACtB,MACF,IAAK,UAEH2rC,EAAOrmE,EAAE2mD,EAAO3mD,KAEhBmmE,EAAKpmE,EAAEtD,EAAOgF,OAASi5B,GACvB0rC,EAAMrmE,EAAEtD,EAAOgF,OAASi5B,GACxB4rC,EAAItmE,EAAEvD,EAAOiF,OAASilE,EAAQjsC,GAC9B,MACF,IAAK,UAEH4rC,EAAItmE,EAAE2mD,EAAO3mD,KAEbmmE,EAAKpmE,EAAEtD,EAAOgF,OAASi5B,GACvB0rC,EAAMrmE,EAAEtD,EAAOgF,OAASi5B,GACxB2rC,EAAOrmE,EAAEvD,EAAOiF,OAASilE,EAAQjsC,GACjC,MACF,QACEj/B,EAAOc,MAAM,wBAA0BoqD,EAAOtoD,MAGlD,CASA,IAAgBq/C,EAAY7yC,GAC1B,MAAM2uD,EAAS9b,EAAWwJ,UAG1B,IAAI0f,EAAU,EACVC,EAAU,OACO,IAAVh8D,IACT+7D,EAAU/7D,EAAM9K,IAChB8mE,EAAUh8D,EAAM7K,KAElB,MAAM8mE,EAAU,IAAIzlB,KAAAA,OACpBylB,EAAQhmE,KAAK,UACb,MAAM41C,EAAU8iB,EAAO5W,WACvB,IAAK,IAAI/oD,EAAI,EAAGA,EAAI68C,EAAQj9C,SAAUI,EAAG,CACvC,MAAM+8C,EAASF,EAAQ78C,GACjB2iD,EAAO5F,EAAO,GAAG,GACjB8F,EAAO9F,EAAO,GAAG,GACjB6F,EAAO7F,EAAO,GAAG,GACjBmwB,EAAY,IAAI1lB,KAAAA,MAAW,CAC/BthD,EAAGy8C,EAAOoqB,EACV5mE,EAAG08C,EAAOmqB,EACVnqE,MAAO+/C,EAAOD,EACd/hB,OAAQ,EACRmK,KAAM,OACNgd,YAAa,EACbC,oBAAoB,EACpBqI,QAAS,GACTppD,KAAM,mBAERgmE,EAAQtsE,IAAIusE,EACd,CACA,OAAOD,CACT,CAQA,IAAmBppB,EAAY7yC,GAC7B,MAAMi8D,EAAUj8D,EAAMu2C,aAAY,SAAUL,GAC1C,MAAuB,WAAhBA,EAAKjgD,MACd,IAAG,QACoB,IAAZgmE,IAETA,EAAQnG,UAER91D,EAAMrQ,IAAIlD,MAAK,GAAgBomD,EAAY7yC,IAE/C,GT7XEm8D,eUxHG,MAOL,IAAQ,UAOR,IAAgB,IAAIlN,GAAaxiE,MAAK,IAQtC,eAAOktE,CAAStd,GACd,OAAOA,aAAqB5C,EAC9B,CAOAmN,OAAAA,GACE,OAAOn6D,MAAK,EACd,CAOA0W,YAAAA,GACE,OAAO1W,MAAK,GAAQ,QACtB,CAOAipE,UAAAA,GACE,OAAO,CACT,CAOAE,UAAAA,GACE,OAAO,CACT,CAQAS,sBAAAA,CAAuBxjB,EAAY8F,GACjC9F,EAAWwJ,UAAY5vD,MAAK,GAAoBksD,GAChD9F,EAAW+mB,YAAYntE,MAAK,MAC5BomD,EAAWI,sBACb,CASA2R,gBAAAA,CAAiB/R,EAAY+D,GAE3B,MAAM52C,EAAQ,IAAIw2C,KAAAA,OAClBx2C,EAAM/J,KAAKxJ,KAAK0W,gBAChBnD,EAAMq3C,SAAQ,GACdr3C,EAAMxM,GAAGq/C,EAAWr/C,IAEpB,MAAMorD,EAAQnyD,MAAK,GAAaomD,EAAY+D,GAC5C52C,EAAMrQ,IAAIlD,MAAK,GAAaomD,EAAY+D,IAExC,MAAMnpC,EAAQhhB,MAAK,GAAckzB,OAAOkzB,EAAY+D,GACpD52C,EAAMrQ,IAAIlD,MAAK,GAAckzB,OAAOkzB,EAAY+D,IAEhD,MAAM4Z,EAAgB/jE,MAAK,GAAwBmyD,GAMnD,OALA5+C,EAAMrQ,IAAIlD,MAAK,GAAc8jE,aAAaC,EAAe/iD,EAAOmpC,IAKzD52C,CACT,CAQA,IAAwB4+C,GACtB,MAAM9E,EAAU8E,EAAM1pD,IAChB6kD,EAAU6E,EAAMzpD,IAChB8hD,EAAU2H,EAAM3H,UAAY7mD,KAAK4G,KAAK,GAAK,EAC3CkgD,EAAU0H,EAAM1H,UAAY9mD,KAAK4G,KAAK,GAAK,EACjD,MAAO,CACL,IAAIwD,EAAQs/C,EAAU7C,EAAS8C,EAAU7C,GACzC,IAAI18C,EAAQs/C,EAAU7C,EAAS8C,EAAU7C,GACzC,IAAI18C,EAAQs/C,EAAU7C,EAAS8C,EAAU7C,GACzC,IAAI18C,EAAQs/C,EAAU7C,EAAS8C,EAAU7C,GAE7C,CAQA,IAAqB0H,GACnB,MAAM9E,EAAU8E,EAAM1pD,IAChB6kD,EAAU6E,EAAMzpD,IAChB06B,EAAS+uB,EAAM/uB,SACrB,MAAO,CACL,IAAIr1B,EAAQs/C,EAAUjqB,EAAO36B,EAAG6kD,GAChC,IAAIv/C,EAAQs/C,EAAUjqB,EAAO36B,EAAG6kD,GAChC,IAAIv/C,EAAQs/C,EAASC,EAAUlqB,EAAO16B,GACtC,IAAIqF,EAAQs/C,EAASC,EAAUlqB,EAAO16B,GAE1C,CASA8mD,UAAAA,CAAW2C,EAAOhI,GAChB,MAAMmjB,EAAYttE,MAAK,GAAqBmyD,GACtC5C,EAAU,GAChB,IAAK,IAAIhtD,EAAI,EAAGA,EAAI+qE,EAAUnrE,SAAUI,EACtCgtD,EAAQtsD,KAAKinD,GACXojB,EAAU/qE,GAAG4H,OACbmjE,EAAU/qE,GAAG6H,OACb,SAAW7H,EACX4nD,IAGJ,OAAOoF,CACT,CAOAa,mBAAAA,CAAoBf,GAElB,MAAM97C,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAIF,MAAM8kB,EAAO7kB,GAAez2C,EAAO,GAC7Bu7D,EAAQ9kB,GAAez2C,EAAO,GAC9Bw7D,EAAS/kB,GAAez2C,EAAO,GAC/By7D,EAAMhlB,GAAez2C,EAAO,GAGlC,OAAQ87C,EAAOtoD,MACf,IAAK,UAEH8nE,EAAKnmE,EAAEomE,EAAMpmE,KACb,MACF,IAAK,UAEHomE,EAAMpmE,EAAEmmE,EAAKnmE,KACb,MACF,IAAK,UAEHqmE,EAAOtmE,EAAEumE,EAAIvmE,KACb,MACF,IAAK,UAEHumE,EAAIvmE,EAAEsmE,EAAOtmE,KACb,MACF,QACEtE,EAAOc,MAAM,wBAA0BoqD,EAAOtoD,MAGlD,CAUAupD,4BAAAA,CAA6BlK,EAAYiJ,EAAQlF,GAE/C,MAAM52C,EAAQ87C,EAAOF,YACf57C,aAAiBw2C,KAAAA,QAKvB/pD,MAAK,GAAaomD,EAAYiJ,EAAQlF,GAEtCnqD,KAAKi0D,mBAAmB7N,EAAY7yC,EAAO42C,QAEH,IAA7B/D,EAAWyN,cAEpB7zD,MAAK,GAAcqjE,eAAejd,EAAY7yC,GAG9CvT,KAAKk0D,gBAAgB3gD,GAMzB,CAQA88C,4BAAAA,CAA6BjK,EAAYiJ,GAEvC,MAAM8S,EAAU/b,EAAWwJ,UACrBzqD,EAASg9D,EAAQjV,YACvB,IAAI1C,EAAU2X,EAAQhV,OAClB1C,EAAU0X,EAAQ/U,OAGtB,OAAQiC,EAAOtoD,MACf,IAAK,UACHyjD,EAAUrlD,EAAOgF,OAASklD,EAAO5mD,IACjC,MACF,IAAK,UACH+hD,EAAU6E,EAAO5mD,IAAMtD,EAAOgF,OAC9B,MACF,IAAK,UACHsgD,EAAU4E,EAAO3mD,IAAMvD,EAAOiF,OAC9B,MACF,IAAK,UACHqgD,EAAUtlD,EAAOiF,OAASilD,EAAO3mD,IACjC,MACF,QACEvE,EAAOc,MAAM,wBAA0BoqD,EAAOtoD,MAIhDq/C,EAAWwJ,UAAY,IAAI5C,GACzB7nD,EAAQxB,KAAKsH,IAAIu/C,GAAU7mD,KAAKsH,IAAIw/C,IAEtCrE,EAAWI,sBACb,CAQAwN,6BAAAA,CAA8B5N,EAAYmO,GAExC,MAAM4N,EAAU/b,EAAWwJ,UACrBzqD,EAASg9D,EAAQjV,YACjBiiB,EAAY,IAAIphE,EACpB5I,EAAOgF,OAASoqD,EAAY9rD,EAC5BtD,EAAOiF,OAASmqD,EAAY7rD,GAE9B09C,EAAWwJ,UAAY,IAAI5C,GACzBmiB,EAAWhN,EAAQhV,OAAQgV,EAAQ/U,QAErChH,EAAWI,sBACb,CASAyN,kBAAAA,CAAmB7N,EAAY7yC,EAAOu6D,GACpC9tE,MAAK,GAAcokE,cAAche,EAAY7yC,EAC/C,CAOA2gD,eAAAA,CAAgB3gD,GACd,MAAMs2C,EAAS7pD,MAAK,GAAUuT,GACxBwwD,EAAgB/jE,MAAK,GAAwB6pD,GACnD7pD,MAAK,GAAck0D,gBAAgB3gD,EAAOwwD,EAC5C,CAQA,IAAoB7X,GAElB,MAAMprD,EAAI6C,KAAKsH,IAAIihD,EAAO,GAAG/hD,OAAS+hD,EAAO,GAAG/hD,QAC1CjC,EAAIvE,KAAKsH,IAAIihD,EAAO,GAAG9hD,OAAS8hD,EAAO,GAAG9hD,QAEhD,OAAO,IAAI4iD,GAAQd,EAAO,GAAIprD,EAAGoH,EACnC,CAOA,MACE,OAAO65D,GAASC,UAAUG,OAC5B,CASA,IAAa/b,EAAY+D,GACvB,MAAMgY,EAAU/b,EAAWwJ,UACrBzqD,EAASg9D,EAAQjV,YACjB9pB,EAAS,CACb36B,EAAG05D,EAAQhV,OACXzkD,EAAGy5D,EAAQ/U,QAGb,OAAO,IAAIrD,KAAAA,SAAc,CACvBthD,EAAGtD,EAAOgF,OACVzB,EAAGvD,EAAOiF,OACVg5B,OAAQA,EACRonB,QAASpnB,EAAO36B,EAChBgiD,QAASrnB,EAAO16B,EAChB2hD,OAAQjE,EAAWrU,OACnBuY,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpB/gD,KAAM,SAEV,CAQA,IAAU+J,GACR,MAAMs2C,EAASt2C,EAAMu2C,YAAYJ,IAAiB,GAClD,GAAMG,aAAkBE,KAAAA,QAGxB,OAAOF,CACT,CAQA,IAAyBzD,GACvB,MAAM+b,EAAU/b,EAAWwJ,UACrBzqD,EAASg9D,EAAQjV,YACvB,OAAO,IAAIn/C,EACT5I,EAAOgF,OAASg4D,EAAQhV,OACxBhoD,EAAOiF,OAAS+3D,EAAQ/U,OAE5B,CASA,IAAahH,EAAYiJ,EAAQye,GAC/B,MAAM3L,EAAU/b,EAAWwJ,UACrBzqD,EAASg9D,EAAQjV,YACjB1C,EAAU2X,EAAQhV,OAClB1C,EAAU0X,EAAQ/U,OAGlB75C,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAGe/pD,MAAK,GAAUuT,GAEvB6vB,OAAO,CACd36B,EAAG+hD,EACH9hD,EAAG+hD,IAIL,MAAMokB,EAAO7kB,GAAez2C,EAAO,GAC7Bu7D,EAAQ9kB,GAAez2C,EAAO,GAC9Bw7D,EAAS/kB,GAAez2C,EAAO,GAC/By7D,EAAMhlB,GAAez2C,EAAO,GAE5B67D,EAAQN,EAAMrmE,IAAMomE,EAAKpmE,KAAO,EAAI,EACpC4mE,EAAQL,EAAItmE,IAAMqmE,EAAOrmE,IAAM,GAAK,EAG1C,OAAQ2mD,EAAOtoD,MACf,IAAK,UAEH8nE,EAAKpmE,EAAE4mD,EAAO5mD,KAEdqmE,EAAMrmE,EAAEtD,EAAOgF,OAASilE,EAAQ5kB,GAChCukB,EAAOrmE,EAAEvD,EAAOiF,OAASqgD,GACzBukB,EAAItmE,EAAEvD,EAAOiF,OAASqgD,GACtB,MACF,IAAK,UAEHqkB,EAAMrmE,EAAE4mD,EAAO5mD,KAEfomE,EAAKpmE,EAAEtD,EAAOgF,OAASilE,EAAQ5kB,GAC/BukB,EAAOrmE,EAAEvD,EAAOiF,OAASqgD,GACzBukB,EAAItmE,EAAEvD,EAAOiF,OAASqgD,GACtB,MACF,IAAK,UAEHskB,EAAOrmE,EAAE2mD,EAAO3mD,KAEhBmmE,EAAKpmE,EAAEtD,EAAOgF,OAASqgD,GACvBskB,EAAMrmE,EAAEtD,EAAOgF,OAASqgD,GACxBwkB,EAAItmE,EAAEvD,EAAOiF,OAASilE,EAAQ5kB,GAC9B,MACF,IAAK,UAEHukB,EAAItmE,EAAE2mD,EAAO3mD,KAEbmmE,EAAKpmE,EAAEtD,EAAOgF,OAASqgD,GACvBskB,EAAMrmE,EAAEtD,EAAOgF,OAASqgD,GACxBukB,EAAOrmE,EAAEvD,EAAOiF,OAASilE,EAAQ5kB,GACjC,MACF,QACEtmD,EAAOc,MAAM,wBAA0BoqD,EAAOtoD,MAGlD,CASA,IAAgBq/C,EAAY7yC,GAC1B,MAAM4uD,EAAU/b,EAAWwJ,UAG3B,IAAI0f,EAAU,EACVC,EAAU,OACO,IAAVh8D,IACT+7D,EAAU/7D,EAAM9K,IAChB8mE,EAAUh8D,EAAM7K,KAElB,MAAM8mE,EAAU,IAAIzlB,KAAAA,OACpBylB,EAAQhmE,KAAK,UACb,MAAM41C,EAAU+iB,EAAQ7W,WACxB,IAAK,IAAI/oD,EAAI,EAAGA,EAAI68C,EAAQj9C,SAAUI,EAAG,CACvC,MAAM+8C,EAASF,EAAQ78C,GACjB2iD,EAAO5F,EAAO,GAAG,GACjB8F,EAAO9F,EAAO,GAAG,GACjB6F,EAAO7F,EAAO,GAAG,GACjBmwB,EAAY,IAAI1lB,KAAAA,MAAW,CAC/BthD,EAAGy8C,EAAOoqB,EACV5mE,EAAG08C,EAAOmqB,EACVnqE,MAAO+/C,EAAOD,EACd/hB,OAAQ,EACRmK,KAAM,OACNgd,YAAa,EACbC,oBAAoB,EACpBqI,QAAS,GACTppD,KAAM,mBAERgmE,EAAQtsE,IAAIusE,EACd,CACA,OAAOD,CACT,CAQA,IAAmBppB,EAAY7yC,GAC7B,MAAMi8D,EAAUj8D,EAAMu2C,aAAY,SAAUL,GAC1C,MAAuB,WAAhBA,EAAKjgD,MACd,IAAG,QACoB,IAAZgmE,IAETA,EAAQnG,UAER91D,EAAMrQ,IAAIlD,MAAK,GAAgBomD,EAAY7yC,IAE/C,GVvZEo8D,kBWzHG,MAOL,IAAQ,aAOR,IAAgB,IAAInN,GAAaxiE,MAAK,IAQtC,eAAOktE,CAAStd,GACd,OAAOA,aAAqB/C,EAC9B,CAOAsN,OAAAA,GACE,OAAOn6D,MAAK,EACd,CAOA0W,YAAAA,GACE,OAAO1W,MAAK,GAAQ,QACtB,CAOAipE,UAAAA,GACE,OAAO,CACT,CAOAE,UAAAA,GACE,OAAO,GACT,CAQAS,sBAAAA,CAAuBxjB,EAAY8F,GACjC9F,EAAWwJ,UAAY5vD,MAAK,GAAoBksD,GAChD9F,EAAW+mB,YAAYntE,MAAK,MAC5BomD,EAAWI,sBACb,CASA2R,gBAAAA,CAAiB/R,EAAY+D,GAC3B,MAAMiY,EAAahc,EAAWwJ,UAGxBr8C,EAAQ,IAAIw2C,KAAAA,OAClBx2C,EAAM/J,KAAKxJ,KAAK0W,gBAChBnD,EAAMq3C,SAAQ,GACdr3C,EAAMxM,GAAGq/C,EAAWr/C,IAEpB,MAAMorD,EAAQnyD,MAAK,GAAaomD,EAAY+D,GAG5C,GAFA52C,EAAMrQ,IAAIlD,MAAK,GAAaomD,EAAY+D,IAEpCiY,EAAWp+D,cAAgBhE,KAAKipE,aAAc,CAEhD,MAAMmE,EAASptE,MAAK,GAAmBomD,EAAY+D,GACnD,IAAK,MAAMkjB,KAASD,EAClB75D,EAAMrQ,IAAImqE,GAGZ,MAAMrsD,EAAQhhB,MAAK,GAAckzB,OAAOkzB,EAAY+D,GACpD52C,EAAMrQ,IAAIlD,MAAK,GAAckzB,OAAOkzB,EAAY+D,IAEhD,MAAM4Z,EAAgB/jE,MAAK,GAAwBmyD,GACnD5+C,EAAMrQ,IAAIlD,MAAK,GAAc8jE,aAAaC,EAAe/iD,EAAOmpC,GAKlE,CACA,OAAO52C,CACT,CASA,IAAwB4+C,GACtB,MAAMjG,EAASiG,EAAMjG,SACf6U,EAAK5O,EAAM1pD,IACXu4D,EAAK7O,EAAMzpD,IACjB,MAAO,CACL,IAAIqF,EAAQm+C,EAAO,GAAK6U,EAAI7U,EAAO,GAAK8U,GAE5C,CAQA,IAAqB7O,GACnB,MAAMjG,EAASiG,EAAMjG,SACf6U,EAAK5O,EAAM1pD,IACXu4D,EAAK7O,EAAMzpD,IACjB,MAAO,CACL,IAAIqF,EAAQm+C,EAAO,GAAK6U,EAAI7U,EAAO,GAAK8U,GACxC,IAAIjzD,EAAQm+C,EAAO,GAAK6U,EAAI7U,EAAO,GAAK8U,GACxC,IAAIjzD,EAAQm+C,EAAO,GAAK6U,EAAI7U,EAAO,GAAK8U,GAE5C,CASAxR,UAAAA,CAAW2C,EAAOhI,GAChB,MAAMmjB,EAAYttE,MAAK,GAAqBmyD,GACtC5C,EAAU,GAChB,IAAK,IAAIhtD,EAAI,EAAGA,EAAI+qE,EAAUnrE,SAAUI,EACtCgtD,EAAQtsD,KAAKinD,GACXojB,EAAU/qE,GAAG4H,OACbmjE,EAAU/qE,GAAG6H,OACb,SAAW7H,EACX4nD,IAGJ,OAAOoF,CACT,CAOAa,mBAAAA,CAAoBmd,GAClB,CAWFjd,4BAAAA,CAA6BlK,EAAYiJ,EAAQlF,GAE/C,MAAM52C,EAAQ87C,EAAOF,YACf57C,aAAiBw2C,KAAAA,QAKvB/pD,MAAK,GAAaomD,EAAYiJ,EAAQlF,GAEtCnqD,KAAKi0D,mBAAmB7N,EAAY7yC,EAAO42C,QAEH,IAA7B/D,EAAWyN,cAEpB7zD,MAAK,GAAcqjE,eAAejd,EAAY7yC,GAG9CvT,KAAKk0D,gBAAgB3gD,GAMzB,CAQA88C,4BAAAA,CAA6BjK,EAAYiJ,GAEvC,MAAM97C,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAGF,MAAMyjB,EAAQxtE,MAAK,GAAUuT,GAEvB0vC,EAAQ+G,GAAez2C,EAAO,GAC9Bq8D,EAAM5lB,GAAez2C,EAAO,GAC5BnB,EAAM43C,GAAez2C,EAAO,GAI5Bk6D,EAAa,IAAI1/D,EACrBk1C,EAAMx6C,IAAM+kE,EAAM/kE,IAClBw6C,EAAMv6C,IAAM8kE,EAAM9kE,KAEdmnE,EAAW,IAAI9hE,EACnB6hE,EAAInnE,IAAM+kE,EAAM/kE,IAChBmnE,EAAIlnE,IAAM8kE,EAAM9kE,KAEZglE,EAAW,IAAI3/D,EACnBqE,EAAI3J,IAAM+kE,EAAM/kE,IAChB2J,EAAI1J,IAAM8kE,EAAM9kE,KAElB09C,EAAWwJ,UAAY,IAAI/C,GAAW,CAAC4gB,EAAYoC,EAAUnC,IAE7DtnB,EAAWI,sBACb,CAQAwN,6BAAAA,CAA8B5N,EAAYmO,GAExC,MAAM6N,EAAahc,EAAWwJ,UACxBkgB,EAAe,GACrB,IAAK,IAAIvtE,EAAI,EAAGA,EAAI,IAAKA,EACvButE,EAAa7sE,KAAK,IAAI8K,EACpBq0D,EAAWjW,SAAS5pD,GAAG4H,OAASoqD,EAAY9rD,EAC5C25D,EAAWjW,SAAS5pD,GAAG6H,OAASmqD,EAAY7rD,IAGhD09C,EAAWwJ,UAAY,IAAI/C,GAAWijB,GAEtC1pB,EAAWI,sBACb,CASAyN,kBAAAA,CAAmB7N,EAAY7yC,EAAOu6D,GACpC9tE,MAAK,GAAcokE,cAAche,EAAY7yC,EAC/C,CAOA2gD,eAAAA,CAAgB3gD,GACd,MAAMs2C,EAAS7pD,MAAK,GAAUuT,GACxBwwD,EAAgB/jE,MAAK,GAAwB6pD,GACnD7pD,MAAK,GAAck0D,gBAAgB3gD,EAAOwwD,EAC5C,CAQA,IAAoB7X,GAClB,OAAO,IAAIW,GAAWX,EACxB,CAOA,MACE,OAAO6V,GAASC,UAAUI,UAC5B,CASA,IAAahc,EAAY+D,GACvB,MAAMiY,EAAahc,EAAWwJ,UACxB1D,EAAS,GACf,IAAK,IAAI3pD,EAAI,EAAGA,EAAI6/D,EAAWp+D,cAAezB,EAC5C2pD,EAAOjpD,KAAKm/D,EAAWjW,SAAS5pD,GAAG4H,QACnC+hD,EAAOjpD,KAAKm/D,EAAWjW,SAAS5pD,GAAG6H,QAIrC,MAAMy/C,EAAS,IAAIE,KAAAA,MAAW,CAC5BmC,OAAQA,EACR7B,OAAQjE,EAAWrU,OACnBuY,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpB/gD,KAAM,UAkBR,OAfI44D,EAAWp+D,cAAgBhE,KAAKipE,cAElCpf,EAAOokB,SAAQ,SAAUvH,GACvBA,EAAQwH,YACRxH,EAAQyH,OACN/L,EAAWjW,SAAS,GAAGhiD,OAAQi4D,EAAWjW,SAAS,GAAG/hD,QACxDs8D,EAAQ0H,OACNhM,EAAWjW,SAAS,GAAGhiD,OAAQi4D,EAAWjW,SAAS,GAAG/hD,QACxDs8D,EAAQ0H,OACNhM,EAAWjW,SAAS,GAAGhiD,OAAQi4D,EAAWjW,SAAS,GAAG/hD,QACxDs8D,EAAQ2H,YACR3H,EAAQ4H,gBAAgBzkB,EAC1B,IAGKA,CACT,CAQA,IAAUt2C,GACR,OAAOq2C,GAAar2C,EACtB,CASA,IAAmB6yC,EAAY+D,GAC7B,MAAMiY,EAAahc,EAAWwJ,UACxB1L,EAAQ,IAAIlB,GAChBof,EAAWjW,SAAS,GAAIiW,EAAWjW,SAAS,IACxChI,EAAQ,IAAInB,GAChBof,EAAWjW,SAAS,GAAIiW,EAAWjW,SAAS,IAE9C,IAAIlpB,EAAQghB,GAASC,EAAOC,GACxB4rB,EAAc7rB,EAAMN,iBACpB3gB,EAAQ,MACVA,EAAQ,IAAMA,EACd8sC,GAAe9sC,GAGjB,MAAMG,EAA0D,GAAjDz/B,KAAKgjB,IAAIu9B,EAAMlgD,YAAamgD,EAAMngD,aAAoB,IAcrE,MAAO,CAbM,IAAI+lD,KAAAA,KAAU,CACzBimB,YAAa5sC,EACb6sC,YAAa7sC,EACbinB,OAAQjE,EAAWrU,OACnBuY,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpBtnB,MAAOA,EACPitC,UAAWH,EACXtnE,EAAG25D,EAAWjW,SAAS,GAAGhiD,OAC1BzB,EAAG05D,EAAWjW,SAAS,GAAG/hD,OAC1BZ,KAAM,cAIV,CAQA,IAAyB48C,GACvB,MAAMgc,EAAahc,EAAWwJ,UACxB1L,EAAQ,IAAIlB,GAChBof,EAAWjW,SAAS,GAAIiW,EAAWjW,SAAS,IACxChI,EAAQ,IAAInB,GAChBof,EAAWjW,SAAS,GAAIiW,EAAWjW,SAAS,IAExCgkB,GACHjsB,EAAMP,cAAcx5C,OAASg6C,EAAMR,cAAcx5C,QAAU,EACxDimE,GACHlsB,EAAMP,cAAcv5C,OAAS+5C,EAAMR,cAAcv5C,QAAU,EAE9D,OAAO,IAAI2D,EACToiE,EACAC,EAEJ,CAUA,IAAahqB,EAAYiJ,EAAQye,GAC/B,MAAM1L,EAAahc,EAAWwJ,UACxB1L,EAAQ,IAAIlB,GAChBof,EAAWjW,SAAS,GAAIiW,EAAWjW,SAAS,IACxChI,EAAQ,IAAInB,GAChBof,EAAWjW,SAAS,GAAIiW,EAAWjW,SAAS,IAGxC54C,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAGF,MAAMyjB,EAAQxtE,MAAK,GAAUuT,GAG7Bi6D,EAAMnqD,SAAS,CAAC5a,EAAG,EAAGC,EAAG,IAEzB8kE,EAAMthB,OAAO,CACXkW,EAAWjW,SAAS,GAAGhiD,OACvBi4D,EAAWjW,SAAS,GAAG/hD,OACvBg4D,EAAWjW,SAAS,GAAGhiD,OACvBi4D,EAAWjW,SAAS,GAAG/hD,OACvBg4D,EAAWjW,SAAS,GAAGhiD,OACvBi4D,EAAWjW,SAAS,GAAG/hD,SAIzB,MAAMimE,EAAO98D,EAAMu2C,aAAY,SAAUL,GACvC,MAAuB,cAAhBA,EAAKjgD,MACd,IAAG,GACH,KAAM6mE,aAAgBtmB,KAAAA,KACpB,OAIF,MAAM9G,EAAQ+G,GAAez2C,EAAO,GAC9Bq8D,EAAM5lB,GAAez2C,EAAO,GAC5BnB,EAAM43C,GAAez2C,EAAO,GAGlC,OAAQ87C,EAAOtoD,MACf,IAAK,UACHk8C,EAAMx6C,EAAE4mD,EAAO5mD,KACfw6C,EAAMv6C,EAAE2mD,EAAO3mD,KACf,MACF,IAAK,UACHknE,EAAInnE,EAAE4mD,EAAO5mD,KACbmnE,EAAIlnE,EAAE2mD,EAAO3mD,KACb,MACF,IAAK,UACH0J,EAAI3J,EAAE4mD,EAAO5mD,KACb2J,EAAI1J,EAAE2mD,EAAO3mD,KAKf,IAAIu6B,EAAQghB,GAASC,EAAOC,GACxB4rB,EAAc7rB,EAAMN,iBACpB3gB,EAAQ,MACVA,EAAQ,IAAMA,EACd8sC,GAAe9sC,GAIjB,MAAMG,EAA0D,GAAjDz/B,KAAKgjB,IAAIu9B,EAAMlgD,YAAamgD,EAAMngD,aAAoB,IACrEqsE,EAAKL,YAAY5sC,GACjBitC,EAAKJ,YAAY7sC,GACjBitC,EAAKptC,MAAMA,GACXotC,EAAKH,UAAUH,GACf,MAAMO,EAAS,CAAC7nE,EAAGmnE,EAAInnE,IAAKC,EAAGknE,EAAIlnE,KACnC2nE,EAAKhtD,SAASitD,GAGd9C,EAAMS,SAAQ,SAAUvH,GACtBA,EAAQwH,YACRxH,EAAQyH,OACN/L,EAAWjW,SAAS,GAAGhiD,OAAQi4D,EAAWjW,SAAS,GAAG/hD,QACxDs8D,EAAQ0H,OACNhM,EAAWjW,SAAS,GAAGhiD,OAAQi4D,EAAWjW,SAAS,GAAG/hD,QACxDs8D,EAAQ0H,OACNhM,EAAWjW,SAAS,GAAGhiD,OAAQi4D,EAAWjW,SAAS,GAAG/hD,QACxDs8D,EAAQ2H,YACR3H,EAAQ4H,gBAAgBd,EAC1B,GACF,CASA,IAAgBkB,EAAaC,GAE7B,CAQA,IAAmBD,EAAaC,GAC9B,GX9ZA4B,iBY1HG,MAOL,IAAQ,YAOR,IAAgB,IAAI/N,GAAaxiE,MAAK,IAQtC,eAAOktE,CAAStd,GACd,OAAOA,aAAqB9E,EAC9B,CAOAqP,OAAAA,GACE,OAAOn6D,MAAK,EACd,CAOA0W,YAAAA,GACE,OAAO1W,MAAK,GAAQ,QACtB,CAOAipE,UAAAA,GACE,OAAO,CACT,CAOAE,UAAAA,GACE,OAAO,CACT,CAQAS,sBAAAA,CAAuBxjB,EAAY8F,GACjC9F,EAAWwJ,UAAY5vD,MAAK,GAAoBksD,GAChD9F,EAAW+mB,YAAYntE,MAAK,MAC5BomD,EAAWI,sBACb,CASA2R,gBAAAA,CAAiB/R,EAAY+D,GAE3B,MAAM52C,EAAQ,IAAIw2C,KAAAA,OAClBx2C,EAAM/J,KAAKxJ,KAAK0W,gBAChBnD,EAAMq3C,SAAQ,GACdr3C,EAAMxM,GAAGq/C,EAAWr/C,IAEpB,MAAMorD,EAAQnyD,MAAK,GAAaomD,EAAY+D,GAC5C52C,EAAMrQ,IAAIivD,GAEV,MAAMnxC,EAAQhhB,MAAK,GAAckzB,OAAOkzB,EAAY+D,GACpD52C,EAAMrQ,IAAI8d,GAEV,MAAM+iD,EAAgB/jE,MAAK,GAAwBmyD,GAMnD,OALA5+C,EAAMrQ,IAAIlD,MAAK,GAAc8jE,aAAaC,EAAe/iD,EAAOmpC,IAKzD52C,CACT,CAQA,IAAwB4+C,GACtB,MAAM4O,EAAK5O,EAAM1pD,IACXu4D,EAAK7O,EAAMzpD,IACXtD,EAAQ+sD,EAAM/sD,QACd+9B,EAASgvB,EAAMhvB,SACrB,MAAO,CACL,IAAIp1B,EAAQgzD,EAAK37D,EAAQ,EAAG47D,GAC5B,IAAIjzD,EAAQgzD,EAAIC,EAAK79B,EAAS,GAC9B,IAAIp1B,EAAQgzD,EAAK37D,EAAQ,EAAG47D,EAAK79B,GACjC,IAAIp1B,EAAQgzD,EAAK37D,EAAO47D,EAAK79B,EAAS,GAE1C,CAQA,IAAqBgvB,GACnB,MAAM4O,EAAK5O,EAAM1pD,IACXu4D,EAAK7O,EAAMzpD,IACXtD,EAAQ+sD,EAAM/sD,QACd+9B,EAASgvB,EAAMhvB,SACrB,MAAO,CACL,IAAIp1B,EAAQgzD,EAAIC,GAChB,IAAIjzD,EAAQgzD,EAAK37D,EAAO47D,GACxB,IAAIjzD,EAAQgzD,EAAK37D,EAAO47D,EAAK79B,GAC7B,IAAIp1B,EAAQgzD,EAAIC,EAAK79B,GAEzB,CASAqsB,UAAAA,CAAW2C,EAAOhI,GAChB,MAAMmjB,EAAYttE,MAAK,GAAqBmyD,GACtC5C,EAAU,GAChB,IAAK,IAAIhtD,EAAI,EAAGA,EAAI+qE,EAAUnrE,SAAUI,EACtCgtD,EAAQtsD,KAAKinD,GACXojB,EAAU/qE,GAAG4H,OACbmjE,EAAU/qE,GAAG6H,OACb,SAAW7H,EACX4nD,IAGJ,OAAOoF,CACT,CAOAa,mBAAAA,CAAoBmd,GAClB,CAWFjd,4BAAAA,CAA6BlK,EAAYiJ,EAAQlF,GAE/C,MAAM52C,EAAQ87C,EAAOF,YACf57C,aAAiBw2C,KAAAA,QAKvB/pD,MAAK,GAAaomD,EAAYiJ,EAAQlF,GAEtCnqD,KAAKi0D,mBAAmB7N,EAAY7yC,EAAO42C,QAEH,IAA7B/D,EAAWyN,cAEpB7zD,MAAK,GAAcqjE,eAAejd,EAAY7yC,GAG9CvT,KAAKk0D,gBAAgB3gD,GAMzB,CAQA88C,4BAAAA,CAA6BjK,EAAYiJ,GAEvC,MAAM97C,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAGF,MAAMymB,EAAUxmB,GAAez2C,EAAO,GAChCk9D,EAAczmB,GAAez2C,EAAO,GAEpCm9D,EAAe,IAAI3iE,EACvByiE,EAAQ/nE,IACR+nE,EAAQ9nE,KAEJioE,EAAmB,IAAI5iE,EAC3B0iE,EAAYhoE,IACZgoE,EAAY/nE,KAGd09C,EAAWwJ,UAAY,IAAI9E,GAAU4lB,EAAcC,GAEnDvqB,EAAWI,sBACb,CAQAwN,6BAAAA,CAA8B5N,EAAYmO,GAExC,MAAM8N,EAAYjc,EAAWwJ,UACvB3M,EAAQof,EAAUnf,WAClB0qB,EAAW,IAAI7/D,EACnBk1C,EAAM94C,OAASoqD,EAAY9rD,EAC3Bw6C,EAAM74C,OAASmqD,EAAY7rD,GAEvB0J,EAAMiwD,EAAUlf,SAChB0qB,EAAS,IAAI9/D,EACjBqE,EAAIjI,OAASoqD,EAAY9rD,EACzB2J,EAAIhI,OAASmqD,EAAY7rD,GAE3B09C,EAAWwJ,UAAY,IAAI9E,GAAU8iB,EAAUC,GAE/CznB,EAAWI,sBACb,CASAyN,kBAAAA,CAAmB7N,EAAY7yC,EAAOu6D,GACpC9tE,MAAK,GAAcokE,cAAche,EAAY7yC,EAC/C,CAOA2gD,eAAAA,CAAgB3gD,GACd,MAAMs2C,EAAS7pD,MAAK,GAAUuT,GACxBwwD,EAAgB/jE,MAAK,GAAwB6pD,GACnD7pD,MAAK,GAAck0D,gBAAgB3gD,EAAOwwD,EAC5C,CAQA,IAAoB7X,GAClB,OAAO,IAAIpB,GAAUoB,EAAO,GAAIA,EAAO,GACzC,CAOA,MACE,OAAO6V,GAASC,UAAUK,SAC5B,CASA,IAAajc,EAAY+D,GACvB,MAAMkY,EAAYjc,EAAWwJ,UAE7B,OAAO,IAAI7F,KAAAA,MAAW,CACpBthD,EAAG45D,EAAUnf,WAAW/4C,OACxBzB,EAAG25D,EAAUnf,WAAW94C,OACxBhF,MAAOi9D,EAAUjX,WACjBjoB,OAAQk/B,EAAUhX,YAClBhB,OAAQjE,EAAWrU,OACnBuY,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpB/gD,KAAM,SAEV,CAQA,IAAU+J,GACR,MAAMs2C,EAASt2C,EAAMu2C,YAAYJ,IAAiB,GAClD,GAAMG,aAAkBE,KAAAA,KAGxB,OAAOF,CACT,CAQA,IAAyBzD,GACvB,MAAMic,EAAYjc,EAAWwJ,UAC7B,OAAO,IAAI7hD,EACTs0D,EAAUnf,WAAW/4C,OACrBk4D,EAAUlf,SAAS/4C,OAEvB,CASA,IAAag8C,EAAYiJ,EAAQye,GAC/B,MAAMzL,EAAYjc,EAAWwJ,UACvB3M,EAAQof,EAAUnf,WAGlB3vC,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAGF,MAAM6mB,EAAQ5wE,MAAK,GAAUuT,GAE7Bq9D,EAAMvtD,SAAS,CACb5a,EAAGw6C,EAAM94C,OACTzB,EAAGu6C,EAAM74C,SAEXwmE,EAAMvqE,KAAK,CACTjB,MAAOi9D,EAAUjX,WACjBjoB,OAAQk/B,EAAUhX,cAIpB,MAAMmlB,EAAUxmB,GAAez2C,EAAO,GAChCs9D,EAAW7mB,GAAez2C,EAAO,GACjCk9D,EAAczmB,GAAez2C,EAAO,GACpCu9D,EAAa9mB,GAAez2C,EAAO,GAGzC,OAAQ87C,EAAOtoD,MACf,IAAK,UAEHypE,EAAQ/nE,EAAE4mD,EAAO5mD,KACjB+nE,EAAQ9nE,EAAE2mD,EAAO3mD,KAEjBmoE,EAASnoE,EAAE2mD,EAAO3mD,KAClBooE,EAAWroE,EAAE4mD,EAAO5mD,KACpB,MACF,IAAK,UAEHooE,EAASpoE,EAAE4mD,EAAO5mD,KAClBooE,EAASnoE,EAAE2mD,EAAO3mD,KAElB8nE,EAAQ9nE,EAAE2mD,EAAO3mD,KACjB+nE,EAAYhoE,EAAE4mD,EAAO5mD,KACrB,MACF,IAAK,UAEHgoE,EAAYhoE,EAAE4mD,EAAO5mD,KACrBgoE,EAAY/nE,EAAE2mD,EAAO3mD,KAErBooE,EAAWpoE,EAAE2mD,EAAO3mD,KACpBmoE,EAASpoE,EAAE4mD,EAAO5mD,KAClB,MACF,IAAK,UAEHqoE,EAAWroE,EAAE4mD,EAAO5mD,KACpBqoE,EAAWpoE,EAAE2mD,EAAO3mD,KAEpB+nE,EAAY/nE,EAAE2mD,EAAO3mD,KACrB8nE,EAAQ/nE,EAAE4mD,EAAO5mD,KACjB,MACF,QACEtE,EAAOc,MAAM,wBAA0BoqD,EAAOtoD,MAGlD,CASA,IAAgBq/C,EAAYuoB,GAC1B,MACMt9D,EADY+0C,EAAWwJ,UACLtE,WAClBylB,EAAS1/D,EAAMhE,IAAIlD,OAASkH,EAAMsV,IAAIxc,OACtC6mE,EAAU3/D,EAAMhE,IAAIjD,OAASiH,EAAMsV,IAAIvc,OAC7C,OAAO,IAAI2/C,KAAAA,MAAW,CACpBthD,EAAG4I,EAAMsV,IAAIxc,OACbzB,EAAG2I,EAAMsV,IAAIvc,OACbhF,MAAO2rE,EACP5tC,OAAQ6tC,EACR1jC,KAAM,OACNgd,YAAa,EACbC,oBAAoB,EACpBqI,QAAS,GACTppD,KAAM,UAEV,CAQA,IAAmB48C,EAAY7yC,GAC7B,MAAMi8D,EAAUj8D,EAAMu2C,aAAY,SAAUL,GAC1C,MAAuB,WAAhBA,EAAKjgD,MACd,IAAG,QACoB,IAAZgmE,IAETA,EAAQnG,UAER91D,EAAMrQ,IAAIlD,MAAK,GAAgBomD,EAAY7yC,IAE/C,GZrVE09D,Wa5HG,MAOL,IAAQ,MAOR,IAAgB,IAAIzO,GAAaxiE,MAAK,IAQtC,eAAOktE,CAAStd,GACd,OAAOA,aAAqB3D,EAC9B,CAOAkO,OAAAA,GACE,OAAOn6D,MAAK,EACd,CAOA0W,YAAAA,GACE,OAAO1W,MAAK,GAAQ,QACtB,CAOAipE,UAAAA,GAGA,CAOAE,UAAAA,GACE,OAAO,GACT,CAQAS,sBAAAA,CAAuBxjB,EAAY8F,GACjC9F,EAAWwJ,UAAY5vD,MAAK,GAAoBksD,GAChD9F,EAAW+mB,YAAYntE,MAAK,MAC5BomD,EAAWI,sBACb,CASA2R,gBAAAA,CAAiB/R,EAAY+D,GAE3B,MAAM52C,EAAQ,IAAIw2C,KAAAA,OAClBx2C,EAAM/J,KAAKxJ,KAAK0W,gBAChBnD,EAAMq3C,SAAQ,GACdr3C,EAAMxM,GAAGq/C,EAAWr/C,IAEpB,MAAMorD,EAAQnyD,MAAK,GAAaomD,EAAY+D,GAC5C52C,EAAMrQ,IAAIlD,MAAK,GAAaomD,EAAY+D,IAExC,MAAMnpC,EAAQhhB,MAAK,GAAckzB,OAAOkzB,EAAY+D,GACpD52C,EAAMrQ,IAAIlD,MAAK,GAAckzB,OAAOkzB,EAAY+D,IAEhD,MAAM4Z,EAAgB/jE,MAAK,GAAwBmyD,GAOnD,OANA5+C,EAAMrQ,IAAIlD,MAAK,GAAc8jE,aAAaC,EAAe/iD,EAAOmpC,IAMzD52C,CACT,CAQA,IAAqB4+C,GACnB,MAAMjG,EAASiG,EAAMjG,SACf6U,EAAK5O,EAAM1pD,IACXu4D,EAAK7O,EAAMzpD,IACX4kE,EAAY,GAClB,IAAK,IAAI/qE,EAAI,EAAGA,EAAI2pD,EAAO/pD,OAAQI,GAAQ,EACzC+qE,EAAUrqE,KAAK,IAAI8K,EACjBm+C,EAAO3pD,GAAKw+D,EACZ7U,EAAO3pD,EAAI,GAAKy+D,IAGpB,OAAOsM,CACT,CAQA,IAAwBnb,GACtB,MAAMjG,EAASiG,EAAMjG,SACf6U,EAAK5O,EAAM1pD,IACXu4D,EAAK7O,EAAMzpD,IACX4kE,EAAY,GAClB,IAAK,IAAI/qE,EAAI,EAAGA,EAAI2pD,EAAO/pD,OAAQI,GAAK,EAAG,CACzC,MAAMmgB,GAAangB,EAAI,GAAK2pD,EAAO/pD,OAC7BguE,GAAQjkB,EAAO3pD,GAAK2pD,EAAOxpC,IAAc,EAAIq+C,EAC7CqP,GAAQlkB,EAAO3pD,EAAI,GAAK2pD,EAAOxpC,EAAY,IAAM,EAAIs+C,EAC3DsM,EAAUrqE,KAAK,IAAI8K,EAAQoiE,EAAMC,GACnC,CACA,OAAO9C,CACT,CASA9d,UAAAA,CAAW2C,EAAOhI,GAChB,MAAMmjB,EAAYttE,MAAK,GAAqBmyD,GACtC5C,EAAU,GAChB,IAAK,IAAIhtD,EAAI,EAAGA,EAAI+qE,EAAUnrE,SAAUI,EACtCgtD,EAAQtsD,KAAKinD,GACXojB,EAAU/qE,GAAG4H,OACbmjE,EAAU/qE,GAAG6H,OACb,SAAW7H,EACX4nD,IAGJ,OAAOoF,CACT,CAOAa,mBAAAA,CAAoBmd,GAClB,CAWFjd,4BAAAA,CAA6BlK,EAAYiJ,EAAQlF,GAE/C,MAAM52C,EAAQ87C,EAAOF,YACf57C,aAAiBw2C,KAAAA,QAKvB/pD,MAAK,GAAaomD,EAAYiJ,EAAQlF,GAEtCnqD,KAAKi0D,mBAAmB7N,EAAY7yC,EAAO42C,QAEH,IAA7B/D,EAAWyN,cAEpB7zD,MAAK,GAAcqjE,eAAejd,EAAY7yC,GAG9CvT,KAAKk0D,gBAAgB3gD,GAMzB,CAQA88C,4BAAAA,CAA6BjK,EAAYiJ,GAEvC,MAAM97C,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAGF,MAAMmnB,EAAOlxE,MAAK,GAAUuT,GAKtB24C,EADM9F,EAAWwJ,UACJxD,YAAY1pD,QACzByuE,EAAW,IAAIpjE,EACnBshD,EAAO5mD,IAAMyoE,EAAKzoE,IAClB4mD,EAAO3mD,IAAMwoE,EAAKxoE,KAGpBwjD,EADcrB,GAAewE,EAAOtoD,OACpBoqE,EAGhB/qB,EAAWwJ,UAAY,IAAI3D,GAAIC,GAE/B9F,EAAWI,sBACb,CAQAwN,6BAAAA,CAA8B5N,EAAYmO,GAExC,MAAM+N,EAAMlc,EAAWwJ,UACjB+R,EAAY,GAClB,IAAK,IAAIp/D,EAAI,EAAGA,EAAI+/D,EAAIt+D,cAAezB,EACrCo/D,EAAU1+D,KAAK,IAAI8K,EACjBu0D,EAAInW,SAAS5pD,GAAG4H,OAASoqD,EAAY9rD,EACrC65D,EAAInW,SAAS5pD,GAAG6H,OAASmqD,EAAY7rD,IAGzC09C,EAAWwJ,UAAY,IAAI3D,GAAI0V,GAE/Bvb,EAAWI,sBACb,CASAyN,kBAAAA,CAAmB7N,EAAY7yC,EAAOu6D,GACpC9tE,MAAK,GAAcokE,cAAche,EAAY7yC,EAC/C,CAOA2gD,eAAAA,CAAgB3gD,GACd,MAAMs2C,EAAS7pD,MAAK,GAAUuT,GACxBwwD,EAAgB/jE,MAAK,GAAwB6pD,GACnD7pD,MAAK,GAAck0D,gBAAgB3gD,EAAOwwD,EAC5C,CAQA,IAAoB7X,GAClB,OAAO,IAAID,GAAIC,EACjB,CAOA,MACE,OAAO6V,GAASC,UAAUM,GAC5B,CASA,IAAalc,EAAY+D,GACvB,MAAMmY,EAAMlc,EAAWwJ,UAEjB/+C,EAAM,GACZ,IAAK,IAAItO,EAAI,EAAGA,EAAI+/D,EAAIt+D,cAAezB,EACrCsO,EAAI5N,KAAKq/D,EAAInW,SAAS5pD,GAAG4H,QACzB0G,EAAI5N,KAAKq/D,EAAInW,SAAS5pD,GAAG6H,QAE3B,OAAO,IAAI2/C,KAAAA,MAAW,CACpBmC,OAAQr7C,EACRw5C,OAAQjE,EAAWrU,OACnBuY,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpB/gD,KAAM,QACNglE,QAAQ,GAEZ,CAQA,IAAUj7D,GACR,OAAOq2C,GAAar2C,EACtB,CAQA,IAAyB6yC,GACvB,MAAMkc,EAAMlc,EAAWwJ,UACvB,OAAO,IAAI7hD,EACTu0D,EAAInW,SAAS,GAAGhiD,OAChBm4D,EAAInW,SAAS,GAAG/hD,OAEpB,CASA,IAAag8C,EAAYiJ,EAAQye,GAG/B,MAAMv6D,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAGF,MAAMmnB,EAAOlxE,MAAK,GAAUuT,GAGtB24C,EAASglB,EAAKhlB,SACd5+C,EAAsC,EAA9Bu9C,GAAewE,EAAOtoD,MACpCmlD,EAAO5+C,GAAS+hD,EAAO5mD,IAAMyoE,EAAKzoE,IAClCyjD,EAAO5+C,EAAQ,GAAK+hD,EAAO3mD,IAAMwoE,EAAKxoE,IACtCwoE,EAAKhlB,OAAOA,GAGZ,MAAMviC,EAAQpW,EAAMu2C,aAAY,SAAUL,GACxC,OAAOA,EAAK1iD,OAASsoD,EAAOtoD,IAC9B,IAAG,GAEH4iB,EAAMlhB,EAAE4mD,EAAO5mD,KACfkhB,EAAMjhB,EAAE2mD,EAAO3mD,IACjB,CASA,IAAgBgmE,EAAaC,GAG7B,CAQA,IAAmBD,EAAaC,GAC9B,GbtRAyC,ac5HG,MAOL,IAAQ,QAOR,IAAgB,IAAI5O,GAAaxiE,MAAK,IAQtC,eAAOktE,CAAStd,GACd,OAAOA,aAAqB5M,EAC9B,CAOAmX,OAAAA,GACE,OAAOn6D,MAAK,EACd,CAOA0W,YAAAA,GACE,OAAO1W,MAAK,GAAQ,QACtB,CAOAipE,UAAAA,GACE,OAAO,CACT,CAOAE,UAAAA,GACE,OAAO,CACT,CAQAS,sBAAAA,CAAuBxjB,EAAY8F,GACjC9F,EAAWwJ,UAAY5vD,MAAK,GAAoBksD,GAChD9F,EAAW+mB,YAAYntE,MAAK,MAC5BomD,EAAWI,sBACb,CASA2R,gBAAAA,CAAiB/R,EAAY+D,GAE3B,MAAM52C,EAAQ,IAAIw2C,KAAAA,OAClBx2C,EAAM/J,KAAKxJ,KAAK0W,gBAChBnD,EAAMq3C,SAAQ,GACdr3C,EAAMxM,GAAGq/C,EAAWr/C,IAEpB,MAAMorD,EAAQnyD,MAAK,GAAaomD,EAAY+D,GAC5C52C,EAAMrQ,IAAIlD,MAAK,GAAaomD,EAAY+D,IAExC,MAAMijB,EAASptE,MAAK,GAAmBomD,EAAY+D,GACnD,IAAK,MAAMkjB,KAASD,EAClB75D,EAAMrQ,IAAImqE,GAGZ,MAAMrsD,EAAQhhB,MAAK,GAAckzB,OAAOkzB,EAAY+D,GACpD52C,EAAMrQ,IAAIlD,MAAK,GAAckzB,OAAOkzB,EAAY+D,IAEhD,MAAM4Z,EAAgB/jE,MAAK,GAAwBmyD,GAMnD,OALA5+C,EAAMrQ,IAAIlD,MAAK,GAAc8jE,aAAaC,EAAe/iD,EAAOmpC,IAKzD52C,CACT,CAQA,IAAwB4+C,GACtB,MAAMjG,EAASiG,EAAMjG,SACf6U,EAAK5O,EAAM1pD,IACXu4D,EAAK7O,EAAMzpD,IACX2kD,GAAWnB,EAAO,GAAKA,EAAO,IAAM,EAAI6U,EACxCzT,GAAWpB,EAAO,GAAKA,EAAO,IAAM,EAAI8U,EAC9C,MAAO,CAAC,IAAIjzD,EAAQs/C,EAASC,GAC/B,CAQA,IAAqB6E,GACnB,MAAMjG,EAASiG,EAAMjG,SACf6U,EAAK5O,EAAM1pD,IACXu4D,EAAK7O,EAAMzpD,IACjB,MAAO,CACL,IAAIqF,EAAQm+C,EAAO,GAAK6U,EAAI7U,EAAO,GAAK8U,GACxC,IAAIjzD,EAAQm+C,EAAO,GAAK6U,EAAI7U,EAAO,GAAK8U,GAE5C,CASAxR,UAAAA,CAAW2C,EAAOhI,GAChB,MAAMmjB,EAAYttE,MAAK,GAAqBmyD,GACtC5C,EAAU,GAChB,IAAK,IAAIhtD,EAAI,EAAGA,EAAI+qE,EAAUnrE,SAAUI,EACtCgtD,EAAQtsD,KAAKinD,GACXojB,EAAU/qE,GAAG4H,OACbmjE,EAAU/qE,GAAG6H,OACb,SAAW7H,EACX4nD,IAGJ,OAAOoF,CACT,CAOAa,mBAAAA,CAAoBmd,GAClB,CAWFjd,4BAAAA,CAA6BlK,EAAYiJ,EAAQlF,GAE/C,MAAM52C,EAAQ87C,EAAOF,YACf57C,aAAiBw2C,KAAAA,QAKvB/pD,MAAK,GAAaomD,EAAYiJ,EAAQlF,GAEtCnqD,KAAKi0D,mBAAmB7N,EAAY7yC,EAAO42C,QAEH,IAA7B/D,EAAWyN,cAEpB7zD,MAAK,GAAcqjE,eAAejd,EAAY7yC,GAG9CvT,KAAKk0D,gBAAgB3gD,GAMzB,CAQA88C,4BAAAA,CAA6BjK,EAAYiJ,GAEvC,MAAM97C,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAGF,MAAMyjB,EAAQxtE,MAAK,GAAUuT,GAEvB0vC,EAAQ+G,GAAez2C,EAAO,GAC9BnB,EAAM43C,GAAez2C,EAAO,GAI5Bk6D,EAAa,IAAI1/D,EACrBk1C,EAAMx6C,IAAM+kE,EAAM/kE,IAClBw6C,EAAMv6C,IAAM8kE,EAAM9kE,KAEdglE,EAAW,IAAI3/D,EACnBqE,EAAI3J,IAAM+kE,EAAM/kE,IAChB2J,EAAI1J,IAAM8kE,EAAM9kE,KAElB09C,EAAWwJ,UAAY,IAAI5M,GAAKyqB,EAAYC,GAE5CtnB,EAAWI,sBACb,CAQAwN,6BAAAA,CAA8B5N,EAAYmO,GAExC,MAAM5P,EAAOyB,EAAWwJ,UAClB3M,EAAQ0B,EAAKzB,WACb0qB,EAAW,IAAI7/D,EACnBk1C,EAAM94C,OAASoqD,EAAY9rD,EAC3Bw6C,EAAM74C,OAASmqD,EAAY7rD,GAEvB0J,EAAMuyC,EAAKxB,SACX0qB,EAAS,IAAI9/D,EACjBqE,EAAIjI,OAASoqD,EAAY9rD,EACzB2J,EAAIhI,OAASmqD,EAAY7rD,GAE3B09C,EAAWwJ,UAAY,IAAI5M,GAAK4qB,EAAUC,GAE1CznB,EAAWI,sBACb,CASAyN,kBAAAA,CAAmB7N,EAAY7yC,EAAOu6D,GACpC9tE,MAAK,GAAcokE,cAAche,EAAY7yC,EAC/C,CAOA2gD,eAAAA,CAAgB3gD,GACd,MAAMs2C,EAAS7pD,MAAK,GAAUuT,GACxBwwD,EAAgB/jE,MAAK,GAAwB6pD,GACnD7pD,MAAK,GAAck0D,gBAAgB3gD,EAAOwwD,EAC5C,CAQA,IAAoB7X,GAClB,OAAO,IAAIlJ,GAAKkJ,EAAO,GAAIA,EAAO,GACpC,CAOA,MACE,OAAO6V,GAASC,UAAUO,KAC5B,CASA,IAAanc,EAAY+D,GACvB,MAAMxF,EAAOyB,EAAWwJ,UAGlB/F,EAAS,IAAIE,KAAAA,MAAW,CAC5BmC,OAAQ,CACNvH,EAAKzB,WAAW/4C,OAChBw6C,EAAKzB,WAAW94C,OAChBu6C,EAAKxB,SAASh5C,OACdw6C,EAAKxB,SAAS/4C,QAEhBigD,OAAQjE,EAAWrU,OACnBuY,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpB/gD,KAAM,UAKFukE,EAAYrpB,GAChBC,EAAMA,EAAKzB,WAFG,GAEkBiH,EAAMxB,gBAClCqlB,EAAYtpB,GAChBC,EAAMA,EAAKxB,SAJG,GAIgBgH,EAAMxB,gBAWtC,OAVAkB,EAAOokB,SAAQ,SAAUvH,GACvBA,EAAQwH,YACRxH,EAAQyH,OAAOJ,EAAU7qB,WAAW/4C,OAAQ4jE,EAAU7qB,WAAW94C,QACjEs8D,EAAQ0H,OAAOL,EAAU5qB,SAASh5C,OAAQ4jE,EAAU5qB,SAAS/4C,QAC7Ds8D,EAAQ0H,OAAOJ,EAAU7qB,SAASh5C,OAAQ6jE,EAAU7qB,SAAS/4C,QAC7Ds8D,EAAQ0H,OAAOJ,EAAU9qB,WAAW/4C,OAAQ6jE,EAAU9qB,WAAW94C,QACjEs8D,EAAQ2H,YACR3H,EAAQ4H,gBAAgBzkB,EAC1B,IAEOA,CACT,CAQA,IAAUt2C,GACR,OAAOq2C,GAAar2C,EACtB,CASA,IAAmB6yC,EAAY+D,GAC7B,MAAMxF,EAAOyB,EAAWwJ,UAKlBme,EAAYrpB,GAChBC,EAAMA,EAAKzB,WAJG,GAIkBiH,EAAMxB,gBAClC0oB,EAAS,IAAItnB,KAAAA,MAAW,CAC5BmC,OAAQ,CACN6hB,EAAU7qB,WAAW/4C,OACrB4jE,EAAU7qB,WAAW94C,OACrB2jE,EAAU5qB,SAASh5C,OACnB4jE,EAAU5qB,SAAS/4C,QAErBigD,OAAQjE,EAAWrU,OACnBuY,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpB/gD,KAAM,gBAIFwkE,EAAYtpB,GAChBC,EAAMA,EAAKxB,SApBG,GAoBgBgH,EAAMxB,gBActC,MAAO,CAAC0oB,EAbO,IAAItnB,KAAAA,MAAW,CAC5BmC,OAAQ,CACN8hB,EAAU9qB,WAAW/4C,OACrB6jE,EAAU9qB,WAAW94C,OACrB4jE,EAAU7qB,SAASh5C,OACnB6jE,EAAU7qB,SAAS/4C,QAErBigD,OAAQjE,EAAWrU,OACnBuY,YAAaH,EAAMhC,iBACnBoC,oBAAoB,EACpB/gD,KAAM,gBAIV,CAQA,IAAyB48C,GACvB,MAAMzB,EAAOyB,EAAWwJ,UAClB3M,EAAQ0B,EAAKzB,WACb9wC,EAAMuyC,EAAKxB,SAEjB,IAAIr6C,EAAMm6C,EAIV,OAHIA,EAAM74C,OAASgI,EAAIhI,SACrBtB,EAAMsJ,GAEDtJ,CACT,CAUA,IAAas9C,EAAYiJ,EAAQlF,GAC/B,MAAMxF,EAAOyB,EAAWwJ,UAGlBr8C,EAAQ87C,EAAOF,YACrB,KAAM57C,aAAiBw2C,KAAAA,OACrB,OAGF,MAAMyjB,EAAQxtE,MAAK,GAAUuT,GAG7Bi6D,EAAMnqD,SAAS,CAAC5a,EAAG,EAAGC,EAAG,IAEzB8kE,EAAMthB,OAAO,CACXvH,EAAKzB,WAAW/4C,OAChBw6C,EAAKzB,WAAW94C,OAChBu6C,EAAKxB,SAASh5C,OACdw6C,EAAKxB,SAAS/4C,SAIhB,MAAMinE,EAAS99D,EAAMu2C,aAAY,SAAUL,GACzC,MAAuB,gBAAhBA,EAAKjgD,MACd,IAAG,GACH,KAAM6nE,aAAkBtnB,KAAAA,MACtB,OAGF,MAAMunB,EAAS/9D,EAAMu2C,aAAY,SAAUL,GACzC,MAAuB,gBAAhBA,EAAKjgD,MACd,IAAG,GACH,KAAM8nE,aAAkBvnB,KAAAA,MACtB,OAGF,MAAM9G,EAAQ+G,GAAez2C,EAAO,GAC9BnB,EAAM43C,GAAez2C,EAAO,GAGlC,OAAQ87C,EAAOtoD,MACf,IAAK,UACHk8C,EAAMx6C,EAAE4mD,EAAO5mD,KACfw6C,EAAMv6C,EAAE2mD,EAAO3mD,KACf,MACF,IAAK,UACH0J,EAAI3J,EAAE4mD,EAAO5mD,KACb2J,EAAI1J,EAAE2mD,EAAO3mD,KACb,MACF,QACEvE,EAAOc,MAAM,wBAA0BoqD,EAAOtoD,MAKhD,MACMgnE,EAAYrpB,GAChBC,EAAMA,EAAKzB,WAFG,GAEkBiH,EAAMxB,gBACxC0oB,EAAOhuD,SAAS,CAAC5a,EAAG,EAAGC,EAAG,IAC1B2oE,EAAOnlB,OAAO,CAAC6hB,EAAU7qB,WAAW/4C,OAClC4jE,EAAU7qB,WAAW94C,OACrB2jE,EAAU5qB,SAASh5C,OACnB4jE,EAAU5qB,SAAS/4C,SACrB,MAAM4jE,EAAYtpB,GAChBC,EAAMA,EAAKxB,SATG,GASgBgH,EAAMxB,gBACtC2oB,EAAOjuD,SAAS,CAAC5a,EAAG,EAAGC,EAAG,IAC1B4oE,EAAOplB,OAAO,CAAC8hB,EAAU9qB,WAAW/4C,OAClC6jE,EAAU9qB,WAAW94C,OACrB4jE,EAAU7qB,SAASh5C,OACnB6jE,EAAU7qB,SAAS/4C,SAGrBojE,EAAMS,SAAQ,SAAUvH,GACtBA,EAAQwH,YACRxH,EAAQyH,OAAOJ,EAAU7qB,WAAW/4C,OAAQ4jE,EAAU7qB,WAAW94C,QACjEs8D,EAAQ0H,OAAOL,EAAU5qB,SAASh5C,OAAQ4jE,EAAU5qB,SAAS/4C,QAC7Ds8D,EAAQ0H,OAAOJ,EAAU7qB,SAASh5C,OAAQ6jE,EAAU7qB,SAAS/4C,QAC7Ds8D,EAAQ0H,OAAOJ,EAAU9qB,WAAW/4C,OAAQ6jE,EAAU9qB,WAAW94C,QACjEs8D,EAAQ2H,YACR3H,EAAQ4H,gBAAgBd,EAC1B,GACF,CASA,IAAgBkB,EAAaC,GAE7B,CAQA,IAAmBD,EAAaC,GAC9B,IdjZF3J,OAAQ,CACNuM,UDkEG,MAML,IAKAvvE,WAAAA,CAAYmgD,GACVniD,MAAK,GAAOmiD,CACd,CAOA,IAAU,IAAIkiB,GAOd,KAAc,EAOd,IAAmB,IAAI5iD,GAOvBuvC,QAAAA,CAAS+Z,GAEHA,IACF/qE,MAAK,IAAc,EAEvB,CAKAi4C,IAAAA,GACE,CAQFkzB,GAAAA,CAAIC,GACF,QAA2B,IAAhBA,EAAK7T,OACd,MAAM,IAAIr1D,MAAM,wCAKlB,GAHAlC,MAAK,GAAQukE,OAAO6G,EAAKzkD,KACzB3mB,MAAK,GAAQykE,OAAO2G,EAAK/9D,KAErBrN,MAAK,GAAa,CACpB,MAAMojB,EAAQpjB,MAAK,GAAKwmE,QAAQ4E,EAAK7T,QAAQn0C,MAC7CpjB,MAAK,GAAQ0kE,iBAAiBthD,GAC9BpjB,MAAK,IAAc,CACrB,CACA,MAAMsnD,EAAU,IAAIyd,GAAiB/kE,MAAK,GAASorE,EAAK7T,OAAQv3D,MAAK,IACrEsnD,EAAQ4d,UAAYllE,MAAK,GACzBsnD,EAAQ6d,OAASnlE,MAAK,GACtBsnD,EAAQE,UAERxnD,MAAK,GAAKwwD,eAAelJ,EAC3B,CASAvS,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAcK,IACZhiB,MAAK,GAAiB+hB,UAAUC,EAAM,GC7KtCwvD,MDmRG,MAML,IAKAxvE,WAAAA,CAAYmgD,GACVniD,MAAK,GAAOmiD,CACd,CAOA,IAAmB,IAAI1gC,GAOvBuvC,QAAAA,CAAS4V,GACP,CAMF3uB,IAAAA,GACE,CAQFkzB,GAAAA,CAAIC,GACF,QAA2B,IAAhBA,EAAK7T,OACd,MAAM,IAAIr1D,MAAM,qCAElB,MAAM8iE,EAAS,IAAIF,GACb1hD,EAAQpjB,MAAK,GAAKwmE,QAAQ4E,EAAK7T,QAAQn0C,MAC7C4hD,EAAON,iBAAiBthD,GACxB,MAAMkkC,EAAU,IAAIyd,GAAiBC,EAAQoG,EAAK7T,OAAQv3D,MAAK,IAC/DsnD,EAAQ4d,UAAYllE,MAAK,GACzBsnD,EAAQ6d,OAASnlE,MAAK,GACtBsnD,EAAQE,UAERxnD,MAAK,GAAKwwD,eAAelJ,EAC3B,CASAvS,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAcK,IACZhiB,MAAK,GAAiB+hB,UAAUC,EAAM,GCxWtCyvD,QDoLG,MAML,IAKAzvE,WAAAA,CAAYmgD,GACVniD,MAAK,GAAOmiD,CACd,CAOA,IAAmB,IAAI1gC,GAOvBuvC,QAAAA,CAAS4V,GACP,CAMF3uB,IAAAA,GACE,CAQFkzB,GAAAA,CAAIC,GACF,QAA2B,IAAhBA,EAAK7T,OACd,MAAM,IAAIr1D,MAAM,uCAElB,MAAM8iE,EAAS,IAAIH,GACbzhD,EAAQpjB,MAAK,GAAKwmE,QAAQ4E,EAAK7T,QAAQn0C,MAC7C4hD,EAAON,iBAAiBthD,GACxB,MAAMkkC,EAAU,IAAIyd,GAAiBC,EAAQoG,EAAK7T,OAAQv3D,MAAK,IAC/DsnD,EAAQ4d,UAAYllE,MAAK,GACzBsnD,EAAQ6d,OAASnlE,MAAK,GACtBsnD,EAAQE,UAERxnD,MAAK,GAAKwwD,eAAelJ,EAC3B,CASAvS,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAcK,IACZhiB,MAAK,GAAiB+hB,UAAUC,EAAM,KgBnZnC,MAAM0nD,GAMX3iE,GAOA2qE,gBAOA9hB,UAOAC,gBAOA9d,OAOA4/B,eAQA3e,SAQAa,cAOAvW,YAOAwa,YAOA,IAQApqC,kBAAAA,GACE,IAAI5kB,EAOJ,YANgC,IAArB9I,KAAK83D,cAIdhvD,EAAM4kB,GAHU1tB,KAAK83D,YAAY,GAAGr1D,YAAYsc,OAC9C/e,KAAK83D,YAAY,GAAGr1D,eAIjBqG,CACT,CAOAmvC,IAAAA,CAAK2K,QACiC,IAAzB5iD,KAAK0xE,iBAKhB1xE,MAAK,GAAkB4iD,EAEvB5iD,KAAK0xE,gBAAkB9uB,EAAe/I,qBAEtC75C,KAAKs9C,YACHsF,EAAe7R,qBAAqB/wC,KAAK0xE,iBAGtC9uB,EAAe5G,4BAClBh8C,KAAK83D,YAAclV,EAAevF,eAChCuF,EAAehJ,wBAdjBz1C,EAAOW,MAAM,qCAiBjB,CAQAozD,gBAAAA,CAAiB0Z,GACf,IAAI9oE,GAAM,EAIV,QAAgC,IAArB9I,KAAK83D,YAEV8Z,EAAY51B,4BACdlzC,GAAM,OAEH,CAEL,MAAM6kB,EAAUikD,EAAYx0B,aACtBy0B,EAAU,IAAI7kE,EAAQ2gB,EAAQ,GAAIA,EAAQ,GAAIA,EAAQ,IACtDmkD,EAAU,IAAI9kE,EAAQ2gB,EAAQ,GAAIA,EAAQ,GAAIA,EAAQ,IAExDkkD,EAAQhvE,OAAO7C,KAAK83D,YAAY,KACpCga,EAAQjvE,OAAO7C,KAAK83D,YAAY,MAC9BhvD,GAAM,EAEV,CACA,OAAOA,CACT,CAOAy9C,iBAAAA,CAAkB3D,GAEXA,EAAe3R,iBAAiBjxC,KAAK0xE,kBAIrC1xE,KAAKk4D,iBAAiBtV,EAAelF,oBAG1C19C,MAAK,GAAkB4iD,EAGvB5iD,KAAKs9C,YACHsF,EAAe7R,qBAAqB/wC,KAAK0xE,iBAC7C,CAOA1jE,WAAAA,GACE,IAAIlF,EACJ,QAAoC,IAAzB9I,MAAK,SACwB,IAA/BA,KAAK4vD,UAAU5hD,YAA6B,CAEnD,IAAIka,EAASloB,KAAKs9C,iBACc,IAArBt9C,KAAK83D,cACd5vC,EAASloB,KAAK83D,YAAY,IAE5B,MAAMia,EACJ,IAAInjE,EAAM,CAACsZ,EAAO/d,OAAQ+d,EAAO9d,OAAQ8d,EAAO7d,SAC5C2vC,EACJh6C,MAAK,GAAgBqgD,qBAAqB0xB,GACtC3zB,EAAcp+C,MAAK,GAAgB+5C,iBACnCttC,EAAIutC,EAAYv3C,YAAY27C,GAG5BvB,EAAa78C,KAAK4vD,UAAU5hD,cAClClF,EAAM9I,MAAK,GAAgBk9C,0BAA0BL,EAAYpwC,EACnE,CACA,OAAO3D,CACT,CAQAqkE,WAAAA,CAAYnL,GACV,QAAoC,IAAzBhiE,MAAK,GAAiC,CAC/C,MAAMwvB,EAAWxvB,MAAK,GAAgB69C,mBAEH,IAAxBmkB,EAAUxyC,GACnBxvB,KAAKgzD,SAAWgP,EAAUxyC,GAE1BxvB,KAAKgzD,SAAWgP,EAAU,IAE9B,MACE79D,EAAOa,KAAK,iDAEhB,CAQAi0D,OAAAA,GACE,OvEnIG,SAAsBlpD,EAAU9N,GACrC,IAAI6G,EAAM,GAEV,GAAIiH,QACF,OAAOjH,EAIT,GAFAA,EAAMiH,EAEF9N,QACF,OAAO6G,EAIT,MAAMgK,EAAOhD,EAASC,GACtB,IAAK,IAAIxN,EAAI,EAAGA,EAAIuQ,EAAK3Q,SAAUI,EAAG,CACpC,MAAMyvE,EAAW/vE,EAAO6Q,EAAKvQ,IAC7B,GAAIyvE,SACiB,OAAnBA,EAASlwE,YAA4C,IAAnBkwE,EAASlwE,MAAuB,CAElE,IAAImwE,EAAWD,EAASlwE,MAAMowE,YAAY,GAIpB,OAAlBF,EAASt7C,WACc,IAAlBs7C,EAASt7C,MACS,IAAzBs7C,EAASt7C,KAAKv0B,SACQ,gBAAlB6vE,EAASt7C,OACXu7C,GAAY,KAEdA,GAAYhjE,EAAKC,EAAE8iE,EAASt7C,OAG9B,MAAMkF,EAAO,IAAM9oB,EAAKvQ,GAAK,IAE7BuG,EAAMA,EAAI2xB,QAAQmB,EAAMq2C,EAC1B,CACF,CAEA,OAAOnpE,CACT,CuE4FWqpE,CAAanyE,KAAKgzD,SAAUhzD,KAAK2xE,eAC1C,CAKAnrB,oBAAAA,QACsC,IAAzBxmD,MAAK,SACqB,IAA5BA,KAAK4vD,UAAU7L,WACtB/jD,KAAK2xE,eAAiB3xE,KAAK4vD,UAAU7L,SACnC/jD,MAAK,GACL8P,EAAS9P,KAAKgzD,WAEpB,CAOAtE,UAAAA,GACE,IAAI0jB,EAEJ,QAAgC,IAArB9M,GAAYvW,KACrB,IAAK,MAAMsjB,KAAe/M,GAAYvW,KAAM,CAC1C,MAAMrvD,EAAU4lE,GAAYvW,KAAKsjB,GACjC,GAAI3yE,EAAQwtE,SAASltE,KAAK4vD,WAAY,CACpCwiB,EAAM,IAAI1yE,EACV,KACF,CACF,CAGF,QAAmB,IAAR0yE,EACT,IAAK,MAAMC,KAAerF,GAAmBje,KAAM,CACjD,MAAMrvD,EAAUstE,GAAmBje,KAAKsjB,GACxC,GAAI3yE,EAAQwtE,SAASltE,KAAK4vD,WAAY,CACpCwiB,EAAM,IAAI1yE,EACV,KACF,CACF,CAKF,YAHmB,IAAR0yE,GACTjuE,EAAOa,KAAK,yCAEPotE,CACT,ECxRK,MAAMxY,GAAwB,CACnC,YACA,YACA,UACA,WACA,QACA,WACA,aACA,YACA,YAMW3G,GAAW,CAOtBC,aAAAA,CAAc9M,EAAYzkC,GACxB,MAAMqxC,EAAWsf,OAAO,QAASlsB,EAAW4M,UAC3B,OAAbA,IACF5M,EAAW4M,SAAWA,EACtBrxC,EAASykC,GAEb,GASF,SAASmsB,GAAoBC,GAE3B,IAAIC,EAAa,EACbC,EAAY,EAChB,GAAuB,IAAnBF,EAAQrwE,aACmB,IAAtBqwE,EAAQ,GAAG1iB,OAAwB,CAC1C,IAAI6iB,EAAeH,EAAQ,GAAG1iB,OAAO6iB,aACrC,KAAOA,GACArwE,MAAMqwE,EAAaF,cACtBA,GAAcE,EAAaF,YAExBnwE,MAAMqwE,EAAaD,aACtBA,GAAaC,EAAaD,WAE5BC,EAAeA,EAAaA,YAEhC,MACExuE,EAAOW,MAAM,kCAGf,MAAMwoE,EAAY,GAClB,IAAK,IAAI/qE,EAAI,EAAGA,EAAIiwE,EAAQrwE,SAAUI,EACpC+qE,EAAUrqE,KAAK,IAAI8K,EACjBykE,EAAQjwE,GAAGqwE,MAAQH,EACnBD,EAAQjwE,GAAGswE,MAAQH,IAGvB,OAAOpF,CACT,CAQO,SAASnH,GAAenkD,GAC7B,IAAIsrD,EAAY,GAUhB,YATmC,IAAxBtrD,EAAM8wD,eACgB,IAA/B9wD,EAAM8wD,cAAc3wE,OAEpBmrE,EAAYiF,GAAoBvwD,EAAM8wD,oBACG,IAAzB9wD,EAAM+wD,gBACU,IAAhC/wD,EAAM+wD,eAAe5wE,SAErBmrE,EAAYiF,GAAoBvwD,EAAM+wD,iBAEjCzF,CACT,CAQO,SAASlZ,GAAcpyC,GAK5B,OAAO,IAAIjU,EACTiU,EAAMstD,QACNttD,EAAMutD,QAEV,CAaO,SAASyD,GAAgB5tE,EAAO+9B,GAErC,MAAM8vC,EAAUvgB,SAASwgB,cAAc,UACvCD,EAAQ7tE,MAAQA,EAChB6tE,EAAQ9vC,OAASA,EAEjB,MAAMgwC,EAAUzgB,SAASwgB,cAAc,UACvCC,EAAQ/tE,MAAQ,EAChB+tE,EAAQhwC,OAAS,EAEjB,MAAMiwC,EAAUH,EAAQI,WAAW,MAC7BC,EAAUH,EAAQE,WAAW,MAUnC,OARID,IACFA,EAAQG,SAASnuE,EAAQ,EAAG+9B,EAAS,EAAG,EAAG,GAI3CmwC,EAAQE,UAAUP,EAAS7tE,EAAQ,EAAG+9B,EAAS,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,IAG5DmwC,GAAwD,IAA7CA,EAAQ/G,aAAa,EAAG,EAAG,EAAG,GAAGt5D,KAAK,EAC1D,CC/HO,MAAMwgE,GAOX,IAOA,IAAkB,KAOlB,IAAU,KAOV,IAAmB,KAOnB,IAAW,KAOX,KAAmB,EAOnB,IAAa,KAOb,IAOA,IAOA,IAAW,EAOX,IAAS,CAAChrE,EAAG,EAAGC,EAAG,GAOnB,IAAY,CAACD,EAAG,EAAGC,EAAG,GAOtB,IAAa,CAACD,EAAG,EAAGC,EAAG,EAAGC,EAAG,GAO7B,IAAU,CAACF,EAAG,EAAGC,EAAG,GAOpB,IAAc,CAACD,EAAG,EAAGC,EAAG,GAOxB,IAAc,CAACD,EAAG,EAAGC,EAAG,GAOxB,IAAc,CAACD,EAAG,EAAGC,EAAG,GAOxB,IAAc,CAACD,EAAG,EAAGC,EAAG,GAOxB,IAAmB,KAOnB,IAOA,IAAmB,IAAI+Y,GASvB,KAAkB,EAOlB,IAOA,IAMAzf,WAAAA,CAAY4yD,GACV50D,MAAK,GAAgB40D,EAErB50D,MAAK,GAAc60D,WAAa,YAClC,CAOAnE,SAAAA,GACE,OAAO1wD,MAAK,EACd,CAOA0zE,QAAAA,GACE,OAAO1zE,MAAK,EACd,CAOA2zE,qBAAAA,GACE,MAAO,CACLlrE,EAAGzI,MAAK,GAAYyI,EAAIzI,MAAK,GAAUyI,EACvCC,EAAG1I,MAAK,GAAY0I,EAAI1I,MAAK,GAAU0I,EAE3C,CAOAkrE,iBAAAA,CAAkBh4C,GAChB57B,MAAK,GAAkB47B,CACzB,CAQAi4C,OAAAA,CAAQl8B,EAAM4f,GACZv3D,MAAK,GAAUu3D,EAEf5f,EAAK5C,iBAAiB,WAAY/0C,MAAK,IACvC23C,EAAK5C,iBAAiB,kBAAmB/0C,MAAK,IAC9C23C,EAAK5C,iBAAiB,iBAAkB/0C,MAAK,IAC7C23C,EAAK5C,iBAAiB,kBAAmB/0C,MAAK,IAE9C,IAAK,IAAIoD,EAAI,EAAGA,EAAI80C,GAAe/1C,SAAUiB,EAC3Cu0C,EAAK5C,iBAAiBmD,GAAe90C,GAAIpD,MAAK,IAGhDA,MAAK,GAAkB,IAAIy9C,GAAe9F,GAE1C33C,KAAK8zE,WACP,CAOAhxB,iBAAAA,GACE,OAAO9iD,MAAK,EACd,CAOAusE,YAAAA,GACE,OAAOvsE,MAAK,EACd,CAQA+zE,WAAc/xD,IAERhiB,MAAK,KAAYgiB,EAAMyuC,SACzBzwD,MAAK,GAAgBu4C,SAASv2B,EAAMlgB,MAAM,IAC1C9B,MAAK,GAAaA,MAAK,GAAgB4/C,eAAen5B,SACtDzmB,MAAK,IAAmB,EAC1B,EAMF8zE,SAAAA,GACM9zE,MAAK,IACPA,MAAK,GAAgBuhD,kBAAkBvhD,KAE3C,CAKAg0E,WAAAA,GACMh0E,MAAK,IACPA,MAAK,GAAgB2hD,oBAAoB3hD,KAE7C,CAQAyhD,qBAAwBz/B,IAElBhiB,MAAK,KAAYgiB,EAAMyuC,SACzBzwD,MAAK,GAAmBA,MAAK,GAAgB85C,qBAE7C95C,MAAK,IAAmB,EACxBA,KAAK+uD,OACP,EASFrN,sBAAyB1/B,IAEvB,GAAIhiB,MAAK,KAAYgiB,EAAMyuC,OAAQ,CACjC,MAAMwjB,EAASj0E,MAAK,GAAgB4/C,eAAen5B,QACnD,GAAIzmB,MAAK,GAAUyI,IAAMwrE,EAAOxrE,GAC9BzI,MAAK,GAAU0I,IAAMurE,EAAOvrE,EAAG,CAG/B,QAAsC,IAA3B1I,MAAK,SACqB,IAA5BA,MAAK,GAAoC,CAChD,MAAMk0E,EAAUl0E,MAAK,GAAgB2oB,YAC/BiuC,EAAe52D,MAAK,GAAmB2O,MAAMulE,GAC7ChsD,EAASloB,MAAK,GAAgB2oB,UAClC3oB,MAAK,GAAgB45C,sBAEjB0C,EAAct8C,MAAK,GAAkB2O,MAAMuZ,GACjDloB,KAAK22D,cAAcC,EAActa,EACnC,CAEAt8C,MAAK,GAAai0E,GAElBj0E,MAAK,IAAmB,EACxBA,KAAK+uD,MACP,CACF,GAUFqG,KAAAA,GACE,OAAOp1D,MAAK,GAAc+G,EAC5B,CAKAsuD,aAAAA,GACEr1D,MAAK,GAAc4hB,QACrB,CAOAuuC,WAAAA,GACE,OAAOnwD,MAAK,EACd,CAOA8/C,iBAAAA,GACE,OAAO9/C,MAAK,GAAgB8/C,mBAC9B,CAOAwV,UAAAA,GACE,OAAOt1D,MAAK,EACd,CAOAu1D,UAAAA,CAAWC,GACT,GAAIA,IAAUx1D,MAAK,GACjB,OAGFA,MAAK,GAAW2D,KAAKgjB,IAAIhjB,KAAK0J,IAAImoD,EAAO,GAAI,GAS7C,MAAMxzC,EAAQ,CACZN,KAAM,gBACN5f,MAAO,CAAC9B,MAAK,KAEfA,MAAK,GAAWgiB,EAClB,CAKAyzC,cAAAA,GACEz1D,MAAK,GAAYyI,GAAKzI,MAAK,GAAQoF,MAAQpF,MAAK,GAAOyI,EACvDzI,MAAK,GAAQyI,GAAKzI,MAAK,GAAYyI,CACrC,CAKAitD,cAAAA,GACE11D,MAAK,GAAY0I,GAAK1I,MAAK,GAAQmjC,OAASnjC,MAAK,GAAO0I,EACxD1I,MAAK,GAAQ0I,GAAK1I,MAAK,GAAY0I,CACrC,CAKAitD,UAAAA,GACE31D,MAAK,GAAWyI,IAAM,CACxB,CAKAmtD,UAAAA,GACE51D,MAAK,GAAW0I,IAAM,CACxB,CAKAmtD,UAAAA,GACE71D,MAAK,GAAW2I,IAAM,CACxB,CAQAmtD,QAAAA,CAASC,EAAU5wD,GACjB,MAAMgwD,EAASn1D,MAAK,GAAgB09C,iBAC9BsY,EAAmBb,EAAO5X,6BAA6B,CAC3D90C,EAAGstD,EAASttD,EAAIzI,MAAK,GAAWyI,EAChCC,EAAGqtD,EAASrtD,EAAI1I,MAAK,GAAW0I,EAChCC,EAAGotD,EAASptD,EAAI3I,MAAK,GAAW2I,IAE5BstD,EAAgB,CACpBxtD,EAAGzI,MAAK,GAAUyI,EAAIutD,EAAiBvtD,EACvCC,EAAG1I,MAAK,GAAU0I,EAAIstD,EAAiBttD,GAGzC,GAA6B,IAAzB/E,KAAKsH,IAAI8qD,EAASttD,IACK,IAAzB9E,KAAKsH,IAAI8qD,EAASrtD,IACO,IAAzB/E,KAAKsH,IAAI8qD,EAASptD,GAAU,CAE5B,MAAMutD,EAAc,CAClBztD,EAAGzI,MAAK,GAAQyI,EAAIzI,MAAK,GAAYyI,EACrCC,EAAG1I,MAAK,GAAQ0I,EAAI1I,MAAK,GAAY0I,GAGvC1I,MAAK,GAAc,CAACyI,EAAG,EAAGC,EAAG,GAC7B1I,MAAK,GAAUk2D,CACjB,MACE,QAAsB,IAAX/wD,EAAwB,CACjC,IAAIgxD,EAAchB,EAAO3Y,2BAA2B,CAClD/zC,EAAGtD,EAAOgF,OACVzB,EAAGvD,EAAOiF,OACVzB,EAAGxD,EAAOkF,SAKZ8rD,EAAc,CACZ1tD,EAAG0tD,EAAY1tD,EAAIzI,MAAK,GAAYyI,EACpCC,EAAGytD,EAAYztD,EAAI1I,MAAK,GAAY0I,GAGtC,MAAM0tD,EAAYC,GAChBr2D,MAAK,GAASA,MAAK,GAAQi2D,EAAeE,GAEtCG,EAAgB,CACpB7tD,EAAGzI,MAAK,GAAYyI,EAAI2tD,EAAU3tD,EAAIzI,MAAK,GAAQyI,EACnDC,EAAG1I,MAAK,GAAY0I,EAAI0tD,EAAU1tD,EAAI1I,MAAK,GAAQ0I,GAGrD1I,MAAK,GAAcs2D,EACnBt2D,MAAK,GAAUo2D,CACjB,CAIFp2D,MAAK,GAASi2D,CAChB,CASAM,SAAAA,CAAUR,EAAUS,GAClB,MACMR,EADSh2D,MAAK,GAAgB09C,iBACJH,6BAA6B,CAC3D90C,EAAGstD,EAASttD,EAAIzI,MAAK,GAAWyI,EAChCC,EAAGqtD,EAASrtD,EAAI1I,MAAK,GAAW0I,EAChCC,EAAGotD,EAASptD,EAAI3I,MAAK,GAAW2I,IAE5BstD,EAAgB,CACpBxtD,EAAGzI,MAAK,GAAUyI,EAAIutD,EAAiBvtD,EACvCC,EAAG1I,MAAK,GAAU0I,EAAIstD,EAAiBttD,GAEzC1I,MAAK,GAASi2D,EAEdj2D,MAAK,GAAc,CACjByI,EAAG+tD,EAAmB/tD,EAAIzI,MAAK,GAAUyI,EACzCC,EAAG8tD,EAAmB9tD,EAAI1I,MAAK,GAAU0I,GAE3C1I,MAAK,GAAU,CACbyI,EAAGzI,MAAK,GAAQyI,EAAIzI,MAAK,GAAYyI,EACrCC,EAAG1I,MAAK,GAAQ0I,EAAI1I,MAAK,GAAY0I,EAEzC,CAWAiuD,aAAAA,CACEC,EAActa,EACd63B,EAAkBC,GAClB,MAAMjf,EAASn1D,MAAK,GAAgB09C,iBAC9BU,EAAc+W,EAAO3X,uBACrB4Y,EAAYjB,EAAO3Y,2BAA2B,CAClD/zC,EAAmB,IAAhB21C,EAAoBwY,EAAazsD,OAASmyC,EAAYnyC,OACzDzB,EAAmB,IAAhB01C,EAAoBwY,EAAaxsD,OAASkyC,EAAYlyC,OACzDzB,EAAmB,IAAhBy1C,EAAoBwY,EAAavsD,OAASiyC,EAAYjyC,SAErDwsD,EAAc72D,MAAK,GAAYyI,IAAM2tD,EAAU3tD,GACnDzI,MAAK,GAAY0I,IAAM0tD,EAAU1tD,EAenC,YAbgC,IAArByrE,QACoB,IAAtBC,IACPp0E,MAAK,GAAoBm0E,EACzBn0E,MAAK,GAAqBo0E,GAGxBvd,IACF72D,MAAK,GAAU,CACbyI,EAAGzI,MAAK,GAAQyI,EAAIzI,MAAK,GAAYyI,EAAI2tD,EAAU3tD,EACnDC,EAAG1I,MAAK,GAAQ0I,EAAI1I,MAAK,GAAY0I,EAAI0tD,EAAU1tD,GAErD1I,MAAK,GAAco2D,GAEdS,CACT,CAOAJ,SAAAA,CAAUL,GACR,MACMM,EADS12D,MAAK,GAAgB09C,iBACNlB,2BAA2B4Z,GACzDp2D,MAAK,GAAU,CACbyI,EAAGiuD,EAAejuD,EAChBzI,MAAK,GAAYyI,EACjBzI,MAAK,GAAYyI,EACjBzI,MAAK,GAAYyI,EACjBzI,MAAK,GAAYyI,EACnBC,EAAGguD,EAAehuD,EAChB1I,MAAK,GAAY0I,EACjB1I,MAAK,GAAY0I,EACjB1I,MAAK,GAAY0I,EACjB1I,MAAK,GAAY0I,EAEvB,CAQA69D,mBAAAA,CAAoBr4D,GAClB,MAAM84D,EAAWhnE,KAAKinE,kBAAkB/4D,GACxC,OAAO,IAAInM,EAAM,CACf4B,KAAKiD,MAAMogE,EAAS78D,QACpBxG,KAAKiD,MAAMogE,EAAS58D,SAExB,CAQAy9D,mBAAAA,CAAoB35D,GAClB,OAAO,IAAIH,EACTG,EAAQ/D,OAASnK,MAAK,GAAOyI,EAC7ByF,EAAQ9D,OAASpK,MAAK,GAAO0I,EAEjC,CAQAu+D,iBAAAA,CAAkB/4D,GAChB,MAAMmmE,EAAWr0E,KAAK6nE,oBAAoB35D,GAC1C,OAAO,IAAIH,EACTsmE,EAASlqE,OAASnK,MAAK,GAAQyI,EAC/B4rE,EAASjqE,OAASpK,MAAK,GAAQ0I,EAEnC,CASA4rE,iBAAAA,CAAkBpmE,GAChB,IAAIqmE,GACDrmE,EAAQ/D,OAASnK,MAAK,GAAQyI,EAAIzI,MAAK,GAAYyI,GAAKzI,MAAK,GAAOyI,EACnE+rE,GACDtmE,EAAQ9D,OAASpK,MAAK,GAAQ0I,EAAI1I,MAAK,GAAY0I,GAAK1I,MAAK,GAAO0I,EAQvE,OANI6rE,EAAO,GAAKA,GAAQv0E,MAAK,GAAQoF,SACnCmvE,OAAO/zE,IAELg0E,EAAO,GAAKA,GAAQx0E,MAAK,GAAQmjC,UACnCqxC,OAAOh0E,GAEF,IAAIuN,EAAQwmE,EAAMC,EAC3B,CAQAtM,qBAAAA,CAAsBh6D,GACpB,MAAM84D,EAAWhnE,KAAKinE,kBAAkB/4D,GACxC,OAAO,IAAIH,EACTi5D,EAAS78D,OAASnK,MAAK,GAAYyI,EACnCu+D,EAAS58D,OAASpK,MAAK,GAAY0I,EAEvC,CAOAouD,OAAAA,CAAQl7B,GACN57B,MAAK,GAAcmqD,MAAM2M,QAAUl7B,EAAO,GAAK,MACjD,CAOAm7B,SAAAA,GACE,MAA4C,KAArC/2D,MAAK,GAAcmqD,MAAM2M,OAClC,CASA/H,IAAAA,GAEE,IAAK/uD,MAAK,GACR,OAUF,IAAIgiB,EAAQ,CACVN,KAAM,cACNuoD,QAASjqE,KAAKo1D,QACd3E,OAAQzwD,KAAK0wD,aAEf1wD,MAAK,GAAWgiB,GAGZhiB,MAAK,IACPA,MAAK,KAIPA,MAAK,GAASy0E,YAAcz0E,MAAK,GAGjCA,KAAKw6B,QAQLx6B,MAAK,GAAS00E,aACZ10E,MAAK,GAAOyI,EACZ,EACA,EACAzI,MAAK,GAAO0I,GACX,EAAI1I,MAAK,GAAQyI,EAAIzI,MAAK,GAAOyI,GACjC,EAAIzI,MAAK,GAAQ0I,EAAI1I,MAAK,GAAO0I,GAIpC1I,MAAK,GAAS20E,sBAAwB30E,MAAK,GAE3CA,MAAK,GAASwzE,UAAUxzE,MAAK,GAAkB,EAAG,GASlDgiB,EAAQ,CACNN,KAAM,YACNuoD,QAASjqE,KAAKo1D,QACd3E,OAAQzwD,KAAK0wD,aAEf1wD,MAAK,GAAWgiB,EAClB,CASA47B,UAAAA,CAAWv3C,EAAM8hB,EAASqtC,GAExBx1D,MAAK,GAAemoB,EACpBnoB,MAAK,GAAW2D,KAAKgjB,IAAIhjB,KAAK0J,IAAImoD,EAAO,GAAI,GAI7Cx1D,MAAK,GAAU0yD,SAASwgB,cAAc,UACtClzE,MAAK,GAAc40E,YAAY50E,MAAK,IAG/BA,MAAK,GAAQqzE,YAKlBrzE,MAAK,GAAWA,MAAK,GAAQqzE,WAAW,MACnCrzE,MAAK,IAMVA,MAAK,GAAmB0yD,SAASwgB,cAAc,UAG/ClzE,MAAK,GAAaqG,GAGlBrG,MAAK,IAAmB,GAXtB60E,MAAM,yCANNA,MAAM,sCAkBV,CAOA,IAAaxuE,GAEX,IAAK2sE,GAAgB3sE,EAAKoC,EAAGpC,EAAKqC,GAChC,MAAM,IAAIxG,MAAM,kCACdmE,EAAKoC,EAAI,KAAOpC,EAAKqC,GAIzB1I,MAAK,GAAYqG,EAGjBrG,MAAK,GAAiBoF,MAAQpF,MAAK,GAAUyI,EAC7CzI,MAAK,GAAiBmjC,OAASnjC,MAAK,GAAU0I,EAE9C1I,MAAK,GAAS80E,UAAU,EAAG,EAAG90E,MAAK,GAAUyI,EAAGzI,MAAK,GAAU0I,GAC/D1I,MAAK,GAAaA,MAAK,GAAS+0E,gBAC9B/0E,MAAK,GAAUyI,EAAGzI,MAAK,GAAU0I,EACrC,CASA2vD,cAAAA,CAAeC,EAAeC,EAAqBC,GACjD,IAAIwc,GAAY,EAGhB,GAAIh1E,MAAK,GAAQoF,QAAUkzD,EAAc7vD,GACvCzI,MAAK,GAAQmjC,SAAWm1B,EAAc5vD,EAAG,CACzC,IAAKsqE,GAAgB1a,EAAc7vD,EAAG6vD,EAAc5vD,GAClD,MAAM,IAAIxG,MAAM,wBACdo2D,EAAc7vD,EAAI,KAAO6vD,EAAc5vD,GAG3C1I,MAAK,GAAQoF,MAAQkzD,EAAc7vD,EACnCzI,MAAK,GAAQmjC,OAASm1B,EAAc5vD,EAEpCssE,GAAY,CACd,CAGA,MAAMvc,EAAsB,CAC1BhwD,EAAG8vD,EAAsBv4D,MAAK,GAAayI,EAC3CC,EAAG6vD,EAAsBv4D,MAAK,GAAa0I,GAKvCqtD,EAAW,CACfttD,EAAGzI,MAAK,GAAOyI,EAAIgwD,EAAoBhwD,EAAIzI,MAAK,GAAUyI,EAC1DC,EAAG1I,MAAK,GAAO0I,EAAI+vD,EAAoB/vD,EAAI1I,MAAK,GAAU0I,GAIxD1I,MAAK,GAAOyI,IAAMstD,EAASttD,GAC7BzI,MAAK,GAAO0I,IAAMqtD,EAASrtD,IAC3B1I,MAAK,GAAYy4D,EACjBz4D,MAAK,GAAS+1D,EAEdif,GAAY,GAId,MAAMtc,EAAgB,CACpBjwD,EAAG+vD,EAAU/vD,EAAIgwD,EAAoBhwD,EACrCC,EAAG8vD,EAAU9vD,EAAI+vD,EAAoB/vD,GAGjCiwD,EAAkB,CACtBlwD,EAAG6vD,EAAc7vD,EAAIgwD,EAAoBhwD,EACzCC,EAAG4vD,EAAc5vD,EAAI+vD,EAAoB/vD,GAErCkwD,EAAgB,CACpBnwD,EAA0B,IAAvBzI,MAAK,GAAYyI,EAAUkwD,EAAgBlwD,EAAI,EAClDC,EAA0B,IAAvB1I,MAAK,GAAY0I,EAAUiwD,EAAgBjwD,EAAI,GAIhD1I,MAAK,GAAYyI,IAAMiwD,EAAcjwD,GACvCzI,MAAK,GAAY0I,IAAMgwD,EAAchwD,GACrC1I,MAAK,GAAYyI,IAAMmwD,EAAcnwD,GACrCzI,MAAK,GAAY0I,IAAMkwD,EAAclwD,IAErC1I,MAAK,GAAU,CACbyI,EAAGzI,MAAK,GAAQyI,EACdiwD,EAAcjwD,EAAIzI,MAAK,GAAYyI,EACnCmwD,EAAcnwD,EAAIzI,MAAK,GAAYyI,EACrCC,EAAG1I,MAAK,GAAQ0I,EACdgwD,EAAchwD,EAAI1I,MAAK,GAAY0I,EACnCkwD,EAAclwD,EAAI1I,MAAK,GAAY0I,GAGvC1I,MAAK,GAAc44D,EACnB54D,MAAK,GAAc04D,EAEnBsc,GAAY,GAIVA,GACFh1E,KAAK+uD,MAET,CAKA0K,eAAAA,GAEEz5D,MAAK,GAAcmqD,MAAMuP,cAAgB,OAEzC,MAAMC,EAAQC,GACd,IAAK,IAAIr3D,EAAI,EAAGA,EAAIo3D,EAAMx3D,SAAUI,EAAG,CACrC,MAAM0yE,EAAYtb,EAAMp3D,GAClB2yE,EAAwB,UAAdD,EAChBj1E,MAAK,GAAc+0C,iBACjBkgC,EAAWj1E,MAAK,GAAY,CAACk1E,QAASA,GAC1C,CACF,CAKArb,iBAAAA,GAEE75D,MAAK,GAAcmqD,MAAMuP,cAAgB,OAEzC,MAAMC,EAAQC,GACd,IAAK,IAAIr3D,EAAI,EAAGA,EAAIo3D,EAAMx3D,SAAUI,EAClCvC,MAAK,GAAcg1C,oBAAoB2kB,EAAMp3D,GAAIvC,MAAK,GAE1D,CASA+0C,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAcK,IACZA,EAAM+3C,WAAa/5D,KAAKo1D,QACxBpzC,EAAMyuC,OAASzwD,MAAK,GACpBA,MAAK,GAAiB+hB,UAAUC,EAAM,EAQxC,MAEEhiB,MAAK,GAAgBk7C,kBAAkBl7C,MAAK,IAE5CA,MAAK,GAAiBqzE,WAAW,MAAM8B,aAAan1E,MAAK,GAAY,EAAG,GAExEA,MAAK,IAAmB,CAC1B,CAOA,IAAegiB,SAE8B,IAAvBA,EAAM84B,eACD,IAAvB94B,EAAM84B,eAEN96C,MAAK,IAAmB,EACxBA,KAAK+uD,OACP,EAQF,IAAsB/sC,SACuB,IAAvBA,EAAM84B,eACD,IAAvB94B,EAAM84B,eAEN96C,MAAK,IAAmB,EACxBA,KAAK+uD,OACP,EAQF,IAAqB/sC,IAGnB,QAF2C,IAAvBA,EAAM84B,eACD,IAAvB94B,EAAM84B,aACG,CACT,IAAIX,GAAQ,EAKZ,QAJ2B,IAAhBn4B,EAAMm4B,QACfA,EAAQn4B,EAAMm4B,OAGXA,EAME,CAEL,MAAMi7B,EAAS,CAAC,EAAG,EAAG,GAEhBC,EACJD,EAAO7nE,QAAQvN,MAAK,GAAgB+5C,kBACtCq7B,EAAOtzD,OAAOuzD,EAAkB,GAMR,IAJPrzD,EAAMhf,SAASgiE,QAAO,SAAUvmD,GAC/C,OAAiC,IAA1B22D,EAAO7nE,QAAQkR,EACxB,IAEatc,QAAiBnC,MAAK,KAEjCA,MAAK,IAAmB,EAExBA,MAAK,IAAmB,EACxBA,KAAK+uD,OAET,MAvBM/uD,MAAK,KACPA,MAAK,IAAmB,EACxBA,KAAKw6B,QAsBX,GAQF,IAAsBxY,SACuB,IAAvBA,EAAM84B,eACD,IAAvB94B,EAAM84B,eAEN96C,MAAK,IAAmB,EACxBA,KAAK+uD,OACP,EAUF9U,kBAAAA,CAAmB52B,EAAUw1B,GAC3B,OAAO74C,MAAK,GAAgBi6C,mBAAmB52B,EACjD,CAKAmX,KAAAA,GAGEx6B,MAAK,GAASs1E,OAEdt1E,MAAK,GAAS00E,aAAa,EAAG,EAAG,EAAG,EAAG,EAAG,GAC1C10E,MAAK,GAAS80E,UAAU,EAAG,EAAG90E,MAAK,GAAQoF,MAAOpF,MAAK,GAAQmjC,QAE/DnjC,MAAK,GAASu1E,SAChB,ECtkCK,SAASC,GAA8BC,GAC5C,MAAMrmE,EAAQqmE,EAASrmE,MAAM,WAI7B,OAHqB,IAAjBA,EAAMjN,QACRgC,EAAOa,KAAK,2CAEP,CACL29C,WAAYvzC,EAAM,GAClBsmE,WAAYtmE,EAAM,GAClBq6D,QAASgM,EAEb,CAUO,SAASjzB,GAAyBxgC,GACvC,IAAIlZ,EAAM,KAEV,MAAM6sE,EAAW3zD,EAAM8tC,OAAO8lB,QAAQ,UAItC,OAHID,QAAmC,IAAhBA,EAAS5uE,KAC9B+B,EAAM0sE,GAA8BG,EAAS5uE,KAExC+B,CACT,CAYO,SAASutD,GAAgBnyD,EAAQskD,EAAOuN,EAAU5wD,GAUvD,MAAM0wE,GACA1wE,EAAOsD,EAAIvE,EAAOuE,GAAK+/C,EAAM//C,EAD7BotE,GAEA1wE,EAAOuD,EAAIxE,EAAOwE,GAAK8/C,EAAM9/C,EAEnC,MAAO,CACLD,EAAGtD,EAAOsD,EAAKotE,EAAgB9f,EAASttD,EACxCC,EAAGvD,EAAOuD,EAAKmtE,EAAgB9f,EAASrtD,EAE5C,CAkBO,MAAMotE,GAOX,IAUA,IAAU,GAOV,IAAS,CAACrtE,EAAG,EAAGC,EAAG,EAAGC,EAAG,GAOzB,IAAa,CAACF,EAAG,EAAGC,EAAG,EAAGC,EAAG,GAO7B,IAAU,CAACF,EAAG,EAAGC,EAAG,EAAGC,EAAG,GAO1B,SAAwBnI,EAOxB,SAAwBA,EAOxB,IAAmB,IAAIihB,GAOvB,KAAiB,EAOjB,IAAyB,GAOzB,IAOA,IAOA,KAAkB,EAKlBzf,WAAAA,CAAY4yD,GACV50D,MAAK,GAAgB40D,CACvB,CAOAmhB,gBAAAA,GACE,OAAO/1E,MAAK,EACd,CAOAg2E,gBAAAA,CAAiBp6C,GACf57B,MAAK,GAAiB47B,EAClBA,GAEF57B,KAAK+0C,iBAAiB,eAAgB/0C,MAAK,IAC3CA,KAAK+0C,iBAAiB,aAAc/0C,MAAK,IAEzCA,MAAK,OAGLA,KAAKg1C,oBAAoB,eAAgBh1C,MAAK,IAC9CA,KAAKg1C,oBAAoB,aAAch1C,MAAK,IAE5CA,MAAK,KAET,CAOA4zE,iBAAAA,CAAkBh4C,GAChB57B,MAAK,GAAkB47B,EAEvB,IAAK,MAAMkuC,KAAS9pE,MAAK,GACnB8pE,aAAiB2J,IACnB3J,EAAM8J,kBAAkBh4C,EAG9B,CAOA,IAA4BwpC,IAC1BplE,MAAK,IAAmB,EAQ1Bi2E,QAAAA,GACE,OAAOj2E,MAAK,GAAc+G,EAC5B,CAOA2sE,QAAAA,GACE,OAAO1zE,MAAK,EACd,CAOA0oD,YAAAA,GACE,OAAO1oD,MAAK,EACd,CAQAk2E,aAAAA,GACE,MAAO,CACLztE,EAAGzI,MAAK,GAAOyI,EAAIzI,MAAK,GAAWyI,EACnCC,EAAG1I,MAAK,GAAO0I,EAAI1I,MAAK,GAAW0I,EACnCC,EAAG3I,MAAK,GAAO2I,EAAI3I,MAAK,GAAW2I,EAEvC,CAOAwtE,SAAAA,GACE,OAAOn2E,MAAK,EACd,CAOAo2E,iBAAAA,GACE,IAAI5tD,EAAQ,EAMZ,OALAxoB,MAAK,GAAQovD,SAAQ3wC,SACC,IAATA,GACT+J,GACF,IAEKA,CACT,CASA7X,QAAAA,CAAS5J,GACP,QAAkB,IAAPA,EACT,OAAO,EAET,IAAK,MAAM+iE,KAAS9pE,MAAK,GACvB,QAAqB,IAAV8pE,GACTA,EAAM1U,UAAYruD,EAClB,OAAO,EAGX,OAAO,CACT,CAWAsvE,aAAAA,CAAcnkE,QACc,IAAfA,IACTA,EAAa,WACX,OAAO,CACT,GAEF,MAAMpJ,EAAM,GACZ,IAAK,MAAMghE,KAAS9pE,MAAK,GACnB8pE,aAAiB2J,IACnBvhE,EAAW43D,IACXhhE,EAAI7F,KAAK6mE,GAGb,OAAOhhE,CACT,CAUAwtE,aAAAA,CAAcpkE,GACZ,IAAIqkE,GAAS,EACb,IAAK,MAAMzM,KAAS9pE,MAAK,GACvB,GAAI8pE,aAAiB2J,IACnBvhE,EAAW43D,GAAQ,CACnByM,GAAS,EACT,KACF,CAEF,OAAOA,CACT,CAWAvM,aAAAA,CAAc93D,QACc,IAAfA,IACTA,EAAa,WACX,OAAO,CACT,GAEF,MAAMpJ,EAAM,GACZ,IAAK,MAAMghE,KAAS9pE,MAAK,GACnB8pE,aAAiBnV,IACnBziD,EAAW43D,IACXhhE,EAAI7F,KAAK6mE,GAGb,OAAOhhE,CACT,CAOA0tE,qBAAAA,GACE,IAAIhuD,EAAQ,EAOZ,OANAxoB,MAAK,GAAQovD,SAAQ3wC,SACC,IAATA,GACTA,aAAgBg1D,IAChBjrD,GACF,IAEKA,CACT,CAOAq6B,kBAAAA,GACE,IAAIinB,EACJ,QAA0C,IAA/B9pE,MAAK,GAAuC,CACrD,MAAMy2E,EAAWz2E,MAAK,GAAQA,MAAK,IAC/By2E,aAAoBhD,KACtB3J,EAAQ2M,EAEZ,CACA,OAAO3M,CACT,CAOA4M,gBAAAA,GAGE,IAAIC,EACJ,IAAK,MAAM7M,KAAS9pE,MAAK,GACvB,GAAI8pE,aAAiB2J,GAAW,CAC9BkD,EAAY7M,EACZ,KACF,CAEF,QAAyB,IAAd6M,EAIX,OAAOA,EAHLxyE,EAAOa,KAAK,iBAIhB,CAQA4xE,qBAAAA,CAAsBrf,GAIpB,OAAOv3D,KAAKq2E,eAHO,SAAUvM,GAC3B,OAAOA,EAAMpZ,cAAgB6G,CAC/B,GAEF,CAQAsf,gBAAAA,CAAiBriD,GACf,MAAM1rB,EAAM,GACZ,IAAK,MAAMghE,KAAS9pE,MAAK,GACnB8pE,aAAiB2J,IACf3J,EAAMhnB,oBAAoB9C,eAAexrB,IAC3C1rB,EAAI7F,KAAK6mE,GAIf,OAAOhhE,CACT,CAOAguE,kBAAAA,GACE,MAAMhuE,EAAM,GACZ,IAAK,MAAMghE,KAAS9pE,MAAK,GACnB8pE,aAAiB2J,IACnB3qE,EAAI7F,KAAK6mE,EAAMpZ,aAGnB,OAAO5nD,CACT,CAOA0/D,kBAAAA,GACE,IAAIsB,EACJ,QAA0C,IAA/B9pE,MAAK,GAAuC,CACrD,MAAMy2E,EAAWz2E,MAAK,GAAQA,MAAK,IAC/By2E,aAAoB9hB,KACtBmV,EAAQ2M,EAEZ,CACA,OAAO3M,CACT,CAQAiN,qBAAAA,CAAsBxf,GAIpB,OAAOv3D,KAAKgqE,eAHO,SAAUF,GAC3B,OAAOA,EAAMpZ,cAAgB6G,CAC/B,GAEF,CAOAyf,kBAAAA,CAAmB1pE,GACbtN,MAAK,GAAQsN,aAAkBmmE,IACjCzzE,MAAK,GAAwBsN,EAS7BtN,MAAK,GAAW,CACd0hB,KAAM,oBACN5f,MAAO,CAAC9B,MAAK,GAAQsN,OAGvBnJ,EAAOa,KAAK,8CACVsI,EAEN,CAOA2pE,0BAAAA,CAA2B1f,GACzB,IAAIjqD,EACJ,IAAK,IAAI/K,EAAI,EAAGA,EAAIvC,MAAK,GAAQmC,SAAUI,EACzC,GAAIvC,MAAK,GAAQuC,aAAckxE,IAC7BzzE,MAAK,GAAQuC,GAAGmuD,cAAgB6G,EAAQ,CAExCjqD,EAAQ/K,EACR,KACF,MAEmB,IAAV+K,EACTtN,KAAKg3E,mBAAmB1pE,GAExBnJ,EAAOa,KAAK,+CACVuyD,EAEN,CAQA2f,kBAAAA,CAAmB5pE,GACjBtN,MAAK,GAAwBsN,EAC7BtN,MAAK,GAAW,CACd0hB,KAAM,oBACN5f,MAAO,CAAC9B,MAAK,GAAQsN,KAEzB,CAOAu7D,0BAAAA,CAA2BtR,GACzB,IAAIjqD,EACJ,IAAK,IAAI/K,EAAI,EAAGA,EAAIvC,MAAK,GAAQmC,SAAUI,EACzC,GAAIvC,MAAK,GAAQuC,aAAcoyD,IAC7B30D,MAAK,GAAQuC,GAAGmuD,cAAgB6G,EAAQ,CAExCjqD,EAAQ/K,EACR,KACF,MAEmB,IAAV+K,EACTtN,KAAKk3E,mBAAmB5pE,GAExBnJ,EAAOa,KAAK,+CACVuyD,EAEN,CASA4f,YAAAA,GAEE,MAAMC,EAAiBp3E,MAAK,GAAQmC,OAE9Bk1E,EAAMr3E,MAAK,KAEjBA,MAAK,GAAcs3E,OAAOD,GAE1B,MAAMvN,EAAQ,IAAI2J,GAAU4D,GAS5B,OARAvN,EAAM8J,kBAAkB5zE,MAAK,IAE7BA,MAAK,GAAQiD,KAAK6mE,GAElB9pE,KAAKg3E,mBAAmBI,GAExBp3E,MAAK,GAAe8pE,GAEbA,CACT,CASAyN,YAAAA,GAEEv3E,MAAK,GAAwBA,MAAK,GAAQmC,OAE1C,MAAMk1E,EAAMr3E,MAAK,KAEjBA,MAAK,GAAcs3E,OAAOD,GAE1B,MAAMvN,EAAQ,IAAInV,GAAU0iB,GAM5B,OAJAr3E,MAAK,GAAQiD,KAAK6mE,GAElB9pE,MAAK,GAAe8pE,GAEbA,CACT,CAOA,IAAetoB,GAEbA,EAAUzM,iBACR,iBAAkB/0C,KAAKw3E,8BAEzB,IAAK,MAAMvC,KAAa/8B,GACtBsJ,EAAUzM,iBAAiBkgC,EAAWj1E,MAAK,IAG7CwhD,EAAUzM,iBAAiB,cAAe/0C,MAAK,IAC/CwhD,EAAUzM,iBAAiB,YAAa/0C,MAAK,GAC/C,CAOA,IAAiBwhD,GAEfA,EAAUxM,oBACR,iBAAkBh1C,KAAKw3E,8BAEzB,IAAK,MAAMvC,KAAa/8B,GACtBsJ,EAAUxM,oBAAoBigC,EAAWj1E,MAAK,IAGhDwhD,EAAUxM,oBAAoB,cAAeh1C,MAAK,IAClDwhD,EAAUxM,oBAAoB,YAAah1C,MAAK,IAIhDwhD,EAAUwyB,aACZ,CAOA,IAAevlB,GAEbA,EAAU1Z,iBACR,iBAAkB/0C,KAAKw3E,8BACzB/oB,EAAU1Z,iBACR,iBAAkB/0C,MAAK,IAEzByuD,EAAU1Z,iBAAiB,aAAc/0C,MAAK,IAC9CyuD,EAAU1Z,iBAAiB,aAAc/0C,MAAK,GAChD,CAOA,IAAiByuD,GAEfA,EAAUzZ,oBACR,iBAAkBh1C,KAAKw3E,8BACzB/oB,EAAUzZ,oBACR,iBAAkBh1C,MAAK,IAEzByuD,EAAUzZ,oBAAoB,aAAch1C,MAAK,IACjDyuD,EAAUzZ,oBAAoB,aAAch1C,MAAK,GACnD,CAOA,MACE,MAAMq3E,EAAM3kB,SAASwgB,cAAc,OAInC,OAHAmE,EAAItwE,GAAmB/G,KAAKi2E,WAvuBV,UAuuBsBj2E,MAAK,GAAQmC,OACrDk1E,EAAIxiB,UAAY,QAChBwiB,EAAIltB,MAAMuP,cAAgB,OACnB2d,CACT,CAKAI,KAAAA,GACEz3E,MAAK,GAAU,GAEfA,MAAK,QAAwBQ,EAC7BR,MAAK,QAAwBQ,EAE7BR,MAAK,KAEL,MAAM+b,EAAW/b,MAAK,GAAc03E,uBAAuB,SAC3D,GAAI37D,EACF,KAAOA,EAAS5Z,OAAS,GACvB4Z,EAAS,GAAG6F,QAGlB,CAOA+1D,oBAAAA,CAAqBpgB,GACnB,IAAK,MAAMuS,KAAS9pE,MAAK,QACF,IAAV8pE,GACTA,EAAMpZ,cAAgB6G,GACtBv3D,KAAK43E,YAAY9N,EAGvB,CAUA8N,WAAAA,CAAY9N,GAEV,MAAMx8D,EAAQtN,MAAK,GAAQksC,WAAWztB,GAASA,IAASqrD,IACxD,IAAe,IAAXx8D,EACF,MAAM,IAAIpL,MAAM,+BAGd4nE,aAAiB2J,IACnBzzE,MAAK,GAAiB8pE,GAClB9pE,MAAK,KAA0BsN,IACjCtN,MAAK,QAAwBQ,KAG/BR,MAAK,GAAiB8pE,GAClB9pE,MAAK,KAA0BsN,IACjCtN,MAAK,QAAwBQ,IAIjCR,MAAK,GAAQsN,QAAS9M,EAEtBspE,EAAMzU,eACR,CAQA,IAAkBhyC,GAUhB,IAAIszD,OAToB,IAAbtzD,IACTA,EAAWrjB,MAAK,IAIlBA,MAAK,KAKL,IAAK,MAAM8pE,KAAS9pE,MAAK,GACvB,GAAI8pE,aAAiB2J,GAAW,CAC9BkD,EAAY7M,EACZ,KACF,CAEF,QAAyB,IAAd6M,EAET,YADAxyE,EAAOa,KAAK,8BAId,MACMgiE,EADK2P,EAAU7zB,oBACD1C,6BAA6B/8B,GAC3Cw0D,EAAalB,EAAUrC,kBAAkBtN,GAG/C,QAAiC,IAAtB6Q,EAAWztE,OAAwB,CAC5C,MAAM0tE,EAAQplB,SAASwgB,cAAc,MACrC4E,EAAM/wE,GAAK/G,KAAKi2E,WAAa,+BAC7B6B,EAAMjjB,UAAY,aAClBijB,EAAM3tB,MAAM/kD,MAAQpF,MAAK,GAAc+3E,YAAc,KACrDD,EAAM3tB,MAAM0kB,KAAO,MACnBiJ,EAAM3tB,MAAM6kB,IAAM6I,EAAWztE,OAAS,KAEtCpK,MAAK,GAAuBiD,KAAK60E,GAEjC93E,MAAK,GAAc40E,YAAYkD,EACjC,CAGA,QAAiC,IAAtBD,EAAW1tE,OAAwB,CAC5C,MAAM6tE,EAAQtlB,SAASwgB,cAAc,MACrC8E,EAAMjxE,GAAK/G,KAAKi2E,WAAa,6BAC7B+B,EAAMnjB,UAAY,WAClBmjB,EAAM7tB,MAAM/kD,MAAQpF,MAAK,GAAci4E,aAAe,KACtDD,EAAM7tB,MAAM0kB,KAAQgJ,EAAW1tE,OAAU,KACzC6tE,EAAM7tB,MAAM6kB,IAAM,MAElBhvE,MAAK,GAAuBiD,KAAK+0E,GAEjCh4E,MAAK,GAAc40E,YAAYoD,EACjC,CACF,CAKA,MACE,IAAK,MAAMnmE,KAAW7R,MAAK,GACzB6R,EAAQ+P,SAEV5hB,MAAK,GAAyB,EAChC,CAQAsnE,WAAAA,CAAY39C,GAEV3pB,KAAKunE,mBAEL,MAAM/lB,EAAYxhD,KAAK6iD,qBACjBD,EAAiBpB,EAAUsB,oBAC3BkkB,EAAWxlB,EAAUylB,kBAAkBt9C,GACvCtG,EAAWu/B,EAAe1F,0BAA0B8pB,GACpDllE,EAAQ8gD,EAAerE,sBAAsBl7B,GAGnD,QAAqB,IAAVvhB,EAAuB,CAChC,MAAMo2E,EAAOxlB,SAASwgB,cAAc,QACpCgF,EAAKnxE,GAAK,iBAEVmxE,EAAK/tB,MAAM0kB,KAAQllD,EAAMxf,OAAS,GAAM,KACxC+tE,EAAK/tB,MAAM6kB,IAAOrlD,EAAMvf,OAAS,GAAM,KACvC,IAAI8uD,EAAOloD,EAAelP,EAAO,GAAGU,gBACS,IAAlCogD,EAAejsB,iBACxBuiC,GAAQ,IAAMtW,EAAejsB,gBAE/BuhD,EAAKtD,YAAYliB,SAASylB,eAAejf,IAEzCl5D,MAAK,GAAsBk4E,EAE3Bl4E,MAAK,GAAc40E,YAAYsD,EACjC,CACF,CAKA3Q,gBAAAA,QAC0C,IAA7BvnE,MAAK,KACdA,MAAK,GAAoB4hB,SACzB5hB,MAAK,QAAsBQ,EAE/B,CAQAs5C,kBAAAA,CAAmBz2B,GACjB,OAAOrjB,KAAKs2E,eAAc,SAAUxM,GAClC,OAAOA,EAAMhnB,oBAAoBhJ,mBAAmBz2B,EACtD,GACF,CAOA6C,SAAAA,GACE,OAAOlmB,KAAKs2E,eAAc,SAAUxM,GAClC,OAAOA,EAAMhnB,oBAAoB58B,WACnC,GACF,CASAH,WAAAA,CAAY85B,GACV,OAAO7/C,KAAKs2E,eAAc,SAAUxM,GAClC,OAAOA,EAAMhnB,oBAAoB/8B,YAAY85B,EAC/C,GACF,CAQA23B,6BAAgCx1D,IAE9B,IAAK,MAAM8nD,KAAS9pE,MAAK,QACF,IAAV8pE,IACTA,EAAM90B,oBACJ,iBAAkBh1C,KAAKw3E,8BACzB1N,EAAM90B,oBAAoB,iBAAkBh1C,MAAK,KAIrD,MAAMsN,EAAQ,IAAIvL,EAAMigB,EAAMlgB,MAAM,IAC9BuhB,EAAW,IAAIzU,EAAMoT,EAAMlgB,MAAM,IAGvC9B,MAAK,GAAmBqjB,EAEpBrjB,MAAK,IACPA,MAAK,GAAkBqjB,GAIzB,MAAM+0D,EAAmB,CAAC,EAC1B,IAAIC,EACAC,EAEJ,IAAK,MAAMxO,KAAS9pE,MAAK,GAAS,CAChC,QAAqB,IAAV8pE,EACT,SAEF,IAAIyO,GAAe,EAGnB,GAAIzO,aAAiB2J,GAAW,CAC9B,MAAM+E,EAAK1O,EAAMhnB,oBAEXoxB,EAAUsE,EAAG7vD,YAEbT,EAASswD,EAAG7vD,UAAUtF,GAE5B,IAAIuzC,EACAta,EAEJ,QAAmC,IAAxBg8B,EAETD,EAAuBnE,EACvBoE,EAAsBpwD,EAEtB0uC,EAAe,IAAI1sD,EAAS,EAAG,EAAG,GAClCoyC,EAAc,IAAIpyC,EAAS,EAAG,EAAG,QAEjC,GAAIsuE,EAAG1+B,mBAAmBz2B,SACN,IAAX6E,EAAwB,CAE/B,MAAMuwD,EAAaJ,EAAqB1pE,MAAMulE,GAC9Ctd,EAAe,IAAI1sD,EACjBuuE,EAAWtuE,OAAQsuE,EAAWruE,OAAQquE,EAAWpuE,QACnD,MAAMquE,EAAYJ,EAAoB3pE,MAAMuZ,GAC5Co0B,EAAc,IAAIpyC,EAChBwuE,EAAUvuE,OAAQuuE,EAAUtuE,OAAQsuE,EAAUruE,OAClD,MAI0B,IAAjBusD,QACc,IAAhBta,IACPi8B,EACEzO,EAAMnT,cACJC,EAActa,EACdg8B,EAAqBD,GAGzBD,EAAiBtO,EAAM1U,SAAW,CAChCujB,OAAQ/hB,EACRgiB,MAAOt8B,GAGb,CAGA,GAAIwtB,aAAiBnV,GAAW,CAC9B,MAAMkkB,EAAaT,EAAiBtO,EAAM9U,4BAChB,IAAf6jB,IACTN,EACEzO,EAAMnT,cAAckiB,EAAWF,OAAQE,EAAWD,OAExD,CAGA,IAAIE,GAAY,EACZhP,EAAM1U,UAAYpzC,EAAM+3C,aAC1B+e,EAAYhP,EAAM7vB,mBAAmB52B,EAAU/V,KAI5CwrE,GAAaP,GAChBzO,EAAM/a,MAEV,CAGA,IAAK,MAAM+a,KAAS9pE,MAAK,QACF,IAAV8pE,IACTA,EAAM/0B,iBACJ,iBAAkB/0C,KAAKw3E,8BACzB1N,EAAM/0B,iBAAiB,iBAAkB/0C,MAAK,IAElD,EASF+4E,sBAAAA,GAEE,GAAuC,IAAnC/4E,MAAK,GAAc+3E,aACe,IAApC/3E,MAAK,GAAci4E,aACnB,MAAM,IAAI/1E,MAAM,uCAGlB,MAAM82E,EAAeh5E,KAAKi5E,kBAC1B,QAA4B,IAAjBD,EAAX,CAMA,GAAwC,IAApCh5E,MAAK,GAAci4E,aAAoB,CACzC,MAAMje,EAASh6D,MAAK,GAAc+3E,YAAciB,EAAavwE,EACvD06B,EAAS61C,EAAatwE,EAAIsxD,EAChCh6D,MAAK,GAAcmqD,MAAMhnB,OAASA,EAAS,IAC7C,CAEA,OAAOx/B,KAAKgjB,IACV3mB,MAAK,GAAc+3E,YAAciB,EAAavwE,EAC9CzI,MAAK,GAAci4E,aAAee,EAAatwE,EAZjD,CAcF,CAOA2vD,cAAAA,CAAeE,GAEb,MAAMygB,EAAeh5E,KAAKi5E,kBAE1B,QAA4B,IAAjBD,EACT,OAGF,MAAM1gB,EAAgB,CACpB7vD,EAAGzI,MAAK,GAAc+3E,YACtBrvE,EAAG1I,MAAK,GAAci4E,cAGlBzf,EAAY,CAChB/vD,GAAI,IACD6vD,EAAc7vD,EAAI9E,KAAKiD,MAAMoyE,EAAavwE,EAAI8vD,IACjD7vD,GAAI,IACD4vD,EAAc5vD,EAAI/E,KAAKiD,MAAMoyE,EAAatwE,EAAI6vD,KAInD,IAAK,MAAMuR,KAAS9pE,MAAK,QACF,IAAV8pE,GACTA,EAAMzR,eAAeC,EAAeC,EAAqBC,GAKzDx4D,MAAK,IACPA,MAAK,IAET,CAOAi5E,eAAAA,GACE,IAAIC,EAAU,CAACzwE,EAAG,EAAGC,EAAG,GACxB,IAAK,MAAMohE,KAAS9pE,MAAK,GACvB,GAAI8pE,aAAiB2J,GAAW,CAC9B,MAAMptE,EAAOyjE,EAAMhqB,oBACfz5C,EAAKoC,EAAIywE,EAAQzwE,IACnBywE,EAAQzwE,EAAIpC,EAAKoC,GAEfpC,EAAKqC,EAAIwwE,EAAQxwE,IACnBwwE,EAAQxwE,EAAIrC,EAAKqC,EAErB,CAKF,OAHkB,IAAdwwE,EAAQzwE,GAAyB,IAAdywE,EAAQxwE,IAC7BwwE,OAAU14E,GAEL04E,CACT,CAKArjB,UAAAA,GACE71D,MAAK,GAAW2I,IAAM,EACtB3I,KAAK81D,SAAS91D,MAAK,GACrB,CAQAmoE,QAAAA,CAASgR,EAAWh0E,GAClB,MAAM4wD,EAAW,CACfttD,EAAGzI,MAAK,GAAOyI,GAAK,EAAI0wE,GACxBzwE,EAAG1I,MAAK,GAAO0I,GAAK,EAAIywE,GACxBxwE,EAAG3I,MAAK,GAAO2I,GAAK,EAAIwwE,IAE1Bn5E,KAAK81D,SAASC,EAAU5wD,EAC1B,CASA2wD,QAAAA,CAASC,EAAU5wD,GACjBnF,MAAK,GAAS+1D,EAEd,IAAK,MAAM+T,KAAS9pE,MAAK,QACF,IAAV8pE,GACTA,EAAMhU,SAAS91D,MAAK,GAAQmF,GAKhC,MAAMrD,EAAQ,CACZi0D,EAASttD,EACTstD,EAASrtD,EACTqtD,EAASptD,QAEW,IAAXxD,IACTrD,EAAMmB,KAAKkC,EAAOgF,QAClBrI,EAAMmB,KAAKkC,EAAOiF,QAClBtI,EAAMmB,KAAKkC,EAAOkF,SAWpBrK,MAAK,GAAW,CACd0hB,KAAM,aACN5f,MAAOA,GAEX,CAOAgmE,cAAAA,CAAevT,GACbv0D,KAAKy2D,UAAU,CACbhuD,EAAGzI,MAAK,GAAQyI,EAAI8rD,EAAY9rD,EAChCC,EAAG1I,MAAK,GAAQ0I,EAAI6rD,EAAY7rD,EAChCC,EAAG3I,MAAK,GAAQ2I,EAAI4rD,EAAY5rD,GAEpC,CAQA8tD,SAAAA,CAAUL,GAERp2D,MAAK,GAAUo2D,EAEf,IAAK,MAAM0T,KAAS9pE,MAAK,QACF,IAAV8pE,GACTA,EAAMrT,UAAUz2D,MAAK,IAYzBA,MAAK,GAAW,CACd0hB,KAAM,eACN5f,MAAO,CACL9B,MAAK,GAAQyI,EACbzI,MAAK,GAAQ0I,EACb1I,MAAK,GAAQ2I,IAGnB,CAKAsmD,KAAAA,GACEjvD,KAAK81D,SAAS91D,MAAK,IACnBA,KAAKy2D,UAAU,CAAChuD,EAAG,EAAGC,EAAG,EAAGC,EAAG,GACjC,CAKAomD,IAAAA,GACE,IAAK,MAAM+a,KAAS9pE,MAAK,QACF,IAAV8pE,GACTA,EAAM/a,MAGZ,CAOA+H,OAAAA,CAAQl7B,GACN,IAAK,MAAMkuC,KAAS9pE,MAAK,QACF,IAAV8pE,GACTA,EAAMhT,QAAQl7B,EAGpB,CASAmZ,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAcK,IACZhiB,MAAK,GAAiB+hB,UAAUC,EAAM,EChsCnC,MAAMo3D,GAAa,CACxBC,kBA/IK,MACLC,aAAe,WACb,MAAO,UACT,EACAC,YAAc,SAAU92B,GACtB,OAAO,SAAUzgC,GACf,MAAMw3D,EAAa/2B,EAAWm0B,sBAAsB50D,EAAMyuC,QAC1D,GAA0B,IAAtB+oB,EAAWr3E,OAAc,CAC3B,MAAMq2E,EAAKgB,EAAW,GAAG12B,oBACzB,GAA2B,IAAvB9gC,EAAMlgB,MAAMK,OAAc,CAC5B,MAAM0D,EAAK,IAAIX,EAAY8c,EAAMlgB,MAAM,GAAIkgB,EAAMlgB,MAAM,IACvD02E,EAAGt/B,eAAerzC,EACpB,CAC2B,IAAvBmc,EAAMlgB,MAAMK,QACdq2E,EAAGz9B,qBAAqB/4B,EAAMlgB,MAAM,GAExC,CACF,CACF,GA8HA23E,eAtGK,MACLH,aAAe,WACb,MAAO,gBACT,EACAC,YAAc,SAAU92B,GACtB,OAAO,SAAUzgC,GACf,MAAM03D,EAAc13D,EAAMlgB,MAAM,GAC1B02E,EAAK/1B,EAAWI,qBAAqBC,oBAErC62B,EAAanB,EAAG5+B,qBAChBggC,EAAcD,EAAWx3E,SACzB03E,EAAYH,EAAYv3E,OAC1B03E,IAAcD,IACZC,IAAcD,EAAc,EAE9BF,EAAYz2E,KAAK02E,EAAWt4E,IAAIu4E,EAAc,IACrCC,IAAcD,EAAc,GAErCF,EAAYjpE,OAGhB+nE,EAAGv+B,mBAAmB,IAAIrrC,EAAM8qE,GAClC,CACF,GAgFAI,WA1EK,MACLR,aAAe,WACb,MAAO,YACT,EACAC,YAAc,SAAU92B,GACtB,OAAO,SAAUzgC,GACf,MAAMwmC,EAAQ,CACZ//C,EAAGuZ,EAAMlgB,MAAM,GACf4G,EAAGsZ,EAAMlgB,MAAM,GACf6G,EAAGqZ,EAAMlgB,MAAM,IAEjB,IAAIqD,EACuB,IAAvB6c,EAAMlgB,MAAMK,SACdgD,EAAS,IAAI6H,EACXgV,EAAMlgB,MAAM,GACZkgB,EAAMlgB,MAAM,GACZkgB,EAAMlgB,MAAM,KAGhB2gD,EAAWqT,SAAStN,EAAOrjD,GAC3Bs9C,EAAWsM,MACb,CACF,GAqDAgrB,aA/CK,MACLT,aAAe,WACb,MAAO,cACT,EACAC,YAAc,SAAU92B,GACtB,OAAO,SAAUzgC,GACfygC,EAAWgU,UAAU,CACnBhuD,EAAGuZ,EAAMlgB,MAAM,GACf4G,EAAGsZ,EAAMlgB,MAAM,GACf6G,EAAGqZ,EAAMlgB,MAAM,KAEjB2gD,EAAWsM,MACb,CACF,GAmCAirB,cA7BK,MACLV,aAAe,WACb,MAAO,eACT,EACAC,YAAc,SAAU92B,GACtB,OAAO,SAAUzgC,GAEf,QAA4B,IAAjBA,EAAMyuC,OACf,OAGF,MAAM+oB,EAAa/2B,EAAWm0B,sBAAsB50D,EAAMyuC,QACpDkmB,EAAYl0B,EAAWi0B,mBACH,IAAtB8C,EAAWr3E,QAAgBw0E,IAAc6C,EAAW,KACtDA,EAAW,GAAGjkB,WAAWvzC,EAAMlgB,OAC/B03E,EAAW,GAAGzqB,OAElB,CACF,GAYAkrB,gBA5HK,MACLX,aAAe,WACb,MAAO,iBACT,EACAC,YAAc,SAAU92B,GACtB,OAAO,SAAUzgC,GACf,MAAMw3D,EAAa/2B,EAAWm0B,sBAAsB50D,EAAMyuC,QAChC,IAAtB+oB,EAAWr3E,QACFq3E,EAAW,GAAG12B,oBACtBjL,aAAa71B,EAAMlgB,MAAM,GAEhC,CACF,IAuHK,MAAMo4E,GAOX,IAAe,GAOf,IAOA,KAAkB,EAGlB,IAAW,GAEX,IAAiB,KAQjBC,aAAAA,CAAc7sE,GACZ,OAAOtN,MAAK,GAAasN,EAC3B,CAOA8sE,sBAAAA,GACE,OAAOp6E,MAAK,GAAamC,MAC3B,CAOAinE,mBAAAA,GACE,OAAOppE,KAAKm6E,cAAcn6E,MAAK,GACjC,CAOAq6E,mBAAAA,CAAoB/sE,QACuB,IAA9BtN,KAAKm6E,cAAc7sE,GAC5BtN,MAAK,GAAyBsN,EAE9BnJ,EAAOa,KAAK,+CACVsI,EAEN,CAQAspE,qBAAAA,CAAsBrf,GACpB,IAAIzuD,EAAM,GACV,IAAK,IAAIvG,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAC9CuG,EAAMA,EAAIiW,OAAO/e,MAAK,GAAauC,GAAGq0E,sBAAsBrf,IAE9D,OAAOzuD,CACT,CAWAutE,aAAAA,CAAcnkE,GACZ,IAAIpJ,EAAM,GACV,IAAK,IAAIvG,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAC9CuG,EAAMA,EAAIiW,OAAO/e,MAAK,GAAauC,GAAG8zE,cAAcnkE,IAEtD,OAAOpJ,CACT,CAQAiuE,qBAAAA,CAAsBxf,GACpB,IAAIzuD,EAAM,GACV,IAAK,IAAIvG,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAC9CuG,EAAMA,EAAIiW,OAAO/e,MAAK,GAAauC,GAAGw0E,sBAAsBxf,IAE9D,OAAOzuD,CACT,CAWAkhE,aAAAA,CAAc93D,GACZ,IAAIpJ,EAAM,GACV,IAAK,IAAIvG,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAC9CuG,EAAMA,EAAIiW,OAAO/e,MAAK,GAAauC,GAAGynE,cAAc93D,IAEtD,OAAOpJ,CACT,CAUAwxE,aAAAA,CAAcC,GACZv6E,MAAK,GAAyBA,MAAK,GAAamC,OAChD,MAAMsgD,EAAa,IAAIqzB,GAAWyE,GAClC93B,EAAWmxB,kBAAkB5zE,MAAK,IAElC,MAAMw6E,EAAUx6E,MAAK,IAAiD,IAA/BA,MAAK,GAAemC,OAS3D,OARIq4E,GACFx6E,KAAKy6E,oBAEPz6E,MAAK,GAAaiD,KAAKw/C,GACnB+3B,GACFx6E,KAAK06E,kBAGAj4B,CACT,CAQAC,oBAAAA,CAAqB37C,GACnB,OAAO/G,MAAK,GAAakqB,MAAK,SAAUzL,GACtC,OAAOA,EAAKw3D,aAAelvE,CAC7B,GACF,CAOA4zE,UAAAA,CAAW70B,GACT,GAAI,MAAOA,EACT,MAAM,IAAI5jD,MAAM,wCAEW,IAAzBlC,MAAK,GAASmC,QAChBnC,KAAKy6E,oBAEPz6E,MAAK,GAAW8lD,EAAKpjD,QACrB1C,KAAK06E,iBACP,CAKAjD,KAAAA,GACEz3E,KAAKy6E,oBACL,IAAK,IAAIl4E,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAC9CvC,MAAK,GAAauC,GAAGk1E,QAEvBz3E,MAAK,GAAe,GACpBA,MAAK,QAAyBQ,CAChC,CAOAm3E,oBAAAA,CAAqBpgB,GACnB,IAAK,MAAM9U,KAAcziD,MAAK,GAC5ByiD,EAAWk1B,qBAAqBpgB,EAEpC,CAOAqjB,gBAAAA,CAAiBn4B,GAEf,MAAMn1C,EAAQtN,MAAK,GAAaksC,WAAWztB,GAASA,IAASgkC,IAC7D,IAAe,IAAXn1C,EACF,MAAM,IAAIpL,MAAM,oCAGlBlC,KAAKy6E,oBAELh4B,EAAWg1B,QAEXz3E,MAAK,GAAa8hB,OAAOxU,EAAO,GAE5BtN,MAAK,KAA2BsN,IAClCtN,MAAK,QAAyBQ,GAGhCR,KAAK06E,iBACP,CAKAzrB,KAAAA,GACE,IAAK,IAAI1sD,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAC9CvC,MAAK,GAAauC,GAAG0sD,OAEzB,CAKAF,IAAAA,GACE,IAAK,IAAIxsD,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAC9CvC,MAAK,GAAauC,GAAGwsD,MAEzB,CAMAsJ,cAAAA,GAEE,IAAIwiB,EACJ,MAAMC,EAAW,GACjB,IAAK,IAAIv4E,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAAG,CACjD,MAAMmlB,EAAQ1nB,MAAK,GAAauC,GAAGw2E,8BACd,IAAVrxD,IACTozD,EAAS73E,KAAKV,SACU,IAAbs4E,GAA4BnzD,EAAQmzD,KAC7CA,EAAWnzD,GAGjB,CAEA,QAAwB,IAAbmzD,EAIX,IAAK,IAAIz3E,EAAI,EAAGA,EAAIpD,MAAK,GAAamC,SAAUiB,EAC1C03E,EAASnqE,SAASvN,IACpBpD,MAAK,GAAaoD,GAAGi1D,eAAewiB,EAG1C,CAKAH,eAAAA,GACE,GAAiC,IAA7B16E,MAAK,GAAamC,QACS,IAA7BnC,MAAK,GAAamC,QACO,IAAzBnC,MAAK,GAASmC,OAFhB,CAMAnC,MAAK,GAAiB,IAAIof,MAAMpf,MAAK,GAAamC,QAElD,IAAK,IAAII,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAC9C,IAAK,IAAIa,EAAI,EAAGA,EAAIpD,MAAK,GAASmC,SAAUiB,EAC1CpD,MAAK,GAAmBuC,EAAGvC,MAAK,GAASoD,GAN7C,CASF,CAKAq3E,iBAAAA,GACE,GAAiC,IAA7Bz6E,MAAK,GAAamC,QACS,IAA7BnC,MAAK,GAAamC,QACO,IAAzBnC,MAAK,GAASmC,QACbnC,MAAK,GAHR,CAOA,IAAK,IAAIuC,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAC9C,IAAK,IAAIa,EAAI,EAAGA,EAAIpD,MAAK,GAASmC,SAAUiB,EAC1CpD,MAAK,GAAsBuC,EAAGvC,MAAK,GAASoD,IAIhDpD,MAAK,GAAiB,IARtB,CASF,CAOA4zE,iBAAAA,CAAkBh4C,GAChB57B,MAAK,GAAkB47B,EAEvB,IAAK,IAAIr5B,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAC9CvC,MAAK,GAAauC,GAAGqxE,kBAAkBh4C,EAE3C,CAUA,IAAmBm/C,EAAQztE,QACiB,IAA/BtN,MAAK,GAAesN,KAC7BtN,MAAK,GAAesN,GAAS,IAG/B,IAAI0tE,EADUh7E,MAAK,GAAesN,GACZ4c,MAAK,SAAU+wD,GACnC,OAAOA,EAAKF,SAAWA,CACzB,IAgBA,YAfyB,IAAdC,IAETA,EAAY,CACVD,OAAQA,EACRp5D,SAAWK,IAEThiB,MAAK,GAAsBsN,EAAOytE,GAElCA,EAAOxB,YAAYv5E,MAAK,GAAasN,GAArCytE,CAA6C/4D,GAE7ChiB,MAAK,GAAmBsN,EAAOytE,EAAO,GAG1C/6E,MAAK,GAAesN,GAAOrK,KAAK+3E,IAE3BA,EAAUr5D,QACnB,CAQA,IAAmBrU,EAAOytE,GACxB,IAAK,IAAIx4E,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAC1CA,IAAM+K,GACRtN,MAAK,GAAasN,GAAOynC,iBACvBgmC,EAAOzB,eACPt5E,MAAK,GAAmB+6E,EAAQx4E,GAIxC,CAQA,IAAsB+K,EAAOytE,GAC3B,IAAK,IAAIx4E,EAAI,EAAGA,EAAIvC,MAAK,GAAamC,SAAUI,EAC1CA,IAAM+K,GACRtN,MAAK,GAAasN,GAAO0nC,oBACvB+lC,EAAOzB,eACPt5E,MAAK,GAAmB+6E,EAAQx4E,GAIxC,EClhBK,MAAM24E,GAMX,IAKAl5E,WAAAA,CAAYu1D,GACVv3D,MAAK,GAAUu3D,CACjB,CAQA4jB,QAAAA,CAASC,GACP,MAAMnoE,EAAOu2B,KAAKtpB,MAAMk7D,GACxB,IAAItyE,EAAM,KACV,GAAqB,QAAjBmK,EAAKooE,QACPvyE,EAAM9I,MAAK,GAASiT,QACf,GAAqB,QAAjBA,EAAKooE,QACdvyE,EAAM9I,MAAK,GAASiT,QACf,GAAqB,QAAjBA,EAAKooE,QACdvyE,EAAM9I,MAAK,GAASiT,QACf,GAAqB,QAAjBA,EAAKooE,QACdvyE,EAAM9I,MAAK,GAASiT,OACf,IAAqB,QAAjBA,EAAKooE,QAGd,MAAM,IAAIn5E,MAAM,uCACd+Q,EAAKooE,QAAU,MAHjBvyE,EAAM9I,MAAK,GAASiT,EAItB,CACA,OAAOnK,CACT,CAQAhF,KAAAA,CAAMq+C,EAAKlvC,GACT,MACM2vC,EADaT,EAAIinB,sBAEVvmB,qBAAqBC,oBAE5Bj9C,EAAK,IAAIX,EAAY+N,EAAK,iBAAkBA,EAAK,iBACvD2vC,EAAe1J,eAAerzC,GAE9B+8C,EAAevK,gBAAgB,IAAIt2C,EAAMkR,EAAKoQ,WAE9C,MAAMi4D,EAAYn5B,EAAIinB,sBAAsB1gB,eAC5C,IAAIF,EAAQ,KACRtkD,EAAS,KACb,QAAgC,IAArB+O,EAAKsoE,YAA6B,CAC3C/yB,EAAQ,CACN//C,EAAGwK,EAAKu1C,MAAQ8yB,EAAU7yE,EAC1BC,EAAGuK,EAAKu1C,MAAQ8yB,EAAU5yE,EAC1BC,EAAG,GASL,MAAM6yE,EAAUvoE,EAAKsoE,YAAY9yE,EAAIwK,EAAKsoE,YAAY9yE,EAAIwK,EAAKu1C,MACzDizB,EAAUxoE,EAAKsoE,YAAY7yE,EAAIuK,EAAKsoE,YAAY7yE,EAAIuK,EAAKu1C,MACzDkzB,EAAQF,EAAUvoE,EAAKshD,YAAY9rD,EAAI+/C,EAAM//C,EAC7CkzE,EAAQF,EAAUxoE,EAAKshD,YAAY7rD,EAAI8/C,EAAM9/C,EACnDxE,EAAS,CACPuE,GAAIizE,EAAQlzB,EAAM//C,EAClBC,GAAIizE,EAAQnzB,EAAM9/C,EAClBC,EAAG,EAEP,MACE6/C,EAAQ,CACN//C,EAAGwK,EAAKu1C,MAAM//C,EAAI6yE,EAAU7yE,EAC5BC,EAAGuK,EAAKu1C,MAAM9/C,EAAI4yE,EAAU5yE,EAC5BC,EAAG2yE,EAAU3yE,GAEfzE,EAAS,CACPuE,EAAGwK,EAAK/O,OAAOuE,EACfC,EAAGuK,EAAK/O,OAAOwE,EACfC,EAAG,GAGPw5C,EAAIinB,sBAAsBtT,SAAStN,GACnCrG,EAAIinB,sBAAsB3S,UAAUvyD,GAEpCi+C,EAAIy5B,YAAY3oE,EAAK4oE,SAAU5oE,EAAK6oE,gBAAiB97E,MAAK,GAC5D,CAQA,IAASiT,GAEP,MAAM8oE,EAmJV,SAAoCC,GAClC,MAAMC,EAAc,GACdH,EAAkB,CAAC,EAEzB,IAAII,EACAC,EAEJ,IAAK,IAAI1vE,EAAI,EAAGszB,EAAOi8C,EAAc75E,OAAQsK,EAAIszB,IAAQtzB,EAAG,CAE1DwvE,EAAYxvE,GAAK,GACjB,IAAK,IAAI6U,EAAI,EAAG86D,EAAOJ,EAAcvvE,GAAGtK,OAAQmf,EAAI86D,IAAQ96D,EAAG,CAE7D46D,EAAaF,EAAcvvE,GAAG6U,GAC9B,MAAM+6D,EAAmB,GAEzB,IAAK,IAAIp0E,EAAI,EAAGq0E,EAAOJ,EAAW/5E,OAAQ8F,EAAIq0E,IAAQr0E,EAAG,CAEvDk0E,EAAYpyB,KAAAA,KAAW72B,OAAOgpD,EAAWj0E,IAEzCk0E,EAAUvxB,SAAQ,GAElB,IAAIj7C,EAAM,CAAClH,EAAG,EAAGC,EAAG,GAEpB,MAAMmhD,EAASsyB,EAAUryB,aAAY,SAAUL,GAC7C,MAAuB,UAAhBA,EAAKjgD,MACd,IAAG,GAGH,GAFAqgD,EAAOQ,OAAO9gD,EAAgBsgD,EAAOQ,WAEZ,eAArB8xB,EAAU3yE,OAAyB,CAErC2yE,EAAU3yE,KAAK,eAEf,MAAM6nE,EAAS,IAAItnB,KAAAA,MAAW,CAC5BmC,OAAQ,CAACrC,EAAOqC,SAAS,GACvBrC,EAAOqC,SAAS,GAChBrC,EAAOqC,SAAS,GAChBrC,EAAOqC,SAAS,IAClB1iD,KAAM,gBAER2yE,EAAUj5E,IAAImuE,GACd,MAAMC,EAAS,IAAIvnB,KAAAA,MAAW,CAC5BmC,OAAQ,CAACrC,EAAOqC,SAAS,GACvBrC,EAAOqC,SAAS,GAChBrC,EAAOqC,SAAS,GAChBrC,EAAOqC,SAAS,IAClB1iD,KAAM,gBAER2yE,EAAUj5E,IAAIouE,EAChB,CAEA,MAAMiL,EAAQJ,EAAUryB,aAAY,SAAUL,GAC5C,MAAuB,QAAhBA,EAAKjgD,MACd,IACqB,IAAjB+yE,EAAMp6E,QACRo6E,EAAM,GAAG/yE,KAAK,aAGhB,MAAMgzE,EAASL,EAAUryB,aAAY,SAAUL,GAC7C,MAAuB,SAAhBA,EAAKjgD,MACd,IAEA,IAAIm5D,EAAQ,IAAI5Y,KAAAA,MAAW,CACzBvgD,KAAM,OACN0vD,KAAM,KAEc,IAAlBsjB,EAAOr6E,QACTwN,EAAIlH,EAAI+zE,EAAO,GAAG/zE,IAClBkH,EAAIjH,EAAI8zE,EAAO,GAAG9zE,IAElB8zE,EAAO,GAAG56D,SAEV+gD,EAAQ6Z,EAAO,IAGgB,IAA3B3yB,EAAOqC,SAAS/pD,SAClBwN,EAAM,CAAClH,EAAGohD,EAAOqC,SAAS,GACxBxjD,EAAGmhD,EAAOqC,SAAS,KAIzB,MAAMkX,EAAS,IAAIrZ,KAAAA,OAAY,CAC7BthD,EAAGkH,EAAIlH,EACPC,EAAGiH,EAAIjH,EACPc,KAAM,UAER45D,EAAOlgE,IAAIy/D,GACXS,EAAOlgE,IAAI,IAAI6mD,KAAAA,MAEfoyB,EAAUj5E,IAAIkgE,GAEdiZ,EAAiBp5E,KAAKumC,KAAKC,UAAU0yC,EAAUM,aAG/C,IAAIzpB,EAAW2P,EAAMzJ,OACrB,MAAMwjB,EAAS1pB,EAAS7wD,OACxB,IAAI6hD,EAAQ,KAEa,gBAArBm4B,EAAU3yE,QACZw6C,EAAQ,CACN7hD,OAAQ,CACNL,MAAOgtB,WAAWkkC,EAASpjD,UAAU,EAAG8sE,EAAS,IACjDhmD,KAAMs8B,EAASpjD,WAAW,KAG9BojD,EAAW,YACmB,kBAArBmpB,EAAU3yE,QACY,oBAArB2yE,EAAU3yE,QACpBw6C,EAAQ,CACN9gB,QAAS,CACPphC,MAAOgtB,WAAWkkC,EAASpjD,UAAU,EAAG8sE,EAAS,IACjDhmD,KAAMs8B,EAASpjD,WAAW,KAG9BojD,EAAW,aACmB,qBAArBmpB,EAAU3yE,QACY,oBAArB2yE,EAAU3yE,SACpBw6C,EAAQ,CACN/gB,MAAO,CACLnhC,MAAOgtB,WAAWkkC,EAASpjD,UAAU,EAAG8sE,EAAS,IACjDhmD,KAAMs8B,EAASpjD,WAAW,KAG9BojD,EAAW,WAGb8oB,EAAgBK,EAAUp1E,MAAQ,CAChCisD,SAAUA,EACV2pB,SAAU,GACV34B,MAAOA,EAGX,CACAi4B,EAAYxvE,GAAGxJ,KAAKo5E,EACtB,CACF,CAEA,MAAO,CAACR,SAAUI,EAAaH,gBAAiBA,EAClD,CA5RqBc,CAA2B3pE,EAAK4oE,UAQjD,OANA5oE,EAAK4oE,SAAWgB,GAAiBd,EAASF,UAAUY,WACpDxpE,EAAK6oE,gBAAkBgB,GACrBf,EAASD,kBAEX7oE,EAAO8pE,GAAa9pE,IACf4oE,SAAWmB,GAAiB/pE,EAAK4oE,UAC/B5oE,CACT,CAQA,IAASA,GAQP,OANAA,EAAK4oE,SAAWgB,GAAiB5pE,EAAK4oE,UAAUY,WAChDxpE,EAAK6oE,gBAAkBgB,GAkR3B,SAAiCG,GAC/B,MAAMn0E,EAAM,CAAC,EAEPo0E,EAAkC,iBAAZD,EACxBzzC,KAAKtpB,MAAM+8D,GAAWA,EAE1B,IAAK,IAAIxwE,EAAI,EAAGszB,EAAOm9C,EAAa/6E,OAAQsK,EAAIszB,IAAQtzB,EAEtD,IAAK,IAAI6U,EAAI,EAAG86D,EAAOc,EAAazwE,GAAGtK,OAAQmf,EAAI86D,IAAQ96D,EAEzD,IAAK,IAAIrZ,EAAI,EAAGq0E,EAAOY,EAAazwE,GAAG6U,GAAGnf,OAAQ8F,EAAIq0E,IAAQr0E,EAAG,CAC/D,MAAMsL,EAAQ2pE,EAAazwE,GAAG6U,GAAGrZ,GACjCa,EAAIyK,EAAMxM,IAAM,CACdisD,SAAUz/C,EAAMy/C,SAChB2pB,SAAUppE,EAAMopE,SAChB34B,MAAOzwC,EAAMywC,MAEjB,CAGJ,OAAOl7C,CACT,CAtSMq0E,CAAwBlqE,EAAK6oE,mBAE/B7oE,EAAO8pE,GAAa9pE,IACf4oE,SAAWmB,GAAiB/pE,EAAK4oE,UAC/B5oE,CACT,CAQA,IAASA,GAMP,OAJAA,EAAK6oE,gBAAkBgB,GAAwB7pE,EAAK6oE,kBAEpD7oE,EAAO8pE,GAAa9pE,IACf4oE,SAAWmB,GAAiB/pE,EAAK4oE,UAC/B5oE,CACT,CAQA,IAASA,GAIP,OAFAA,EAAO8pE,GAAa9pE,IACf4oE,SAAWmB,GAAiB/pE,EAAK4oE,UAC/B5oE,CACT,CAOA,IAASA,GACP,OAAOA,CACT,EAYF,SAAS4pE,GAAiBhB,GAExB,IAAItoE,EAAO6pE,EAAaC,EAmBxB,MAAM5uB,EAAY,IAAI1E,KAAAA,OAAY,CAChCmN,WAAW,EACXtM,SAAS,IAIL0yB,EAAoC,iBAAbzB,EACzBryC,KAAKtpB,MAAM27D,GAAYA,EAE3B,IAAK,IAAIpvE,EAAI,EAAGszB,EAAOu9C,EAAcn7E,OAAQsK,EAAIszB,IAAQtzB,EAEvD,IAAK,IAAI6U,EAAI,EAAG86D,EAAOkB,EAAc7wE,GAAGtK,OAAQmf,EAAI86D,IAAQ96D,EAE1D,GADA87D,EAAcE,EAAc7wE,GAAG6U,GACJ,IAAvB87D,EAAYj7E,OAAc,CAE5Bk7E,EAAc,IAAItzB,KAAAA,OAAY,CAC5BhjD,IAvBwBw2E,EAuBG,IAAIx7E,EAAM,CAAC,EAAG,EAAG0K,EAAG6U,IAnB9C,SAHai8D,EAAgBl8E,IAAI,GAGR,WAFiB,IAA7Bk8E,EAAgBp7E,SAChCo7E,EAAgBl8E,IAAI,GAAK,IAqBvBmI,KAAM,iBACNohD,SAAS,IAIX,IAAK,IAAI3iD,EAAI,EAAGq0E,EAAOc,EAAYj7E,OAAQ8F,EAAIq0E,IAAQr0E,EAErDsL,EAAQw2C,KAAAA,KAAW72B,OAAOkqD,EAAYn1E,IAGtCsL,EAAMo3C,WAAU,GAChBp3C,EAAMu2C,cAAcsF,SAAQ,SAAUouB,GACpCA,EAAM7yB,WAAU,EAClB,IAEA0yB,EAAYn6E,IAAIqQ,GAGlBk7C,EAAUvrD,IAAIm6E,EAChB,CA3CJ,IAAgCE,EA+ChC,OAAO9uB,CACT,CA4LA,SAASquB,GAAwBG,GAC/B,MAAMn0E,EAAM,CAAC,EACPgK,EAAO5R,OAAO4R,KAAKmqE,GAEzB,IAAK,IAAIxwE,EAAI,EAAGszB,EAAOjtB,EAAK3Q,OAAQsK,EAAIszB,IAAQtzB,EAAG,CACjD,MAAMgxE,EAASR,EAAQnqE,EAAKrG,IAC5B3D,EAAIgK,EAAKrG,IAAM,CACb+nB,KAAM,CACJw+B,SAAUyqB,EAAOzqB,SACjB2pB,SAAUc,EAAOd,SACjBhL,eAAgB8L,EAAOz5B,OAG7B,CACA,OAAOl7C,CACT,CAUA,SAASi0E,GAAa9pE,GACpB,MAAMtD,EAAMsD,EAAKoQ,SAEjB,OADApQ,EAAKoQ,SAAW,CAAC1T,EAAIpN,EAAGoN,EAAIvM,EAAGuM,EAAIlD,GAC5BwG,CACT,CAUA,SAAS+pE,GAAiBhB,GAExB,MAAMhjB,EAAYgjB,EAAcroB,SAChC,IAAK,IAAIlnD,EAAI,EAAGszB,EAAOi5B,EAAU72D,OAAQsK,EAAIszB,IAAQtzB,EAAG,CACtD,MAAMkrD,EAAWqB,EAAUvsD,GAErBixE,EADK/lB,EAASgmB,MAAM52E,GACXqI,MAAM,KACfwuE,EAAc/mE,SAAS6mE,EAAI,GAAG9tE,UAAU,GAAI,IAC5CiuE,EAAchnE,SAAS6mE,EAAI,GAAG9tE,UAAU,GAAI,IAClD,IAAIkuE,EAAQ,MAEVA,GADkB,IAAhBF,GAAqC,IAAhBC,EACdA,EAEAD,EAEXjmB,EAASgmB,MAAM52E,GAAK+2E,CACtB,CACA,OAAO9B,CACT,CCtgBO,SAAS+B,GAAcC,GAG5B,IAAIC,EAIJ,MAH+B,SAA3Bh9B,OAAOi9B,SAASh2D,SAClB+1D,EAAOh9B,OAAOi9B,SAASh2D,QAElB,IAAIi2D,IAAIH,EAAKC,EACtB,CAYO,SAASG,GAASJ,GAEvB,MAAM5hE,EAAS,CAAC,EAEhB,IAAIiiE,EAAW,KACf,GAAIL,IAA0C,KAAlCK,EAAWL,EAAIzwE,QAAQ,MAAc,CAE/C6O,EAAO6hE,KAAOD,EAAIpuE,UAAU,EAAGyuE,GAE/B,IAAIC,EAAYN,EAAIzwE,QAAQ,MACT,IAAf+wE,IACFA,EAAYN,EAAI77E,QAElB,MAAMo8E,EAAQP,EAAIpuE,UAAUyuE,EAAW,EAAGC,GAE1CliE,EAAOmiE,M7EaJ,SAA6BxuE,GAElC,MAAMqM,EAAS,CAAC,EAEhB,GAAIrM,EAAU,CAEZ,MAAMyuE,EAAQzuE,EAASX,MAAM,KAC7B,IAAK,IAAI7M,EAAI,EAAGA,EAAIi8E,EAAMr8E,SAAUI,EAAG,CACrC,MAAMk8E,EAAOD,EAAMj8E,GAAG6M,MAAM,KAEvBgN,EAAOqiE,EAAK,KAITriE,EAAOqiE,EAAK,cAAer/D,QAC/BhD,EAAOqiE,EAAK,IAAM,CAACriE,EAAOqiE,EAAK,MAEjCriE,EAAOqiE,EAAK,IAAIx7E,KAAKw7E,EAAK,KAN1BriE,EAAOqiE,EAAK,IAAMA,EAAK,EAQ3B,CACF,CACA,OAAOriE,CACT,C6EnCmBsiE,CAAoBH,EACrC,CAEA,OAAOniE,CACT,CC3CO,MAAMuiE,GAMX,IAAS,GAOT,IAAe,EAOf,IAAmB,IAAIl9D,GAOvBm9D,YAAAA,GACE,OAAO5+E,MAAK,GAAOmC,MACrB,CAOA08E,oBAAAA,GACE,OAAO7+E,MAAK,EACd,CAQAkD,GAAAA,CAAI47E,GAEF9+E,MAAK,GAASA,MAAK,GAAO0C,MAAM,EAAG1C,MAAK,IAExCA,MAAK,GAAOiD,KAAK67E,KAEf9+E,MAAK,GAUPA,MAAK,GAAW,CACd0hB,KAAM,UACN4lC,QAASw3B,EAAI3kB,WAEjB,CASAv4C,MAAAA,CAAOpY,GACL,IAAIV,GAAM,EACV,MAGMwE,EAAQtN,MAAK,GAAOksC,WAHL,SAAUr6B,GAC7B,OAAOA,EAAQsoD,YAAc3wD,CAC/B,IAuBA,OArBe,IAAX8D,IAEFtN,MAAK,GAAO8hB,OAAOxU,EAAO,KAExBtN,MAAK,GAEP8I,GAAM,EAUN9I,MAAK,GAAW,CACd0hB,KAAM,aACN4lC,QAAS99C,KAGNV,CACT,CAOAsxD,IAAAA,GAEMp6D,MAAK,GAAe,MAEpBA,MAAK,GAEPA,MAAK,GAAOA,MAAK,IAAco6D,OAS/Bp6D,MAAK,GAAW,CACd0hB,KAAM,OACN4lC,QAAStnD,MAAK,GAAOA,MAAK,IAAcm6D,YAG9C,CAOA4kB,IAAAA,GACM/+E,MAAK,GAAeA,MAAK,GAAOmC,SAElCnC,MAAK,GAAOA,MAAK,IAAcwnD,UAS/BxnD,MAAK,GAAW,CACd0hB,KAAM,OACN4lC,QAAStnD,MAAK,GAAOA,MAAK,IAAcm6D,cAGxCn6D,MAAK,GAEX,CASA+0C,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAcK,IACZhiB,MAAK,GAAiB+hB,UAAUC,EAAM,ECnLnC,MAAMg9D,GAOX,IAOA,IAAgB,KAOhB,IAAiB,GAOjB,IAAe,CAAC,EAKhBh9E,WAAAA,CAAYqjE,GACVrlE,MAAK,GAAYqlE,CACnB,CAKAptB,IAAAA,GACE,IAAK,MAAMj3C,KAAOhB,MAAK,GACrBA,MAAK,GAAUgB,GAAKi3C,OAGtBj4C,KAAKi/E,iBAAgB,EACvB,CAQAA,eAAAA,CAAgBrjD,GACVA,EACFqlB,OAAOlM,iBAAiB,UACtB/0C,MAAK,GAAa,SAAU,YAAY,GAE1CihD,OAAOjM,oBAAoB,UACzBh1C,MAAK,GAAa,SAAU,YAAY,EAE9C,CAOAk/E,WAAAA,GACE,OAAOl/E,MAAK,EACd,CAQAm/E,OAAAA,CAAQ31E,GACN,YAA2C,IAA7BxJ,KAAKk/E,cAAc11E,EACnC,CAOA41E,eAAAA,GACE,OAAOp/E,MAAK,EACd,CASAq/E,2BAAAA,CAA4BC,GAC1B,OAAOt/E,KAAKo/E,kBAAkBE,EAChC,CAOAC,eAAAA,CAAgB/1E,GAEd,IAAKxJ,KAAKm/E,QAAQ31E,GAChB,MAAM,IAAItH,MAAM,kBAAqBsH,EAAO,KAG1CxJ,MAAK,IACPA,MAAK,GAAcgxD,UAAS,GAG9BhxD,MAAK,GAAgBA,MAAK,GAAUwJ,GAEpCxJ,MAAK,GAAcgxD,UAAS,EAC9B,CAOAwuB,eAAAA,CAAgB15B,GACV9lD,KAAKo/E,mBACPp/E,KAAKo/E,kBAAkBvY,YAAY/gB,EAEvC,CAQA25B,cAAAA,CAAeh9B,EAAYqnB,GACzB,MAAMtE,EAAQ/iB,EAAWwzB,WAEzBxzB,EAAW1N,iBACT,oBAAqB/0C,MAAK,GAA6BwlE,IAEzDxlE,MAAK,GAAwBwlE,EAAOsE,EACtC,CAQA,IAAwB4V,EAAiB5V,QAEW,IAAvC9pE,MAAK,GAAa0/E,IAC3B1/E,MAAK,GAAaA,MAAK,GAAa0/E,IAGtC1/E,MAAK,GAAa0/E,GAAmB5V,EAErC9pE,MAAK,GAAW8pE,EAClB,CAQA,IAA6BtE,GAC3B,OAAQxjD,IACN,MAAM8nD,EAAQ9nD,EAAMlgB,MAAM,QACL,IAAVgoE,GACT9pE,MAAK,GAAwBwlE,EAAOsE,EACtC,CAEJ,CAOA,IAAWA,GACTA,EAAMrQ,kBAEN,MAAME,EAAQC,GACd,IAAK,IAAIr3D,EAAI,EAAGA,EAAIo3D,EAAMx3D,SAAUI,EAClCunE,EAAM/0B,iBAAiB4kB,EAAMp3D,GAC3BvC,MAAK,GAAa8pE,EAAM1U,QAASuE,EAAMp3D,IAE7C,CAOA,IAAaunE,GACXA,EAAMjQ,oBAEN,MAAMF,EAAQC,GACd,IAAK,IAAIr3D,EAAI,EAAGA,EAAIo3D,EAAMx3D,SAAUI,EAClCunE,EAAM90B,oBAAoB2kB,EAAMp3D,GAC9BvC,MAAK,GAAa8pE,EAAM1U,QAASuE,EAAMp3D,IAE7C,CAWA,IAAaknE,EAAS6V,GAKpB,QAJ4C,IAAjCt/E,MAAK,GAAeypE,KAC7BzpE,MAAK,GAAeypE,GAAW,SAGsB,IAA5CzpE,MAAK,GAAeypE,GAAS6V,GAA4B,CAClE,MAAMK,EAAqB39D,IAEzB,GAAIhiB,MAAK,GAAe,CACtB,MAAM8G,EAAO9G,MAAK,GAAcgiB,EAAMN,MAClC5a,GACFA,EAAKkb,EAET,GAGFhiB,MAAK,GAAeypE,GAAS6V,GAAaK,CAC5C,CAEA,OAAO3/E,MAAK,GAAeypE,GAAS6V,EACtC,ECtPK,MAAMM,GAWX,IAAc,GAOd,IAAsB,EAOtB,IAKA59E,WAAAA,CAAY2f,GACV3hB,MAAK,GAAY2hB,CACnB,CAOAk+D,qBAAAA,CAAsBC,GACpB9/E,MAAK,GAAsB8/E,CAC7B,CAOAC,UAAAA,CAAWr/E,GACT,IAAK,IAAI6B,EAAI,EAAGA,EAAI7B,IAAK6B,EAAG,CAC1BvC,MAAK,GAAYuC,GAAK,GACtB,IAAK,IAAIa,EAAI,EAAGA,EAAIpD,MAAK,KAAuBoD,EAC9CpD,MAAK,GAAYuC,GAAGa,GAAK,CAE7B,CACF,CAQA48E,WAAch+D,IAEZ,IAAKA,EAAMi+D,iBACT,OAEF,QAA8B,IAAnBj+D,EAAMk+D,SACf,OAEF,QAA2B,IAAhBl+D,EAAM1U,MACf,OAGF,MAAM6yE,EAA0B,IAAfn+D,EAAMo+D,OAAgBp+D,EAAMq+D,MAE7CrgF,MAAK,GAAYgiB,EAAM1U,OAAO0U,EAAMk+D,UAAYC,EAGhD,IAAI1hE,EAAO,KAETA,OADwB,IAAfuD,EAAMvD,KACRuD,EAAMvD,KAEN,CACL2hE,OAAQpgF,MAAK,GAAiBgiB,EAAM1U,OACpC+yE,MAAO,IACPC,OAAQt+D,EAAMs+D,QAKlBtgF,MAAK,GAAU,CACbigF,kBAAkB,EAClBG,OAAQpgF,MAAK,KACbqgF,MAAO,IACP5hE,KAAMA,GACN,EASJ,IAAiBnR,GACf,IAAIia,EAAM,EACV,IAAK,IAAInkB,EAAI,EAAGA,EAAIpD,MAAK,KAAuBoD,EAC9CmkB,GAAOvnB,MAAK,GAAYsN,GAAOlK,GAEjC,OAAOmkB,EAAMvnB,MAAK,EACpB,CAOA,MACE,IAAIunB,EAAM,EACV,MAAMg5D,EAAUvgF,MAAK,GAAYmC,OACjC,IAAK,IAAII,EAAI,EAAGA,EAAIg+E,IAAWh+E,EAC7BglB,GAAOvnB,MAAK,GAAiBuC,GAE/B,OAAOoB,KAAK0N,MAAMkW,EAAMg5D,EAC1B,CAeAC,sBAAAA,CAAuBlzE,EAAO4yE,GAC5B,OAAQl+D,IACNA,EAAM1U,MAAQA,EACd0U,EAAMk+D,SAAWA,EACjBlgF,KAAKggF,WAAWh+D,EAAM,CAE1B,CASAy+D,+BAAAA,CAAgCP,GAC9B,OAAQl+D,IACNA,EAAMk+D,SAAWA,EACjBlgF,KAAKggF,WAAWh+D,EAAM,CAE1B,ECzJK,MAAM0+D,GAOX,IAAa,KAOb,IAAY,GAOZ,IAAiB,KAOjB,IAAS,EAOT,IAAY,EAOZ,IAOA,GAOA1iE,sBAAAA,GACE,OAAOhe,MAAK,CACd,CAOAie,sBAAAA,CAAuBC,GACrBle,MAAK,EAAuBke,CAC9B,CAOA,IAAgBjL,GACdjT,MAAK,GAAaiT,EAElBjT,MAAK,GAAS,EACdA,MAAK,GAAY,EAEjBA,MAAK,IAAY,EAEjBA,MAAK,KACLA,MAAK,IACP,CAOA,IAAc2gF,GACZ3gF,MAAK,GAAUiD,KAAK09E,EACtB,CAMA,MACE3gF,MAAK,GAAY,EACnB,CAOA,IAAa4gF,GACX5gF,MAAK,GAAiB4gF,CACxB,CAMA,MACE5gF,MAAK,GAAiB,IACxB,CAQA,IAAYolE,IACVplE,MAAK,KAIDA,MAAK,KAAWA,MAAK,GAAWmC,QAClCnC,KAAK6gF,OAAO,CACVP,OAAQtgF,MAAK,IAEjB,EASF,IAAeolE,IACbplE,MAAK,KAIDA,MAAK,KAAcA,MAAK,GAAWmC,QACrCnC,KAAK8gF,UAAU,CACbR,OAAQtgF,MAAK,IAEjB,EAeF,IAAsB2hB,EAAU2+D,GAC9B,OAAQt+D,IACNA,EAAMs+D,OAASA,EACf3+D,EAASK,EAAM,CAEnB,CAQA++D,IAAAA,CAAK9tE,EAAMk3D,GAETnqE,KAAKghF,YAAY,CACfV,OAAQrtE,IAIU,IAAhBA,EAAK9Q,SACN0N,EAASoD,EAAK,GAAI,aACnBpD,EAASoD,EAAK,GAAI,YAClBjT,MAAK,GAAciT,EAAK,GAAIk3D,GAE5BnqE,MAAK,GAAUiT,EAAMk3D,EAEzB,CAUA,IAAgByW,EAAQ7gE,EAAaxd,GACnC,OAAQyf,IAIN,MAAMi/D,EAASj/D,EAAM8tC,OAAOmxB,OACb,MAAXA,GAA6B,IAAXA,GACpBjhF,KAAKkhF,QAAQ,CACXZ,OAAQvgE,EACR9a,MAAO,OAAS+c,EAAM8tC,OAAOqxB,YAC3B,IAAMn/D,EAAM8tC,OAAOmxB,OACnB,KAAOj/D,EAAM8tC,OAAOsxB,WAAa,IACnCtxB,OAAQ9tC,EAAM8tC,SAEhB9vD,MAAK,MAEL4gF,EAAOG,KAAK/+D,EAAM8tC,OAAOuxB,SAAUthE,EAAaxd,EAClD,CAEJ,CAYA,IAAU0Q,EAAMk3D,GAEd,QAAoB,IAATl3D,GAAwC,IAAhBA,EAAK9Q,OACtC,OAEFnC,MAAK,GAAgBiT,GAGrB,MAAMquE,EAAe,IAAI1B,GAAqB5/E,KAAKggF,YACnDsB,EAAavB,WAAW9sE,EAAK9Q,QAG7B,MAAMo/E,EAAU,GAChB,IAAK,IAAIj2E,EAAI,EAAGA,EAAIk2E,GAAWr/E,SAAUmJ,EACvCi2E,EAAQt+E,KAAK,IAAIu+E,GAAWl2E,IAI9B,IAAIyU,EAAc9M,EAAK,GACnB2tE,EAAS,KACTa,GAAc,EAClB,IAAK,IAAIp+E,EAAI,EAAGA,EAAIk+E,EAAQp/E,SAAUkB,EAEpC,GADAu9E,EAASW,EAAQl+E,GACbu9E,EAAOc,WAAW3hE,EAAaoqD,GAAU,CAC3CsX,GAAc,EAEdb,EAAO1W,WAAW,CAChB92C,cAAengB,EAAK9Q,OACpBw/E,oBAAqB3hF,KAAKge,2BAI5B4iE,EAAOZ,WAAasB,EAAab,gCAAgC,GACjEG,EAAOgB,WAAa5hF,KAAK4hF,WACzBhB,EAAOC,OAAS7gF,MAAK,GACrB4gF,EAAOE,UAAY9gF,MAAK,GACxB4gF,EAAOM,QAAUlhF,KAAKkhF,QACtBN,EAAOiB,QAAU7hF,KAAK6hF,QAGtB7hF,MAAK,GAAa4gF,GAElB,KACF,CAEF,IAAKa,EACH,MAAM,IAAIv/E,MAAM,4BAA8B6d,GAIhD,IAAI+hE,EAAsB,EAC1B,MAAMC,EAAmBA,KAEnBD,EAAsB9hF,MAAK,GAAUmC,OAAS,IAAMnC,MAAK,OACzD8hF,EACF9hF,MAAK,GAAU8hF,GAAqBE,KAAK,MAC3C,EAIF,IAAK,IAAIz/E,EAAI,EAAGA,EAAI0Q,EAAK9Q,SAAUI,EAAG,CAIpC,GAHAwd,EAAc9M,EAAK1Q,IAGdq+E,EAAOc,WAAW3hE,EAAaoqD,GAClC,MAAM,IAAIjoE,MAAM,gCAAkC6d,GASpD,MAAM4gE,EAAU,IAAIsB,eAIpB,GAHAtB,EAAQuB,KAAK,MAAOniE,GAAa,QAGV,IAAZoqD,EAAyB,CAElC,QAAsC,IAA3BA,EAAQgY,eAAgC,CACjD,MAAMA,EAAiBhY,EAAQgY,eAC/B,IAAK,IAAI/+E,EAAI,EAAGA,EAAI++E,EAAehgF,SAAUiB,OACL,IAA3B++E,EAAe/+E,GAAGoG,WACQ,IAA5B24E,EAAe/+E,GAAGtB,OACzB6+E,EAAQyB,iBACND,EAAe/+E,GAAGoG,KAAM24E,EAAe/+E,GAAGtB,MAGlD,MAGuC,IAA5BqoE,EAAQkY,kBACjB1B,EAAQ0B,gBAAkBlY,EAAQkY,gBAEtC,CAIA1B,EAAQX,WAAahgF,MAAK,GACxBshF,EAAad,uBAAuBj+E,EAAG,GAAIwd,GAC7C4gE,EAAQE,OAAS7gF,MAAK,GAAgB4gF,EAAQ7gE,EAAaxd,GAC3Do+E,EAAQG,UAAYiB,EACpB,MAAMO,EACJtiF,MAAK,GAAsBA,KAAKkhF,QAASnhE,GAC3C4gE,EAAQO,QAAWl/D,IACjBhiB,MAAK,KACLsiF,EAActgE,EAAM,EAEtB,MAAMugE,EACJviF,MAAK,GAAsBA,KAAK6hF,QAAS9hE,GAC3C4gE,EAAQkB,QAAW7/D,IACjBhiB,MAAK,KACLuiF,EAAcvgE,EAAM,EAnWb,IAsWL4+D,EAAO4B,cACT7B,EAAQ8B,aAAe,eAIzBziF,MAAK,GAAc2gF,EACrB,CAGA,IAAI+B,EAAY1iF,MAAK,GAAUmC,YACR,IAAZgoE,QAEwB,IAAtBA,EAAQuY,WAA2C,IAAdA,IAC9CA,EAAY/+E,KAAKgjB,IAAIwjD,EAAQuY,UAAW1iF,MAAK,GAAUmC,SAG3D,IAAK,IAAIR,EAAI,EAAGA,EAAI+gF,IAAa/gF,EAC1B3B,MAAK,KACR8hF,EAAsBngF,EACtB3B,MAAK,GAAU8hF,GAAqBE,KAAK,MAG/C,CAQA,IAAcW,EAAaxY,GAEzB,MAAMwW,EAAU,IAAIsB,eACpBtB,EAAQuB,KAAK,MAAOS,GAAa,GACjChC,EAAQ8B,aAAe,cAKvB9B,EAAQE,OAAU7+D,IAEhB,MAAMi/D,EAASj/D,EAAM8tC,OAAOmxB,OAC5B,GAAe,MAAXA,GAA6B,IAAXA,EACpBjhF,KAAKkhF,QAAQ,CACXZ,OAAQqC,EACR19E,MAAO,OAAS+c,EAAM8tC,OAAOqxB,YAC3B,IAAMn/D,EAAM8tC,OAAOmxB,OACnB,KAAOj/D,EAAM8tC,OAAOsxB,WAAa,IACnCtxB,OAAQ9tC,EAAM8tC,SAEhB9vD,KAAK8gF,UAAU,CAAC,OACX,CAEL,MAEM8B,EjE8hBP,SAAiC3vE,GAEtC,MAAM4vE,EAAS,IAAI9kE,GACnB8kE,EAAO3iE,MAAMjN,GACb,MAAMgN,EAAW4iE,EAAOxkE,mBAGxB,QAAoC,IAAzB4B,EAAS,kBACoB,IAA/BA,EAAS,YAAYne,MAE5B,YADAqC,EAAOa,KAAK,mDAGd,MAAM89E,EAAS7iE,EAAS,YAAYne,MAEpC,GAAsB,IAAlBghF,EAAO3gF,OAET,YADAgC,EAAOa,KAAK,2DAId,MAAM+9E,EAAU,GAChB,IAAIC,EAAS,KACTC,EAAQ,KACZ,IAAK,IAAI1gF,EAAI,EAAGA,EAAIugF,EAAO3gF,SAAUI,EAAG,CAEtC,QAAqC,IAA1BugF,EAAOvgF,GAAG,kBACoB,IAAhCugF,EAAOvgF,GAAG,YAAYT,MAC7B,SAEF,MAAMohF,EAAUJ,EAAOvgF,GAAG,YAAYT,MAAM,GAG5C,GAAgB,UAAZohF,EACFD,EAAQ,GACRF,EAAQ9/E,KAAKggF,QACR,GAAgB,WAAZC,EACTF,EAAS,GACTC,EAAMhgF,KAAK+/E,QACN,GAAgB,UAAZE,EAAqB,CAE9B,QAAqC,IAA1BJ,EAAOvgF,GAAG,kBACoB,IAAhCugF,EAAOvgF,GAAG,YAAYT,MAC7B,SAEF,MAAMqhF,EAAaL,EAAOvgF,GAAG,YAAYT,MAEzCkhF,EAAO//E,KAAKkgF,EAAW1iD,KAAK,KAC9B,CACF,CACA,OAAOsiD,CACT,CiEjlBqBK,CAAwBphE,EAAM8tC,OAAOuxB,UAEhC,GAAG,GAEfgC,EAAsBV,EjFpQtBvzE,MAAM,KAAK1M,MAAM,GAAI,GAAG+9B,KAAK,KiFqQ7B6iD,EAAW,GACjB,IAAK,IAAI/gF,EAAI,EAAGA,EAAIqgF,EAAKzgF,SAAUI,EACjC+gF,EAASrgF,KAAKogF,EAAU,IAAMT,EAAKrgF,IAGrCvC,MAAK,GAAUsjF,EAAUnZ,EAC3B,GAEFwW,EAAQO,QAAWl/D,IACjBhiB,MAAK,GAAsBA,KAAKkhF,QAASyB,EAAzC3iF,CAAsDgiB,GACtDhiB,KAAK8gF,UAAU,CAAC,EAAE,EAEpBH,EAAQkB,QAAW7/D,IACjBhiB,MAAK,GAAsBA,KAAK6hF,QAASc,EAAzC3iF,CAAsDgiB,GACtDhiB,KAAK8gF,UAAU,CAAC,EAAE,EAIpBH,EAAQqB,KAAK,KACf,CAKAuB,KAAAA,GACEvjF,MAAK,IAAY,EAEjB,IAAK,IAAIuC,EAAI,EAAGA,EAAIvC,MAAK,GAAUmC,SAAUI,EAEN,IAAjCvC,MAAK,GAAUuC,GAAGihF,YACpBxjF,MAAK,GAAUuC,GAAGghF,QAIlBvjF,MAAK,IAAkBA,MAAK,GAAeyjF,aAC7CzjF,MAAK,GAAeujF,OAExB,CAQAvC,WAAAA,CAAY5b,GAAS,CAQrB4a,UAAAA,CAAW5a,GAAS,CASpBwc,UAAAA,CAAWxc,GAAS,CASpByb,MAAAA,CAAOzb,GAAS,CAShB0b,SAAAA,CAAU1b,GAAS,CAQnB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,ECngBZ,MAAMse,GAKX1hF,WAAAA,CAAY2hF,GACV3jF,KAAK2jF,SAAWA,EAEhB3jF,KAAK4jF,UAAY,GAEjB5jF,KAAK6jF,YAAc,GAEnB,IAAK,IAAIthF,EAAI,EAAGA,EAAIohF,IAAYphF,EAC9BvC,KAAK6jF,YAAY5gF,KAAK,IAAI6gF,GAAa9jF,OAGzCA,KAAK+jF,eAAiB,EACxB,CAQAC,aAAAA,CAAcC,GAMZ,GAJIjkF,KAAK6jF,YAAY1hF,SAAWnC,KAAK2jF,UACnC3jF,KAAKkkF,YAAY,CAACxiE,KAAM,eAGtB1hB,KAAK6jF,YAAY1hF,OAAS,EAAG,CAE/B,MAAMgiF,EAAenkF,KAAK6jF,YAAYO,QAEtCpkF,KAAK+jF,eAAe9gF,KAAKkhF,GAEzBA,EAAahZ,IAAI8Y,EACnB,MAEEjkF,KAAK4jF,UAAU3gF,KAAKghF,EAExB,CAKAV,KAAAA,GAEEvjF,MAAK,KAELA,KAAK6hF,QAAQ,CAACngE,KAAM,eACpB1hB,KAAKqkF,UAAU,CAAC3iE,KAAM,YACxB,CAOA4iE,SAAAA,CAAUH,GAER,GAAInkF,KAAK4jF,UAAUzhF,OAAS,EAAG,CAE7B,MAAM8hF,EAAajkF,KAAK4jF,UAAUQ,QAElCD,EAAahZ,IAAI8Y,EACnB,KAAO,CAELE,EAAa/iC,OAEbphD,KAAK6jF,YAAY5gF,KAAKkhF,GAEtB,IAAK,IAAI5hF,EAAI,EAAGA,EAAIvC,KAAK+jF,eAAe5hF,SAAUI,EAC5CvC,KAAK+jF,eAAexhF,GAAG6yD,UAAY+uB,EAAa/uB,SAClDp1D,KAAK+jF,eAAejiE,OAAOvf,EAAG,GAI9BvC,KAAK6jF,YAAY1hF,SAAWnC,KAAK2jF,WACnC3jF,KAAKukF,OAAO,CAAC7iE,KAAM,SACnB1hB,KAAKqkF,UAAU,CAAC3iE,KAAM,aAE1B,CACF,CAOA8iE,kBAAqBxiE,IAEnBhiB,MAAK,KAELA,KAAKkhF,QAAQ,CAACj8E,MAAO+c,IACrBhiB,KAAKqkF,UAAU,CAAC3iE,KAAM,YAAY,EASpC,MAEE1hB,KAAK4jF,UAAY,GAEjB,IAAK,IAAIrhF,EAAI,EAAGA,EAAIvC,KAAK+jF,eAAe5hF,SAAUI,EAChDvC,KAAK+jF,eAAexhF,GAAG6+C,OAEzBphD,KAAK+jF,eAAiB,EACxB,CASAG,WAAAA,CAAY9e,GAAS,CASrBqf,UAAAA,CAAWrf,GAAS,CASpBmf,MAAAA,CAAOnf,GAAS,CAShBif,SAAAA,CAAUjf,GAAS,CAQnB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,EAenB,MAAM0e,GAKJ9hF,WAAAA,CAAY0iF,GACV1kF,KAAK0kF,WAAaA,EAElB1kF,KAAK+G,GAAKpD,KAAKmkB,SAAStlB,SAAS,IAAIoN,UAAU,EAAG,IAElD5P,KAAK2kF,YAAc,KAEnB3kF,KAAK4kF,MACP,CAOAxvB,KAAAA,GACE,OAAOp1D,KAAK+G,EACd,CAOAokE,GAAAA,CAAI8Y,GAEFjkF,KAAK2kF,YAAcV,OAEQ,IAAhBjkF,KAAK4kF,SACd5kF,KAAK4kF,OAAS,IAAIC,OAAO7kF,KAAK2kF,YAAYG,QAE1C9kF,KAAK4kF,OAAOG,UAAY/kF,KAAK+kF,UAC7B/kF,KAAK4kF,OAAO1D,QAAUlhF,KAAKkhF,SAG7BlhF,KAAK4kF,OAAOI,YAAYhlF,KAAK2kF,YAAYM,aAC3C,CAKA7jC,IAAAA,QAE6B,IAAhBphD,KAAK4kF,SACd5kF,KAAK4kF,OAAOM,YAEZllF,KAAK4kF,YAASpkF,EAElB,CASAukF,UAAa/iE,IAEXA,EAAMmjE,WAAanlF,KAAK2kF,YAAY5/E,KAAKogF,WACzCnjE,EAAMojE,cAAgBplF,KAAK2kF,YAAY5/E,KAAKqgF,cAC5CpjE,EAAM1U,MAAQtN,KAAK2kF,YAAY5/E,KAAKuI,MAEpCtN,KAAK0kF,WAAWD,WAAWziE,GAE3BhiB,KAAK0kF,WAAWJ,UAAUtkF,KAAK,EAQjCkhF,QAAWl/D,IAETA,EAAMmjE,WAAanlF,KAAK2kF,YAAY5/E,KAAKogF,WACzCnjE,EAAMojE,cAAgBplF,KAAK2kF,YAAY5/E,KAAKqgF,cAC5CpjE,EAAM1U,MAAQtN,KAAK2kF,YAAY5/E,KAAKuI,MAEpCtN,KAAK0kF,WAAWF,kBAAkBxiE,GAElChiB,KAAKohD,MAAM,EAOR,MAAMikC,GAMXrjF,WAAAA,CAAY8iF,EAAQ5nD,EAASn4B,GAE3B/E,KAAK8kF,OAASA,EAEd9kF,KAAKilF,aAAe/nD,EAEpBl9B,KAAK+E,KAAOA,CACd,ECxRF,MAAMugF,GAA+C,oBAAdC,UAUjCC,GAEa,oBAATC,WAAmD,IAAlBA,KAAKC,SAW1CC,GAA0C,oBAAbC,SAOtBC,GAAiB,CAC5Bh2D,SAAU,GACV,gBAAiB,GACjB,gBAAiB,GACjBi2D,IAAK,IAMP,MAAMC,GAOJ,IAOA,IAAQ,IAAIrC,GAAW,IAOvB,KAAmB,EAOnB1hF,WAAAA,CAAY8iF,EAAQkB,GAClBhmF,MAAK,GAAU8kF,CACjB,CASA3oE,MAAAA,CAAOgX,EAAa8yD,EAAWlhF,GACxB/E,MAAK,KACRA,MAAK,IAAmB,EAExBA,MAAK,GAAMkkF,YAAclkF,KAAKkmF,cAC9BlmF,MAAK,GAAMykF,WAAazkF,KAAKmmF,cAC7BnmF,MAAK,GAAMukF,OAASvkF,KAAKomF,UACzBpmF,MAAK,GAAMqkF,UAAYrkF,KAAKqmF,YAC5BrmF,MAAK,GAAMkhF,QAAUlhF,KAAKkhF,QAC1BlhF,MAAK,GAAM6hF,QAAU7hF,KAAK6hF,SAG5B,MAAMoC,EAAa,IAAIoB,GACrBrlF,MAAK,GACL,CACEmT,OAAQggB,EACRqB,KAAMyxD,GAERlhF,GAGF/E,MAAK,GAAMgkF,cAAcC,EAC3B,CAKAV,KAAAA,GAEEvjF,MAAK,GAAMujF,OACb,CAQA2C,aAAAA,CAAc9gB,GAAS,CASvB+gB,aAAAA,CAAc/gB,GAAS,CASvBghB,SAAAA,CAAUhhB,GAAS,CASnBihB,WAAAA,CAAYjhB,GAAS,CAQrB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,EAOnB,MAAMkhB,GAOJ,IAOA,IAMAtkF,WAAAA,CAAYukF,EAAUC,GACpBxmF,MAAK,GAAYumF,EACjBvmF,MAAK,GAAgBwmF,CACvB,CAGA,IAAe,EAYfrqE,MAAAA,CAAOgX,EAAa8yD,EAAWlhF,KAC3B/E,MAAK,GAEP,IAAIymF,EAAU,KACVC,EAAgB,KACpB,GAAuB,kBAAnB1mF,MAAK,GAA+B,CACtC,IAAKwlF,GACH,MAAM,IAAItjF,MAAM,qCAGlB,MAAM0W,EAAMqtE,EAAU1oE,cAAgB,EAChCopE,EAAM,IAAI71E,WAAWqiB,GAE3BszD,EAAU,IAAIhB,KAAKC,SAASkB,QAC5B,MAAMC,EAAUJ,EAAQtqE,OAAOwqE,EAAIxzE,OAAQ,EAAGwzE,EAAIxzE,OAAOH,WAAY4F,GACrC,IAA5BqtE,EAAU1oE,cAEVmpE,EADET,EAAU9/E,SACI,IAAI4S,UAAU8tE,EAAQ1zE,QAEtB,IAAIrC,WAAW+1E,EAAQ1zE,QAEJ,KAA5B8yE,EAAU1oE,gBAEjBmpE,EADET,EAAU9/E,SACI,IAAI6S,WAAW6tE,EAAQ1zE,QAEvB,IAAIyH,YAAYisE,EAAQ1zE,QAG9C,MAAO,GAAuB,kBAAnBnT,MAAK,GAA+B,CAC7C,IAAKslF,GACH,MAAM,IAAIpjF,MAAM,qCAGlBukF,EAAU,IAAIlB,UACdkB,EAAQvmE,MAAMiT,GACduzD,EAAgBD,EAAQjgB,QAAQigB,EAAQrhF,MAAOqhF,EAAQtjD,OACzD,MAAO,GAAuB,aAAnBnjC,MAAK,GAA0B,CACxC,IAAK2lF,GACH,MAAM,IAAIzjF,MAAM,iCAIlBukF,EAAU,IAAIb,SACda,EAAQvmE,MAAMiT,GAEduzD,EAAgBD,EAAQK,MAAM,GAAGxuE,KACnC,KAA8B,QAAnBtY,MAAK,KAGdymF,EAAU,IAAIM,WAAWC,WAEzBN,EAAgBD,EAAQtqE,OACtBgX,EACA8yD,EAAU1oE,cACV0oE,EAAU9/E,SACV8/E,EAAU7hE,UACV6hE,EAAUt2D,gBACVs2D,EAAU7xD,sBAGdp0B,KAAKmmF,cAAc,CACjBlzE,KAAM,CAACyzE,GACPp5E,MAAOvI,EAAKuI,MACZ83E,cAAergF,EAAKqgF,cACpBD,WAAYpgF,EAAKogF,aAGfnlF,MAAK,KAAiBA,MAAK,KAC7BA,KAAKomF,UAAU,CAAC,GAChBpmF,KAAKqmF,YAAY,CAAC,GAEtB,CAKA9C,KAAAA,GAGEvjF,KAAK6hF,QAAQ,CAAC,GACd7hF,KAAKqmF,YAAY,CAAC,EACpB,CAQAH,aAAAA,CAAc9gB,GAAS,CASvB+gB,aAAAA,CAAc/gB,GAAS,CASvBghB,SAAAA,CAAUhhB,GAAS,CASnBihB,WAAAA,CAAYjhB,GAAS,CAQrB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,EAUZ,MAAM6hB,GAOX,KAAmB,EAQnB,IAAgB,KAMhBjlF,WAAAA,CAAYukF,EAAUC,QAEU,IAAnBX,SAC2B,IAA7BA,GAAeU,GACtBvmF,MAAK,GAAgB,IAAI+lF,GACvBF,GAAeU,GAAWC,GAE5BxmF,MAAK,GAAgB,IAAIsmF,GACvBC,EAAUC,EAEhB,CASArqE,MAAAA,CAAOgX,EAAa8yD,EAAWlhF,GACxB/E,MAAK,KACRA,MAAK,IAAmB,EAExBA,MAAK,GAAckmF,cAAgBlmF,KAAKkmF,cACxClmF,MAAK,GAAcmmF,cAAgBnmF,KAAKmmF,cACxCnmF,MAAK,GAAcomF,UAAYpmF,KAAKomF,UACpCpmF,MAAK,GAAcqmF,YAAcrmF,KAAKqmF,YACtCrmF,MAAK,GAAckhF,QAAUlhF,KAAKkhF,QAClClhF,MAAK,GAAc6hF,QAAU7hF,KAAK6hF,SAGpC7hF,MAAK,GAAcmc,OAAOgX,EAAa8yD,EAAWlhF,EACpD,CAKAw+E,KAAAA,GAEEvjF,MAAK,GAAcujF,OACrB,CAQA2C,aAAAA,CAAc9gB,GAAS,CASvB+gB,aAAAA,CAAc/gB,GAAS,CASvBghB,SAAAA,CAAUhhB,GAAS,CASnBihB,WAAAA,CAAYjhB,GAAS,CAQrB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,ECxcnB,MAAMtnD,GAAU,CACdopE,aAAc,WACdC,mBAAoB,WACpBC,uBAAwB,WACxBC,yBAA0B,WAC1BC,6BAA8B,YAQzB,MAAMC,GAIXC,aAKAC,mBAKAC,uBAKAC,yBAKAC,qBAOAplF,QAAAA,GACE,OAAOxC,KAAKwnF,aAAe,IACzBxnF,KAAK4nF,qBAAqBplF,UAC9B,EA2CK,SAASqlF,GAA0B/lF,GAExC,MAAM2c,EAAO,CAAC,EAqBd,YAnB0C,IAA/B3c,EAAM8lF,uBACfnpE,EAAK6oE,6BAA+B,CAClCxlF,MAAO,CAACogC,GAAiBpgC,EAAM8lF,8BAGK,IAA7B9lF,EAAM2lF,qBACfhpE,EAAK0oE,mBAAqBrlF,EAAM2lF,yBAEU,IAAjC3lF,EAAM4lF,yBACfjpE,EAAK2oE,uBAAyBtlF,EAAM4lF,6BAEQ,IAAnC5lF,EAAM6lF,2BACflpE,EAAK4oE,yBAA2BvlF,EAAM6lF,+BAEN,IAAvB7lF,EAAM0lF,eACf/oE,EAAKyoE,aAAeplF,EAAM0lF,cAIrB/oE,CACT,CC7GA,MAAMX,GAAU,CACdgqE,sBAAuB,WACvBC,kCAAmC,YAQ9B,MAAMC,GAIXC,cAKAC,0BAOA1lF,QAAAA,GACE,IAAIsG,EAAM9I,KAAKioF,cAAczlF,WAI7B,YAH8C,IAAnCxC,KAAKkoF,4BACdp/E,GAAO,IAAM9I,KAAKkoF,0BAA0B1lF,YAEvCsG,CACT,EA+BK,SAASq/E,GAA+BC,GAE7C,MAAM3pE,EAAO,CAAC,EAcd,YAZyC,IAA9B2pE,EAAYH,gBACrBxpE,EAAKqpE,sBAAwB,CAC3BhmF,MAAO,CAAC+lF,GAA0BO,EAAYH,uBAGG,IAA1CG,EAAYF,4BACrBzpE,EAAKspE,kCAAoC,CACvCjmF,MAAO,CAACogC,GAAiBkmD,EAAYF,8BAKlCzpE,CACT,CC3FA,MAAMX,GAAU,CACdkrB,sBAAuB,WACvBC,yBAA0B,YAQrB,MAAMo/C,GAIXzgD,sBAKAC,yBAOArlC,QAAAA,GACE,OAAOxC,KAAK6nC,yBAA2B,YACrC7nC,KAAK4nC,sBAAwB,GACjC,EASK,SAAS0gD,GAAwB15D,GACtC,MAAM25D,EAAM,IAAIF,GAWhB,YAT2D,IAAhDz5D,EAAa9Q,GAAQkrB,yBAC9Bu/C,EAAI3gD,sBACFhZ,EAAa9Q,GAAQkrB,uBAAuBlnC,MAAM,SAEQ,IAAnD8sB,EAAa9Q,GAAQmrB,4BAC9Bs/C,EAAI1gD,yBACFjZ,EAAa9Q,GAAQmrB,0BAA0BnnC,MAAM,IAGlDymF,CACT,CAQO,SAASC,GAAiCD,GAE/C,MAAM9pE,EAAO,CAAC,EAUd,YARyC,IAA9B8pE,EAAI3gD,wBACbnpB,EAAKuqB,sBAAwBu/C,EAAI3gD,4BAES,IAAjC2gD,EAAI1gD,2BACbppB,EAAKwqB,yBAA2Bs/C,EAAI1gD,0BAI/BppB,CACT,CCnEA,MAAMX,GAAU,CACd2qE,sBAAuB,WACvBC,sBAAuB,WACvBhgD,wBAAyB,YAQpB,MAAMigD,GAIXC,sBAKAC,sBAKAC,wBAKAC,YAOAvmF,QAAAA,GACE,OAAOxC,KAAK4oF,sBAAsBpmF,UACpC,EAkCK,SAASwmF,GAA2BT,GAEzC,MAAM9pE,EAAO,CAAC,EAgBd,YAdyC,IAA9B8pE,EAAIM,wBACbpqE,EAAKgqE,sBAAwBF,EAAIM,4BAEM,IAA9BN,EAAIK,wBACbnqE,EAAKiqE,sBAAwB,CAC3B5mF,MAAO,CAAC0mF,GAAiCD,EAAIK,+BAGN,IAAhCL,EAAIO,0BACbrqE,EAAKiqB,wBACH6/C,EAAIO,yBAIDrqE,CACT,CCzFA,MAAMX,GAAU,CACdmrE,0BAA2B,WAC3BC,YAAa,WACbC,YAAa,WACbC,YAAa,YAMFC,GACJ,QADIA,GAEC,aAFDA,GAGD,WAHCA,GAIH,SAJGA,GAKF,UAQJ,MAAMC,GAIXC,YAKAC,YAKAC,0BAKAV,YAOAvmF,QAAAA,GACE,OAAOxC,KAAKwpF,YACV,KAAOxpF,KAAKupF,YAAc,GAC9B,EAkCK,SAASG,GAA8BC,GAE5C,MAAMlrE,EAAO,CAAC,EAgBd,YAdgD,IAArCkrE,EAAOF,4BAChBhrE,EAAKwqE,0BAA4BU,EAAOF,gCAER,IAAvBE,EAAOJ,cAChB9qE,EAAKyqE,YAAcS,EAAOJ,kBAEM,IAAvBI,EAAOH,cAChB/qE,EAAK0qE,YAAcQ,EAAOH,kBAEM,IAAvBG,EAAOZ,cAChBtqE,EAAK2qE,YAAcO,EAAOZ,aAIrBtqE,CACT,CCjHA,MAAMX,GAAU,CACdorE,YAAa,WACbC,YAAa,WACbS,8BAA+B,WAC/BR,YAAa,YAQR,MAAMS,GAIXN,YAKAC,YAKAM,8BAKAf,YAOAvmF,QAAAA,GACE,OAAOxC,KAAKwpF,YACV,IAAMxpF,KAAKupF,YAAc,GAC7B,EAmCK,SAASQ,GAAgCJ,GAE9C,MAAMlrE,EAAO,CAAC,EAiBd,YAfkC,IAAvBkrE,EAAOJ,cAChB9qE,EAAKyqE,YAAcS,EAAOJ,kBAEM,IAAvBI,EAAOH,cAChB/qE,EAAK0qE,YAAcQ,EAAOH,kBAEwB,IAAzCG,EAAOG,gCAChBrrE,EAAKmrE,8BACHD,EAAOG,oCAEuB,IAAvBH,EAAOZ,cAChBtqE,EAAK2qE,YAAcO,EAAOZ,aAIrBtqE,CACT,CClEA,MAAMX,GAAU,CACd4qE,sBAAuB,WACvBsB,iBAAkB,WAClBC,UAAW,WACXC,wBAAyB,WACzBC,oBAAqB,WACrBC,gBAAiB,WACjBC,SAAU,WACVx4D,KAAM,WACNy4D,KAAM,WACNC,IAAK,WACLC,WAAY,WACZC,UAAW,WACXC,oBAAqB,YAQVC,GACD,WADCA,GAEI,iBAFJA,GAMG,gBASHC,GAAa,CACxB1xB,KAAM,OACN4mB,IAAK,MACLhyD,KAAM,OACN9B,KAAM,OACN3D,KAAM,OACNwiE,SAAU,WACVC,OAAQ,SACRC,MAAO,QACPC,UAAW,YACX5nE,MAAO,QACP6nE,SAAU,WACVtB,OAAQ,SACRuB,SAAU,WACVC,OAAQ,SACRl0B,UAAW,YACXm0B,MAAO,SAMIC,GAAwB,CACnCC,KAAM,YACNC,KAAM,OACNC,KAAM,OACNC,SAAU,WACVC,OAAQ,MACRC,MAAO,aACPC,UAAW,uBAQN,MAAMC,GAMXC,UAMAC,gBAMAC,iBAOAC,gBAOAnqF,MAKAE,WAAAA,CAAY8pF,GACV9rF,KAAK8rF,UAAYA,CACnB,CAQAtpF,QAAAA,CAASm4B,QACe,IAAXA,IACTA,EAAS,IAGX,IAAI7xB,EAAM,GAcV,QAZqC,IAA1B9I,KAAKgsF,mBACdljF,GAAO,IAAM9I,KAAKgsF,iBAAmB,MAGvCljF,GAAO9I,KAAK8rF,UAAY,UAEY,IAAzB9rF,KAAK+rF,kBACdjjF,GAAO9I,KAAK+rF,gBAAgBvpF,YAG9BsG,GAAO,MAAQ9I,KAAK8B,MAAMU,gBAEU,IAAzBxC,KAAKisF,gBACd,IAAK,MAAMxtE,KAAQze,KAAKisF,gBACtBnjF,GAAO,KAAO6xB,EAAS,KAAOlc,EAAKjc,SAASm4B,EAAS,MAIzD,OAAO7xB,CACT,EAwBK,SAASojF,GAAat9D,GAE3B,IAAIk9D,EAAY,QAC+B,IAApCl9D,EAAa9Q,GAAQmsE,aAC9B6B,EAAYl9D,EAAa9Q,GAAQmsE,WAAWnoF,MAAM,IAGpD,MAAMqqF,EAAU,IAAIN,GAAeC,GAenC,QAZsD,IAA3Cl9D,EAAa9Q,GAAQksE,oBAC9BmC,EAAQH,iBACNp9D,EAAa9Q,GAAQksE,kBAAkBloF,MAAM,SAGY,IAAlD8sB,EAAa9Q,GAAQosE,2BAC9BiC,EAAQJ,gBACN9pD,GAAQrT,EAAa9Q,GAAQosE,yBAAyBpoF,MAAM,KAK5DgqF,IAAclB,GAAW98D,KAC3Bq+D,EAAQrqF,MAAQmgC,GACdrT,EAAa9Q,GAAQqsE,qBAAqBroF,MAAM,SAC7C,GAAIgqF,IAAclB,GAAW9K,IAClCqM,EAAQrqF,ML9KL,SAA+B8sB,GACpC,MAAMw5D,EAAc,IAAIJ,GAYxB,YAV2D,IAAhDp5D,EAAa9Q,GAAQgqE,yBAC9BM,EAAYH,cDOT,SAA0Br5D,GAC/B,MAAM9sB,EAAQ,IAAIylF,GAuBlB,YArBkD,IAAvC34D,EAAa9Q,GAAQopE,gBAC9BplF,EAAM0lF,aAAe54D,EAAa9Q,GAAQopE,cAAcplF,MAAM,SAER,IAA7C8sB,EAAa9Q,GAAQqpE,sBAC9BrlF,EAAM2lF,mBACJ74D,EAAa9Q,GAAQqpE,oBAAoBrlF,MAAM,SAES,IAAjD8sB,EAAa9Q,GAAQspE,0BAC9BtlF,EAAM4lF,uBACJ94D,EAAa9Q,GAAQspE,wBAAwBtlF,MAAM,SAEO,IAAnD8sB,EAAa9Q,GAAQupE,4BAC9BvlF,EAAM6lF,yBACJ/4D,EAAa9Q,GAAQupE,0BAA0BvlF,MAAM,SAGvD,IADS8sB,EAAa9Q,GAAQwpE,gCAE9BxlF,EAAM8lF,qBAAuB3lD,GAC3BrT,EAAa9Q,GAAQwpE,8BAA8BxlF,MAAM,KAGtDA,CACT,CChCgCsqF,CAC1Bx9D,EAAa9Q,GAAQgqE,uBAAuBhmF,MAAM,UAGpD,IADS8sB,EAAa9Q,GAAQiqE,qCAE9BK,EAAYF,0BAA4BjmD,GACtCrT,EAAa9Q,GAAQiqE,mCAAmCjmF,MAAM,KAG3DsmF,CACT,CKgKoBiE,CAAsBz9D,QACjC,GAAIk9D,IAAclB,GAAWxnE,MAClC+oE,EAAQrqF,MH/KL,SAA2B8sB,GAChC,MAAM25D,EAAM,IAAII,GAehB,YAb2D,IAAhD/5D,EAAa9Q,GAAQ2qE,yBAC9BF,EAAIM,sBACFj6D,EAAa9Q,GAAQ2qE,uBAAuB3mF,MAAM,SAEK,IAAhD8sB,EAAa9Q,GAAQ4qE,yBAC9BH,EAAIK,sBAAwBN,GAC1B15D,EAAa9Q,GAAQ4qE,uBAAuB5mF,MAAM,UAEO,IAAlD8sB,EAAa9Q,GAAQ4qB,2BAC9B6/C,EAAIO,wBACFl6D,EAAa9Q,GAAQ4qB,yBAAyB5mC,MAAM,IAGjDymF,CACT,CG8JoB+D,CAAkB19D,QAC7B,GAAIk9D,IAAclB,GAAWI,UAClCmB,EAAQrqF,MAAQwmF,GACd15D,EAAa9Q,GAAQ4qE,uBAAuB5mF,MAAM,SAE/C,GAAIgqF,IAAclB,GAAWjB,OAClCwC,EAAQrqF,MFrKL,SAA8B8sB,GACnC,MAAM+6D,EAAS,IAAIL,GAenB,YAbiD,IAAtC16D,EAAa9Q,GAAQorE,eAC9BS,EAAOJ,YAAc36D,EAAa9Q,GAAQorE,aAAapnF,YAER,IAAtC8sB,EAAa9Q,GAAQqrE,eAC9BQ,EAAOH,YAAc56D,EAAa9Q,GAAQqrE,aAAarnF,MAAM,SAEA,IAApD8sB,EAAa9Q,GAAQmrE,6BAC9BU,EAAOF,0BACL76D,EAAa9Q,GAAQmrE,2BAA2BnnF,MAAM,SAET,IAAtC8sB,EAAa9Q,GAAQsrE,eAC9BO,EAAOZ,YAAcn6D,EAAa9Q,GAAQsrE,aAAatnF,MAAM,IAExD6nF,CACT,CEoJoB4C,CAAqB39D,QAChC,GAAIk9D,IAAclB,GAAWM,SAClCiB,EAAQrqF,MD1LL,SAAgC8sB,GACrC,MAAM+6D,EAAS,IAAIE,GAgBnB,YAdiD,IAAtCj7D,EAAa9Q,GAAQorE,eAC9BS,EAAOJ,YAAc36D,EAAa9Q,GAAQorE,aAAapnF,YAER,IAAtC8sB,EAAa9Q,GAAQqrE,eAC9BQ,EAAOH,YAAc56D,EAAa9Q,GAAQqrE,aAAarnF,MAAM,SAG7D,IADS8sB,EAAa9Q,GAAQ8rE,iCAE9BD,EAAOG,8BACLl7D,EAAa9Q,GAAQ8rE,+BAA+B9nF,MAAM,SAEb,IAAtC8sB,EAAa9Q,GAAQsrE,eAC9BO,EAAOZ,YAAcn6D,EAAa9Q,GAAQsrE,aAAatnF,MAAM,IAExD6nF,CACT,CCwKoB6C,CAAuB59D,OAClC,CACL,MAAM69D,EAAepB,GAAsBS,QACf,IAAjBW,EACTN,EAAQrqF,MAAQ8sB,EAAa9Q,GAAQ2uE,IAAe3qF,MAAM,GAE1D+C,QAAQG,KAAK,gCAAkC8mF,EAEnD,CAGA,QAA2B,IADPl9D,EAAa9Q,GAAQssE,iBACD,CACtC+B,EAAQF,gBAAkB,GAC1B,IAAK,MAAMxtE,KAAQmQ,EAAa9Q,GAAQssE,iBAAiBtoF,MACvDqqF,EAAQF,gBAAgBhpF,KAAKipF,GAAaztE,GAE9C,CAEA,OAAO0tE,CACT,CAQO,SAASO,GAAsBP,GAEpC,IAAIQ,EAAc,CAAC,EAenB,QAbwC,IAA7BR,EAAQH,mBACjBW,EAAY3C,iBAAmBmC,EAAQH,uBAER,IAAtBG,EAAQL,YACjBa,EAAY1C,UAAYkC,EAAQL,gBAEK,IAA5BK,EAAQJ,kBACjBY,EAAYzC,wBAA0B,CACpCpoF,MAAO,CAACogC,GAAiBiqD,EAAQJ,oBAKX,SAAtBI,EAAQL,UACVa,EAAYxC,oBAAsB,CAChCroF,MAAO,CAACogC,GAAiBiqD,EAAQrqF,cAE9B,GAAIqqF,EAAQL,YAAclB,GAAW9K,IAC1C6M,EAAc,IACTA,KACAxE,GAA+BgE,EAAQrqF,aAEvC,GAAIqqF,EAAQL,YAAclB,GAAWxnE,MAC1CupE,EAAc,IACTA,KACA3D,GAA2BmD,EAAQrqF,aAEnC,GAAIqqF,EAAQL,YAAclB,GAAWI,UAC1C2B,EAAc,IACTA,KACAnE,GAAiC2D,EAAQrqF,aAEzC,GAAIqqF,EAAQL,YAAclB,GAAWjB,OAC1CgD,EAAc,IACTA,KACAjD,GAA8ByC,EAAQrqF,aAEtC,GAAIqqF,EAAQL,YAAclB,GAAWM,SAC1CyB,EAAc,IACTA,KACA5C,GAAgCoC,EAAQrqF,YAExC,CACL,MAAM2qF,EAAepB,GAAsBc,EAAQL,gBACvB,IAAjBW,EACTE,EAAYF,GAAgBN,EAAQrqF,MAEpC+C,QAAQG,KAAK,iCAAmCmnF,EAAQL,UAE5D,CAEA,QAAuC,IAA5BK,EAAQF,gBAAiC,CAClDU,EAAYvC,gBAAkB,CAC5BtoF,MAAO,IAET,IAAK,MAAM2c,KAAQ0tE,EAAQF,gBACzBU,EAAYvC,gBAAgBtoF,MAAMmB,KAAKypF,GAAsBjuE,GAEjE,CAEA,OAAOkuE,CACT,CAUO,SAASC,GAAsBpjF,EAAM1H,EAAO40B,GACjD,MAAMq1D,EtE0BD,SAA4BviF,GACjC,MAAMiV,EAAOukB,GAA4Bx5B,GACzC,IAAIskB,EAIJ,YAHoB,IAATrP,IACTqP,EAAOyU,GAAa9jB,EAAKzd,IAAKyd,EAAK+jB,SAE9B1U,CACT,CsEjC0B++D,CAAmBrjF,GAE3C,QAA+B,IAApBuiF,EACT,OAGF,MAAMI,EAAU,IAAIN,GAAejB,GAAW9K,KAC9CqM,EAAQH,iBAAmBrB,GAC3BwB,EAAQJ,gBAAkBA,EAE1B,MAAMe,EAAU,IAAIvF,GACpBuF,EAAQtF,aAAe1lF,EACvBgrF,EAAQlF,qBtEyFH,SAAiCp+E,GACtC,MAAMxI,EAAMwiC,GAA2Bh6B,GACvC,IAAIskB,EAOJ,YANmB,IAAR9sB,EACT8sB,EAAOyU,GAAavhC,EAAK,aACD,IAARA,IAEhB8sB,EAAOyU,GAAa,IAAK,SAEpBzU,CACT,CsEnGiCi/D,CAAwBr2D,GACvD,MAAMs2D,EAAa,IAAIhF,GAKvB,OAJAgF,EAAW/E,cAAgB6E,EAE3BX,EAAQrqF,MAAQkrF,EAETb,CACT,CCzSO,MAAMc,GAOX,GAQA39D,UAAAA,GACE,OAAOtvB,MAAK,CACd,CAQAuvB,aAAAA,CAAcX,GAEZ5uB,MAAK,OAAWQ,EAEhB,MAAM0sF,EAAYhB,GAAat9D,GAS/B,YARyC,IAA9Bs+D,EAAUnB,gBACfmB,EAAUnB,gBAAgBjqF,QAAU2gC,KAA0B3gC,QAChE9B,MAAK,EAAW,2BAGlBA,MAAK,EAAW,4BAGXA,MAAK,CACd,CAQA,IAAoBye,GAClB,MAAM2nC,EAAa,IAAIsjB,GACvBtjB,EAAWwJ,UHwGR,SAA4B+5B,GAEjC,MAAMwD,EAAaxD,EAAOJ,YAAYpnF,OACtC,GAAIgrF,EAAa,GAAM,EACrB,MAAM,IAAIjrF,MAAM,wDAElB,MAAMgqD,EAAS,GACf,IAAK,IAAI3pD,EAAI,EAAGA,EAAI4qF,EAAY5qF,GAAK,EACnC2pD,EAAOjpD,KAAK,IAAI8K,EACd+gB,WAAW66D,EAAOJ,YAAYhnF,IAC9BusB,WAAW66D,EAAOJ,YAAYhnF,EAAI,MAGtC,IAAI6qF,GAAW,EACf,MAAMC,EAAiBnhC,EAAO/pD,OAC9B,GAAIkrF,EAAiB,EAAG,CACtB,MAAMC,EAAaphC,EAAO,GACpBqhC,EAAYrhC,EAAOmhC,EAAiB,GAC1CD,EAAWE,EAAWzqF,OAAO0qF,EAC/B,CAGA,IAAIp7B,EACJ,GAAIw3B,EAAOH,cAAgBH,GAAoB,CAC7C,GAAsB,IAAlBn9B,EAAO/pD,OACT,MAAM,IAAID,MAAM,+BAElBiwD,EAAQjG,EAAO,EACjB,MAAO,GAAIy9B,EAAOH,cAAgBH,GAAqB,CACrD,GAAsB,IAAlBn9B,EAAO/pD,OACT,MAAM,IAAID,MAAM,kCAElB,MAAMiD,EAAS+mD,EAAO,GAEhB9oB,EADiB8oB,EAAO,GACAj+C,YAAY9I,GAC1CgtD,EAAQ,IAAIjE,GAAO/oD,EAAQi+B,EAC7B,MAAO,GAAIumD,EAAOH,cAAgBH,GAAsB,CACtD,GAAsB,IAAlBn9B,EAAO/pD,OACT,MAAM,IAAID,MAAM,mCAGlB,MAAMsoD,EAAU0B,EAAO,GAAGj+C,YAAYi+C,EAAO,IAAM,EAC7CzB,EAAUyB,EAAO,GAAGj+C,YAAYi+C,EAAO,IAAM,EAC7C/mD,EAAS,IAAI4I,EACjBm+C,EAAO,GAAG/hD,OAASqgD,EACnB0B,EAAO,GAAG9hD,QAEZ+nD,EAAQ,IAAInF,GAAQ7nD,EAAQqlD,EAASC,EACvC,MAAO,GAAIk/B,EAAOH,cAAgBH,GAChC,GAAK+D,EAOH,GAAsB,IAAlBlhC,EAAO/pD,OAAc,CACvB,MAAM+hD,EAAQ,IAAIlB,GAAKkJ,EAAO,GAAIA,EAAO,IACnC/H,EAAQ,IAAInB,GAAKkJ,EAAO,GAAIA,EAAO,IACnCshC,EAAQ,IAAIxqC,GAAKkJ,EAAO,GAAIA,EAAO,IACnCuhC,EAAQ,IAAIzqC,GAAKkJ,EAAO,GAAIA,EAAO,IAIvCiG,EAHE1N,GAAcP,EAAOC,IACvBM,GAAcN,EAAOqpC,IACrB/oC,GAAc+oC,EAAOC,GACb,IAAI3iC,GAAUoB,EAAO,GAAIA,EAAO,IAGhC,IAAID,GAAIC,EAAOxpD,MAAM,GAAI,GAErC,MAEEyvD,EAAQ,IAAIlG,GAAIC,EAAOxpD,MAAM,GAAI,SArBb,IAAlBwpD,EAAO/pD,OACTgwD,EAAQ,IAAInP,GAAKkJ,EAAO,GAAIA,EAAO,IACR,IAAlBA,EAAO/pD,SAChBgwD,EAAQ,IAAItF,GAAW,CAACX,EAAO,GAAIA,EAAO,GAAIA,EAAO,MAuB3D,OAAOiG,CACT,CGrL2Bu7B,CAAmBjvE,EAAK3c,OAE/CskD,EAAWr/C,GAAK8gB,KAChBu+B,EAAW4M,SAAW,GAEtB,IAAK,MAAMt2B,KAAWje,EAAKwtE,gBAAiB,CAe1C,GAbIvvD,EAAQovD,YAAclB,GAAWxnE,OACnCsZ,EAAQsvD,mBAAqBrB,IAC7B7oD,GAAYpF,EAAQqvD,gBAAiBppD,QACrCyjB,EAAWsrB,gBACTh1C,EAAQ56B,MAAM8mF,sBAAsB/gD,0BAGpCnL,EAAQovD,YAAclB,GAAWE,QACnCpuD,EAAQsvD,mBAAqBrB,IAC7B7oD,GAAYpF,EAAQqvD,gBAAiBnpD,QACrCwjB,EAAWr/C,GAAK21B,EAAQ56B,OAGtB46B,EAAQovD,YAAclB,GAAW1xB,MACnCx8B,EAAQsvD,mBAAqBrB,IAC7B7oD,GAAYpF,EAAQqvD,gBAAiBlpD,QACrCujB,EAAW4M,SAAWt2B,EAAQ56B,WACS,IAA5B46B,EAAQuvD,iBACjB,IAAK,MAAM0B,KAAcjxD,EAAQuvD,gBAC3B0B,EAAW7B,YAAclB,GAAWjB,QACtCgE,EAAW3B,mBAAqBrB,IAChC7oD,GACE6rD,EAAW5B,gBAAiBjpD,QAC9BsjB,EAAWyN,cAAgB,IAAI9lD,EAC7B4/E,EAAW7rF,MAAMynF,YAAY,GAC7BoE,EAAW7rF,MAAMynF,YAAY,KAavC,GANI7sD,EAAQovD,YAAclB,GAAW1xB,MACnCx8B,EAAQsvD,mBAAqBrB,IAC7B7oD,GAAYpF,EAAQqvD,gBAAiBhpD,QACrCqjB,EAAWrU,OAASrV,EAAQ56B,OAG1B46B,EAAQovD,YAAclB,GAAWjB,QACnCjtD,EAAQsvD,mBAAqBrB,IAC7B7oD,GAAYpF,EAAQqvD,gBAAiBjpD,OACrCpG,EAAQ56B,MAAM0nF,cAAgBH,GAAyB,CACvD,MAAMn9B,EAAS,GACf,IAAK,IAAI3pD,EAAI,EAAGA,EAAIm6B,EAAQ56B,MAAMynF,YAAYpnF,OAAQI,GAAK,EACzD2pD,EAAOjpD,KAAK,IAAI8K,EACd2uB,EAAQ56B,MAAMynF,YAAYhnF,GAC1Bm6B,EAAQ56B,MAAMynF,YAAYhnF,EAAI,KAGlC6jD,EAAWyJ,gBAAkB3D,CAC/B,CAEA,GAAIxvB,EAAQovD,YAAclB,GAAWM,UACnCxuD,EAAQsvD,mBAAqBrB,IAC7B7oD,GACEpF,EAAQqvD,gBAAiBrpD,OAC3BhG,EAAQ56B,MAAM0nF,cAAgBH,GAAyB,CACvD,MAAMp2E,EAAOypB,EAAQ56B,MAAMynF,YACrBr9B,EAAS,GACT0hC,EAAUjqF,KAAKiD,MAAMqM,EAAK9Q,OAAS,GACzC,IAAK,IAAII,EAAI,EAAGA,EAAIqrF,IAAWrrF,EAAG,CAChC,MAAMa,EAAQ,EAAJb,EACV2pD,EAAOjpD,KAAK,IAAI+J,EAAQiG,EAAK7P,GAAI6P,EAAK7P,EAAI,GAAI6P,EAAK7P,EAAI,IACzD,CACAgjD,EAAW0R,YAAc5L,CAC3B,CAEA,GAAIxvB,EAAQovD,YAAclB,GAAW9K,KACnCpjD,EAAQsvD,mBAAqBrB,GAA4B,CACzD,MAAMkD,EACJvqD,GAAsB5G,EAAQqvD,iBAChC,QAA2B,IAAhB8B,EACT,SAEF,MAAM5F,EAAgBvrD,EAAQ56B,MAAMmmF,cAC9B6F,EAAc/oD,GAClBkjD,EAAcL,2BACyB,IAA9BxhC,EAAWurB,iBACpBvrB,EAAWurB,eAAiB,CAAC,GAE/BvrB,EAAWurB,eAAekc,GAAe,CACvC/rF,MAAOmmF,EAAcT,aACrB9wD,KAAMo3D,EAEV,CACF,CACA,OAAO1nC,CACT,CAQAlzB,MAAAA,CAAOtE,GACL,MAAMm/D,EAAc,GACdb,EAAYhB,GAAat9D,GAC/B,IAAK,MAAMnQ,KAAQyuE,EAAUjB,gBACvBxtE,EAAKqtE,YAAclB,GAAWjB,QAChCoE,EAAY9qF,KAAKjD,MAAK,GAAoBye,IAG9C,MAAM64C,EAAkB,IAAIzR,GAAgBkoC,GAEtCl5D,EAAU,SAAU7zB,GACxB,IAAI8H,EACJ,MAAM+I,EAAU+c,EAAa5tB,GAI7B,YAHuB,IAAZ6Q,IACT/I,EAAM+I,EAAQ/P,MAAM,IAEfgH,CACT,EAGAwuD,EAAgB3Q,aAAa,mBAAoB9xB,EAAQ,aAEzDyiC,EAAgB3Q,aAAa,WAAY9xB,EAAQ,aAEjDyiC,EAAgB3Q,aAAa,cAAe9xB,EAAQ,aACpDyiC,EAAgB3Q,aAAa,YAAa9xB,EAAQ,aAClDyiC,EAAgB3Q,aAAa,mBAAoB9xB,EAAQ,aACzDyiC,EAAgB3Q,aAAa,aAAc9xB,EAAQ,aAGnD,MAAMhjB,EAAU+c,EAAa,YAC7B,QAAuB,IAAZ/c,EAAyB,CAClC,MAAMm8E,EAAgBn8E,EAAQ/P,MAAM,GAAG,iBACV,IAAlBksF,GACT12B,EAAgB3Q,aACd,2BAA4B,CAC1B7kD,MAAO,CAAC,CACN6zB,kBAAmBq4D,EAAclsF,MAAM,MAKjD,CAEA,OAAOw1D,CACT,CAQA,IAAoBlR,GAClB,MAAM6nC,EAAW,IAAIpC,GAAejB,GAAWjB,QAC/CsE,EAASjC,iBAAmBrB,GACxBvkC,EAAWwJ,qBAAqB5M,GAClCirC,EAASlC,gBvEENxpD,GAAa,SAAU,OuEA1B0rD,EAASlC,gBvElBNxpD,GAAa,SAAU,OuEoB5B0rD,EAASnsF,MHvJN,SAA4BqwD,GACjC,MAAMw3B,EAAS,IAAIL,GAEnB,GAAIn3B,aAAiBpkD,EACnB47E,EAAOJ,YAAc,CACnBp3B,EAAMhoD,OAAO3H,WACb2vD,EAAM/nD,OAAO5H,YAEfmnF,EAAOH,YAAcH,QAChB,GAAIl3B,aAAiBnP,GAC1B2mC,EAAOJ,YAAc,CACnBp3B,EAAMjP,WAAW/4C,OAAO3H,WACxB2vD,EAAMjP,WAAW94C,OAAO5H,WACxB2vD,EAAMhP,SAASh5C,OAAO3H,WACtB2vD,EAAMhP,SAAS/4C,OAAO5H,YAExBmnF,EAAOH,YAAcH,QAChB,GAAIl3B,aAAiBtF,GAAY,CACtC88B,EAAOJ,YAAc,GACrB,IAAK,IAAIhnF,EAAI,EAAGA,EAAI,IAAKA,EACvBonF,EAAOJ,YAAYtmF,KAAKkvD,EAAMhG,SAAS5pD,GAAG4H,OAAO3H,YACjDmnF,EAAOJ,YAAYtmF,KAAKkvD,EAAMhG,SAAS5pD,GAAG6H,OAAO5H,YAEnDmnF,EAAOH,YAAcH,EACvB,MAAO,GAAIl3B,aAAiBlG,GAAK,CAC/B09B,EAAOJ,YAAc,GACrB,IAAK,IAAIhnF,EAAI,EAAGA,EAAI4vD,EAAMnuD,cAAezB,EACvConF,EAAOJ,YAAYtmF,KAAKkvD,EAAMhG,SAAS5pD,GAAG4H,OAAO3H,YACjDmnF,EAAOJ,YAAYtmF,KAAKkvD,EAAMhG,SAAS5pD,GAAG6H,OAAO5H,YAGnD,MAAM8qF,EAAan7B,EAAMhG,SAAS,GAClCw9B,EAAOJ,YAAYtmF,KAAKqqF,EAAWnjF,OAAO3H,YAC1CmnF,EAAOJ,YAAYtmF,KAAKqqF,EAAWljF,OAAO5H,YAE1CmnF,EAAOH,YAAcH,EACvB,MAAO,GAAIl3B,aAAiBjE,GAAQ,CAClC,MAAM/oD,EAASgtD,EAAMjF,YACfghC,EAAiB,IAAIngF,EACzB5I,EAAOgF,OAASgoD,EAAMhE,YAAahpD,EAAOiF,QAE5Cu/E,EAAOJ,YAAc,CACnBpkF,EAAOgF,OAAO3H,WACd2C,EAAOiF,OAAO5H,WACd0rF,EAAe/jF,OAAO3H,WACtB0rF,EAAe9jF,OAAO5H,YAExBmnF,EAAOH,YAAcH,EACvB,MAAO,GAAIl3B,aAAiBnF,GAAS,CACnC,MAAM7nD,EAASgtD,EAAMjF,YACf1C,EAAU2H,EAAMhF,OAChB1C,EAAU0H,EAAM/E,OACtBu8B,EAAOJ,YAAc,EAClBpkF,EAAOgF,OAASqgD,GAAShoD,WAC1B2C,EAAOiF,OAAO5H,YACb2C,EAAOgF,OAASqgD,GAAShoD,WAC1B2C,EAAOiF,OAAO5H,WACd2C,EAAOgF,OAAO3H,YACb2C,EAAOiF,OAASqgD,GAASjoD,WAC1B2C,EAAOgF,OAAO3H,YACb2C,EAAOiF,OAASqgD,GAASjoD,YAE5BmnF,EAAOH,YAAcH,EACvB,MAAO,GAAIl3B,aAAiBrH,GAAW,CACrC,MAAM7H,EAAQkP,EAAMjP,WACd9wC,EAAM+/C,EAAMhP,SAElBwmC,EAAOJ,YAAc,CACnBtmC,EAAM94C,OAAO3H,WACbygD,EAAM74C,OAAO5H,WACbygD,EAAM94C,OAAO3H,WACb4P,EAAIhI,OAAO5H,WACX4P,EAAIjI,OAAO3H,WACX4P,EAAIhI,OAAO5H,WACX4P,EAAIjI,OAAO3H,WACXygD,EAAM74C,OAAO5H,WACbygD,EAAM94C,OAAO3H,WACbygD,EAAM74C,OAAO5H,YAEfmnF,EAAOH,YAAcH,EACvB,CAEA,OAAOM,CACT,CGoEqBwE,CAAmB/nC,EAAWwJ,WAE/C,MAAMw+B,EAAsB,GAGtBC,EAAU,IAAIxC,GAAejB,GAAWxnE,OAC9CirE,EAAQrC,iBAAmBrB,GAC3B0D,EAAQtC,gBAAkBppD,KAC1B,MAAM2rD,EAAS,IAAIjG,GACnBiG,EAAO1mD,sBAAwB,GAC/B0mD,EAAOzmD,yBAA2Bue,EAAWsrB,gBAC7C,MAAM6c,EAAW,IAAI5F,GACrB4F,EAAS3F,sBAAwB0F,EACjCD,EAAQvsF,MAAQysF,EAChBH,EAAoBnrF,KAAKorF,GAGzB,MAAMG,EAAQ,IAAI3C,GAAejB,GAAWE,QAC5C0D,EAAMxC,iBAAmBrB,GACzB6D,EAAMzC,gBAAkBnpD,KACxB4rD,EAAM1sF,MAAQskD,EAAWr/C,GACzBqnF,EAAoBnrF,KAAKurF,GAGzB,MAAMC,EAAa,IAAI5C,GAAejB,GAAW1xB,MAKjD,GAJAu1B,EAAWzC,iBAAmBrB,GAC9B8D,EAAW1C,gBAAkBlpD,KAC7B4rD,EAAW3sF,MAAQskD,EAAW4M,cAEU,IAA7B5M,EAAWyN,cAA+B,CACnD,MAAMA,EAAgB,IAAIg4B,GAAejB,GAAWjB,QACpD91B,EAAcm4B,iBAAmBrB,GACjC92B,EAAck4B,gBAAkBjpD,KAChC,MAAM4rD,EAAiB,IAAIpF,GAC3BoF,EAAelF,YAAcH,GAC7B,MAAME,EAAc,CAClBnjC,EAAWyN,cAAc1pD,OAAO3H,WAChC4jD,EAAWyN,cAAczpD,OAAO5H,YAElCksF,EAAenF,YAAcA,EAC7B11B,EAAc/xD,MAAQ4sF,EAGtBD,EAAWxC,gBAAkB,CAACp4B,EAChC,CACAu6B,EAAoBnrF,KAAKwrF,GAGzB,MAAM18C,EAAS,IAAI85C,GAAejB,GAAW1xB,MAO7C,GANAnnB,EAAOi6C,iBAAmBrB,GAC1B54C,EAAOg6C,gBAAkBhpD,KACzBgP,EAAOjwC,MAAQskD,EAAWrU,OAC1Bq8C,EAAoBnrF,KAAK8uC,QAGiB,IAA/BqU,EAAWyJ,gBAAiC,CACrD,MAAMA,EAAkB,IAAIg8B,GAAejB,GAAWjB,QACtD95B,EAAgBm8B,iBAAmBrB,GACnC96B,EAAgBk8B,gBAAkBjpD,KAClC,MAAM6rD,EAAkB,IAAIrF,GAC5BqF,EAAgBnF,YAAcH,GAC9B,MAAME,EAAc,GACpB,IAAK,MAAM5/D,KAASy8B,EAAWyJ,gBAC7B05B,EAAYtmF,KAAK0mB,EAAMxf,OAAO3H,YAC9B+mF,EAAYtmF,KAAK0mB,EAAMvf,OAAO5H,YAEhCmsF,EAAgBpF,YAAcA,EAE9B15B,EAAgB/tD,MAAQ6sF,EACxBP,EAAoBnrF,KAAK4sD,EAC3B,CAGA,QAAsC,IAA3BzJ,EAAW0R,YAA6B,CACjD,MAAMA,EAAc,IAAI+zB,GAAejB,GAAWM,UAClDpzB,EAAYk0B,iBAAmBrB,GAC/B7yB,EAAYi0B,gBAAkBrpD,KAC9B,MAAMksD,EAAe,IAAI/E,GACzB+E,EAAapF,YAAcH,GAC3B,MAAME,EAAc,GACpB,IAAK,MAAM1sC,KAAcuJ,EAAW0R,YAClCyxB,EAAYtmF,KAAK45C,EAAW1yC,OAAO3H,YACnC+mF,EAAYtmF,KAAK45C,EAAWzyC,OAAO5H,YACnC+mF,EAAYtmF,KAAK45C,EAAWxyC,OAAO7H,YAErCosF,EAAarF,YAAcA,EAE3BzxB,EAAYh2D,MAAQ8sF,EACpBR,EAAoBnrF,KAAK60D,EAC3B,CAGA,QAAyC,IAA9B1R,EAAWurB,eACpB,IAAK,MAAM3wE,KAAOolD,EAAWurB,eAAgB,CAC3C,MAAMkd,EAAgBjC,GACpB5rF,EACAolD,EAAWurB,eAAe3wE,GAAKc,MAC/BskD,EAAWurB,eAAe3wE,GAAK01B,WAEJ,IAAlBm4D,GACTT,EAAoBnrF,KAAK4rF,EAE7B,CAIF,OADAZ,EAAShC,gBAAkBmC,EACpBH,CACT,CASA//C,OAAAA,CAAQopB,EAAiBnpB,GACvB,IAAI36B,EAAO8jD,EAAgBlpB,UAG3B56B,EAAKshB,kBAAoB,sBAEzBthB,EAAKyc,YAAc,gCACnBzc,EAAKuhB,wBAA0B,gCAC/BvhB,EAAKs7E,eAAiB,UACtBt7E,EAAKu7E,iBAAmB,aAExB,MAAMxgD,EAAM,IAAI1c,KAChBre,EAAKg7B,YAAcjiB,GAAaR,GAAcwiB,IAC9C/6B,EAAKi7B,YAAchiB,GAAaN,GAAcoiB,IAE9C,MAAM09C,EAAkB,GACxB,IAAK,MAAM7lC,KAAckR,EAAgBvR,UACvCkmC,EAAgBhpF,KAAKjD,MAAK,GAAoBomD,IAIhD,GAA+B,IAA3B6lC,EAAgB9pF,OAAc,CAChC,MAAM+qF,EAAY,IAAIrB,GAAejB,GAAW3zB,WAChDi2B,EAAUnB,gBAAkBtpD,KAC5ByqD,EAAUjB,gBAAkBA,EAE5Bz4E,EAAO,IACFA,KACAk5E,GAAsBQ,GAE7B,CAOA,YAJyB,IAAd/+C,GAtXf,SAAmBgC,EAAOC,GACxB,MAAMC,EAAQnvC,OAAO4R,KAAKs9B,GAC1B,IAAK,MAAME,KAAYD,OACG7vC,IAApB2vC,EAAMG,IACRnsC,EAAOQ,MAAM,qBAAuB2rC,GAEtCH,EAAMG,GAAYF,EAAME,EAE5B,CA+WMC,CAAU/8B,EAAM26B,GAGXlN,GAAwBztB,EACjC,ECvaK,MAAMw7E,GAMXx6D,KAOApR,MAMAk0C,gBAKAt1D,WAAAA,CAAYwyB,GACVx0B,KAAKw0B,KAAOA,CACd,EAMK,MAAMy6D,GAOX,IAAY,CAAC,EAOb,KAAkB,EAOlB,IAAmB,IAAIxtE,GAOvBytE,aAAAA,GAEE,QADElvF,MAAK,GACAA,MAAK,GAAewC,UAC7B,CAOA2sF,UAAAA,GACE,OAAOjuF,OAAO4R,KAAK9S,MAAK,GAC1B,CAKAivD,KAAAA,GACEjvD,MAAK,GAAY,CAAC,CACpB,CAQAqB,GAAAA,CAAIk2D,GACF,OAAOv3D,MAAK,GAAUu3D,EACxB,CAQA63B,qBAAAA,CAAsBhiD,GACpB,MAAMtkC,EAAM,GAEZ,QAAoB,IAATskC,GACO,IAAhBA,EAAKjrC,OACL,OAAO2G,EAET,MAAMgK,EAAO5R,OAAO4R,KAAK9S,MAAK,IAC9B,IAAK,MAAMgB,KAAO8R,OACyB,IAA9B9S,MAAK,GAAUgB,GAAKoiB,OAC7BpjB,MAAK,GAAUgB,GAAKoiB,MAAM8tB,kBAAkB9D,IAC5CtkC,EAAI7F,KAAKjC,GAGb,OAAO8H,CACT,CAQAyvC,QAAAA,CAASgf,EAAQn0C,GACfpjB,MAAK,GAAUu3D,GAAQn0C,MAAQA,EAU/BpjB,MAAK,GAAW,CACd0hB,KAAM,eACN5f,MAAO,CAACshB,GACRqtC,OAAQ8G,IAGVn0C,EAAM2xB,iBAAiB,qBAAsB/0C,MAAK,GAAcu3D,IAChEn0C,EAAM2xB,iBAAiB,sBAAuB/0C,MAAK,GAAcu3D,GACnE,CAQAr0D,GAAAA,CAAIq0D,EAAQtkD,GACV,QAAsC,IAA3BjT,MAAK,GAAUu3D,GACxB,MAAM,IAAIr1D,MAAM,oCAAsCq1D,GAGxDv3D,MAAK,GAAUu3D,GAAUtkD,EASzBjT,MAAK,GAAW,CACd0hB,KAAM,UACN+uC,OAAQ8G,SAGgB,IAAftkD,EAAKmQ,QACdnQ,EAAKmQ,MAAM2xB,iBACT,qBAAsB/0C,MAAK,GAAcu3D,IAC3CtkD,EAAKmQ,MAAM2xB,iBACT,sBAAuB/0C,MAAK,GAAcu3D,UAEV,IAAzBtkD,EAAKqkD,kBACdrkD,EAAKqkD,gBAAgBviB,iBACnB,gBAAiB/0C,MAAK,GAAcu3D,IACtCtkD,EAAKqkD,gBAAgBviB,iBACnB,mBAAoB/0C,MAAK,GAAcu3D,IACzCtkD,EAAKqkD,gBAAgBviB,iBACnB,mBAAoB/0C,MAAK,GAAcu3D,IAE7C,CAOA31C,MAAAA,CAAO21C,GACL,QAAsC,IAA3Bv3D,MAAK,GAAUu3D,GAAyB,CAEjD,MAAMn0C,EAAQpjB,MAAK,GAAUu3D,GAAQn0C,WAChB,IAAVA,IACTA,EAAM4xB,oBACJ,qBAAsBh1C,MAAK,GAAcu3D,IAC3Cn0C,EAAM4xB,oBACJ,sBAAuBh1C,MAAK,GAAcu3D,KAE9C,MAAMD,EAAkBt3D,MAAK,GAAUu3D,GAAQD,qBAChB,IAApBA,IACTA,EAAgBtiB,oBACd,gBAAiBh1C,MAAK,GAAcu3D,IACtCD,EAAgBtiB,oBACd,mBAAoBh1C,MAAK,GAAcu3D,IACzCD,EAAgBtiB,oBACd,mBAAoBh1C,MAAK,GAAcu3D,YAGpCv3D,MAAK,GAAUu3D,GAStBv3D,MAAK,GAAW,CACd0hB,KAAM,aACN+uC,OAAQ8G,GAEZ,CACF,CAQAlR,MAAAA,CAAOkR,EAAQtkD,GACb,QAAsC,IAA3BjT,MAAK,GAAUu3D,GACxB,MAAM,IAAIr1D,MAAM,+BAAiCq1D,GAEnD,MAAM83B,EAAervF,MAAK,GAAUu3D,QAGF,IAAvB83B,EAAajsE,YACA,IAAfnQ,EAAKmQ,OAEZisE,EAAajsE,MAAM0vB,YAAY7/B,EAAKmQ,OAKtC,IAAIksE,EAAQ,GAGVA,OAFmC,IAA1Br8E,EAAKuhB,KAAK,YAEX,WAEA,WAEV66D,EAAa76D,KClOV,SAAsB+6D,EAAMC,EAAMF,EAAOG,GAC9C,MAAM3mF,EAAM,CAAC,EAEb,IAAKwmF,EACH,MAAM,IAAIptF,MAAM,iDAAmDotF,GAEnE,IAAKpuF,OAAOM,UAAUC,eAAeC,KAAK6tF,EAAMD,GAC9C,MAAM,IAAIptF,MAAM,mDACdotF,EAAQ,UAAYC,GAExB,IAAKruF,OAAOM,UAAUC,eAAeC,KAAK8tF,EAAMF,GAC9C,MAAM,IAAIptF,MAAM,oDACdotF,EAAQ,UAAYE,GAU1B,IAAIE,GAAa,EAMjB,GALIxuF,OAAOM,UAAUC,eAAeC,KAAK6tF,EAAKD,GAAQ,WACpDC,EAAKD,GAAOK,SACZD,GAAa,IAGVxuF,OAAOM,UAAUC,eAAeC,KAAK6tF,EAAKD,GAAQG,GACrD,MAAM,IAAIvtF,MAAM,qDACdotF,EAAQ,eAAiBG,EAAW,UAAYF,GAEpD,IAAKruF,OAAOM,UAAUC,eAAeC,KAAK8tF,EAAKF,GAAQG,GACrD,MAAM,IAAIvtF,MAAM,sDACdotF,EAAQ,eAAiBG,EAAW,UAAYD,GAEpD,IAAII,EAAML,EAAKD,GAAOG,GACtB,MAAMI,EAAML,EAAKF,GAAOG,GAAU,GAGlC,GADA3mF,EAAIwmF,GAASC,EAAKD,GACdI,EAAY,CAEd,IAAK,IAAIjjF,EAAI,EAAGA,EAAImjF,EAAIztF,SAAUsK,EAChC,GAAImjF,EAAInjF,KAAOojF,EACb,MAAM,IAAI3tF,MAAM,0CACd2tF,EAAM,UAAYD,GAGxB9mF,EAAIwmF,GAAOG,GAAUxsF,KAAK4sF,EAC5B,KAAO,CAEL,GADAD,EAAMA,EAAI,GACNA,IAAQC,EACV,MAAM,IAAI3tF,MAAM,sCACd0tF,EAAM,UAAYC,GAGtB/mF,EAAIwmF,GAAOG,GAAUxsF,KAAK4sF,GAC1B/mF,EAAIwmF,GAAOK,QAAS,CACtB,CAGA,MAAMh4E,EAAQzW,OAAO4R,KAAKy8E,GAEpBl/C,EAAQnvC,OAAO4R,KAAK08E,GAAMxqB,QAAO,SAAUvmD,GAC/C,OAAO9G,EAAMpK,QAAQkR,GAAQ,CAC/B,IACM3L,EAAO6E,EAAMoH,OAAOsxB,GAG1B,IAAK,IAAI9tC,EAAI,EAAGA,EAAIuQ,EAAK3Q,SAAUI,EAAG,CACpC,MAAMvB,EAAM8R,EAAKvQ,GACjB,GAAIvB,IAAQsuF,EAAO,CAEjB,IAAIQ,EACAC,EAQAC,EACAC,EAQAnuF,EAQJ,GAxBIZ,OAAOM,UAAUC,eAAeC,KAAK6tF,EAAMvuF,KAC7C8uF,EAASP,EAAKvuF,GACVE,OAAOM,UAAUC,eAAeC,KAAKouF,EAAQL,KAC/CM,EAAYD,EAAOL,KAMnBvuF,OAAOM,UAAUC,eAAeC,KAAK8tF,EAAMxuF,KAC7CgvF,EAASR,EAAKxuF,GACVE,OAAOM,UAAUC,eAAeC,KAAKsuF,EAAQP,KAC/CQ,EAAYD,EAAOP,UAMD,IAAXK,EACThuF,EAAQguF,OACmB,IAAXE,IAChBluF,EAAQkuF,IAGLr+E,EAAYo+E,EAAWE,GAE1B,GAAIP,EAAY,CACd,GAAItwE,MAAMwhB,QAAQmvD,GAAY,CAG5BjuF,EAAM2tF,GAAY,CAAC,EACnB,IAAK,IAAIrsF,EAAI,EAAGA,EAAIwsF,EAAIztF,SAAUiB,EAChCtB,EAAM2tF,GAAUG,EAAIxsF,IAAM2sF,CAE9B,MACEjuF,EAAM2tF,GAAYM,OAGW,IAApBjuF,EAAM2tF,KACf3tF,EAAM2tF,GAAY,CAAC,GAGrB3tF,EAAM2tF,GAAUI,GAAOI,CACzB,KAAO,CAEL,MAAM74C,EAAW,CAAC,EAClBA,EAASw4C,GAAOG,EAChB34C,EAASy4C,GAAOI,EAChBnuF,EAAM2tF,GAAYr4C,CACpB,CAGFtuC,EAAI9H,GAAOc,CACb,CACF,CACA,OAAOgH,CACT,CD+FwBonF,CAClBb,EAAa76D,KACbvhB,EAAKuhB,KACL86D,EACA,SAUFtvF,MAAK,GAAW,CACd0hB,KAAM,aACN+uC,OAAQ8G,GAEZ,CASAxiB,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAcK,IACZhiB,MAAK,GAAiB+hB,UAAUC,EAAM,EAUxC,IAAcu1C,GACZ,OAAQv1C,IACNA,EAAMyuC,OAAS8G,EACfv3D,MAAK,GAAWgiB,EAAM,CAE1B,EEnTK,MAAMmuE,GAOX,IAOAjmB,UAAAA,CAAWkmB,GACTpwF,MAAK,GAAWowF,CAClB,CAQA,IAAgB,KAGhB,IAAoB,GACpB,IAAoB,GACpB,IAAqB,GACrB,IAAa,GASb,IAAYnwE,GACV,IAAIvgB,EACJ,MAAM2wF,EAAkBpwE,EAAS,YACjC,QAA+B,IAApBowE,EAAiC,CAC1C,MAAM7gE,EAAW6gE,EAAgBvuF,MAAM,GACtB,QAAb0tB,EAEF9vB,EAAU,IAAI6qC,GACQ,OAAb/a,IAET9vB,EAAU,IAAIutF,GAElB,CAQA,YANuB,IAAZvtF,QAEmB,IADPugB,EAAS,cAE5BvgB,EAAU,IAAI2vB,IAGX3vB,CACT,CAQA,IAAc4N,EAAO4a,GACnB,MAAM0G,EAAe5uB,MAAK,GAAkBsN,GAAO+Q,mBAC7C3e,EAAUM,MAAK,GAAWsN,GAEhC,QAAuB,IAAZ5N,EAIX,IACE,MAAMuT,EAAO,IAAI+7E,GAAUpgE,GACvBlvB,aAAmButF,GACrBh6E,EAAKqkD,gBAAkB53D,EAAQwzB,OAAOtE,GAEtC3b,EAAKmQ,MAAQ1jB,EAAQwzB,OACnBtE,EACA5uB,MAAK,GAAkBsN,GACvBtN,MAAK,GAASozB,eAGlBpzB,KAAK4hF,WAAW,CACd3uE,KAAMA,EACNqtE,OAAQp4D,EACRljB,KAAMtF,EAAQ4vB,cAElB,CAAE,MAAOrqB,GACPjF,KAAKkhF,QAAQ,CACXj8E,MAAOA,EACPq7E,OAAQp4D,IAEVloB,KAAK8gF,UAAU,CACbR,OAAQp4D,GAEZ,CACF,CAQA,IAA2B5a,EAAO4a,GAEhCloB,KAAKggF,WAAW,CACdC,kBAAkB,EAClBG,OAAQ,IACRC,MAAO,IACP/yE,MAAOA,EACPgzE,OAAQp4D,IAGVloB,MAAK,GAAcsN,EAAO4a,GAE1BloB,KAAK6gF,OAAO,CACVP,OAAQp4D,IAEVloB,KAAK8gF,UAAU,CACbR,OAAQp4D,GAEZ,CASA,IAAyB5a,EAAO6lB,EAAaozD,GAC3C,MAAM+J,EAActwF,MAAK,GAAkBsN,GAOrC24E,EAAY,CAChB1oE,cAJA+yE,EAAYjyE,mBAAmB,YAAYvc,MAAM,GAKjDqE,SAAmC,IAHnCmqF,EAAYjyE,mBAAmB,YAAYvc,MAAM,IAK7CyuF,EAAiBD,EAAYjyE,mBAAmB,YAChDmyE,EAAcF,EAAYjyE,mBAAmB,iBACrB,IAAnBkyE,QACc,IAAhBC,IACPvK,EAAU7hE,UAAYmsE,EAAezuF,MAAM,GAAK0uF,EAAY1uF,MAAM,IAEpE,MAAM2uF,EACJH,EAAYjyE,mBAAmB,iBACK,IAA3BoyE,IACTxK,EAAUt2D,gBAAkB8gE,EAAuB3uF,MAAM,IAE3D,MAAM4uF,EACJJ,EAAYjyE,mBAAmB,iBACS,IAA/BqyE,IACTzK,EAAU7xD,oBAAsBs8D,EAA2B5uF,MAAM,IAGnE,MAAMsjF,EAAgBjyD,EAAYhxB,OAGP,OAAvBnC,MAAK,KACPA,MAAK,GAAgB,IAAIinF,GACvBV,EAAUnB,GAGZplF,MAAK,GAAcmmF,cAAiBnkE,IAClChiB,MAAK,GAAegiB,GAEhBA,EAAMmjE,WAAa,IAAMnjE,EAAMojE,gBACjCplF,KAAK6gF,OAAO7+D,GACZhiB,KAAK8gF,UAAU9+D,GACjB,EAIFhiB,MAAK,GAAckhF,QAAUlhF,KAAKkhF,QAClClhF,MAAK,GAAc6hF,QAAU7hF,KAAK6hF,SAIpC,IAAK,IAAIt/E,EAAI,EAAGA,EAAI6iF,IAAiB7iF,EACnCvC,MAAK,GAAcmc,OAAOgX,EAAY5wB,GAAI0jF,EACxC,CACEd,WAAY5iF,EACZ6iF,cAAeA,EACf93E,MAAOA,GAIf,CAOA,IAAe0U,GAEbhiB,KAAKggF,WAAW,CACdC,kBAAkB,EAClBG,OAAQp+D,EAAMmjE,WAAa,EAC3B9E,MAAOr+D,EAAMojE,cACb93E,MAAO0U,EAAM1U,MACbgzE,OAAQp4D,SAGV,MAAMyoE,EAAY3uE,EAAM1U,MAGlBsjF,EAAc5uE,EAAM/O,KAAK,GAC/B,GAA4B,IAAxB+O,EAAMojE,cAAqB,CAE7B,QAAkD,IAAvCplF,MAAK,GAAmB2wF,GAA4B,CAC7D3wF,MAAK,GAAmB2wF,GAAaC,EAAYzuF,OACjD,MAAM0uF,EAAW7uE,EAAMojE,cACrBplF,MAAK,GAAmB2wF,GAC1B,IACE3wF,MAAK,GAAkB2wF,GACrB,IAAIC,EAAY5uF,YAAY6uF,EAChC,CAAE,MAAO5rF,GACP,GAAIA,aAAiBwY,WAAY,CAC/B,MAAMC,EAAW/Z,KAAKiD,MAAMjD,KAAKga,IAAIkzE,GAAYltF,KAAKga,IAAI,IAC1DxZ,EAAOc,MAAM,mBACX2rF,EAAY5uF,YAAYwH,KACxB,aACAqnF,EAAW,QAAUnzE,EAAW,2BACpC,CAYA,OAVA1d,MAAK,GAAcujF,QAEnBvjF,KAAKkhF,QAAQ,CACXj8E,MAAOA,EACPq7E,OAAQp4D,cAEVloB,KAAK8gF,UAAU,CACbR,OAAQp4D,QAIZ,CACF,CAEI0oE,EAAYzuF,SAAWnC,MAAK,GAAmB2wF,IACjDxsF,EAAOa,KAAK,+CACV4rF,EAAYzuF,OAAS,OAASnC,MAAK,GAAmB2wF,IAG1D3wF,MAAK,GAAkB2wF,GAAWv9E,IAChCw9E,EAAa5wF,MAAK,GAAmB2wF,GAAa3uE,EAAMmjE,WAC5D,MACEnlF,MAAK,GAAkB2wF,GAAaC,EAIb,IAArB5uE,EAAMmjE,YACRnlF,MAAK,GAAc2wF,EAAWzoE,OAElC,CAQA,IAAoB5a,EAAO4a,GACzBloB,MAAK,GAAcsN,EAAO4a,GAE1BloB,KAAK6gF,OAAO,CACVP,OAAQp4D,IAEVloB,KAAK8gF,UAAU,CACbR,OAAQp4D,GAEZ,CAQA,IAAiB5a,EAAO4a,GACtB,MAAMooE,EAActwF,MAAK,GAAkBsN,GAErC6lB,EAAcm9D,EAAYjyE,mBAAmB,YAAYvc,MAE/DwuF,EAAYjyE,mBAAmB,YAAYvc,MAAQ,GACnD9B,MAAK,GAAkBsN,GAAS6lB,EAAY,GAG5C,MACMozD,ExF/DH,SAAoCvpE,GACzC,IAAI8zE,EAUJ,OATI1zE,GAAyBJ,GAC3B8zE,EAAO,WACE5zE,GAA6BF,GACtC8zE,EAAO,gBACE3zE,GAA6BH,GACtC8zE,EAAO,gBACEzzE,GAAoBL,KAC7B8zE,EAAO,OAEFA,CACT,CwFmDqBC,CADFT,EAAYjyE,mBAAmB,YAAYvc,MAAM,SAElB,IAAbykF,EAI/BvmF,MAAK,GACHsN,EACA6lB,EACAozD,GAEFvmF,MAAK,GAA2BsN,EAAO4a,EAE3C,CASA8oE,OAAAA,CAAQ79E,EAAQ+U,EAAQyoE,GAEtB3wF,KAAKghF,YAAY,CACfV,OAAQp4D,EACR5a,MAAOqjF,IAIT,MAAML,EAAc,IAAIvyE,GAMxB,IAAIre,OAJ6C,IAAtCM,MAAK,GAAS2hF,qBACvB2O,EAAYryE,uBAAuBje,MAAK,GAAS2hF,qBAInD,IACE2O,EAAYpwE,MAAM/M,GAElBzT,EAAUM,MAAK,GAAYswF,EAAYjyE,yBAChB,IAAZ3e,GACTA,EAAQ6vB,cAAc+gE,EAAYjyE,mBAEtC,CAAE,MAAOpZ,GAQP,OAPAjF,KAAKkhF,QAAQ,CACXj8E,MAAOA,EACPq7E,OAAQp4D,SAEVloB,KAAK8gF,UAAU,CACbR,OAAQp4D,GAGZ,CAGAloB,MAAK,GAAkB2wF,GAAaL,EACpCtwF,MAAK,GAAW2wF,GAAajxF,EAGzBA,aAAmButF,GACrBjtF,MAAK,GAAoB2wF,EAAWzoE,GAEpCloB,MAAK,GAAiB2wF,EAAWzoE,EAErC,CAKAq7D,KAAAA,GAEMvjF,MAAK,IACPA,MAAK,GAAcujF,OAEvB,CAQAvC,WAAAA,CAAY5b,GAAS,CAQrBwc,UAAAA,CAAWxc,GAAS,CAQpB4a,UAAAA,CAAW5a,GAAS,CASpByb,MAAAA,CAAOzb,GAAS,CAQhB0b,SAAAA,CAAU1b,GAAS,CAQnB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,EC5bZ,MAAM6rB,GAOX,IAAa,KAOb,IAAiB,KAOjB,IAAS,EAOT,IAAY,EAOZ,GAOAjzE,sBAAAA,GACE,OAAOhe,MAAK,CACd,CAOAie,sBAAAA,CAAuBC,GACrBle,MAAK,EAAuBke,CAC9B,CAOA,IAAgBjL,GACdjT,MAAK,GAAaiT,EAElBjT,MAAK,GAAS,EACdA,MAAK,GAAY,EAEjBA,MAAK,IACP,CAOA,IAAa4gF,GACX5gF,MAAK,GAAiB4gF,CACxB,CAMA,MACE5gF,MAAK,GAAiB,IACxB,CAQA,IAAYolE,IACVplE,MAAK,KAIDA,MAAK,KAAWA,MAAK,GAAWmC,QAClCnC,KAAK6gF,OAAO,CACVP,OAAQtgF,MAAK,IAEjB,EASF,IAAeolE,IACbplE,MAAK,KAIDA,MAAK,KAAcA,MAAK,GAAWmC,QACrCnC,KAAK8gF,UAAU,CACbR,OAAQtgF,MAAK,IAEjB,EAQF+gF,IAAAA,CAAK9tE,GAEH,QAAoB,IAATA,GAAwC,IAAhBA,EAAK9Q,OACtC,OAEFnC,MAAK,GAAgBiT,GAGrBjT,KAAKghF,YAAY,CACfV,OAAQrtE,IAIV,MAAMquE,EAAe,IAAI1B,GAAqB5/E,KAAKggF,YACnDsB,EAAavB,WAAW9sE,EAAK9Q,QAC7Bm/E,EAAazB,sBAAsB,GAGnC,MAAM0B,EAAU,GAChB,IAAK,IAAIj2E,EAAI,EAAGA,EAAIk2E,GAAWr/E,SAAUmJ,EACvCi2E,EAAQt+E,KAAK,IAAIu+E,GAAWl2E,IAI9B,IAAIyU,EAAc9M,EAAK,GACnB2tE,EAAS,KACTa,GAAc,EAClB,IAAK,IAAIp+E,EAAI,EAAGA,EAAIk+E,EAAQp/E,SAAUkB,EAEpC,GADAu9E,EAASW,EAAQl+E,GACbu9E,EAAOsQ,cAAcnxE,GAAc,CACrC0hE,GAAc,EAEdb,EAAO1W,WAAW,CAChB92C,cAAengB,EAAK9Q,OACpBw/E,oBAAqB3hF,KAAKge,2BAI5B4iE,EAAOZ,WAAasB,EAAab,gCAAgC,GACjEG,EAAOgB,WAAa5hF,KAAK4hF,WACzBhB,EAAOC,OAAS7gF,MAAK,GACrB4gF,EAAOE,UAAY9gF,MAAK,GACxB4gF,EAAOM,QAAUlhF,KAAKkhF,QACtBN,EAAOiB,QAAU7hF,KAAK6hF,QAGtB7hF,MAAK,GAAa4gF,GAElB,KACF,CAEF,IAAKa,EACH,MAAM,IAAIv/E,MAAM,6BAA+B6d,EAAYoxE,UAI7D,IAAK,IAAI5uF,EAAI,EAAGA,EAAI0Q,EAAK9Q,SAAUI,EAAG,CAGpC,GAFAwd,EAAc9M,EAAK1Q,IAEdq+E,EAAOsQ,cAAcnxE,GACxB,MAAM,IAAI7d,MAAM,iCACd6d,EAAYoxE,UAGhBvQ,EAAOG,KAAKhhE,EAAY9M,KAAM8M,EAAYoxE,SAAU5uF,EACtD,CACF,CAKAghF,KAAAA,GAEMvjF,MAAK,IAAkBA,MAAK,GAAeyjF,aAC7CzjF,MAAK,GAAeujF,OAExB,CAQAvC,WAAAA,CAAY5b,GAAS,CAQrB4a,UAAAA,CAAW5a,GAAS,CASpBwc,UAAAA,CAAWxc,GAAS,CASpByb,MAAAA,CAAOzb,GAAS,CAShB0b,SAAAA,CAAU1b,GAAS,CAQnB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,EChQnB,SAASgsB,GAAkBC,GAGzB,MAAMC,EAAUD,EAAUp+E,KAAK9Q,OACzBgR,EAAS,IAAIrC,WAAYwgF,EAAU,EAAK,GAC9C,IAAIluF,EAAI,EACR,IAAK,IAAIb,EAAI,EAAGA,EAAI+uF,EAAS/uF,GAAK,EAChC4Q,EAAO/P,GAAKiuF,EAAUp+E,KAAK1Q,GAC3B4Q,EAAO/P,EAAI,GAAKiuF,EAAUp+E,KAAK1Q,EAAI,GACnC4Q,EAAO/P,EAAI,GAAKiuF,EAAUp+E,KAAK1Q,EAAI,GACnCa,GAAK,EAEP,OAAO+P,CACT,CAaA,SAASo+E,GACPnsF,EAAO+9B,EAAQ6J,EACfwkD,EAAatwE,EACbq5B,GAEA,MAAM6xB,EAAY,IAAItmD,GAAK,CAAC1gB,EAAO+9B,EAAQ,IAGrCsuD,EAAe,IAAIzpE,GAAQ,CAAC,EAAG,EAAG,IAElCE,EAAS,IAAIlb,EAAQ,EAAG,EAAGggC,GAE3BlZ,EAAW,IAAI7L,GAASC,EAAQkkD,EAAWqlB,GAC3CruE,EAAQ,IAAI8Q,GAAMJ,EAAU09D,EAAa,CAACj3C,IAChDn3B,EAAM+Q,6BAA6B,OAEnC,MAAMK,EAAO,CACbA,WAAkB,GAMlB,YAL8B,IAAnBtT,IACTsT,EAAKpB,cAAgBlS,GAEvBkC,EAAM2U,QAAQvD,GAEPpR,CACT,C,yBCvDO,MAAMo+D,GAAa,CCEnB,MAOL,IAAW,CAAC,EAOZ,KAAa,EAObtX,UAAAA,CAAWkmB,GACTpwF,MAAK,GAAWowF,CAClB,CAOA3M,SAAAA,GACE,OAAOzjF,MAAK,EACd,CAMA,IAAQ,IAAImwF,GASZpP,IAAAA,CAAK5tE,EAAQ+U,EAAQ5a,GAEdtN,MAAK,KAERA,MAAK,GAAMkqE,WAAWlqE,MAAK,IAE3BA,MAAK,GAAMghF,YAAchhF,KAAKghF,YAC9BhhF,MAAK,GAAMggF,WAAahgF,KAAKggF,WAC7BhgF,MAAK,GAAM4hF,WAAa5hF,KAAK4hF,WAC7B5hF,MAAK,GAAM6gF,OAAS7gF,KAAK6gF,OACzB7gF,MAAK,GAAM8gF,UAAa9+D,IAEtBhiB,MAAK,IAAa,EAElBA,KAAK8gF,UAAU9+D,EAAM,EAEvBhiB,MAAK,GAAMkhF,QAAWl/D,IACpBA,EAAMs+D,OAASp4D,EACfloB,KAAKkhF,QAAQl/D,EAAM,EAErBhiB,MAAK,GAAM6hF,QAAU7hF,KAAK6hF,SAI5B7hF,MAAK,IAAa,EAElBA,MAAK,GAAMgxF,QAAQ79E,EAAQ+U,EAAQ5a,EACrC,CAKAi2E,KAAAA,GAEEvjF,MAAK,IAAa,EAElBA,MAAK,GAAMujF,OACb,CAWAmO,WAAAA,CAAYC,GACV,MAAMrhF,EAAMF,EAAiBuhF,EAAKnoF,MAGlC,OAF0B,OAAR8G,GACS,QAARA,CAErB,CAeAoxE,UAAAA,CAAWkQ,EAAKznB,GAEd,QAAuB,IAAZA,EAAyB,CAElC,QAAmC,IAAxBA,EAAQ0nB,aACO,UAAxB1nB,EAAQ0nB,YACR,OAAO,EAGT,QAAsC,IAA3B1nB,EAAQgY,eAAgC,CACjD,MAAM2P,EAAe,SAAUjgF,GAC7B,MAAwB,WAAjBA,EAAQrI,IACjB,EACMuoF,EAAe5nB,EAAQgY,eAAej4D,KAAK4nE,GACjD,QAA4B,IAAjBC,EAA8B,CAEvC,MAAMC,EAAc,oBACpB,OAAOxiF,EAAWuiF,EAAajwF,MAAOkwF,IACO,MAA3CD,EAAajwF,MAAMkwF,EAAY7vF,OACnC,CACF,CACF,CAEA,MAAM8vF,EAAYlU,GAAc6T,GAE1BthF,EAAMF,EAAiB6hF,EAAUC,UACjCC,EAAoB,OAAR7hF,EACZ8hF,EAAqB,QAAR9hF,EAEb+hF,EAAcJ,EAAUK,aAAajxF,IAAI,eAK/C,OAJuBgxF,QAEsB,sBAAhBA,EAEkBF,GAAYC,CAC7D,CAQAlB,aAAAA,CAAcqB,GACZ,MAAMF,EAAcE,EAAI,gBACxB,QAA2B,IAAhBF,GACTA,EAAY7iF,WAAW,qBACvB,OAAO,EAET,QAA4B,IAAjB+iF,EAAIpB,SAA0B,CACvC,MAAMqB,EAAU,IAAIC,KAAK,CAAC,eAAgBF,EAAIpB,UAC9C,OAAOnxF,KAAK0xF,YAAYc,EAC1B,CACA,OAAO,CACT,CAOAE,UAAAA,GACE,OAAOC,GAAiBjzD,WAC1B,CAOA8iD,SAAAA,GACE,OjB3LW,CiB4Lb,CAQAxB,WAAAA,CAAY5b,GAAS,CAQrB4a,UAAAA,CAAW5a,GAAS,CASpBwc,UAAAA,CAAWxc,GAAS,CASpByb,MAAAA,CAAOzb,GAAS,CAShB0b,SAAAA,CAAU1b,GAAS,CAQnB8b,OAAAA,CAAQ9b,GAAS,CAOjByc,OAAAA,CAAQzc,GAAS,GCtPZ,MAOL,KAAa,EAOb8E,UAAAA,CAAW0oB,GACT,CAQFnP,SAAAA,GACE,OAAOzjF,MAAK,EACd,CASA+gF,IAAAA,CAAK7nB,EAAMhxC,EAAQ5a,GAEjBtN,MAAK,IAAa,EAClBA,KAAKghF,YAAY,CACfV,OAAQp4D,IAGV,IACEloB,KAAKggF,WAAW,CACdC,kBAAkB,EAClBG,OAAQ,IACRC,MAAO,IACP/yE,MAAOA,EACPgzE,OAAQp4D,IAEV,MAAMjV,EAAO,CACXA,KAAMimD,EACNonB,OAAQp4D,GAGVloB,KAAK4hF,WAAW3uE,GAChBjT,KAAK6gF,OAAO5tE,EACd,CAAE,MAAOhO,GACPjF,KAAKkhF,QAAQ,CACXj8E,MAAOA,EACPq7E,OAAQp4D,GAEZ,CAAE,QAEAloB,MAAK,IAAa,EAClBA,KAAK8gF,UAAU,CACbR,OAAQp4D,GAEZ,CACF,CAKAq7D,KAAAA,GAEEvjF,MAAK,IAAa,EAElBA,KAAK6hF,QAAQ,CAAC,GACd7hF,KAAK8gF,UAAU,CAAC,EAClB,CASA4Q,WAAAA,CAAYC,GAEV,MAAgB,SADJvhF,EAAiBuhF,EAAKnoF,KAEpC,CAcAk4E,UAAAA,CAAWkQ,EAAKznB,GAEd,QAAuB,IAAZA,EAAyB,CAElC,QAAmC,IAAxBA,EAAQ0nB,aACO,SAAxB1nB,EAAQ0nB,YACR,OAAO,EAGT,QAAsC,IAA3B1nB,EAAQgY,eAAgC,CACjD,MAAM2P,EAAe,SAAUjgF,GAC7B,MAAwB,WAAjBA,EAAQrI,IACjB,EACMuoF,EAAe5nB,EAAQgY,eAAej4D,KAAK4nE,GACjD,QAA4B,IAAjBC,EAET,OAAOviF,EAAWuiF,EAAajwF,MAAO,qBACpC0N,EAAWuiF,EAAajwF,MAAO,yBAErC,CACF,CAIA,MAAgB,SADJsO,EADM2tE,GAAc6T,GACOM,SAEzC,CAQAhB,aAAAA,CAAcqB,GACZ,MAAMF,EAAcE,EAAI,gBACxB,QAA2B,IAAhBF,GACTA,EAAY7iF,WAAW,oBACvB,OAAO,EAET,QAA4B,IAAjB+iF,EAAIpB,SAA0B,CACvC,MAAMqB,EAAU,IAAIC,KAAK,CAAC,eAAgBF,EAAIpB,UAC9C,OAAOnxF,KAAK0xF,YAAYc,EAC1B,CACA,OAAO,CACT,CAOAE,UAAAA,GACE,OAAOC,GAAiBE,IAC1B,CAOArQ,SAAAA,GACE,OlBvKI,CkBwKN,CAQAxB,WAAAA,CAAY5b,GAAS,CAQrB4a,UAAAA,CAAW5a,GAAS,CASpBwc,UAAAA,CAAWxc,GAAS,CASpByb,MAAAA,CAAOzb,GAAS,CAShB0b,SAAAA,CAAU1b,GAAS,CAQnB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,GCjOZ,MAOL,KAAa,EAOb8E,UAAAA,CAAW0oB,GACT,CAQFnP,SAAAA,GACE,OAAOzjF,MAAK,EACd,CASA+gF,IAAAA,CAAK5tE,EAAQ+U,EAAQ5a,GAEnBtN,KAAKghF,YAAY,CACfV,OAAQp4D,IAGVloB,MAAK,IAAa,EAElB,MAAM8yF,EAAW,IAAI7B,GAErB6B,EAAS9S,WAAc+S,IAErBA,EAAS3S,OAAS,GAAK2S,EAAS3S,OAAS,EAEzC2S,EAASzlF,MAAQA,EACjBtN,KAAKggF,WAAW+S,EAAS,EAE3BD,EAASlR,WAAa5hF,KAAK4hF,WAC3BkR,EAASjS,OAAS7gF,KAAK6gF,OACvBiS,EAAShS,UAAa9+D,IAEpBhiB,MAAK,IAAa,EAElBA,KAAK8gF,UAAU9+D,EAAM,EAEvB8wE,EAAS5R,QAAUlhF,KAAKkhF,QACxB4R,EAASjR,QAAU7hF,KAAK6hF,QAExBiR,EAAS/R,KnGyIN,SAAwBlwE,GAC7B,MAAMmiF,EAAU,IAAIliF,WAAWD,GAEzB0B,EAAQ,GAEd,GAAuB,IAAnBygF,EAAQ7wF,OACV,OAAOoQ,EAIT,MACM0gF,EAAkB5gF,EADA,IAAIvB,WAAW,CAAC,GAAM,GAAM,GAAM,MAI1D,IAAIoiF,EAAqBjhF,EACvB+gF,EAASC,EAAiB,GAE5B,QAAkC,IAAvBC,EACT,MAAM,IAAIhxF,MAAM,oDAElB,MAEMixF,EAAQrhF,EAFUkhF,EAAQtwF,MAAM,EAAGwwF,IAES9jF,MAAM,QAExD,IAAIgkF,EACJ,IAAK,IAAI7wF,EAAI,EAAGA,EAAI4wF,EAAMhxF,SAAUI,EAClC,GAAoB,MAAhB4wF,EAAM5wF,GAAG,IAA8B,MAAhB4wF,EAAM5wF,GAAG,GAAY,CAC9C6wF,EAAcD,EAAM5wF,GACpB,KACF,CAEF,QAA2B,IAAhB6wF,EACT,MAAM,IAAIlxF,MAAM,+CAElB,MACMmxF,EAAahhF,EADFzB,EAAmBwiF,IAE9BE,EAAcF,EAAYjxF,OAGhC,IAAIoxF,EAAoBthF,EACtB+gF,EAASK,EAAY,GAIvB,UAAqC,IAAvBH,GAAoC,CAChD,MAAMM,EAAO,CAAC,EAMRC,EACJ3hF,EAJiBkhF,EAAQtwF,MACzB6wF,EAAoBD,EAAaJ,IAGF9jF,MAAM,QACvC,IAAK,IAAI/L,EAAI,EAAGA,EAAIowF,EAAgBtxF,SAAUkB,EAAG,CAC/C,MAAMshD,EAAO8uC,EAAgBpwF,GACvBqwF,EAAiB/uC,EAAKp3C,QAAQ,KACpC,IAAwB,IAApBmmF,EAAuB,CACzB,MAAM1yF,EAAM2jD,EAAK/0C,UAAU,EAAG8jF,GAAgBl0E,OACxCnd,EAAMsiD,EAAK/0C,UAAU8jF,EAAiB,GAAGl0E,OAC/Cg0E,EAAKxyF,GAAOqB,CACd,CACF,CAOA,GAJAkxF,EAAoBthF,EAClB+gF,EAASK,EAAYH,QAGU,IAAtBK,EACT,MAKF,MAAMI,EAAiBT,EAAqB,EAEtCU,EAAeL,EAAoB,EAEvCC,EAAKvgF,KADH0gF,EAAiBC,EACPZ,EAAQtwF,MAAMixF,EAAgBC,GAAczgF,OAE5C,IAAIrC,WAIlByB,EAAMtP,KAAKuwF,GAGXN,EAAqBjhF,EACnB+gF,EAASC,EACTM,EAAoBD,EAExB,CAEA,OAAO/gF,CACT,CmGvOkBshF,CAAe1gF,GAC/B,CAKAowE,KAAAA,GAEEvjF,MAAK,IAAa,EAElBA,KAAK6hF,QAAQ,CAAC,GACd7hF,KAAK8gF,UAAU,CAAC,EAClB,CASA4Q,WAAAA,CAAYoC,GACV,OAAO,CACT,CAYApS,UAAAA,CAAWkQ,EAAKznB,GAEd,QAAuB,IAAZA,EAAyB,CAElC,QAAmC,IAAxBA,EAAQ0nB,aACO,cAAxB1nB,EAAQ0nB,YACR,OAAO,EAGT,QAAsC,IAA3B1nB,EAAQgY,eAAgC,CACjD,MAAM2P,EAAe,SAAUjgF,GAC7B,MAAwB,WAAjBA,EAAQrI,IACjB,EACMuoF,EAAe5nB,EAAQgY,eAAej4D,KAAK4nE,GACjD,QAA4B,IAAjBC,EAET,OAAOviF,EAAWuiF,EAAajwF,MAAO,oBAE1C,CACF,CAEA,OAAO,CACT,CAQAovF,aAAAA,CAAc6C,GACZ,OAAO,CACT,CAOArB,UAAAA,GACE,OAAOC,GAAiBjzD,WAC1B,CAOA8iD,SAAAA,GACE,OnBnJW,CmBoJb,CAQAxB,WAAAA,CAAY5b,GAAS,CAQrB4a,UAAAA,CAAW5a,GAAS,CASpBwc,UAAAA,CAAWxc,GAAS,CASpByb,MAAAA,CAAOzb,GAAS,CAShB0b,SAAAA,CAAU1b,GAAS,CAQnB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,GC9MZ,MAOL,KAAW,EAOX8E,UAAAA,CAAW0oB,GACT,CAQFnP,SAAAA,GACE,OAAO,CACT,CASA,IAAepC,EAAU2S,GAEvB,IAAIC,EAAYD,EACXC,GAA2B,QAAdA,IAChBA,EAAY,QAGd,MAAMtC,EAAO,IAAIuC,KAAK,CAAC7S,GAAW,CAAC3/D,KAAM,SAAWuyE,IACpD,OAAOhzC,OAAOk9B,IAAIgW,gBAAgBxC,EACpC,CASA5Q,IAAAA,CAAK5tE,EAAQ+U,EAAQ5a,GACnBtN,MAAK,IAAW,EAEhB,MAAMojB,EAAQ,IAAI8Q,MA6BlB,GA3BA9Q,EAAMy9D,OAAS,KACb,IACE,IAAK7gF,MAAK,GAAU,CAClBA,KAAKggF,WAAW,CACdC,kBAAkB,EAClBG,OAAQ,IACRC,MAAO,IACP/yE,MAAOA,EACPgzE,OAAQp4D,IAEV,MAAMjV,ELHT,SAA6BmhF,EAAUlsE,EAAQ5a,GAEpD,MAAMlI,EAAQgvF,EAAShvF,MACjB+9B,EAASixD,EAASjxD,OAGlBkxD,EAAS3hC,SAASwgB,cAAc,UACtCmhB,EAAOjvF,MAAQA,EACfivF,EAAOlxD,OAASA,EAChB,MAAMmxD,EAAMD,EAAOhhB,WAAW,MAC9BihB,EAAI9gB,UAAU4gB,EAAU,EAAG,GAE3B,MAAM/C,EAAYiD,EAAI/nB,aAAa,EAAG,EAAGnnE,EAAO+9B,GAG1Cp+B,EAAO,CAAC,EACQ,iBAAXmjB,EACTnjB,EAAa,OAAI,CAACjD,MAAOomB,IAEzBnjB,EAAe,SAAI,CAACjD,MAAOomB,EAAO1e,MAClCzE,EAAe,SAAI,CAACjD,MAAOomB,EAAOxG,MAClC3c,EAA2B,qBAAI,CAACjD,MAAOomB,EAAOqsE,eAEhDxvF,EAAiB,WAAI,CAACjD,MAAOsD,GAC7BL,EAAkB,YAAI,CAACjD,MAAOqhC,GAE9B,MAAM6J,EAAa1/B,GAAgB,EASnC,OARAvI,EAAe,SAAI,CAACjD,MAAOkrC,GAQpB,CACL/5B,KAAM,CACJmQ,MANUmuE,GACZnsF,EAAO+9B,EAAQ6J,EAFGokD,GAAkBC,GAEI,EAAGrkD,EAAWxqC,YAMpDuC,KAAMA,GAERu7E,OAAQp4D,EAEZ,CKvCuBssE,CAAoBpxE,EAAO8E,EAAQ5a,GAEhDtN,KAAK4hF,WAAW3uE,GAChBjT,KAAK6gF,OAAO5tE,EACd,CACF,CAAE,MAAOhO,GACPjF,KAAKkhF,QAAQ,CACXj8E,MAAOA,EACPq7E,OAAQp4D,GAEZ,CAAE,QACAloB,KAAK8gF,UAAU,CACbR,OAAQp4D,GAEZ,GAGoB,iBAAX/U,EAETiQ,EAAMqxE,IAAMthF,OACP,GAAsB,iBAAX+U,EAAqB,CAErC,MAAM5X,EAAM4X,EAAO9Y,MAAM,KAAKqB,MAAMD,cACpC4S,EAAMqxE,IAAMz0F,MAAK,GAAemT,EAAQ7C,EAC1C,CACF,CAKAizE,KAAAA,GACEvjF,MAAK,IAAW,EAChBA,KAAK6hF,QAAQ,CAAC,GACd7hF,KAAK8gF,UAAU,CAAC,EAClB,CASA4Q,WAAAA,CAAYC,GACV,YAA6B,IAAdA,EAAKjwE,MACa,OAA/BiwE,EAAKjwE,KAAKxR,MAAM,UACpB,CAiBAwxE,UAAAA,CAAWkQ,EAAKznB,GAEd,QAAuB,IAAZA,EAAyB,CAElC,QAAmC,IAAxBA,EAAQ0nB,aACO,aAAxB1nB,EAAQ0nB,YACR,OAAO,EAGT,QAAsC,IAA3B1nB,EAAQgY,eAAgC,CACjD,MAAM2P,EAAe,SAAUjgF,GAC7B,MAAwB,WAAjBA,EAAQrI,IACjB,EACMuoF,EAAe5nB,EAAQgY,eAAej4D,KAAK4nE,GACjD,QAA4B,IAAjBC,EAET,OAAOviF,EAAWuiF,EAAajwF,MAAO,SAE1C,CACF,CAEA,MAAMmwF,EAAYlU,GAAc6T,GAE1BthF,EAAMF,EAAiB6hF,EAAUC,UACjCwC,EAAuB,SAARpkF,GAA4B,QAARA,GAC9B,QAARA,GAA2B,QAARA,EAEhB+hF,EAAcJ,EAAUK,aAAajxF,IAAI,eAO/C,OANuBgxF,QAEsB,eAAhBA,GACV,cAAhBA,GACgB,cAAhBA,EAE2CqC,CAChD,CAQAxD,aAAAA,CAAcqB,GACZ,QAA4B,IAAjBA,EAAIpB,SAA0B,CACvC,MAAMqB,EAAU,IAAIC,KAAK,CAAC,eAAgBF,EAAIpB,UAC9C,OAAOnxF,KAAK0xF,YAAYc,EAC1B,CACA,OAAO,CACT,CAOAE,UAAAA,GACE,OAAOC,GAAiBgC,OAC1B,CAOAnS,SAAAA,GACE,OpBrMW,CoBsMb,CAQAxB,WAAAA,CAAY5b,GAAS,CAQrB4a,UAAAA,CAAW5a,GAAS,CASpBwc,UAAAA,CAAWxc,GAAS,CASpByb,MAAAA,CAAOzb,GAAS,CAShB0b,SAAAA,CAAU1b,GAAS,CAQnB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,GC7PZ,MAOL8E,UAAAA,CAAW0oB,GACT,CAQFnP,SAAAA,GACE,OAAO,CACT,CASA,IAAepC,EAAU2S,GAEvB,MAAMpoB,EAAQ,IAAI96D,WAAWuwE,GAC7B,IAAIuT,EAAe,GACnB,IAAK,IAAIryF,EAAI,EAAGA,EAAIqpE,EAAM54D,aAAczQ,EACtCqyF,GAAgB7iF,OAAOC,aAAa45D,EAAMrpE,IAK5C,MAFY,cAAgByxF,EAC1B,WAAa/yC,OAAO4zC,KAAKD,EAE7B,CASA7T,IAAAA,CAAK5tE,EAAQ+U,EAAQ5a,GAEnB,MAAMwnF,EAAQpiC,SAASwgB,cAAc,SACrC,GAAsB,iBAAXhrD,EAAqB,CAE9B,MAAM5X,EAAM4X,EAAO9Y,MAAM,KAAKqB,MAAMD,cACpCskF,EAAML,IAAMz0F,MAAK,GAAemT,EAAQ7C,EAC1C,MACEwkF,EAAML,IAAMthF,EAGd2hF,EAAMC,iBAAoB/yE,IACxB,KNyDC,SACL8yE,EAAOlT,EAAYf,EAAQb,EAAYc,EACvC54D,EAAQyoE,GAER,MAAMvrF,EAAQ0vF,EAAME,WACd7xD,EAAS2xD,EAAMG,YAKf/zE,EAAiBvd,KAAKuxF,KAFV,GAEeJ,EAAMK,UAGjCpwF,EAAO,CAAC,EACQ,iBAAXmjB,EACTnjB,EAAa,OAAI,CAACjD,MAAOomB,IAEzBnjB,EAAe,SAAI,CAACjD,MAAOomB,EAAO1e,MAClCzE,EAAe,SAAI,CAACjD,MAAOomB,EAAOxG,MAClC3c,EAA2B,qBAAI,CAACjD,MAAOomB,EAAOqsE,eAEhDxvF,EAAiB,WAAI,CAACjD,MAAOsD,GAC7BL,EAAkB,YAAI,CAACjD,MAAOqhC,GAC9Bp+B,EAAqB,eAAI,CAACjD,MAAOof,GACjCnc,EAAe,SAAI,CAACjD,MAAO,GAG3B,MAAMuyF,EAAS3hC,SAASwgB,cAAc,UACtCmhB,EAAOjvF,MAAQA,EACfivF,EAAOlxD,OAASA,EAChB,MAAMmxD,EAAMD,EAAOhhB,WAAW,MAG9ByhB,EAAM//C,iBAAiB,UAkDvB,SAASqgD,EAASpzE,IAxClB,WAEEg+D,EAAW,CACTC,kBAAkB,EAClBG,OAAQ9rC,EACR+rC,MAAOn/D,EACP5T,MAAOqjF,EACPrQ,OAAQp4D,IAGVosE,EAAI9gB,UAAUshB,EAAO,EAAG,GAExB,MAAMO,EAAYjE,GAChBkD,EAAI/nB,aAAa,EAAG,EAAGnnE,EAAO+9B,IACb,IAAfmR,GAEFlxB,EAAQmuE,GACNnsF,EAAO+9B,EAAQ,EAAGkyD,EAAWn0E,EAAgByvE,EAAUnuF,YAEzDo/E,EAAW,CACT3uE,KAAM,CACJmQ,MAAOA,EACPre,KAAMA,GAERu7E,OAAQp4D,KAGV9E,EAAMgxB,kBAAkBihD,EAAW/gD,KAGnCA,CACJ,EAWEghD,GAGAC,GAAY,EAhFI,GAiFZA,GAAYvzE,EAAM8tC,OAAOqlC,SAC3Bn1F,KAAKw1F,YAAcD,GAEnB1U,EAAO,CACLP,OAAQp4D,IAEV44D,EAAU,CACRR,OAAQp4D,IAGV4sE,EAAM9/C,oBAAoB,SAAUogD,GAExC,IApE2C,GAG3C,IAAI9gD,EAAa,EAEblxB,EAAQ,KAsCRmyE,EAAW,EA4BfT,EAAMU,YAAcD,CACtB,CMjKQE,CAAoBzzE,EAAM8tC,OACxB9vD,KAAK4hF,WAAY5hF,KAAK6gF,OACtB7gF,KAAKggF,WAAYhgF,KAAK8gF,UACtB54D,EAAQ5a,EACZ,CAAE,MAAOrI,GACPjF,KAAKkhF,QAAQ,CACXj8E,MAAOA,EACPq7E,OAAQp4D,IAEVloB,KAAK8gF,UAAU,CACbR,OAAQp4D,GAEZ,EAEJ,CAKAq7D,KAAAA,GACEvjF,KAAK6hF,QAAQ,CAAC,GACd7hF,KAAK8gF,UAAU,CAAC,EAClB,CASA4Q,WAAAA,CAAYC,GACV,YAA6B,IAAdA,EAAKjwE,MACa,OAA/BiwE,EAAKjwE,KAAKxR,MAAM,UACpB,CAcAwxE,UAAAA,CAAWkQ,EAAKznB,GAEd,QAAuB,IAAZA,EAAyB,CAElC,QAAmC,IAAxBA,EAAQ0nB,aACO,aAAxB1nB,EAAQ0nB,YACR,OAAO,EAGT,QAAsC,IAA3B1nB,EAAQgY,eAAgC,CACjD,MAAM2P,EAAe,SAAUjgF,GAC7B,MAAwB,WAAjBA,EAAQrI,IACjB,EACMuoF,EAAe5nB,EAAQgY,eAAej4D,KAAK4nE,GACjD,QAA4B,IAAjBC,EAET,OAAOviF,EAAWuiF,EAAajwF,MAAO,SAE1C,CACF,CAEA,MACMwO,EAAMF,EADM2tE,GAAc6T,GACOM,UACvC,MAAgB,QAAR5hF,GACG,QAARA,GACQ,SAARA,CACL,CAQA4gF,aAAAA,CAAcqB,GACZ,QAA4B,IAAjBA,EAAIpB,SAA0B,CACvC,MAAMqB,EAAU,IAAIC,KAAK,CAAC,eAAgBF,EAAIpB,UAC9C,OAAOnxF,KAAK0xF,YAAYc,EAC1B,CACA,OAAO,CACT,CAOAE,UAAAA,GACE,OAAOC,GAAiBgC,OAC1B,CAOAnS,SAAAA,GACE,OrBzKW,CqB0Kb,CAQAxB,WAAAA,CAAY5b,GAAS,CAQrB4a,UAAAA,CAAW5a,GAAS,CASpBwc,UAAAA,CAAWxc,GAAS,CASpByb,MAAAA,CAAOzb,GAAS,CAShB0b,SAAAA,CAAU1b,GAAS,CAQnB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,GC3NZ,MAOL,KAAa,EAOb8E,UAAAA,CAAW0oB,GACT,CAQFnP,SAAAA,GACE,OAAOzjF,MAAK,EACd,CAEA,IAAY,GACZ,IAAS,GACT,IAAS,KAST,IAAkBmsF,EAASjkE,EAAQ5a,GACjCtN,MAAK,GAAOiD,KAAK,CAACkuF,SAAUnxF,MAAK,GAAWiT,KAAMk5E,IAIlD,MAAMuJ,EAAoC,IAArB11F,MAAK,GAAOmC,OAAenC,MAAK,GAAOmC,OAc5D,GAbAnC,KAAKggF,WAAW,CACdC,kBAAkB,EAClBG,OAASsV,EAAe,EACxBrV,MAAO,IACP/yE,MAAOA,EACPmR,KAAM,CACJ2hE,OAAQsV,EACRrV,MAAO,IACPC,OAAQp4D,KAKRloB,MAAK,GAAOmC,OAASnC,MAAK,GAAOmC,OAAQ,CAC3C,MAAM29E,EAAM9/E,MAAK,GAAOmC,OACxBnC,MAAK,GAAYA,MAAK,GAAO8/E,GAAKt2E,KAClCxJ,MAAK,GAAO8/E,GAAK6V,MAAM,eAAeC,MAAMzJ,IAC1CnsF,MAAK,GAAkBmsF,EAASjkE,EAAQ5a,EAAM,GAElD,KAAO,CACL,MAAMwlF,EAAW,IAAI7B,GAErB6B,EAAS9S,WAAc+S,IAErBA,EAAS3S,OAAS,GAAK2S,EAAS3S,OAAS,EAEzC2S,EAASzlF,MAAQA,EACjBtN,KAAKggF,WAAW+S,EAAS,EAE3BD,EAASlR,WAAa5hF,KAAK4hF,WAC3BkR,EAASjS,OAAS7gF,KAAK6gF,OACvBiS,EAAShS,UAAa9+D,IAEpBhiB,MAAK,IAAa,EAElBA,KAAK8gF,UAAU9+D,EAAM,EAEvB8wE,EAAS5R,QAAUlhF,KAAKkhF,QACxB4R,EAASjR,QAAU7hF,KAAK6hF,QAExBiR,EAAS/R,KAAK/gF,MAAK,GACrB,CACF,CASA+gF,IAAAA,CAAK5tE,EAAQ+U,EAAQ5a,GAEnBtN,KAAKghF,YAAY,CACfV,OAAQp4D,IAGVloB,MAAK,IAAa,EAElB61F,KAAAA,UAAgB1iF,GAAQyiF,MAAME,IAC5B91F,MAAK,GAAS,GACdA,MAAK,GAAS81F,EAAInE,KAAK,WAEvB,MAAM7R,EAAM9/E,MAAK,GAAOmC,OACxBnC,MAAK,GAAYA,MAAK,GAAO8/E,GAAKt2E,KAClCxJ,MAAK,GAAO8/E,GAAK6V,MAAM,eAAeC,MAAMzJ,IAC1CnsF,MAAK,GAAkBmsF,EAASjkE,EAAQ5a,EAAM,GAC9C,GAEN,CAKAi2E,KAAAA,GAEEvjF,MAAK,IAAa,EAElBA,KAAK6hF,QAAQ,CAAC,GACd7hF,KAAK8gF,UAAU,CAAC,EAClB,CASA4Q,WAAAA,CAAYC,GAEV,MAAgB,QADJvhF,EAAiBuhF,EAAKnoF,KAEpC,CAcAk4E,UAAAA,CAAWkQ,EAAKznB,GAEd,QAAuB,IAAZA,EAAyB,CAElC,QAAmC,IAAxBA,EAAQ0nB,aACO,QAAxB1nB,EAAQ0nB,YACR,OAAO,EAGT,QAAsC,IAA3B1nB,EAAQgY,eAAgC,CACjD,MAAM2P,EAAe,SAAUjgF,GAC7B,MAAwB,WAAjBA,EAAQrI,IACjB,EACMuoF,EAAe5nB,EAAQgY,eAAej4D,KAAK4nE,GACjD,QAA4B,IAAjBC,EAET,OAAOviF,EAAWuiF,EAAajwF,MAAO,kBAE1C,CACF,CAIA,MAAgB,QADJsO,EADM2tE,GAAc6T,GACOM,SAEzC,CAQAhB,aAAAA,CAAcqB,GACZ,MAAMF,EAAcE,EAAI,gBACxB,QAA2B,IAAhBF,GACTA,EAAY7iF,WAAW,mBACvB,OAAO,EAET,QAA4B,IAAjB+iF,EAAIpB,SAA0B,CACvC,MAAMqB,EAAU,IAAIC,KAAK,CAAC,eAAgBF,EAAIpB,UAC9C,OAAOnxF,KAAK0xF,YAAYc,EAC1B,CACA,OAAO,CACT,CAOAE,UAAAA,GACE,OAAOC,GAAiBjzD,WAC1B,CAOA8iD,SAAAA,GACE,OtB5NW,CsB6Nb,CAQAxB,WAAAA,CAAY5b,GAAS,CAQrB4a,UAAAA,CAAW5a,GAAS,CASpBwc,UAAAA,CAAWxc,GAAS,CASpByb,MAAAA,CAAOzb,GAAS,CAShB0b,SAAAA,CAAU1b,GAAS,CAQnB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,IC5RNutB,GAAmB,CAC9BE,KAAM,EACNnzD,YAAa,EACbi1D,QAAS,GAMJ,MAAMoB,GAOX,IAAa,KAOb,IAAW,GAOX,IAAiB,KAOjB,IAAS,EAOT,IAAY,EAOZ,GAOA/3E,sBAAAA,GACE,OAAOhe,MAAK,CACd,CAOAie,sBAAAA,CAAuBC,GACrBle,MAAK,EAAuBke,CAC9B,CAOA,IAAgBjL,GACdjT,MAAK,GAAaiT,EAElBjT,MAAK,GAAS,EACdA,MAAK,GAAY,EAEjBA,MAAK,KACLA,MAAK,IACP,CAOA,IAAase,GACXte,MAAK,GAASiD,KAAKqb,EACrB,CAMA,MACEte,MAAK,GAAW,EAClB,CAOA,IAAa4gF,GACX5gF,MAAK,GAAiB4gF,CACxB,CAMA,MACE5gF,MAAK,GAAiB,IACxB,CAQA,IAAYolE,IACVplE,MAAK,KAIDA,MAAK,KAAWA,MAAK,GAAWmC,QAClCnC,KAAK6gF,OAAO,CACVP,OAAQtgF,MAAK,IAEjB,EASF,IAAeolE,IACbplE,MAAK,KAIDA,MAAK,KAAcA,MAAK,GAAWmC,QACrCnC,KAAK8gF,UAAU,CACbR,OAAQtgF,MAAK,IAEjB,EAeF,IAAsB2hB,EAAU2+D,GAC9B,OAAQt+D,IACNA,EAAMs+D,OAASA,EACf3+D,EAASK,EAAM,CAEnB,CAUA,IAAgB4+D,EAAQ7gE,EAAaxd,GACnC,OAAQyf,IACN4+D,EAAOG,KAAK/+D,EAAM8tC,OAAO1zC,OAAQ2D,EAAaxd,EAAE,CAEpD,CAQAw+E,IAAAA,CAAK9tE,GAEH,QAAoB,IAATA,GAAwC,IAAhBA,EAAK9Q,OACtC,OAEFnC,MAAK,GAAgBiT,GAGrBjT,KAAKghF,YAAY,CACfV,OAAQrtE,IAIV,MAAMquE,EAAe,IAAI1B,GAAqB5/E,KAAKggF,YACnDsB,EAAavB,WAAW9sE,EAAK9Q,QAG7B,MAAMo/E,EAAU,GAChB,IAAK,IAAIj2E,EAAI,EAAGA,EAAIk2E,GAAWr/E,SAAUmJ,EACvCi2E,EAAQt+E,KAAK,IAAIu+E,GAAWl2E,IAI9B,IAAIyU,EAAc9M,EAAK,GACnB2tE,EAAS,KACTa,GAAc,EAClB,IAAK,IAAIp+E,EAAI,EAAGA,EAAIk+E,EAAQp/E,SAAUkB,EAEpC,GADAu9E,EAASW,EAAQl+E,GACbu9E,EAAO8Q,YAAY3xE,GAAc,CACnC0hE,GAAc,EAEdb,EAAO1W,WAAW,CAChB92C,cAAengB,EAAK9Q,OACpBw/E,oBAAqB3hF,KAAKge,2BAI5B4iE,EAAOZ,WAAasB,EAAab,gCAAgC,GACjEG,EAAOgB,WAAa5hF,KAAK4hF,WACzBhB,EAAOC,OAAS7gF,MAAK,GACrB4gF,EAAOE,UAAY9gF,MAAK,GACxB4gF,EAAOM,QAAUlhF,KAAKkhF,QACtBN,EAAOiB,QAAU7hF,KAAK6hF,QAGtB7hF,MAAK,GAAa4gF,GAElB,KACF,CAEF,IAAKa,EACH,MAAM,IAAIv/E,MAAM,6BAA+B6d,EAAYvW,MAI7D,IAAK,IAAIjH,EAAI,EAAGA,EAAI0Q,EAAK9Q,SAAUI,EAAG,CAIpC,GAHAwd,EAAc9M,EAAK1Q,IAGdq+E,EAAO8Q,YAAY3xE,GACtB,MAAM,IAAI7d,MAAM,iCAAmC6d,GAUrD,MAAMzB,EAAS,IAAI03E,WAEnBh2F,MAAK,GAAase,GAIlBA,EAAO0hE,WAAahgF,MAAK,GACvBshF,EAAad,uBAAuBj+E,EAAG,GAAIwd,GAC7CzB,EAAOuiE,OAAS7gF,MAAK,GAAgB4gF,EAAQ7gE,EAAaxd,GAE1D,MAAM+/E,EACJtiF,MAAK,GAAsBA,KAAKkhF,QAASnhE,GAC3CzB,EAAO4iE,QAAWl/D,IAChBhiB,MAAK,KACLsiF,EAActgE,EAAM,EAEtB,MAAMugE,EACJviF,MAAK,GAAsBA,KAAK6hF,QAAS9hE,GAC3CzB,EAAOujE,QAAW7/D,IAChBhiB,MAAK,KACLuiF,EAAcvgE,EAAM,EAGlB4+D,EAAO8R,eAAiBC,GAAiBE,KAC3Cv0E,EAAO23E,WAAWl2E,GACT6gE,EAAO8R,eAAiBC,GAAiBgC,QAClDr2E,EAAO43E,cAAcn2E,GACZ6gE,EAAO8R,eAAiBC,GAAiBjzD,aAClDphB,EAAO63E,kBAAkBp2E,EAE7B,CACF,CAKAwjE,KAAAA,GAEE,IAAK,IAAIhhF,EAAI,EAAGA,EAAIvC,MAAK,GAASmC,SAAUI,EAEN,IAAhCvC,MAAK,GAASuC,GAAGihF,YACnBxjF,MAAK,GAASuC,GAAGghF,QAIjBvjF,MAAK,IAAkBA,MAAK,GAAeyjF,aAC7CzjF,MAAK,GAAeujF,OAExB,CAQAvC,WAAAA,CAAY5b,GAAS,CAQrB4a,UAAAA,CAAW5a,GAAS,CASpBwc,UAAAA,CAAWxc,GAAS,CASpByb,MAAAA,CAAOzb,GAAS,CAShB0b,SAAAA,CAAU1b,GAAS,CAQnB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,ECjXZ,MAAMgxB,GAOX,GAOA,IAAkB,CAAC,EAKnBp0F,WAAAA,CAAY2/E,GACV3hF,MAAK,EAAuB2hF,CAC9B,CAQA0U,SAAAA,CAAUC,EAAO/+B,GAGH,SADA++B,EAAM,GAAG9sF,KAAK4F,MAAM,KAAKqB,MAAMD,cAEzCxQ,MAAK,GAAes2F,EAAM,GAAI/+B,GAE9Bv3D,MAAK,GAAgBs2F,EAAO/+B,EAEhC,CAYAg/B,QAAAA,CAAS3T,EAAMrrB,EAAQ4S,GAGT,SADAyY,EAAK,GAAGxzE,MAAM,KAAKqB,MAAMD,cAEnCxQ,MAAK,GAAc4iF,EAAK,GAAIrrB,EAAQ4S,GAEpCnqE,MAAK,GAAe4iF,EAAMrrB,EAAQ4S,EAEtC,CASAqsB,eAAAA,CAAgBvjF,EAAMskD,GAEpB,MAAMu7B,EAAW,IAAI7B,GAErBjxF,MAAK,GAAUiT,EAAM6/E,EAAU,QAASv7B,EAC1C,CAOAk/B,iBAAAA,GACE,OAAOv1F,OAAO4R,KAAK9S,MAAK,GAC1B,CAOAujF,KAAAA,CAAMhsB,QACwC,IAAjCv3D,MAAK,GAAgBu3D,KAC9Bv3D,MAAK,GAAgBu3D,GAAQqpB,OAAO2C,eAC7BvjF,MAAK,GAAgBu3D,GAEhC,CAUA,IAAgB++B,EAAO/+B,GAErB,MAAMm/B,EAAS,IAAIX,GACnBW,EAAOz4E,uBAAuBje,MAAK,GAEnCA,MAAK,GAAUs2F,EAAOI,EAAQ,QAASn/B,EACzC,CAWA,IAAeqrB,EAAMrrB,EAAQ4S,GAE3B,MAAMwsB,EAAQ,IAAIjW,GAClBiW,EAAM14E,uBAAuBje,MAAK,GAElCA,MAAK,GAAU4iF,EAAM+T,EAAO,QAASp/B,EAAQ4S,EAC/C,CAQA,IAAewnB,EAAMp6B,GAEnB,MAAMm/B,EAAS,IAAIX,GAEnB/1F,MAAK,GAAU,CAAC2xF,GAAO+E,EAAQ,QAASn/B,EAC1C,CAYA,IAAcq6B,EAAKr6B,EAAQ4S,GAEzB,MAAMwsB,EAAQ,IAAIjW,GAElB1gF,MAAK,GAAU,CAAC4xF,GAAM+E,EAAO,QAASp/B,EAAQ4S,EAChD,CAWA,IAAUl3D,EAAM2tE,EAAQgW,EAAUr/B,EAAQ4S,GACxC,MAAM0sB,EAAY,CAChBC,SAAUF,EACVnmC,OAAQ8G,GAIVqpB,EAAOI,YAAeh/D,IAEpBhiB,MAAK,GAAgBu3D,GAAU,CAC7BqpB,OAAQA,EACRmW,aAAa,GAGf/2F,MAAK,GAAsBA,KAAKghF,YAAa6V,EAA7C72F,CAAwDgiB,EAAM,EAEhE4+D,EAAOZ,WAAahgF,MAAK,GAAsBA,KAAKggF,WAAY6W,GAChEjW,EAAOgB,WAAc5/D,IACnB,MAAMg1E,EAAgB,CACpBF,SAAUF,EACVnmC,OAAQ8G,QAEkC,IAAjCv3D,MAAK,GAAgBu3D,KAC9By/B,EAAcC,YAAcj3F,MAAK,GAAgBu3D,GAAQw/B,aAG3D/2F,MAAK,GAAsBA,KAAK4hF,WAAYoV,EAA5Ch3F,CAA2DgiB,QAEf,IAAjChiB,MAAK,GAAgBu3D,IAC9Bv3D,MAAK,GAAgBu3D,GAAQw/B,cAC7B/2F,MAAK,GAAgBu3D,GAAQw/B,aAAc,EAC7C,EAEFnW,EAAOC,OAAS7gF,MAAK,GAAsBA,KAAK6gF,OAAQgW,GACxDjW,EAAOE,UAAa9+D,WAEXhiB,MAAK,GAAgBu3D,GAE5Bv3D,MAAK,GAAsBA,KAAK8gF,UAAW+V,EAA3C72F,CAAsDgiB,EAAM,EAE9D4+D,EAAOM,QAAUlhF,MAAK,GAAsBA,KAAKkhF,QAAS2V,GAC1DjW,EAAOiB,QAAU7hF,MAAK,GAAsBA,KAAK6hF,QAASgV,GAE1D,IACEjW,EAAOG,KAAK9tE,EAAMk3D,EACpB,CAAE,MAAOllE,GAQP,OAPAjF,KAAKkhF,QAAQ,CACXj8E,MAAOA,EACPwrD,OAAQ8G,SAEVv3D,KAAK8gF,UAAU,CACbrwB,OAAQ8G,GAGZ,CACF,CAUA,IAAsB51C,EAAU5c,GAC9B,OAAO,SAAUid,GACf,MAAMlP,EAAO5R,OAAO4R,KAAK/N,GACzB,IAAK,IAAIxC,EAAI,EAAGA,EAAIuQ,EAAK3Q,SAAUI,EAAG,CACpC,MAAMvB,EAAM8R,EAAKvQ,GACjByf,EAAMhhB,GAAO+D,EAAK/D,EACpB,CACA2gB,EAASK,EACX,CACF,CAQAg/D,WAAAA,CAAY5b,GAAS,CAQrB4a,UAAAA,CAAW5a,GAAS,CASpByb,MAAAA,CAAOzb,GAAS,CAShBwc,UAAAA,CAAWxc,GAAS,CASpB0b,SAAAA,CAAU1b,GAAS,CAQnB8b,OAAAA,CAAQ9b,GAAS,CAQjByc,OAAAA,CAAQzc,GAAS,ECpSnB,SAAS8xB,GAAqBhmF,GAC5B,OAAO,SAAU4uE,GACf,OAAOl1E,OAAOk1E,GAAK5N,YAAYhhE,EACjC,CACF,CASA,SAASimF,GAA2Bh1F,GAClC,IAAI2G,EAAM,GACV,IAAK,IAAIvG,EAAI,EAAGA,EAAIJ,IAAUI,EAClB,IAANA,IACFuG,GAAO,MAETA,GAAO,KAAOvG,EAAI,IAEpB,OAAOuG,CACT,CAeA,SAASqpE,GAAapiE,EAAU9N,GAC9B,IAAI6G,EAAMiH,EACV,IAAK,IAAIxN,EAAI,EAAGA,EAAIN,EAAOE,SAAUI,EACnCuG,EAAMA,EAAI2xB,QAAQ,KAAOl4B,EAAI,IAAKN,EAAOM,IAE3C,OAAOuG,CACT,CAKO,MAAMsuF,GAOX,IAOA,IAOA,IAOA,IAAc,GAOd,IAOA,IAAQ,GAOR,IAOA,IAAmB,IAAI31E,GAOvBzf,WAAAA,CAAYmgD,EAAKoV,EAAQ8/B,GACvBr3F,MAAK,GAAOmiD,EACZniD,MAAK,GAAUu3D,EACfv3D,MAAK,GAAWq3F,EAGhB,MAAMvkF,EAAO5R,OAAO4R,KAAK9S,MAAK,IAC9B,IAAK,IAAIuC,EAAI,EAAGA,EAAIuQ,EAAK3Q,SAAUI,EAAG,CACpC,MAAMyvC,EAAShyC,MAAK,GAAS8S,EAAKvQ,IAClC,IAAK,IAAIa,EAAI,EAAGA,EAAI4uC,EAAO7vC,SAAUiB,EAAG,CACtC,MAAMk8E,EAAYttC,EAAO5uC,GAAG4e,WACH,IAAds9D,IACJt/E,MAAK,GAAY2Q,SAAS2uE,IAC7Bt/E,MAAK,GAAYiD,KAAKq8E,GAG5B,CACF,CAEAt/E,KAAKs3F,iBACP,CAKAroC,KAAAA,GACEjvD,MAAK,GAAQ,GACbA,MAAK,QAAkBQ,CACzB,CAOA+2F,WAAAA,CAAYtkF,GAEV,IAAIukF,EAEJ,QAAgC,IAArBvkF,EAAK,YAGZukF,OAF8B,IAArBvkF,EAAK,YAEJA,EAAK,YAAYnR,MAAM,GAEvBmR,EAAK9Q,OAEjBnC,MAAK,GAAMw3F,GA6KjB,SAA2BhnD,EAAe6mD,GACxC,MAAMI,EAAW,GACjB,IAAIjoE,EACJ,MAAMkoE,EAAalnD,EAAc,YACjC,QAA0B,IAAfknD,EAGT,OAAOD,EAFPjoE,EAAWkoE,EAAW51F,MAAM,GAI9B,MAAMkwC,EAASqlD,EAAQ7nE,IAAa6nE,EAAQ,KAC5C,IAAKrlD,EACH,OAAOylD,EAGT,IAAK,IAAI/2F,EAAI,EAAGA,EAAIsxC,EAAO7vC,SAAUzB,EAAG,CAEtC,MAAMi3F,EAAUnuD,KAAKtpB,MAAMspB,KAAKC,UAAUuI,EAAOtxC,KAG3C8S,EAAOmkF,EAAQnkF,KACrB,QAAoB,IAATA,GAAwC,IAAhBA,EAAKrR,OAAc,CAEpD,MAAMF,EAAS,GACf,IAAK,IAAIM,EAAI,EAAGA,EAAIiR,EAAKrR,SAAUI,OAEb,IADPiuC,EAAch9B,EAAKjR,IAE9BN,EAAOgB,KAAKutC,EAAch9B,EAAKjR,IAAIT,OAEnCG,EAAOgB,KAAK,SAIc,IAAnB00F,EAAQC,QAA6C,OAAnBD,EAAQC,SACnDD,EAAQC,OAAST,GAA2Bl1F,EAAOE,SAErDw1F,EAAQ71F,MAAQqwE,GAAawlB,EAAQC,OAAQ31F,GAAQud,MACvD,CAGAi4E,EAASx0F,KAAK00F,EAChB,CAGA,MAAME,EAAYrnD,EAAc,YAChC,QAAyB,IAAdqnD,GACkB,IAA3BA,EAAU/1F,MAAMK,OAChB,CACA,MAAM21F,EAAMD,EAAU/1F,MAAM,GACtBi2F,EAAMF,EAAU/1F,MAAM,GAC5B21F,EAASx0F,KAAK,CACZ0M,IAAK,KAAM7N,MAAOg2F,EAAKF,OAAQ,SAEjCH,EAASx0F,KAAK,CACZ0M,IAAK,KAAM7N,MAAOua,GAAsBy7E,GAAMF,OAAQ,SAExDH,EAASx0F,KAAK,CACZ0M,IAAK,KAAM7N,MAAOi2F,EAAKH,OAAQ,SAEjCH,EAASx0F,KAAK,CACZ0M,IAAK,KAAM7N,MAAOua,GAAsB07E,GAAMH,OAAQ,QAE1D,CAEA,OAAOH,CACT,CA7O4BO,CAAkB/kF,EAAMjT,MAAK,QAC9C,CAEL,MAAM8S,EAAO5R,OAAO4R,KAAKG,GACzB,IAAK,IAAIpS,EAAI,EAAGA,EAAIiS,EAAK3Q,SAAUtB,EAAG,CACpC,MAAMS,EAAM2R,EAAKH,EAAKjS,IACtB,GAAgB,aAAZiS,EAAKjS,GAAmB,CAC1B22F,EAAUl2F,EAAIQ,MACd,KACF,CACF,CACA9B,MAAK,GAAMw3F,GA2OjB,SAAiCzyF,EAAMsyF,GACrC,MAAMI,EAAW,GACXzlD,EAASqlD,EAAQY,IACvB,IAAKjmD,EACH,OAAOylD,EAGT,MAAMS,EAAWh3F,OAAO4R,KAAK/N,GAE7B,IAAK,IAAIrE,EAAI,EAAGA,EAAIsxC,EAAO7vC,SAAUzB,EAAG,CAEtC,MAAMi3F,EAAUnuD,KAAKtpB,MAAMspB,KAAKC,UAAUuI,EAAOtxC,KAG3C8S,EAAOmkF,EAAQnkF,KACrB,QAAoB,IAATA,GAAwC,IAAhBA,EAAKrR,OAAc,CAEpD,MAAMF,EAAS,GACf,IAAK,IAAIM,EAAI,EAAGA,EAAIiR,EAAKrR,SAAUI,EACjC,IAAK,IAAIa,EAAI,EAAGA,EAAI80F,EAAS/1F,SAAUiB,EACjCoQ,EAAKjR,KAAO21F,EAAS90F,IACvBnB,EAAOgB,KAAK8B,EAAKmzF,EAAS90F,IAAItB,YAKN,IAAnB61F,EAAQC,QAA6C,OAAnBD,EAAQC,SACnDD,EAAQC,OAAST,GAA2Bl1F,EAAOE,SAErDw1F,EAAQ71F,MAAQqwE,GAAawlB,EAAQC,OAAQ31F,GAAQud,MACvD,CAGAi4E,EAASx0F,KAAK00F,EAChB,CAEA,OAAOF,CACT,CAhR4BU,CAAwBllF,EAAMjT,MAAK,GAC3D,CAEAA,MAAK,GAAkBw3F,CACzB,CAOA,IAAkBx1E,IACZA,EAAMyuC,SAAWzwD,MAAK,SAGA,IAAfgiB,EAAM/O,WACgB,IAAxB+O,EAAM/O,KAAKsnC,UAClBv6C,MAAK,KAAoBgiB,EAAM/O,KAAKsnC,WACpCv6C,MAAK,GAAkBgiB,EAAM/O,KAAKsnC,SAClCv6C,MAAK,GAAYgiB,GACnB,EASF,IAAeA,IACb,GAAIA,EAAMyuC,SAAWzwD,MAAK,GACxB,OAGF,MAAMo4F,EAAmBp4F,MAAK,GAAMA,MAAK,IACzC,QAAgC,IAArBo4F,EAAX,CAKA,IAAK,IAAI13F,EAAI,EAAGA,EAAI03F,EAAiBj2F,SAAUzB,EAAG,CAChD,IAAIw4D,EACJ,QAAwC,IAA7Bk/B,EAAiB13F,GAAG8S,KAEV,mBAAfwO,EAAMN,OACRw3C,EAAOk/B,EAAiB13F,GAAGoB,YAI7B,QAAyC,IAA9Bs2F,EAAiB13F,GAAGshB,OAC7Bo2E,EAAiB13F,GAAGshB,QAAUA,EAAMN,KAAM,CAC1C,MAAMk2E,EAASQ,EAAiB13F,GAAGk3F,OACnC,IAAI31F,EAAS+f,EAAMlgB,MAEnB,QAA6C,IAAlCs2F,EAAiB13F,GAAGwQ,UAA2B,CACxD,IAAImnF,EAAU,KAEZA,EADoC,UAAlCD,EAAiB13F,GAAGwQ,UACZvN,KAAK0N,MAEL6lF,GAAqBkB,EAAiB13F,GAAGwQ,WAErDjP,EAASA,EAAO4hB,IAAIw0E,EACtB,CACAn/B,EAAOiZ,GAAaylB,EAAQ31F,EAC9B,MAEkB,IAATi3D,IACTk/B,EAAiB13F,GAAGoB,MAAQo3D,EAEhC,CAUAl5D,MAAK,GAAW,CACd0hB,KAAM,cACNzO,KAAMmlF,GA3CR,MAFEvzF,QAAQG,KAAK,8BAAgChF,MAAK,GA8ClD,EAQJs4F,WAAAA,GACE,OAAOt4F,MAAK,EACd,CAKAs3F,eAAAA,GAEEt3F,MAAK,GAAK+0C,iBAAiB,iBAAkB/0C,MAAK,IAElD,IAAK,IAAIuC,EAAI,EAAGA,EAAIvC,MAAK,GAAYmC,SAAUI,EAC7CvC,MAAK,GAAK+0C,iBAAiB/0C,MAAK,GAAYuC,GAAIvC,MAAK,IAGvDA,MAAK,IAAe,CACtB,CAKAu4F,kBAAAA,GAEEv4F,MAAK,GAAKg1C,oBAAoB,iBAAkBh1C,MAAK,IAErD,IAAK,IAAIuC,EAAI,EAAGA,EAAIvC,MAAK,GAAYmC,SAAUI,EAC7CvC,MAAK,GAAKg1C,oBAAoBh1C,MAAK,GAAYuC,GAAIvC,MAAK,IAG1DA,MAAK,IAAe,CACtB,CASA+0C,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAOA,IAAWK,GACThiB,MAAK,GAAiB+hB,UAAUC,EAClC,EC5RK,MAAMw2E,GAMXhzB,MAOAp9C,YAMAkzB,UAMAsX,QAQA6lC,aAMA5hE,aAMAC,YAKA90B,WAAAA,CAAYwjE,GACVxlE,KAAKwlE,MAAQA,CACf,EAMK,MAAMkzB,GAQXvuB,QAKAnoE,WAAAA,CAAYmoE,GACVnqE,KAAKmqE,QAAUA,CACjB,EAMK,MAAMwuB,GAMXC,gBAMAC,MAMAC,QAOAC,oBASApX,oBAMAqX,cAMAC,aAMAj3F,WAAAA,CAAY42F,GACV54F,KAAK44F,gBAAkBA,CACzB,EAyBK,MAAMM,GAOX,IAAW,KAOX,IAAkB,KAOlB,IAAqB,KAOrB,IAAkB,KAOlB,IAAS,KAOT,IAAa,KAOb,IAAS,IAAIlxC,GAGb,IAAgB,CAAC,EAOjB,IAAmB,IAAIvmC,GAQvB+kD,OAAAA,CAAQjP,GACN,OAAOv3D,MAAK,GAAgBqB,IAAIk2D,EAClC,CASAjf,QAAAA,CAASif,GACP,IAAIzuD,EAIJ,YAHoC,IAAzB9I,KAAKwmE,QAAQjP,KACtBzuD,EAAM9I,KAAKwmE,QAAQjP,GAAQn0C,OAEtBta,CACT,CAQAyvC,QAAAA,CAASgf,EAAQlZ,GACfr+C,MAAK,GAAgBu4C,SAASgf,EAAQlZ,EACxC,CAQA86C,OAAAA,CAAQlmF,GAEN,MAAMskD,EAASv3D,MAAK,GAAgBkvF,gBAWpC,OATAlvF,MAAK,GAAgBkD,IACnBq0D,EACAtkD,GAOKskD,CACT,CAQA6hC,WAAAA,CAAY7hC,GACV,IAAIzuD,EAIJ,YAHgD,IAArC9I,MAAK,GAAgBqB,IAAIk2D,KAClCzuD,EAAM9I,MAAK,GAAgBqB,IAAIk2D,GAAQ/iC,MAElC1rB,CACT,CAOAqmF,UAAAA,GACE,OAAOnvF,MAAK,GAAgBmvF,YAC9B,CAQAC,qBAAAA,CAAsBhiD,GACpB,OAAOptC,MAAK,GAAgBovF,sBAAsBhiD,EACpD,CASAlnB,SAAAA,GAGE,OAFkBlmB,MAAK,GAAOopE,sBAAsBvmB,qBACvBC,oBACX58B,WACpB,CAUAorB,cAAAA,GAGE,OAFkBtxC,MAAK,GAAOopE,sBAAsBvmB,qBACvBC,oBACXxR,gBACpB,CAOA4kC,aAAAA,GACE,OAAOl2E,MAAK,GAAOopE,sBAAsB8M,eAC3C,CAOAxtB,YAAAA,GACE,OAAO1oD,MAAK,GAAOopE,sBAAsB1gB,cAC3C,CAOAytB,SAAAA,GACE,OAAOn2E,MAAK,GAAOopE,sBAAsB+M,WAC3C,CAOAkjB,oBAAAA,GACE,OAAOr5F,MAAK,EACd,CAQAopE,mBAAAA,GACE,OAAOppE,MAAK,GAAOopE,qBACrB,CAOAiR,mBAAAA,CAAoB/sE,GAClBtN,MAAK,GAAOq6E,oBAAoB/sE,EAClC,CASAspE,qBAAAA,CAAsBrf,GACpB,OAAOv3D,MAAK,GAAO42E,sBAAsBrf,EAC3C,CAWA8e,aAAAA,CAAcnkE,GACZ,OAAOlS,MAAK,GAAOq2E,cAAcnkE,EACnC,CASA6kE,qBAAAA,CAAsBxf,GACpB,OAAOv3D,MAAK,GAAO+2E,sBAAsBxf,EAC3C,CAWAyS,aAAAA,CAAc93D,GACZ,OAAOlS,MAAK,GAAOgqE,cAAc93D,EACnC,CASAwwC,oBAAAA,CAAqB8iB,GACnB,OAAOxlE,MAAK,GAAO0iD,qBAAqB8iB,EAC1C,CAOA4U,sBAAAA,GACE,OAAOp6E,MAAK,GAAOo6E,wBACrB,CAOA3qB,QAAAA,GACE,OAAOzvD,MAAK,EACd,CASAwwD,eAAkBsuB,IACQ,OAApB9+E,MAAK,IACPA,MAAK,GAAWkD,IAAI47E,EACtB,EAWFwa,oBAAuB9vF,IACrB,IAAIV,GAAM,EAIV,OAHwB,OAApB9I,MAAK,KACP8I,EAAM9I,MAAK,GAAW4hB,OAAOpY,IAExBV,CAAG,EAmCZmvC,IAAAA,CAAKm4C,GAqBH,GAnBApwF,MAAK,GAAWowF,OAEiC,IAAtCpwF,MAAK,GAAS+4F,sBACvB/4F,MAAK,GAAS+4F,qBAAsB,QAEO,IAAlC/4F,MAAK,GAAS44F,kBACvB54F,MAAK,GAAS44F,gBAAkB,CAAC,QAEO,IAA/B54F,MAAK,GAASi5F,eACvBj5F,MAAK,GAASi5F,aAAevmC,UAI/B1yD,MAAK,GAAa,IAAI2+E,GACtB3+E,MAAK,GAAW+0C,iBAAiB,UAAW/0C,MAAK,IACjDA,MAAK,GAAW+0C,iBAAiB,OAAQ/0C,MAAK,IAC9CA,MAAK,GAAW+0C,iBAAiB,OAAQ/0C,MAAK,SAGX,IAAxBA,MAAK,GAAS64F,MAAuB,CAE9C,MAAMU,EAAc,CAAC,EACfzmF,EAAO5R,OAAO4R,KAAK9S,MAAK,GAAS64F,OACvC,IAAK,IAAI3pF,EAAI,EAAGA,EAAI4D,EAAK3Q,SAAU+M,EAAG,CACpC,MAAMsqF,EAAW1mF,EAAK5D,GAEtB,IAAIuqF,EAAYl0B,GAAgBi0B,GAKhC,QAHyB,IAAdC,IACTA,EAAYp0B,GAASm0B,SAEE,IAAdC,EAA2B,CAIpC,GAFAF,EAAYC,GAAY,IAAIC,EAAUz5F,WAEgB,IAA3Cu5F,EAAYC,GAAUzkD,iBAAkC,CACjE,MAAM4kB,EAAQ4/B,EAAYC,GAAU5uB,gBACpC,IAAK,IAAIxnE,EAAI,EAAGA,EAAIu2D,EAAMx3D,SAAUiB,EAClCm2F,EAAYC,GAAUzkD,iBAAiB4kB,EAAMv2D,GAAIpD,MAAK,GAE1D,CAEA,MAAM05F,EAAa15F,MAAK,GAAS64F,MAAMW,GACvC,QAAkC,IAAvBE,EAAWvvB,SACU,IAA9BuvB,EAAWvvB,QAAQhoE,OAAc,CACjC,IAIIw3F,EAJAj4E,EAAO,MAKX,QAJoD,IAAzC63E,EAAYC,GAAUpvB,iBAC/B1oD,EAAO63E,EAAYC,GAAUpvB,kBAGlB,aAAT1oD,GAAgC,YAATA,EAAoB,CAC7Ci4E,EAAiB,CAAC,EAClB,IAAK,IAAIp3F,EAAI,EAAGA,EAAIm3F,EAAWvvB,QAAQhoE,SAAUI,EAAG,CAClD,MAAMq3F,EAAaF,EAAWvvB,QAAQ5nE,GACtC,IAAIs3F,EAAkBD,EACT,YAATl4E,IACFm4E,GAAmB,WAErB,MAAMC,EAAgBN,EAASO,OAAO,GAAGvpF,cACvCgpF,EAAS92F,MAAM,GAEjB,IACIs3F,EADAC,EAAW30B,GAAYw0B,QAEH,IAAbG,IACTD,EAAcC,EAASJ,SAGE,IAAhBG,IACTC,EAAWjtB,GAAmB8sB,QACN,IAAbG,IACTD,EAAcC,EAASJ,UAGA,IAAhBG,EACTL,EAAeC,GAAcI,EAE7B71F,EAAOa,KAAK,oCACV40F,EAEN,CACF,MACED,EAAiBD,EAAWvvB,QAE9BovB,EAAYC,GAAUtvB,WAAWyvB,EACnC,CACF,MACEx1F,EAAOa,KAAK,sCAAwCw0F,EAExD,CAEAx5F,MAAK,GAAqB,IAAIg/E,GAAkBua,EAClD,CAGAv5F,MAAK,GACH,IAAIo2F,GAAep2F,MAAK,GAAS2hF,qBACnC3hF,MAAK,GAAgBghF,YAAchhF,MAAK,GACxCA,MAAK,GAAgBggF,WAAahgF,MAAK,GACvCA,MAAK,GAAgB4hF,WAAa5hF,MAAK,GACvCA,MAAK,GAAgB6gF,OAAS7gF,MAAK,GACnCA,MAAK,GAAgB8gF,UAAY9gF,MAAK,GACtCA,MAAK,GAAgBkhF,QAAUlhF,MAAK,GACpCA,MAAK,GAAgB6hF,QAAU7hF,MAAK,GAGpCA,MAAK,GAAkB,IAAIivF,GAE3BjvF,MAAK,GAAgB+0C,iBAAiB,UAAW/0C,MAAK,IACtDA,MAAK,GAAgB+0C,iBAAiB,aAAc/0C,MAAK,IACzDA,MAAK,GAAgB+0C,iBAAiB,eAAgB/0C,MAAK,IAC3DA,MAAK,GAAgB+0C,iBAAiB,aAAc/0C,MAAK,IAEzDA,MAAK,GAAgB+0C,iBACnB,qBAAsB/0C,MAAK,IAC7BA,MAAK,GAAgB+0C,iBACnB,sBAAuB/0C,MAAK,IAC9BA,MAAK,GAAgB+0C,iBAAiB,gBAAiB/0C,MAAK,IAC5DA,MAAK,GAAgB+0C,iBAAiB,mBAAoB/0C,MAAK,IAC/DA,MAAK,GAAgB+0C,iBAAiB,mBAAoB/0C,MAAK,IAC/DA,MAAK,GAAgB+0C,iBACnB,gCAAiC/0C,MAAK,IAExCA,MAAK,GAAS,IAAIk6E,QACmB,IAA1Bl6E,MAAK,GAAS84F,SACvB94F,MAAK,GAAO26E,WAAW36E,MAAK,GAAS84F,QAEzC,CAKA7pC,KAAAA,GAEEjvD,MAAK,GAAOy3E,QACZz3E,MAAK,GAAgB,CAAC,EAElBA,MAAK,KACPA,MAAK,GAAa,IAAI2+E,GACtB3+E,MAAK,GAAW+0C,iBAAiB,UAAW/0C,MAAK,IACjDA,MAAK,GAAW+0C,iBAAiB,OAAQ/0C,MAAK,IAC9CA,MAAK,GAAW+0C,iBAAiB,OAAQ/0C,MAAK,IAElD,CAKAk6F,WAAAA,GACEl6F,MAAK,GAAOivD,QACZjvD,MAAK,GAAO+uD,MACd,CASAha,gBAAAA,CAAiBrzB,EAAMC,GACrB3hB,MAAK,GAAiBkD,IAAIwe,EAAMC,EAClC,CASAqzB,mBAAAA,CAAoBtzB,EAAMC,GACxB3hB,MAAK,GAAiB4hB,OAAOF,EAAMC,EACrC,CAgBA00E,UAAaC,IAEX,MAAM/+B,EAASv3D,MAAK,GAAgBkvF,gBACf,IAAjBoH,EAAMn0F,OAIVnC,MAAK,GAAgBq2F,UAAUC,EAAO/+B,GAHpCpzD,EAAOa,KAAK,kCAG+B,EAmB/CuxF,SAAWA,CAAC3T,EAAMzY,KAEhB,MAAM5S,EAASv3D,MAAK,GAAgBkvF,gBAChB,IAAhBtM,EAAKzgF,OAITnC,MAAK,GAAgBu2F,SAAS3T,EAAMrrB,EAAQ4S,GAH1ChmE,EAAOa,KAAK,iCAGsC,EAUtDm1F,YAAcA,CAACnc,EAAK7T,KAClB,MAAMoU,E9BnvBH,SAAqBP,GAE1B,MAAMzrE,EAAQ6rE,GAASJ,GAEvB,OAAkC,IAA9B98E,OAAO4R,KAAKP,GAAOpQ,OACd,KAGFoQ,EAAMgsE,KACf,C8B0uBkB6b,CAAYpc,GAGpBqc,EAAYA,KAChBr6F,KAAKg1C,oBAAoB,UAAWqlD,GACpCr6F,KAAKu2F,SAAS,CAAChY,EAAM+b,OAAO,EAI1B/b,QAAgC,IAAhBA,EAAMze,aAEG,IAAhBye,EAAM+b,OAEft6F,KAAK+0C,iBAAiB,UAAWslD,G9B1uBlC,SAAqB9b,EAAO58D,EAAUwoD,GAEvCoU,EAAM78D,MAAuB,aAAf68D,EAAM78D,KAkG1B,SAA6B68D,EAAO58D,GAClC,IAAIq8D,EAAM,GACa,MAAnBO,EAAMze,MAAM,KACdke,EAAM/8B,OAAOi9B,SAASqc,SAAW,KAAOt5C,OAAOi9B,SAASsc,MAG1Dxc,GAAOO,EAAMze,MAqBb,MAAM6gB,EAAU,IAAIsB,eACpBtB,EAAQuB,KAAK,MAAOuY,mBAAmBzc,IAAM,GAC7C2C,EAAQ8B,aAAe,WACvB9B,EAAQE,OAPR,SAAgB7+D,GACdL,EAkBG,SAAwB+4E,EAAUv2E,GACvC,MAAM/H,EAAS,GAITu+E,EAFcD,EAASE,qBAAqB,cACtB,GAAGC,aAAa,WAClB,mDAEpBC,EAAcJ,EAASE,qBAAqB,WAC9CE,EAAY34F,OAAS,GACvBgC,EAAOa,KAAK,6CAGd,MAAM+1F,EAAYD,EAAY,GAAGF,qBAAqB,SAClDG,EAAU54F,OAAS,GACrBgC,EAAOa,KAAK,2CAEd,MAAMg2F,EAAWD,EAAU,GAAGF,aAAa,oBAErCI,EAAaF,EAAU,GAAGH,qBAAqB,UACjDK,EAAW94F,OAAS,GACtBgC,EAAOa,KAAK,4CAEd,MAAMk2F,EAAYD,EAAW,GAAGJ,aAAa,qBAEvCM,EAAeF,EAAW,GAAGL,qBAAqB,YAExD,IAAIvtF,EAAM8tF,EAAah5F,OACnBgiB,EAAU9W,IACZA,EAAM8W,GAER,IAAK,IAAI5hB,EAAI,EAAGA,EAAI8K,IAAO9K,EAAG,CAC5B,MACM64F,EAAOT,EACT,aAAeK,EACf,cAAgBE,EAChB,cAJmBC,EAAa54F,GAAGs4F,aAAa,kBAKpDz+E,EAAOnZ,KAAKm4F,EACd,CAEA,OAAOh/E,CACT,CA1Dai/E,CAAer5E,EAAM8tC,OAAOwrC,YAAa/c,EAAMp6D,SAC1D,EAMAw8D,EAAQO,QAlBR,SAAiBl/D,GACf7d,EAAOa,KAAK,0CACVgd,EAAM8tC,OAAOmxB,OACjB,EAgBAN,EAAQqB,KAAK,KACf,CAlIIuZ,CAAoBhd,EAAO58D,GAG3BA,EAiBG,SAA2Bq8D,EAAKwd,GACrC,MAAMp/E,EAAS,GAGf,IAAIq/E,EAAuB,MACvBD,IACFC,EAAuBD,GAIzB,MAAME,EAAWjB,mBAAmBzc,GAE9B2d,EAAkBvd,GAASsd,GACjC,GAA4C,IAAxCx6F,OAAO4R,KAAK6oF,GAAiBx5F,OAC/Bia,EAAOnZ,KAAKy4F,OACP,CACL,MAAM5oF,EAAO5R,OAAO4R,KAAK6oF,EAAgBpd,OAEzC,IAAIqd,EAAY,KAChB,IAAK,IAAIr5F,EAAI,EAAGA,EAAIuQ,EAAK3Q,SAAUI,EACjC,GAAIo5F,EAAgBpd,MAAMzrE,EAAKvQ,cAAe6c,MAAO,CACnDw8E,EAAY9oF,EAAKvQ,GACjB,KACF,CAGF,GAAKq5F,EAEE,CACL,MAAMC,EAAaF,EAAgBpd,MAAMqd,GAEzC,IAAIE,EAAUH,EAAgB1d,KAKd,KAAZ6d,GAAgC,SAAdF,IACpBE,GAAW,KAEb,IAWIlK,EAXAmK,GAAY,EAChB,IAAK,IAAI34F,EAAI,EAAGA,EAAI0P,EAAK3Q,SAAUiB,EAC7B0P,EAAK1P,KAAOw4F,IACVG,IACFD,GAAW,KAEbA,GAAWhpF,EAAK1P,GAAK,IAAMu4F,EAAgBpd,MAAMzrE,EAAK1P,IACtD24F,GAAY,GAKhB,IAAK,IAAItvF,EAAI,EAAGA,EAAIovF,EAAW15F,SAAUsK,EACvCmlF,EAAMkK,EACFC,IACFnK,GAAO,KAEoB,QAAzB6J,IACF7J,GAAOgK,EAAY,KAGrBhK,GAAOiK,EAAWpvF,GAClB2P,EAAOnZ,KAAK2uF,EAEhB,MApCEx1E,EAAOnZ,KAAKy4F,EAqChB,CAEA,OAAOt/E,CACT,CAnFM4/E,CAAkBzd,EAAMze,MAAOye,EAAM0d,gBACrC9xB,EAEN,C8BmuBM+xB,CAAY3d,EAAOv+E,KAAKu2F,SAAUpsB,GACpC,EAiBFqsB,gBAAmBvjF,IAEjB,MAAMskD,EAASv3D,MAAK,GAAgBkvF,gBACpClvF,MAAK,GAAgBw2F,gBAAgBvjF,EAAMskD,EAAO,EAMpD4kC,aAAAA,GACE,MAAMze,EAAM19E,MAAK,GAAgBy2F,oBACjC,IAAK,MAAM1vF,KAAM22E,EACf19E,KAAKo8F,UAAUr1F,EAEnB,CAOAq1F,SAAAA,CAAU7kC,GAERv3D,MAAK,GAAgBujF,MAAMhsB,GAE3Bv3D,MAAK,GAAgB4hB,OAAO21C,GAE5Bv3D,MAAK,GAAO23E,qBAAqBpgB,EACnC,CAQAc,cAAAA,GACEr4D,MAAK,GAAOq4D,gBACd,CASAgkC,aAAAA,GACoBr8F,MAAK,GAAOopE,sBAAsBvmB,qBACvBC,oBAClBlF,YACb,CAOAg2B,iBAAAA,CAAkBh4C,GAChB57B,MAAK,GAAO4zE,kBAAkBh4C,GAC9B57B,MAAK,GAAO+uD,MACd,CAUAutC,cAAAA,CAAe/kC,EAAQglC,GAErB,GAAsC,OAAlCv8F,MAAK,GAAS44F,sBACyB,IAAlC54F,MAAK,GAAS44F,gBACrB,MAAM,IAAI12F,MAAM,wCAElB,IAAIm1F,EAAU,GAOd,YANqD,IAA1Cr3F,MAAK,GAAS44F,gBAAgBrhC,GACvC8/B,EAAUr3F,MAAK,GAAS44F,gBAAgBrhC,GAC9BglC,QACoC,IAAvCv8F,MAAK,GAAS44F,gBAAgB,OACrCvB,EAAUr3F,MAAK,GAAS44F,gBAAgB,MAEnCvB,CACT,CAYAmF,aAAAA,CAAcjlC,EAAQ5U,EAAY45C,GAEhC,OADgBv8F,KAAKs8F,eAAe/kC,EAAQglC,GAC7BryE,MAAK,SAAUzL,GAC5B,OAAOA,EAAK+mD,QAAU7iB,CACxB,GACF,CAQA85C,kBAAAA,GACE,OAAOz8F,MAAK,GAAS44F,eACvB,CAQA8D,kBAAAA,CAAmBrF,GAEjBr3F,MAAK,GAAOy3E,QAEZz3E,MAAK,GAAS44F,gBAAkBvB,EAEhCr3F,MAAK,GAAmBq3F,EAC1B,CAQAsF,iBAAAA,CAAkBplC,EAAQvlB,GAExB,MAAMqlD,EAAUr3F,MAAK,GAAS44F,gBAQ9B,QAP+B,IAApBvB,EAAQ9/B,KACjB8/B,EAAQ9/B,GAAU,KAMD,IADD8/B,EAAQ9/B,GAAQrrB,WAHf,SAAUztB,GAC3B,OAAOA,EAAK+mD,QAAUxzB,EAAOwzB,KAC/B,IAKE,MAAM,IAAItjE,MAAM,kCAAoCq1D,EAClD,YAAcvlB,EAAOwzB,OAHvBxlE,MAAK,GAAS44F,gBAAgBrhC,GAAQt0D,KAAK+uC,QAOiB,IAAnDhyC,MAAK,GAAO0iD,qBAAqB1Q,EAAOwzB,QACjDxlE,MAAK,GAAkBgyC,QAIuB,IAArChyC,MAAK,GAAgBqB,IAAIk2D,IAClCv3D,KAAKilE,OAAO1N,EAAQ,CAACvlB,GAEzB,CAQA4qD,oBAAAA,CAAqBrlC,EAAQiO,GAE3B,MAAM6xB,EAAUr3F,MAAK,GAAS44F,gBAC9B,QAA+B,IAApBvB,EAAQ9/B,GAEjB,OAEF,MAGMslC,EAAYxF,EAAQ9/B,GAAQrrB,WAHf,SAAUztB,GAC3B,OAAOA,EAAK+mD,QAAUA,CACxB,IAEA,IAAmB,IAAfq3B,IAIJxF,EAAQ9/B,GAAQz1C,OAAO+6E,EAAW,GACH,IAA3BxF,EAAQ9/B,GAAQp1D,eACXk1F,EAAQ9/B,QAI+B,IAArCv3D,MAAK,GAAgBqB,IAAIk2D,IAAyB,CAC3D,MAAMulC,EAAK98F,MAAK,GAAO0iD,qBAAqB8iB,GAC5C,QAAkB,IAAPs3B,EAAoB,CAC7B,MAAMC,EAAMD,EAAGlmB,sBAAsBrf,GAClB,IAAfwlC,EAAI56F,QACN26F,EAAGllB,YAAYmlB,EAAI,IAErB,MAAMC,EAAMF,EAAG/lB,sBAAsBxf,GAIrC,GAHmB,IAAfylC,EAAI76F,QACN26F,EAAGllB,YAAYolB,EAAI,IAEF,IAAfD,EAAI56F,QAA+B,IAAf66F,EAAI76F,OAC1B,MAAM,IAAID,MAAM,gCAEa,IAA3B46F,EAAG1mB,qBACLp2E,MAAK,GAAO46E,iBAAiBkiB,EAEjC,CACF,CACF,CAUAG,oBAAAA,CAAqB1lC,EAAQiO,EAAOxzB,GAClC,MAAMqlD,EAAUr3F,MAAK,GAAS44F,gBAE9B,QAA+B,IAApBvB,EAAQ9/B,GACjB,MAAM,IAAIr1D,MAAM,yBAA2Bq1D,GAG7C,MAGMslC,EAAYxF,EAAQ9/B,GAAQrrB,WAHf,SAAUztB,GAC3B,OAAOA,EAAK+mD,QAAUA,CACxB,IAEA,IAAmB,IAAfq3B,EACF,MAAM,IAAI36F,MAAM,yBACdq1D,EAAS,eAAiBiO,GAG9B,MAAM03B,EAAiB7F,EAAQ9/B,GAAQslC,GACvC,IAAK,MAAMt7F,KAAQywC,EACjBkrD,EAAe37F,GAAQywC,EAAOzwC,GAIhC,MAAMu7F,EAAK98F,MAAK,GAAO0iD,qBAAqBw6C,EAAe13B,OAC3D,QAAkB,IAAPs3B,EAAoB,CAC7B,MAAMC,EAAMD,EAAGlmB,sBAAsBrf,GAClB,IAAfwlC,EAAI56F,QACN26F,EAAGllB,YAAYmlB,EAAI,IAErB,MAAMC,EAAMF,EAAG/lB,sBAAsBxf,GAIrC,GAHmB,IAAfylC,EAAI76F,QACN26F,EAAGllB,YAAYolB,EAAI,IAEF,IAAfD,EAAI56F,QAA+B,IAAf66F,EAAI76F,OAC1B,MAAM,IAAID,MAAM,+BAEpB,MAGgD,IAArClC,MAAK,GAAgBqB,IAAIk2D,IAClCv3D,KAAKilE,OAAO1N,EAAQ,CAAC2lC,GAEzB,CAQA,IAAmBtE,GACjB,MAAMuE,EAAWj8F,OAAO4R,KAAK8lF,GACvBwE,EAAS,GACf,IAAK,IAAI76F,EAAI,EAAGA,EAAI46F,EAASh7F,SAAUI,EAAG,CACxC,MAAM86F,EAAczE,EAAgBuE,EAAS56F,IAC7C,IAAK,IAAIa,EAAI,EAAGA,EAAIi6F,EAAYl7F,SAAUiB,EAAG,CAC3C,MAAMk6F,EAAaD,EAAYj6F,GAE1Bg6F,EAAOzsF,SAAS2sF,EAAW93B,SAC9BxlE,MAAK,GAAkBs9F,GACvBF,EAAOn6F,KAAKq6F,EAAW93B,OAE3B,CACF,CACF,CAQA,IAAkB83B,GAEhB,MAAMzrF,EAAU7R,MAAK,GAASi5F,aAAasE,eAAeD,EAAW93B,OAC/D/iB,EAAaziD,MAAK,GAAOs6E,cAAczoE,GAE7C7R,MAAK,GAAqByiD,EAC5B,CAOA+6C,qBAAAA,CAAsB13C,GAEpB,MAAM23C,EAAY,GAClB,IAAK,IAAIl7F,EAAI,EAAGA,EAAIujD,EAAK3jD,SAAUI,OACE,IAAxB62E,GAAWtzB,EAAKvjD,KACzBk7F,EAAUx6F,KAAK,IAAIm2E,GAAWtzB,EAAKvjD,KAIvCvC,MAAK,GAAO26E,WAAW8iB,EACzB,CAQAx4B,MAAAA,CAAO1N,EAAQ8lC,GACb,GAAI,MAAO9lC,EACT,MAAM,IAAIr1D,MAAM,iCAGlB,MAAMw7F,OACkC,IAA/B19F,KAAKwmE,QAAQjP,GAAQn0C,MACxBu6E,OAC4C,IAAzC39F,KAAKwmE,QAAQjP,GAAQD,gBAc9B,GAV6C,IAAzCt3D,MAAK,GAAOo6E,0BACdp6E,MAAK,GAAmBA,MAAK,GAAS44F,sBAIb,IAAhByE,IACTA,EAAcr9F,KAAKs8F,eAAe/kC,IAIT,IAAvB8lC,EAAYl7F,OAOhB,IAAK,IAAII,EAAI,EAAGA,EAAI86F,EAAYl7F,SAAUI,EAAG,CAC3C,MAAMyvC,EAASqrD,EAAY96F,GACrBkgD,EACJziD,MAAK,GAAO0iD,qBAAqB1Q,EAAOwzB,OAE1C,IAAK/iB,EACH,MAAM,IAAIvgD,MAAM,sBAAwB8vC,EAAOwzB,YAID,IAArCxlE,MAAK,GAAgBqB,IAAIk2D,KAC9BmmC,GACkD,IAApDj7C,EAAWm0B,sBAAsBrf,GAAQp1D,OAEzCnC,MAAK,GAAcu3D,EAAQvlB,GAClB2rD,GAC2C,IAApDl7C,EAAWs0B,sBAAsBxf,GAAQp1D,QAEzCnC,KAAKu3E,aAAahgB,EAAQvlB,IAI9ByQ,EAAWsM,MACb,MA7BE5qD,EAAOY,KAAK,uBAAyBwyD,EACnC,yBA6BN,CASA0Q,IAAAA,CAAKG,EAAM7b,EAAIC,GACb,MAAM/J,EAAaziD,MAAK,GAAOopE,sBAEzB38D,EADiBg2C,EAAWI,qBAAqBC,oBAC9B3E,2BACnBh5C,EAAS,IAAI6H,EAAQu/C,EAAIC,EAAI//C,GACnCg2C,EAAW0lB,SAASC,EAAMjjE,GAC1Bs9C,EAAWsM,MACb,CAQA6uC,SAAAA,CAAUj2B,EAAIC,GACZ,MAAMnlB,EAAaziD,MAAK,GAAOopE,sBAC/B3mB,EAAWqlB,eAAe,CAACr/D,EAAGk/D,EAAIj/D,EAAGk/D,EAAIj/D,EAAG,IAC5C85C,EAAWsM,MACb,CASAwG,UAAAA,CAAWC,GACT,MAAMhU,EAAYxhD,MAAK,GAAOopE,sBAAsBvmB,qBACpDrB,EAAU+T,WAAWC,GACrBhU,EAAUuN,MACZ,CAUA6sB,WAAAA,CAAYC,EAAUC,EAAiBvkB,GACrC,MACM/V,EADaxhD,MAAK,GAAOopE,sBACFvmB,qBACvB4lB,EAAYjnB,EAAUkP,YACtB9N,EAAiBpB,EAAUsB,oBAG3BirC,E5DMH,SAA2BlS,EAAUC,GAC1C,MAAMiS,EAAc,GAMd8P,EAHa9zC,KAAAA,KAAW72B,OAAO2oD,GAGH/xB,YAAYH,IAE9C,IAAK,IAAIpnD,EAAI,EAAGO,EAAO+6F,EAAe17F,OAAQI,EAAIO,IAAQP,EAAG,CAC3D,MACMu7F,EADgBD,EAAet7F,GACFunD,cACnC,IAAK,IAAI1mD,EAAI,EAAGy8B,EAAOi+D,EAAa37F,OAAQiB,EAAIy8B,IAAQz8B,EAAG,CACzD,MAAMgjD,EAAa,IAAIsjB,GAIjBq0B,EAAaD,EAAa,GAEhC13C,EAAWr/C,GAAKg3F,EAAWh3F,KAG3B,MAAMorD,EAAQ4rC,EAAWj0C,YAAYJ,IAAiB,GAItD,GAFAtD,EAAWrU,OAASogB,EAAM9H,SAEA,eAAtB0zC,EAAWv0F,OAAyB,CACtC,MAAM0iD,EAASiG,EAAMjG,SACrB9F,EAAWwJ,UAAY,IAAI7hD,EAAQm+C,EAAO,GAAIA,EAAO,IACrD9F,EAAWyJ,gBAAkB,CAC3B,IAAI9hD,EAAQm+C,EAAO,GAAIA,EAAO,IAElC,MAAO,GAA0B,gBAAtB6xC,EAAWv0F,OAA0B,CAC9C,MAAM0iD,EAASiG,EAAMjG,SACrB9F,EAAWwJ,UAAY,IAAI5M,GACzB,IAAIj1C,EAAQm+C,EAAO,GAAIA,EAAO,IAC9B,IAAIn+C,EAAQm+C,EAAO,GAAIA,EAAO,IAElC,MAAO,GAA0B,oBAAtB6xC,EAAWv0F,OACpB48C,EAAWwJ,UAAY,IAAI9E,GACzB,IAAI/8C,EAAQokD,EAAM1pD,IAAK0pD,EAAMzpD,KAC7B,IAAIqF,EAAQokD,EAAM1pD,IAAM0pD,EAAM/sD,QAAS+sD,EAAMzpD,IAAMypD,EAAMhvB,gBAEtD,GAA0B,cAAtB46D,EAAWv0F,OAAwB,CAC5C,MAAM0iD,EAASiG,EAAMjG,SACf8xC,EAAc,GACpB,IAAK,IAAIz7F,EAAI,EAAGA,EAAI2pD,EAAO/pD,OAAQI,GAAQ,EACzCy7F,EAAY/6F,KAAK,IAAI8K,EAAQm+C,EAAO3pD,GAAI2pD,EAAO3pD,EAAI,KAErD6jD,EAAWwJ,UAAY,IAAI3D,GAAI+xC,EACjC,MAAO,GAA0B,mBAAtBD,EAAWv0F,OAA6B,CACjDrF,EAAOa,KAAK,sCACZ,MAAMknD,EAASiG,EAAMjG,SACf8xC,EAAc,GACpB,IAAK,IAAIz7F,EAAI,EAAGA,EAAI2pD,EAAO/pD,OAAQI,GAAQ,EACzCy7F,EAAY/6F,KAAK,IAAI8K,EAAQm+C,EAAO3pD,GAAI2pD,EAAO3pD,EAAI,KAErD6jD,EAAWwJ,UAAY,IAAI3D,GAAI+xC,EACjC,MAAO,GAA0B,qBAAtBD,EAAWv0F,OAA+B,CACnD,MAAM0iD,EAASiG,EAAMjG,SACrB9F,EAAWwJ,UAAY,IAAI/C,GAAW,CACpC,IAAI9+C,EAAQm+C,EAAO,GAAIA,EAAO,IAC9B,IAAIn+C,EAAQm+C,EAAO,GAAIA,EAAO,IAC9B,IAAIn+C,EAAQm+C,EAAO,GAAIA,EAAO,KAElC,MAAO,GAA0B,kBAAtB6xC,EAAWv0F,OAA4B,CAChD,MAAMy0F,EAAc9rC,EAAM+rC,mBAC1B93C,EAAWwJ,UAAY,IAAI5C,GACzB,IAAIj/C,EAAQkwF,EAAYx1F,EAAGw1F,EAAYv1F,GACvCypD,EAAM3H,UACN2H,EAAM1H,UAEV,MAAO,GAA0B,iBAAtBszC,EAAWv0F,OAA2B,CAC/C,MAAMy0F,EAAc9rC,EAAM+rC,mBAC1B93C,EAAWwJ,UAAY,IAAI1B,GACzB,IAAIngD,EAAQkwF,EAAYx1F,EAAGw1F,EAAYv1F,GACvCypD,EAAM/uB,SAEV,CAGA,GAAI04C,EAAiB,CACnB,MAAMmB,EAAUnB,EAAgBiiB,EAAWh3F,MAC3Cq/C,EAAW4M,SAAWiqB,EAAQzoD,KAAKw+B,SACnC5M,EAAWurB,eAAiBsL,EAAQzoD,KAAKm9C,cAC3C,CAEAoc,EAAY9qF,KAAKmjD,EACnB,CACF,CAEA,OAAO2nC,CACT,C4DlGwBoQ,CAAkBtiB,EAAUC,GAE1C7oE,EAAOjT,KAAK2oE,qBAAqBF,GAEvC,IAAK,MAAMriB,KAAc2nC,EACvB3nC,EAAWG,kBAAkB3D,GAC7B3vC,EAAKqkD,gBAAgBp0D,IAAIkjD,GAG3BpmD,MAAK,GAAgBkD,IAAIq0D,EAAQtkD,GAEjCjT,KAAKilE,OAAO1N,EACd,CAUA6mC,cAAAA,CAAeC,EAAW9mC,GACxB,MAAM+iC,EAAQ,IAAIpf,GAAM3jB,GACxB+iC,EAAMx2F,MAAM9D,KAAMs6F,EAAMnf,SAASkjB,GACnC,CAWAC,SAAWA,KACTt+F,KAAKq4D,gBAAgB,EAUvBsO,UAAa3kD,IASXhiB,MAAK,GAAWgiB,EAAM,EAmBxBu8E,iBAAoBv8E,IAClB,GAAIA,EAAMw8E,QACR,GAAIx8E,EAAMy8E,SAAU,CAClB,MAAMh8C,EAAaziD,MAAK,GAAOopE,sBACzBxmB,EACJH,EAAWI,qBAAqBC,oBAChB,cAAd9gC,EAAMhhB,IACJ4hD,EAAe78B,YAAY,IAC7B68B,EAAe/B,eAAe,GAET,YAAd7+B,EAAMhhB,IACXyhD,EAAWv8B,aACb08B,EAAe7B,uBAEM,eAAd/+B,EAAMhhB,IACXyhD,EAAW18B,YAAY,IACzB68B,EAAehC,eAAe,GAET,cAAd5+B,EAAMhhB,KACXyhD,EAAWv8B,aACb08B,EAAe9B,sBAGrB,MAAO,GAAkB,MAAd9+B,EAAMhhB,IACfhB,MAAK,GAAW++E,YACX,GAAkB,MAAd/8D,EAAMhhB,IACfhB,MAAK,GAAWo6D,YACX,GAAkB,MAAdp4C,EAAMhhB,IACf,IAAK,IAAIuB,EAAI,EAAGA,EAAIvC,MAAK,GAAOo6E,2BAA4B73E,EAC1DvC,MAAK,GAAOm6E,cAAc53E,GAAGyzE,kBAC1Bh2E,MAAK,GAAOm6E,cAAc53E,GAAGwzE,mBAItC,EAQF2oB,YAAAA,GACE1+F,KAAKk6F,cACLl6F,KAAKq8F,eACP,CAKAsC,SAAAA,GACE3+F,KAAKk6F,aACP,CASAriD,YAAAA,CAAaruC,GAETxJ,MAAK,GAAOopE,sBACTvmB,qBAAqBC,oBACXjL,aAAaruC,EAC9B,CASAuxC,oBAAAA,CAAqBhD,GAEjB/3C,MAAK,GAAOopE,sBACTvmB,qBAAqBC,oBACX/H,qBAAqBhD,EACtC,CAOA6mD,OAAAA,CAAQC,GAEN,IAAK,IAAIt8F,EAAI,EAAGA,EAAIvC,MAAK,GAAOo6E,2BAA4B73E,EAAG,CAC7D,MAAMkgD,EAAaziD,MAAK,GAAOm6E,cAAc53E,GAK7C,IAAIunE,EAGFA,EAN0B,SAAT+0B,GACR,aAATA,GACS,cAATA,QAG2C,IAApCp8C,EAAW+lB,qBAGV/lB,EAAWI,qBAFXJ,EAAW+lB,0BAIA,IAAVsB,GACT9pE,MAAK,GAAmBy/E,eAAeh9B,EAAYqnB,EAEvD,CAGA9pE,MAAK,GAAmBu/E,gBAAgBsf,EAC1C,CAOArf,eAAAA,CAAgB15B,GACd9lD,MAAK,GAAmBw/E,gBAAgB15B,EAC1C,CAOAsU,IAAAA,GACEp6D,MAAK,GAAWo6D,MAClB,CAOA2kB,IAAAA,GACE/+E,MAAK,GAAW++E,MAClB,CAOAH,YAAAA,GACE,OAAO5+E,MAAK,GAAW4+E,cACzB,CAOAC,oBAAAA,GACE,OAAO7+E,MAAK,GAAW6+E,sBACzB,CAQAigB,cAAAA,CAAevnC,GACb,IAAItkD,EAIJ,YAHkC,IAAvBjT,MAAK,KACdiT,EAAOjT,MAAK,GAAcu3D,IAErBtkD,CACT,CAOA8rF,sBAAAA,CAAuBxnC,GACrB,MAAMtkD,EAAOjT,KAAK8+F,eAAevnC,QACb,IAATtkD,IACLA,EAAKqlF,cACPrlF,EAAKslF,qBAELtlF,EAAKqkF,kBAGX,CASA3uB,oBAAAA,CAAqBF,GACnB,MACMu2B,EADUh/F,KAAKwmE,QAAQiC,GACLrlD,MAAMgrB,UAExBn7B,EAAO,IAAI+7E,GAAU,CAAC,GAa5B,OAZA/7E,EAAKqkD,gBAAkB,IAAIzR,GAC3B5yC,EAAKqkD,gBAAgB3Q,aAAa,WAAY,MAC9C1zC,EAAKqkD,gBAAgB3Q,aACnB,YAAaq4C,EAAQjpE,WACvB9iB,EAAKqkD,gBAAgB3Q,aACnB,mBAAoBq4C,EAAQvpE,kBAC9BxiB,EAAKqkD,gBAAgB3Q,aACnB,2BAA4B,CAC1B7kD,MAAO,CAAC,CACN6zB,kBAAmBqpE,EAAQrpE,sBAG1B1iB,CACT,CASA21D,0BAAAA,CAA2B31D,EAAMuyD,EAAOiD,GAEtC,MAAMlR,EAASv3D,KAAKm5F,QAAQlmF,GAGtBgsF,EADqBj/F,KAAKs8F,eAAe7zB,GACFv+C,MAC3CrY,GAAWA,EAAQ2zD,QAAUA,IAC/B,QAAiC,IAAtBy5B,EACT,MAAM,IAAI/8F,MAAM,0CAElB,MAAMg9F,EAAqB,IAAI1G,GAAWhzB,GAC1C05B,EAAmB92E,YAAc62E,EAAkB72E,YACnDpoB,KAAK28F,kBAAkBplC,EAAQ2nC,GAE/Bl/F,KAAKilE,OAAO1N,EACd,CASA,IAAcv1C,IACZhiB,MAAK,GAAiB+hB,UAAUC,EAAM,EAQxC,IAAgBA,SAE6B,IAAhChiB,MAAK,GAASg5F,gBACvBh5F,MAAK,GAAcgiB,EAAMyuC,QAAU,IAAI2mC,GACrCp3F,KAAMgiB,EAAMyuC,OAAQzwD,MAAK,GAASg5F,gBAYtCh3E,EAAMN,KAAO,YACb1hB,MAAK,GAAWgiB,EAAM,EAQxB,IAAmBA,IAajBA,EAAMN,KAAO,eACb1hB,MAAK,GAAWgiB,EAAM,EAQxB,IAAeA,SAEa,IAAfA,EAAM/O,MACf9O,EAAOc,MAAM,qCAEe,IAAnB+c,EAAM80E,UACf3yF,EAAOc,MAAM,qCAGf,MAAMk6F,EAAkBn9E,EAAMi1E,YAE9B,IAAImI,EAAgB,KACG,UAAnBp9E,EAAM80E,UACJqI,EACFn/F,MAAK,GAAgBkD,IAAI8e,EAAMyuC,OAAQzuC,EAAM/O,MAE7CjT,MAAK,GAAgBqmD,OAAOrkC,EAAMyuC,OAAQzuC,EAAM/O,MAElDmsF,EAAgBp9E,EAAM/O,KAAKuhB,MACC,UAAnBxS,EAAM80E,WACf92F,KAAKo+F,eAAep8E,EAAM/O,KAAM+O,EAAMyuC,QACtC2uC,EAAgB,SAclBp/F,MAAK,GAAW,CACd0hB,KAAM,WACNzO,KAAMmsF,EACN9e,OAAQt+D,EAAMs+D,OACdwW,SAAU90E,EAAM80E,SAChBrmC,OAAQzuC,EAAMyuC,OACdwmC,YAAaj1E,EAAMi1E,YACnBjyF,KAAMgd,EAAMhd,YAIoB,IAAvBhF,MAAK,SAC8B,IAArCA,MAAK,GAAcgiB,EAAMyuC,SAChCzwD,MAAK,GAAcgiB,EAAMyuC,QAAQ8mC,YAAY6H,GAIxB,UAAnBp9E,EAAM80E,UACqC,IAA7C92F,KAAKs8F,eAAet6E,EAAMyuC,QAAQtuD,QAClCg9F,GAAmBn/F,MAAK,GAAS+4F,qBACjC/4F,KAAKilE,OAAOjjD,EAAMyuC,OACpB,EAQF,IAAWzuC,IASTA,EAAMN,KAAO,OACb1hB,MAAK,GAAWgiB,EAAM,EAQxB,IAAcA,IAYZA,EAAMN,KAAO,UACb1hB,MAAK,GAAWgiB,EAAM,EAQxB,IAAgBA,SAaY,IAAfA,EAAMN,OACfM,EAAMN,KAAO,SAEf1hB,MAAK,GAAWgiB,EAAM,EAQxB,IAAgBA,SAWY,IAAfA,EAAMN,OACfM,EAAMN,KAAO,SAEf1hB,MAAK,GAAWgiB,EAAM,EAQxB,IAAqBzO,GAEnBA,EAAMwhC,iBAAiB,aAAc/0C,MAAK,IAC1CuT,EAAMwhC,iBAAiB,eAAgB/0C,MAAK,IAE5CuT,EAAMwhC,iBAAiB,cAAe/0C,MAAK,IAC3CuT,EAAMwhC,iBAAiB,YAAa/0C,MAAK,IAEzC,IAAK,IAAIoD,EAAI,EAAGA,EAAI80C,GAAe/1C,SAAUiB,EAC3CmQ,EAAMwhC,iBAAiBmD,GAAe90C,GAAIpD,MAAK,IAG7CA,MAAK,IAAsBA,MAAK,GAAmBm/E,QAAQ,UAC7D5rE,EAAMwhC,iBAAiB,aAAc/0C,MAAK,IAC1CuT,EAAMwhC,iBAAiB,aAAc/0C,MAAK,KAG5CuT,EAAMwhC,iBAAiB,YAAa/yB,IAClC,MACMq9E,EADe7pB,GAA8BxzD,EAAM+3C,YAC5BpX,WACvB3Q,EAAShyC,KAAKw8F,cAAcx6E,EAAMyuC,OAAQ4uC,GAAS,QACnC,IAAXrtD,IAETA,EAAOnb,kBAAer2B,EACtBwxC,EAAOlb,iBAAct2B,EACrBwxC,EAAOymD,kBAAej4F,EAEK,IAAvBwhB,EAAMlgB,MAAMK,SACd6vC,EAAOnb,aAAe7U,EAAMlgB,MAAM,GAClCkwC,EAAOlb,YAAc9U,EAAMlgB,MAAM,GACjCkwC,EAAOymD,aAAez2E,EAAMlgB,MAAM,IAEtC,IAEFyR,EAAMwhC,iBAAiB,iBAAkB/yB,IACvC,MACMq9E,EADe7pB,GAA8BxzD,EAAM+3C,YAC5BpX,WACvB3Q,EAAShyC,KAAKw8F,cAAcx6E,EAAMyuC,OAAQ4uC,GAAS,QACnC,IAAXrtD,IACTA,EAAO4gB,QAAU5wC,EAAMlgB,MAAM,GAC/B,IAEFyR,EAAMwhC,iBAAiB,mBAAoB/yB,IACzC,MACMq9E,EADe7pB,GAA8BxzD,EAAM+3C,YAC5BpX,WACvB3Q,EAAShyC,KAAKw8F,cAAcx6E,EAAMyuC,OAAQ4uC,GAAS,QACnC,IAAXrtD,IACTA,EAAOsJ,UAAYt5B,EAAMlgB,MAAM,GACjC,GAEJ,CAQA,IAAcy1D,EAAQ+lC,GACpB,MAAMrqF,EAAOjT,MAAK,GAAgBqB,IAAIk2D,GACtC,IAAKtkD,EACH,MAAM,IAAI/Q,MAAM,kDACdq1D,GAEJ,MAAM9U,EAAaziD,MAAK,GAAO0iD,qBAAqB46C,EAAW93B,OAC/D,IAAK/iB,EACH,MAAM,IAAIvgD,MAAM,mDACdo7F,EAAW93B,OAEf,MAAMtpB,EAAgBjpC,EAAKmQ,MAAMI,cAGjCxjB,MAAK,GAAOy6E,oBAGZ,MACM9iC,GADc,IAAID,IACCxkB,OAAOjgB,EAAKuhB,KAAMvhB,EAAKmQ,OAC1CG,EAAkB8K,GACtB6tB,EAAczyB,iBACdsD,GAAkBuwE,EAAWl1E,cAE/BuvB,EAAKc,eAAel1B,GAIkB,QAAlCtQ,EAAKmQ,MAAMgrB,UAAU3Z,UACvBkjB,EAAKoB,kBAAiB,SAAUj3C,GAC9B,OAAc,IAAVA,EACK,EAEA,GAEX,IAKF,MAAMw9F,EAAqD,IAAvC78C,EAAW+zB,wBAG/B,IAAI5jB,EAAU,OACoB,IAAvB0qC,EAAW1qC,QACpBA,EAAU0qC,EAAW1qC,QAEhB0sC,IACH1sC,EAAU,IAKd,MAAMpR,EAAYiB,EAAW00B,eAC7B31B,EAAUqyB,QAAQl8B,EAAM4f,GACxB,MAAMlkC,EAAS6oB,EAAcz4B,QAAQF,GAAiBkD,QAChD88B,EAAYrH,EAAc5yB,WAAW/F,GAAiBkD,QAC5D+6B,EAAU5D,WAAWvqB,EAAQkwB,EAAWqP,GAGxC,MAAMhQ,EAAiBpB,EAAUsB,oBAEjC,QAAuC,IAA5Bw6C,EAAW7E,aACpB71C,EAAe7H,qBAAqBuiD,EAAW7E,mBAC1C,QAAuC,IAA5B6E,EAAWzmE,mBACO,IAA3BymE,EAAWxmE,YAA6B,CAC/C,MAAMjxB,EAAK,IAAIX,EACbo4F,EAAWzmE,aAAcymE,EAAWxmE,aACtC8rB,EAAe1J,eAAerzC,EAChC,MAEoC,IAAzBy3F,EAAWhiD,UACpBsH,EAAe/K,aAAaylD,EAAWhiD,WAElCgkD,IACmC,OAAlCrsF,EAAKmQ,MAAMgrB,UAAU3Z,SACvBmuB,EAAe/K,aAAa,OAE5B+K,EAAe/K,aAAa,YAMlC73C,MAAK,GAAgB+0C,iBACnB,eAAgByM,EAAUuyB,YAG5B,MAAMjyE,EAAQ,CACZ8gD,EAAexK,kBAAkB31C,YACjCmgD,EAAehJ,qBAAqBn3C,aAEtCggD,EAAW+0B,6BAA6B,CACtC11E,MAAOA,EACPi4D,WAAYvY,EAAU4T,UAIxBp1D,MAAK,GAAOq4D,iBAGZ7W,EAAUiV,UAAUhU,EAAW0zB,aAG/B,MAAMopB,EAAYv/F,MAAK,GACrBk8C,EAAczyB,iBACd6zE,EAAWl1E,aAIb,GAHApoB,MAAK,GAAgBu/F,EAAW/9C,GAG3B89C,EAQH99C,EAAUsU,SAASrT,EAAWixB,gBARd,CAEhB,MAAM8rB,EAAgB/8C,EAAWi0B,mBACjCl1B,EAAU+U,UACR9T,EAAWixB,WACX8rB,EAAc7rB,wBAElB,CAKA3zE,MAAK,GAAO06E,kBACR16E,MAAK,IACPA,MAAK,GAAmBy/E,eAAeh9B,EAAYjB,GAarDxhD,MAAK,GAAW,CACd0hB,KAAM,eACNuoD,QAASzoB,EAAU4T,QACnBqqC,aAAch9C,EAAWwzB,WACzBxlB,OAAQ8G,IAIN+nC,GACEt/F,MAAK,IACPA,MAAK,GAAmBi4C,MAG9B,CAQAs/B,YAAAA,CAAahgB,EAAQ+lC,GACnB,MAAM76C,EAAaziD,MAAK,GAAO0iD,qBAAqB46C,EAAW93B,OAC/D,IAAK/iB,EACH,MAAM,IAAIvgD,MAAM,mDACdo7F,EAAW93B,OAKf,MAAMvyD,EAAOjT,MAAK,GAAgBqB,IAAIk2D,GACtC,IAAKtkD,EACH,MAAM,IAAI/Q,MAAM,kDACdq1D,GAEJ,MAEMmoC,EADJzsF,EAAKqkD,gBAAgB5Q,aAAa,4BACM5kD,MAAM,GAAG6zB,kBAC7C6jD,EAAa/2B,EAAWo0B,iBAAiB,CAC7ClhD,kBAAmB+pE,IAErB,GAA0B,IAAtBlmB,EAAWr3E,OAGb,YAFA0C,QAAQG,KACN,oEAGJ,MAAM26F,EAAenmB,EAAW,GAC1B/Q,EAAYk3B,EAAajvC,YAG/B1wD,MAAK,GAAOy6E,oBAGZ,MAAMmlB,EAAoBD,EAAa78C,oBACvC7vC,EAAKqkD,gBAAgB/Q,kBAAkBq5C,GAGvC,MAAMC,EAAU7/F,MAAK,GAAgBqB,IAAIonE,GACzC,IAAKo3B,EACH,MAAM,IAAI39F,MACR,uDACAumE,GAEJ,MAAMvsB,EAAgB2jD,EAAQz8E,MAAMI,cAE9BD,EAAkB8K,GACtB6tB,EAAczyB,iBACdsD,GAAkBuwE,EAAWl1E,cAEzBiL,EAAS6oB,EAAcz4B,QAAQF,GAAiBkD,QAChD88B,EAAYrH,EAAc5yB,WAAW/F,GAAiBkD,QAEtDgoC,EAAYhM,EAAW80B,eAC7B9oB,EAAU7Q,WAAWvqB,EAAQkwB,EAAWo8C,EAAavqC,SAErD,MAAMwc,EAAc,IAAI31B,GACtBC,EACA34B,GAEFkrC,EAAUyG,eAAe0c,GAGzB,MAAM9vE,EAAQ,CACZ89F,EAAkBxnD,kBAAkB31C,YACpCm9F,EAAkBhmD,qBAAqBn3C,aAEzCggD,EAAW+0B,6BAA6B,CACtC11E,MAAOA,EACPi4D,WAAYtL,EAAU2G,UAIxBp1D,MAAK,GAAOq4D,iBAGZ5J,EAAUgI,UAAUhU,EAAW0zB,aAG/B,MAAMopB,EAAYv/F,MAAK,GACrBk8C,EAAczyB,iBACd6zE,EAAWl1E,aACbpoB,MAAK,GAAgBu/F,EAAW9wC,GAIhCA,EAAU8H,UACR9T,EAAWixB,WACXisB,EAAahsB,yBAIfllB,EAAU4I,mBACRpkD,EAAKqkD,gBACLC,EACAv3D,KAAKwwD,gBAEP/B,EAAUxU,mBACR2lD,EAAkBhmD,qBAClBgmD,EAAkBxnD,mBAIpBp4C,MAAK,GAAO06E,kBACR16E,MAAK,IACPA,MAAK,GAAmBy/E,eAAeh9B,EAAYgM,GAarDzuD,MAAK,GAAW,CACd0hB,KAAM,eACNuoD,QAASxb,EAAU2G,QACnBqqC,aAAch9C,EAAWwzB,WACzBxlB,OAAQ8G,GAEZ,CASA,IAAkBjpC,EAAkBwxE,GAElC,MAAMC,EACJ9yE,GAAwBqB,EAAiB7gB,iBAC3C,QAA+B,IAApBsyF,EACT,MAAM,IAAI79F,MAAM,0CAIlB,MAAM89F,OAAmD,IAA1BF,EACzBG,GAAeD,GACnBF,IAA0BnzE,GAAYC,MAClCszE,GAAiBF,GACrBF,IAA0BnzE,GAAYE,QAClCszE,GAAkBH,GACtBF,IAA0BnzE,GAAYG,SAGlCszE,EAAa,CACjB33F,GAAG,EACHC,GAAG,GAEC23F,EAAY,CAChB53F,GAAG,EACHC,GAAG,EACHC,GAAG,GAiHL,MA9GwB,QAApBo3F,GAEEG,GAAiBC,KACnBE,EAAU13F,GAAI,EACdy3F,EAAW13F,GAAI,GAEY,QAApBq3F,EAELC,GAAmBC,EACrBG,EAAW13F,GAAI,EACNw3F,EACTG,EAAU13F,GAAI,EACLw3F,IACTE,EAAU13F,GAAI,EACdy3F,EAAW33F,GAAI,GAEY,QAApBs3F,EAELC,GAAmBC,EACrBG,EAAW33F,GAAI,EACNy3F,GACTG,EAAU13F,GAAI,EACdy3F,EAAW33F,GAAI,GACN03F,IACTE,EAAU13F,GAAI,GAEa,QAApBo3F,GAETK,EAAW33F,GAAI,EACf23F,EAAW13F,GAAI,GACXw3F,GAAiBC,KACnBE,EAAU13F,GAAI,IAEa,QAApBo3F,GAETK,EAAW13F,GAAI,EACXs3F,GAAmBE,EACrBG,EAAU13F,GAAI,EACLs3F,EACTI,EAAU33F,GAAI,EACLy3F,IACTC,EAAW33F,GAAI,EACf43F,EAAU33F,GAAI,EACd23F,EAAU13F,GAAI,IAGa,QAApBo3F,EAELC,GAAmBE,GACrBE,EAAW33F,GAAI,EACf23F,EAAW13F,GAAI,EACf23F,EAAU53F,GAAI,EACd43F,EAAU13F,GAAI,GACLs3F,GACTG,EAAW33F,GAAI,EACf43F,EAAU53F,GAAI,GACL03F,IACTC,EAAW13F,GAAI,EACf23F,EAAU13F,GAAI,GAEa,QAApBo3F,GAETK,EAAW33F,GAAI,EACXu3F,GAAmBE,EACrBG,EAAU53F,GAAI,EACLw3F,GACTG,EAAW13F,GAAI,EACf23F,EAAU53F,GAAI,EACd43F,EAAU33F,GAAI,GACLy3F,IACTE,EAAU33F,GAAI,IAEa,QAApBq3F,GAETM,EAAU13F,GAAI,GACVq3F,GAAmBG,GAEZD,KADTE,EAAW13F,GAAI,IAIY,QAApBq3F,GAETM,EAAU13F,GAAI,GACVs3F,GAAeC,KACjBE,EAAW33F,GAAI,IAEY,QAApBs3F,GAETK,EAAW33F,GAAI,EACf23F,EAAW13F,GAAI,GACXs3F,GAAmBG,GAEZD,KADTG,EAAU13F,GAAI,IAIa,QAApBo3F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","sources":["webpack://dwv/webpack/universalModuleDefinition","webpack://dwv/external umd {\"root\":\"JSZip\",\"commonjs\":\"jszip\",\"commonjs2\":\"jszip\",\"amd\":\"jszip\"}","webpack://dwv/external umd {\"root\":\"Konva\",\"commonjs\":\"konva\",\"commonjs2\":\"konva\",\"amd\":\"konva\"}","webpack://dwv/external umd {\"root\":\"MagicWand\",\"commonjs\":\"magic-wand-tool\",\"commonjs2\":\"magic-wand-tool\",\"amd\":\"konmagic-wand-tool\"}","webpack://dwv/webpack/bootstrap","webpack://dwv/webpack/runtime/compat get default export","webpack://dwv/webpack/runtime/define property getters","webpack://dwv/webpack/runtime/hasOwnProperty shorthand","webpack://dwv/webpack/runtime/make namespace object","webpack://dwv/./src/math/index.js","webpack://dwv/./src/image/modalityLut.js","webpack://dwv/./src/utils/logger.js","webpack://dwv/./src/image/windowLevel.js","webpack://dwv/./src/image/voiLut.js","webpack://dwv/./src/image/windowLut.js","webpack://dwv/./src/image/luts.js","webpack://dwv/./src/utils/colour.js","webpack://dwv/./src/math/vector.js","webpack://dwv/./src/math/matrix.js","webpack://dwv/./src/math/point.js","webpack://dwv/./src/utils/i18n.js","webpack://dwv/./src/utils/string.js","webpack://dwv/./src/utils/array.js","webpack://dwv/./src/dicom/dictionary.js","webpack://dwv/./src/dicom/dicomTag.js","webpack://dwv/./src/dicom/dataElement.js","webpack://dwv/./src/dicom/dataReader.js","webpack://dwv/./src/dicom/dicomParser.js","webpack://dwv/./src/utils/listen.js","webpack://dwv/./src/image/iterator.js","webpack://dwv/./src/image/rsi.js","webpack://dwv/./src/image/size.js","webpack://dwv/./src/math/stats.js","webpack://dwv/./src/image/spacing.js","webpack://dwv/./src/image/geometry.js","webpack://dwv/./src/dicom/dicomDate.js","webpack://dwv/./src/math/orientation.js","webpack://dwv/./src/dicom/dicomElementsWrapper.js","webpack://dwv/./src/image/imageFactory.js","webpack://dwv/./src/dicom/dataWriter.js","webpack://dwv/./src/dicom/dicomWriter.js","webpack://dwv/./src/dicom/dicomCode.js","webpack://dwv/./src/dicom/dicomSegment.js","webpack://dwv/./src/dicom/dicomSegmentFrameInfo.js","webpack://dwv/./src/image/maskFactory.js","webpack://dwv/./src/image/image.js","webpack://dwv/./src/image/viewFactory.js","webpack://dwv/./src/image/view.js","webpack://dwv/./src/image/viewMonochrome.js","webpack://dwv/./src/image/viewPaletteColor.js","webpack://dwv/./src/image/viewRgb.js","webpack://dwv/./src/image/viewYbrFull.js","webpack://dwv/./src/image/planeHelper.js","webpack://dwv/./src/app/viewController.js","webpack://dwv/./src/tools/scrollWheel.js","webpack://dwv/./src/math/line.js","webpack://dwv/./src/image/annotationGroup.js","webpack://dwv/./src/app/drawController.js","webpack://dwv/./src/gui/style.js","webpack://dwv/./src/tools/drawBounds.js","webpack://dwv/./src/math/rectangle.js","webpack://dwv/./src/math/roi.js","webpack://dwv/./src/math/protractor.js","webpack://dwv/./src/math/ellipse.js","webpack://dwv/./src/math/circle.js","webpack://dwv/./src/tools/drawShapeEditor.js","webpack://dwv/./src/tools/drawTrash.js","webpack://dwv/./src/tools/drawShapeHandler.js","webpack://dwv/./src/gui/drawLayer.js","webpack://dwv/./src/tools/drawCommands.js","webpack://dwv/./src/math/path.js","webpack://dwv/./src/math/bucketQueue.js","webpack://dwv/./src/math/scissors.js","webpack://dwv/./src/app/defaults.js","webpack://dwv/./src/tools/labelFactory.js","webpack://dwv/./src/image/filter.js","webpack://dwv/./src/tools/filter.js","webpack://dwv/./src/tools/index.js","webpack://dwv/./src/tools/windowLevel.js","webpack://dwv/./src/tools/scroll.js","webpack://dwv/./src/tools/zoomPan.js","webpack://dwv/./src/tools/opacity.js","webpack://dwv/./src/tools/draw.js","webpack://dwv/./src/tools/floodfill.js","webpack://dwv/./src/tools/livewire.js","webpack://dwv/./src/tools/arrow.js","webpack://dwv/./src/tools/circle.js","webpack://dwv/./src/tools/ellipse.js","webpack://dwv/./src/tools/protractor.js","webpack://dwv/./src/tools/rectangle.js","webpack://dwv/./src/tools/roi.js","webpack://dwv/./src/tools/ruler.js","webpack://dwv/./src/image/annotation.js","webpack://dwv/./src/gui/generic.js","webpack://dwv/./src/gui/viewLayer.js","webpack://dwv/./src/gui/layerGroup.js","webpack://dwv/./src/gui/stage.js","webpack://dwv/./src/io/state.js","webpack://dwv/./src/utils/uri.js","webpack://dwv/./src/utils/undoStack.js","webpack://dwv/./src/app/toolboxController.js","webpack://dwv/./src/utils/progress.js","webpack://dwv/./src/io/urlsLoader.js","webpack://dwv/./src/utils/thread.js","webpack://dwv/./src/image/decoder.js","webpack://dwv/./src/dicom/dicomMeasuredValue.js","webpack://dwv/./src/dicom/dicomNumericMeasurement.js","webpack://dwv/./src/dicom/dicomSopInstanceReference.js","webpack://dwv/./src/dicom/dicomImageReference.js","webpack://dwv/./src/dicom/dicomSpatialCoordinate.js","webpack://dwv/./src/dicom/dicomSpatialCoordinate3D.js","webpack://dwv/./src/dicom/dicomSRContent.js","webpack://dwv/./src/image/annotationGroupFactory.js","webpack://dwv/./src/app/dataController.js","webpack://dwv/./src/utils/operator.js","webpack://dwv/./src/image/dicomBufferToView.js","webpack://dwv/./src/io/memoryLoader.js","webpack://dwv/./src/image/domReader.js","webpack://dwv/./src/io/loaderList.js","webpack://dwv/./src/io/dicomDataLoader.js","webpack://dwv/./src/io/jsonTextLoader.js","webpack://dwv/./src/io/multipartLoader.js","webpack://dwv/./src/io/rawImageLoader.js","webpack://dwv/./src/io/rawVideoLoader.js","webpack://dwv/./src/io/zipLoader.js","webpack://dwv/./src/io/filesLoader.js","webpack://dwv/./src/app/loadController.js","webpack://dwv/./src/gui/overlayData.js","webpack://dwv/./src/app/application.js","webpack://dwv/./src/image/maskSegmentHelper.js","webpack://dwv/./src/image/deleteSegmentCommand.js","webpack://dwv/./src/image/changeSegmentColourCommand.js","webpack://dwv/./src/image/maskSegmentViewHelper.js","webpack://dwv/./src/math/scalar.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"konva\"), require(\"magic-wand-tool\"), require(\"jszip\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"konva\", \"konmagic-wand-tool\", \"jszip\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"dwv\"] = factory(require(\"konva\"), require(\"magic-wand-tool\"), require(\"jszip\"));\n\telse\n\t\troot[\"dwv\"] = factory(root[\"Konva\"], root[\"MagicWand\"], root[\"JSZip\"]);\n})(this, function(__WEBPACK_EXTERNAL_MODULE__944__, __WEBPACK_EXTERNAL_MODULE__324__, __WEBPACK_EXTERNAL_MODULE__654__) {\nreturn ","module.exports = __WEBPACK_EXTERNAL_MODULE__654__;","module.exports = __WEBPACK_EXTERNAL_MODULE__944__;","module.exports = __WEBPACK_EXTERNAL_MODULE__324__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = function(module) {\n\tvar getter = module && module.__esModule ?\n\t\tfunction() { return module['default']; } :\n\t\tfunction() { return module; };\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Immutable index.\n * Warning: the input array is NOT cloned, modifying it will\n * modify the index values.\n */\nexport class Index {\n\n /**\n * Index values.\n *\n * @type {number[]}\n */\n #values;\n\n /**\n * @param {number[]} values The index values.\n */\n constructor(values) {\n if (!values || typeof values === 'undefined') {\n throw new Error('Cannot create index with no values.');\n }\n if (values.length === 0) {\n throw new Error('Cannot create index with empty values.');\n }\n const valueCheck = function (val) {\n return !isNaN(val);\n };\n if (!values.every(valueCheck)) {\n throw new Error('Cannot create index with non number values.');\n }\n this.#values = values;\n }\n\n /**\n * Get the index value at the given array index.\n *\n * @param {number} i The index to get.\n * @returns {number|undefined} The value or undefined if not in range.\n */\n get(i) {\n return this.#values[i];\n }\n\n /**\n * Get the length of the index.\n *\n * @returns {number} The length.\n */\n length() {\n return this.#values.length;\n }\n\n /**\n * Get a string representation of the Index.\n *\n * @returns {string} The Index as a string.\n */\n toString() {\n return '(' + this.#values.toString() + ')';\n }\n\n /**\n * Get the values of this index.\n *\n * @returns {number[]} The array of values.\n */\n getValues() {\n return this.#values.slice();\n }\n\n /**\n * Check if the input index can be compared to this one.\n *\n * @param {Index} rhs The index to compare to.\n * @returns {boolean} True if both indices are comparable.\n */\n canCompare(rhs) {\n // check input\n if (!rhs) {\n return false;\n }\n // check length\n if (this.length() !== rhs.length()) {\n return false;\n }\n // seems ok!\n return true;\n }\n\n /**\n * Check for Index equality.\n *\n * @param {Index} rhs The index to compare to.\n * @returns {boolean} True if both indices are equal.\n */\n equals(rhs) {\n // check if can compare\n if (!this.canCompare(rhs)) {\n return false;\n }\n // check values\n for (let i = 0, leni = this.length(); i < leni; ++i) {\n if (this.get(i) !== rhs.get(i)) {\n return false;\n }\n }\n // seems ok!\n return true;\n }\n\n /**\n * Compare indices and return different dimensions.\n *\n * @param {Index} rhs The index to compare to.\n * @returns {number[]} The list of different dimensions.\n */\n compare(rhs) {\n // check if can compare\n if (!this.canCompare(rhs)) {\n return null;\n }\n // check values\n const diffDims = [];\n for (let i = 0, leni = this.length(); i < leni; ++i) {\n if (this.get(i) !== rhs.get(i)) {\n diffDims.push(i);\n }\n }\n return diffDims;\n }\n\n /**\n * Add another index to this one.\n *\n * @param {Index} rhs The index to add.\n * @returns {Index} The index representing the sum of both indices.\n */\n add(rhs) {\n // check if can compare\n if (!this.canCompare(rhs)) {\n return null;\n }\n // add values\n const values = [];\n for (let i = 0, leni = this.length(); i < leni; ++i) {\n values.push(this.get(i) + rhs.get(i));\n }\n // seems ok!\n return new Index(values);\n }\n\n /**\n * Get the current index with a new 2D base.\n *\n * @param {number} i The new 0 index.\n * @param {number} j The new 1 index.\n * @returns {Index} The new index.\n */\n getWithNew2D(i, j) {\n const values = [i, j];\n for (let l = 2, lenl = this.length(); l < lenl; ++l) {\n values.push(this.get(l));\n }\n return new Index(values);\n }\n\n} // Index class\n\n/**\n * Get an index with values set to 0 and the input size.\n *\n * @param {number} size The size of the index.\n * @returns {Index} The zero index.\n */\nexport function getZeroIndex(size) {\n const values = new Array(size);\n values.fill(0);\n return new Index(values);\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {RescaleSlopeAndIntercept} from './rsi';\n/* eslint-enable no-unused-vars */\n\n/**\n * Modality LUT class: compensates for any modality-specific presentation.\n * Typically consists of a rescale slope and intercept to\n * rescale the data range.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.11.html}.\n */\nexport class ModalityLut {\n\n /**\n * The rescale slope.\n *\n * @type {RescaleSlopeAndIntercept}\n */\n #rsi;\n\n /**\n * Is the RSI an identity one.\n *\n * @type {boolean}\n */\n #isIdRsi;\n\n /**\n * The size of the LUT array.\n *\n * @type {number}\n */\n #length;\n\n /**\n * The internal LUT array.\n *\n * @type {Float32Array}\n */\n #lut;\n\n /**\n * @param {RescaleSlopeAndIntercept} rsi The rescale slope and intercept.\n * @param {number} bitsStored The number of bits used to store the data.\n */\n constructor(rsi, bitsStored) {\n this.#rsi = rsi;\n this.#isIdRsi = rsi.isID();\n\n this.#length = Math.pow(2, bitsStored);\n\n // create lut if not identity RSI\n if (!this.#isIdRsi) {\n this.#lut = new Float32Array(this.#length);\n for (let i = 0; i < this.#length; ++i) {\n this.#lut[i] = this.#rsi.apply(i);\n }\n }\n }\n\n /**\n * Get the Rescale Slope and Intercept (RSI).\n *\n * @returns {RescaleSlopeAndIntercept} The rescale slope and intercept object.\n */\n getRSI() {\n return this.#rsi;\n }\n\n /**\n * Get the length of the LUT array.\n *\n * @returns {number} The length of the LUT array.\n */\n getLength() {\n return this.#length;\n }\n\n /**\n * Get the value of the LUT at the given offset.\n *\n * @param {number} offset The input offset in [0,2^bitsStored] range\n * or full range for ID rescale.\n * @returns {number} The float32 value of the LUT at the given offset.\n */\n getValue(offset) {\n return this.#isIdRsi ? offset : this.#lut[offset];\n }\n\n} // class ModalityLut\n","export const logger = {\n /**\n * Available log levels.\n * Note: need to activate verbose level in\n * Chrome console to see DEBUG messages.\n */\n levels: {\n TRACE: 0,\n DEBUG: 1,\n INFO: 2,\n WARN: 3,\n ERROR: 4\n },\n\n /**\n * Logger level: default to WARN.\n */\n level: 3,\n\n /**\n * Log a trace message.\n *\n * @param {string} msg The message to log.\n */\n trace: function (msg) {\n if (this.level <= this.levels.TRACE) {\n console.trace(msg);\n }\n },\n\n /**\n * Log a debug message.\n * Careful: depends on console settings.\n *\n * @param {string} msg The message to log.\n */\n debug: function (msg) {\n if (this.level <= this.levels.DEBUG) {\n console.debug(msg);\n }\n },\n\n /**\n * Log an info message.\n *\n * @param {string} msg The message to log.\n */\n info: function (msg) {\n if (this.level <= this.levels.INFO) {\n console.info(msg);\n }\n },\n\n /**\n * Log a warn message.\n *\n * @param {string} msg The message to log.\n */\n warn: function (msg) {\n if (this.level <= this.levels.WARN) {\n console.warn(msg);\n }\n },\n\n /**\n * Log an error message.\n *\n * @param {string} msg The message to log.\n */\n error: function (msg) {\n if (this.level <= this.levels.ERROR) {\n console.error(msg);\n }\n }\n\n}; // logger\n","import {logger} from '../utils/logger';\n\n/**\n * Minimum window width value.\n *\n * Ref: {@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.11.2.html#sect_C.11.2.1.2}.\n */\nconst minWindowWidth = 1;\n\n/**\n * Validate an input window width.\n *\n * @param {number} value The value to test.\n * @returns {number} A valid window width.\n */\nexport function validateWindowWidth(value) {\n return value < minWindowWidth ? minWindowWidth : value;\n}\n\n/**\n * Window and Level also known as window width and center.\n */\nexport class WindowLevel {\n /**\n * The window center.\n *\n * @type {number}\n */\n center;\n\n /**\n * The window width.\n *\n * @type {number}\n */\n width;\n\n /**\n * @param {number} center The window center.\n * @param {number} width The window width.\n */\n constructor(center, width) {\n // check width\n if (width < minWindowWidth) {\n logger.warn('Using minimum window width since input is not valid: ' +\n width);\n width = minWindowWidth;\n }\n this.center = center;\n this.width = width;\n }\n\n /**\n * Check for equality.\n *\n * @param {WindowLevel} rhs The other object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n typeof rhs !== 'undefined' &&\n this.center === rhs.center &&\n this.width === rhs.width;\n }\n\n} // WindowLevel class\n\n/**\n * List of default window level presets.\n *\n * @type {Object.>}\n */\nexport const defaultPresets = {\n CT: {\n mediastinum: new WindowLevel(40, 400),\n lung: new WindowLevel(-500, 1500),\n bone: new WindowLevel(500, 2000),\n brain: new WindowLevel(40, 80),\n head: new WindowLevel(90, 350)\n }\n};\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {WindowLevel} from './windowLevel';\n/* eslint-enable no-unused-vars */\n\n/**\n * VOI (Values of Interest) LUT class: apply window centre and width.\n *\n * ```\n * if (x <= c - 0.5 - (w-1)/2) then y = ymin\n * else if (x > c - 0.5 + (w-1)/2) then y = ymax\n * else y = ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax - ymin) + ymin\n * ```\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.11.2.html}.\n */\nexport class VoiLut {\n\n /**\n * The window and level.\n *\n * @type {WindowLevel}\n */\n #windowLevel;\n\n /**\n * Signed data offset. Defaults to 0.\n *\n * @type {number}\n */\n #signedOffset = 0;\n\n /**\n * Output value minimum. Defaults to 0.\n *\n * @type {number}\n */\n #ymin = 0;\n\n /**\n * Output value maximum. Defaults to 255.\n *\n * @type {number}\n */\n #ymax = 255;\n\n /**\n * Input value minimum (calculated).\n *\n * @type {number}\n */\n #xmin = null;\n\n /**\n * Input value maximum (calculated).\n *\n * @type {number}\n */\n #xmax = null;\n\n /**\n * Window level equation slope (calculated).\n *\n * @type {number}\n */\n #slope = null;\n\n /**\n * Window level equation intercept (calculated).\n *\n * @type {number}\n */\n #inter = null;\n\n /**\n * @param {WindowLevel} wl The window center and width.\n */\n constructor(wl) {\n this.#windowLevel = wl;\n this.#init();\n }\n\n /**\n * Get the window and level.\n *\n * @returns {WindowLevel} The window center and width.\n */\n getWindowLevel() {\n return this.#windowLevel;\n }\n\n /**\n * Initialise members. Called at construction.\n *\n */\n #init() {\n const center = this.#windowLevel.center;\n const width = this.#windowLevel.width;\n const c = center + this.#signedOffset;\n // from the standard\n this.#xmin = c - 0.5 - ((width - 1) / 2);\n this.#xmax = c - 0.5 + ((width - 1) / 2);\n // develop the equation:\n // y = ( ( x - (c - 0.5) ) / (w-1) + 0.5 ) * (ymax - ymin) + ymin\n // y = ( x / (w-1) ) * (ymax - ymin) +\n // ( -(c - 0.5) / (w-1) + 0.5 ) * (ymax - ymin) + ymin\n this.#slope = (this.#ymax - this.#ymin) / (width - 1);\n this.#inter = (-(c - 0.5) / (width - 1) + 0.5) *\n (this.#ymax - this.#ymin) + this.#ymin;\n }\n\n /**\n * Set the signed offset.\n *\n * @param {number} offset The signed data offset,\n * typically: slope * ( size / 2).\n */\n setSignedOffset(offset) {\n this.#signedOffset = offset;\n // re-initialise\n this.#init();\n }\n\n /**\n * Apply the window level on an input value.\n *\n * @param {number} value The value to rescale as an integer.\n * @returns {number} The leveled value, in the\n * [ymin, ymax] range (default [0,255]).\n */\n apply(value) {\n if (value <= this.#xmin) {\n return this.#ymin;\n } else if (value > this.#xmax) {\n return this.#ymax;\n } else {\n return (value * this.#slope) + this.#inter;\n }\n }\n\n} // class VoiLut\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {ModalityLut} from './modalityLut';\nimport {VoiLut} from './voiLut';\n/* eslint-enable no-unused-vars */\n\n/**\n * Window LUT class: combines a modality LUT and a VOI LUT.\n */\nexport class WindowLut {\n\n /**\n * The modality LUT.\n *\n * @type {ModalityLut}\n */\n #modalityLut;\n\n /**\n * The VOI LUT.\n *\n * @type {VoiLut}\n */\n #voiLut;\n\n /**\n * The internal LUT array: Uint8ClampedArray clamps between 0 and 255.\n *\n * @type {Uint8ClampedArray}\n */\n #lut;\n\n /**\n * Shift for signed data.\n *\n * @type {number}\n */\n #signedShift = 0;\n\n /**\n * Is the RSI discrete.\n *\n * @type {boolean}\n */\n #isDiscrete = true;\n\n /**\n * Construct a window LUT object, VOI LUT is set with\n * the 'setVoiLut' method.\n *\n * @param {ModalityLut} modalityLut The associated rescale LUT.\n * @param {boolean} isSigned Flag to know if the data is signed or not.\n * @param {boolean} isDiscrete Flag to know if the input data is discrete.\n */\n constructor(modalityLut, isSigned, isDiscrete) {\n this.#modalityLut = modalityLut;\n\n if (isSigned) {\n const size = this.#modalityLut.getLength();\n this.#signedShift = size / 2;\n } else {\n this.#signedShift = 0;\n }\n\n this.#isDiscrete = isDiscrete;\n }\n\n /**\n * Get the VOI LUT.\n *\n * @returns {VoiLut} The VOI LUT.\n */\n getVoiLut() {\n return this.#voiLut;\n }\n\n /**\n * Get the modality LUT.\n *\n * @returns {ModalityLut} The modality LUT.\n */\n getModalityLut() {\n return this.#modalityLut;\n }\n\n /**\n * Set the VOI LUT.\n *\n * @param {VoiLut} lut The VOI LUT.\n */\n setVoiLut(lut) {\n // store the window values\n this.#voiLut = lut;\n\n // possible signed shift (LUT indices are positive)\n this.#voiLut.setSignedOffset(\n this.#modalityLut.getRSI().getSlope() * this.#signedShift);\n\n // create lut if not continous\n if (this.#isDiscrete) {\n const size = this.#modalityLut.getLength();\n // use clamped array (polyfilled in env.js)\n this.#lut = new Uint8ClampedArray(size);\n // by default WindowLevel returns a value in the [0,255] range\n // this is ok with regular Arrays and ClampedArray.\n for (let i = 0; i < size; ++i) {\n this.#lut[i] = this.#voiLut.apply(this.#modalityLut.getValue(i));\n }\n }\n }\n\n /**\n * Get the value of the LUT at the given offset.\n *\n * @param {number} offset The input offset in [0,2^bitsStored] range\n * for discrete data or full range for non discrete.\n * @returns {number} The integer value (default [0,255]) of the LUT\n * at the given offset.\n */\n getValue(offset) {\n if (this.#isDiscrete) {\n return this.#lut[offset + this.#signedShift];\n } else {\n return Math.floor(this.#voiLut.apply(offset + this.#signedShift));\n }\n }\n\n} // class WindowLut\n","/**\n * Lookup tables for image colour display.\n */\n\nconst lut_range_max = 256;\n\n/**\n * Build a LUT of size lut_range_max.\n *\n * @param {Function} func The i to lut function.\n * @returns {number[]} The LUT.\n */\nfunction buildLut(func) {\n const lut = [];\n for (let i = 0; i < lut_range_max; ++i) {\n lut.push(func(i));\n }\n return lut;\n}\n\n/**\n * Ramp to lut_range_max minus one on the first third values.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction toMaxFirstThird(i) {\n const val = i * 3;\n if (val > lut_range_max - 1) {\n return lut_range_max - 1;\n }\n return val;\n}\n\n/**\n * Ramp to lut_range_max minus one on the second third values,\n * otherwise return 0 for the first third and\n * lut_range_max minus one for the last third.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction toMaxSecondThird(i) {\n const third = lut_range_max / 3;\n let val = 0;\n if (i >= third) {\n val = (i - third) * 3;\n if (val > lut_range_max - 1) {\n return lut_range_max - 1;\n }\n }\n return val;\n}\n\n/**\n * Ramp to lut_range_max minus one on the last third values,\n * otherwise return 0.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction toMaxThirdThird(i) {\n const third = lut_range_max / 3;\n let val = 0;\n if (i >= 2 * third) {\n val = (i - 2 * third) * 3;\n if (val > lut_range_max - 1) {\n return lut_range_max - 1;\n }\n }\n return val;\n}\n\n/**\n * Identity, returns i.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction id(i) {\n return i;\n}\n\n/**\n * Returns lut_range_max minus one minus i.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction invId(i) {\n return (lut_range_max - 1) - i;\n}\n\n/**\n * Colour map: red, green and blue components\n * to associate with intensity values.\n */\nexport class ColourMap {\n /**\n * Red component: 256 values in the [0, 255] range.\n *\n * @type {number[]}\n */\n red;\n /**\n * Green component: 256 values in the [0, 255] range.\n *\n * @type {number[]}\n */\n green;\n /**\n * Blue component: 256 values in the [0, 255] range.\n *\n * @type {number[]}\n */\n blue;\n\n /**\n * @param {number[]} red Red component.\n * @param {number[]} green Green component.\n * @param {number[]} blue Blue component.\n */\n constructor(red, green, blue) {\n this.red = red;\n this.green = green;\n this.blue = blue;\n }\n}\n\n/**\n * List of available lookup tables (lut).\n *\n * @type {Object}\n */\nexport const luts = {\n // plain\n plain: {\n red: buildLut(id),\n green: buildLut(id),\n blue: buildLut(id)\n },\n\n // inverse plain\n invPlain: {\n red: buildLut(invId),\n green: buildLut(invId),\n blue: buildLut(invId)\n },\n\n // rainbow\n /* eslint-disable @stylistic/js/max-len */\n rainbow: {\n blue: [0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 255, 247, 239, 231, 223, 215, 207, 199, 191, 183, 175, 167, 159, 151, 143, 135, 127, 119, 111, 103, 95, 87, 79, 71, 63, 55, 47, 39, 31, 23, 15, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n green: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 251, 249, 247, 245, 243, 241, 239, 237, 235, 233, 231, 229, 227, 225, 223, 221, 219, 217, 215, 213, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 192, 189, 186, 183, 180, 177, 174, 171, 168, 165, 162, 159, 156, 153, 150, 147, 144, 141, 138, 135, 132, 129, 126, 123, 120, 117, 114, 111, 108, 105, 102, 99, 96, 93, 90, 87, 84, 81, 78, 75, 72, 69, 66, 63, 60, 57, 54, 51, 48, 45, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3],\n red: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]\n },\n /* eslint-enable @stylistic/js/max-len */\n\n // hot\n hot: {\n red: buildLut(toMaxFirstThird),\n green: buildLut(toMaxSecondThird),\n blue: buildLut(toMaxThirdThird)\n },\n\n // hot iron\n /* eslint-disable @stylistic/js/max-len */\n hot_iron: {\n red: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n green: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 255],\n blue: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 255]\n },\n /* eslint-enable @stylistic/js/max-len */\n\n // pet\n /* eslint-disable @stylistic/js/max-len */\n pet: {\n red: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n green: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 128, 126, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98, 96, 94, 92, 90, 88, 86, 84, 82, 80, 78, 76, 74, 72, 70, 68, 66, 64, 63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 255],\n blue: [0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 252, 248, 244, 240, 236, 232, 228, 224, 220, 216, 212, 208, 204, 200, 196, 192, 188, 184, 180, 176, 172, 168, 164, 160, 156, 152, 148, 144, 140, 136, 132, 128, 124, 120, 116, 112, 108, 104, 100, 96, 92, 88, 84, 80, 76, 72, 68, 64, 60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 214, 218, 222, 226, 230, 234, 238, 242, 246, 250, 255]\n },\n /* eslint-enable @stylistic/js/max-len */\n\n // hot metal blue\n /* eslint-disable @stylistic/js/max-len */\n hot_metal_blue: {\n red: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 9, 12, 15, 18, 21, 24, 26, 29, 32, 35, 38, 41, 44, 47, 50, 52, 55, 57, 59, 62, 64, 66, 69, 71, 74, 76, 78, 81, 83, 85, 88, 90, 93, 96, 99, 102, 105, 108, 111, 114, 116, 119, 122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 161, 164, 166, 169, 172, 175, 178, 181, 184, 187, 190, 194, 198, 201, 205, 209, 213, 217, 221, 224, 228, 232, 236, 240, 244, 247, 251, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n green: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 9, 11, 13, 15, 17, 19, 21, 23, 24, 26, 28, 30, 32, 34, 36, 38, 40, 41, 43, 45, 47, 49, 51, 53, 55, 56, 58, 60, 62, 64, 66, 68, 70, 72, 73, 75, 77, 79, 81, 83, 85, 87, 88, 90, 92, 94, 96, 98, 100, 102, 104, 105, 107, 109, 111, 113, 115, 117, 119, 120, 122, 124, 126, 128, 130, 132, 134, 136, 137, 139, 141, 143, 145, 147, 149, 151, 152, 154, 156, 158, 160, 162, 164, 166, 168, 169, 171, 173, 175, 177, 179, 181, 183, 184, 186, 188, 190, 192, 194, 196, 198, 200, 201, 203, 205, 207, 209, 211, 213, 215, 216, 218, 220, 222, 224, 226, 228, 229, 231, 233, 235, 237, 239, 240, 242, 244, 246, 248, 250, 251, 253, 255],\n blue: [0, 2, 4, 6, 8, 10, 12, 14, 16, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 184, 186, 188, 190, 192, 194, 196, 198, 200, 197, 194, 191, 188, 185, 182, 179, 176, 174, 171, 168, 165, 162, 159, 156, 153, 150, 144, 138, 132, 126, 121, 115, 109, 103, 97, 91, 85, 79, 74, 68, 62, 56, 50, 47, 44, 41, 38, 35, 32, 29, 26, 24, 21, 18, 15, 12, 9, 6, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 9, 12, 15, 18, 21, 24, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 76, 79, 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 126, 129, 132, 135, 138, 141, 144, 147, 150, 153, 156, 159, 162, 165, 168, 171, 174, 176, 179, 182, 185, 188, 191, 194, 197, 200, 203, 206, 210, 213, 216, 219, 223, 226, 229, 232, 236, 239, 242, 245, 249, 252, 255]\n },\n /* eslint-enable @stylistic/js/max-len */\n\n // pet 20 step\n /* eslint-disable @stylistic/js/max-len */\n pet_20step: {\n red: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n green: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n blue: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]\n }\n /* eslint-enable @stylistic/js/max-len */\n};\n","// example implementation: dcmtk/dcmiod/libsrc/cielabutil.cc\n// https://github.com/DCMTK/dcmtk/blob/DCMTK-3.6.6/dcmiod/libsrc/cielabutil.cc\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Scalar3D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * RGB colour class.\n */\nexport class RGB {\n /**\n * Red component.\n *\n * @type {number}\n */\n r;\n /**\n * Green component.\n *\n * @type {number}\n */\n g;\n /**\n * Blue component.\n *\n * @type {number}\n */\n b;\n /**\n * @param {number} r Red component.\n * @param {number} g Green component.\n * @param {number} b Blue component.\n */\n constructor(r, g, b) {\n this.r = r;\n this.g = g;\n this.b = b;\n }\n}\n\n/**\n * Check if two rgb objects are equal.\n *\n * @param {RGB} c1 The first colour.\n * @param {RGB} c2 The second colour.\n * @returns {boolean} True if both colour are equal.\n */\nexport function isEqualRgb(c1, c2) {\n return c1 !== null &&\n c2 !== null &&\n typeof c1 !== 'undefined' &&\n typeof c2 !== 'undefined' &&\n c1.r === c2.r &&\n c1.g === c2.g &&\n c1.b === c2.b;\n}\n\n/**\n * Convert YBR to RGB.\n *\n * Ref:\n * - {@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.7.6.3.html#sect_C.7.6.3.1.2},\n * - {@link https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion}.\n *\n * @param {number} y The Y component.\n * @param {number} cb The Cb component.\n * @param {number} cr The Cr component.\n * @returns {RGB} RGB equivalent as {r,g,b}.\n */\nexport function ybrToRgb(y, cb, cr) {\n return {\n r: y + 1.402 * (cr - 128),\n g: y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128),\n b: y + 1.772 * (cb - 128)\n };\n}\n\n/**\n * Convert a hex color into RGB.\n *\n * @param {string} hexStr The hex color as '#ab01ef'.\n * @returns {RGB} The RGB values as {r,g,b}.\n */\nexport function hexToRgb(hexStr) {\n return {\n r: parseInt(hexStr.substring(1, 3), 16),\n g: parseInt(hexStr.substring(3, 5), 16),\n b: parseInt(hexStr.substring(5, 7), 16)\n };\n}\n\n/**\n * Convert RGB to its hex equivalent.\n *\n * @param {RGB} rgb The RGB object as {r,g,b}.\n * @returns {string} A string representing the hex color as '#ab01ef'.\n */\nexport function rgbToHex(rgb) {\n return '#' +\n ((1 << 24) + (rgb.r << 16) + (rgb.g << 8) + rgb.b).toString(16).slice(1);\n}\n\n/**\n * Get the brightness of a RGB colour: calculates\n * the luma (Y) of the YIQ colour space.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/YIQ#From_RGB_to_YIQ}.\n *\n * @param {RGB} rgb RGB triplet.\n * @returns {number} The brightness ([0,1]).\n */\nexport function getBrightness(rgb) {\n // 0.001172549 = 0.299 / 255\n // 0.002301961 = 0.587 / 255\n // 0.000447059 = 0.114 / 255\n return rgb.r * 0.001172549 +\n rgb.g * 0.002301961 +\n rgb.b * 0.000447059;\n}\n\n/**\n * Check if a colour given in hexadecimal format is dark.\n *\n * @param {string} hexColour The colour (as '#ab01ef').\n * @returns {boolean} True if the colour is dark (brightness < 0.5).\n */\nexport function isDarkColour(hexColour) {\n return getBrightness(hexToRgb(hexColour)) < 0.5;\n}\n\n/**\n * Get the shadow colour of an input colour.\n *\n * @param {string} hexColour The colour (as '#ab01ef').\n * @returns {string} The shadow colour (white or black).\n */\nexport function getShadowColour(hexColour) {\n return isDarkColour(hexColour) ? '#fff' : '#000';\n}\n\n/**\n * Unsigned int CIE LAB value ([0, 65535]) to CIE LAB value\n * (L: [0, 100], a: [-128, 127], b: [-128, 127]).\n *\n * @param {object} triplet CIE LAB triplet as {l,a,b} with unsigned range.\n * @returns {object} CIE LAB triplet as {l,a,b} with CIE LAB range.\n */\nexport function uintLabToLab(triplet) {\n // 0.001525902 = 100 / 65535\n // 0.003891051 = 255 / 65535\n return {\n l: 0.001525902 * triplet.l,\n a: 0.003891051 * triplet.a - 128,\n b: 0.003891051 * triplet.b - 128,\n };\n}\n\n/**\n * CIE LAB value (L: [0, 100], a: [-128, 127], b: [-128, 127]) to\n * unsigned int CIE LAB ([0, 65535]).\n *\n * @param {object} triplet CIE XYZ triplet as {l,a,b} with CIE LAB range.\n * @returns {object} CIE LAB triplet as {l,a,b} with unsigned range.\n */\nexport function labToUintLab(triplet) {\n // 655.35 = 65535 / 100\n // aUint = (a + 128) * 65535 / 255\n // 257 = 65535 / 255\n // 32896 = 257 * 128\n return {\n l: 655.35 * triplet.l,\n a: 257 * triplet.a + 32896,\n b: 257 * triplet.b + 32896,\n };\n}\n\n/**\n * CIE Standard Illuminant D65, standard 2° observer.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/Illuminant_D65}.\n */\nconst d65 = {\n x: 95.0489,\n y: 100,\n z: 108.884\n};\n\n/**\n * Convert CIE LAB to CIE XYZ (standard illuminant D65, 2degree 1931).\n *\n * Ref: {@link https://en.wikipedia.org/wiki/CIELAB_color_space#From_CIELAB_to_CIEXYZ}.\n *\n * @param {object} triplet CIE LAB triplet as {l,a,b}.\n * @returns {Scalar3D} CIE XYZ triplet as {x,y,z}.\n */\nexport function cielabToCiexyz(triplet) {\n /**\n * Apply the inverse lab function.\n *\n * @param {number} x The input value.\n * @returns {number} The result.\n */\n function invLabFunc(x) {\n let res = null;\n // delta = 6 / 29 = 0.206896552\n if (x > 0.206896552) {\n res = Math.pow(x, 3);\n } else {\n // 0.128418549 = 3 * delta^2\n // 0.017712903 = 3 * delta^2 * (4 / 29)\n res = 0.128418549 * x - 0.017712903;\n }\n return res;\n }\n\n const illuminant = d65;\n const l0 = (triplet.l + 16) / 116;\n\n return {\n x: illuminant.x * invLabFunc(l0 + triplet.a / 500),\n y: illuminant.y * invLabFunc(l0),\n z: illuminant.z * invLabFunc(l0 - triplet.b / 200)\n };\n}\n\n/**\n * Convert CIE XYZ to CIE LAB (standard illuminant D65, 2degree 1931).\n *\n * Ref: {@link https://en.wikipedia.org/wiki/CIELAB_color_space#From_CIEXYZ_to_CIELAB}.\n *\n * @param {Scalar3D} triplet CIE XYZ triplet as {x,y,z}.\n * @returns {object} CIE LAB triplet as {l,a,b}.\n */\nexport function ciexyzToCielab(triplet) {\n /**\n * Apply the lab function.\n *\n * @param {number} x The input value.\n * @returns {number} The result.\n */\n function labFunc(x) {\n let res = null;\n // delta = 6 / 29 = 0.206896552\n // delta^3 = 0.008856452\n if (x > 0.008856452) {\n res = Math.pow(x, 0.333333333);\n } else {\n // 7.787037037 = 1 / 3 * delta^2\n // 0.137931034 = 4 / 29\n res = 7.787037037 * x + 0.137931034;\n }\n return res;\n }\n\n const illuminant = d65;\n const fy = labFunc(triplet.y / illuminant.y);\n\n return {\n l: 116 * fy - 16,\n a: 500 * (labFunc(triplet.x / illuminant.x) - fy),\n b: 200 * (fy - labFunc(triplet.z / illuminant.z))\n };\n}\n\n/**\n * Convert CIE XYZ to sRGB.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/SRGB#From_CIE_XYZ_to_sRGB}.\n *\n * @param {Scalar3D} triplet CIE XYZ triplet as {x,y,z}.\n * @returns {RGB} 'sRGB' triplet as {r,g,b}.\n */\nexport function ciexyzToSrgb(triplet) {\n /**\n * Apply the gamma function.\n *\n * @param {number} x The input value.\n * @returns {number} The result.\n */\n function gammaFunc(x) {\n let res = null;\n if (x <= 0.0031308) {\n res = 12.92 * x;\n } else {\n // 0.416666667 = 1 / 2.4\n res = 1.055 * Math.pow(x, 0.416666667) - 0.055;\n }\n // clip [0,1]\n return Math.min(1, Math.max(0, res));\n }\n\n const x = triplet.x / 100;\n const y = triplet.y / 100;\n const z = triplet.z / 100;\n\n return {\n r: Math.round(255 * gammaFunc(3.2406 * x - 1.5372 * y - 0.4986 * z)),\n g: Math.round(255 * gammaFunc(-0.9689 * x + 1.8758 * y + 0.0415 * z)),\n b: Math.round(255 * gammaFunc(0.0557 * x - 0.2040 * y + 1.0570 * z))\n };\n}\n\n/**\n * Convert sRGB to CIE XYZ.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/SRGB#From_sRGB_to_CIE_XYZ}.\n *\n * @param {RGB} triplet 'sRGB' triplet as {r,g,b}.\n * @returns {Scalar3D} CIE XYZ triplet as {x,y,z}.\n */\nexport function srgbToCiexyz(triplet) {\n /**\n * Apply the inverse gamma function.\n *\n * @param {number} x The input value.\n * @returns {number} The result.\n */\n function invGammaFunc(x) {\n let res = null;\n if (x <= 0.04045) {\n res = x / 12.92;\n } else {\n res = Math.pow((x + 0.055) / 1.055, 2.4);\n }\n return res;\n }\n\n const rl = invGammaFunc(triplet.r / 255);\n const gl = invGammaFunc(triplet.g / 255);\n const bl = invGammaFunc(triplet.b / 255);\n\n return {\n x: 100 * (0.4124 * rl + 0.3576 * gl + 0.1805 * bl),\n y: 100 * (0.2126 * rl + 0.7152 * gl + 0.0722 * bl),\n z: 100 * (0.0193 * rl + 0.1192 * gl + 0.9505 * bl)\n };\n}\n\n/**\n * Convert CIE LAB to sRGB (standard illuminant D65).\n *\n * @param {object} triplet CIE LAB triplet as {l,a,b}.\n * @returns {RGB} 'sRGB' triplet as {r,g,b}.\n */\nexport function cielabToSrgb(triplet) {\n return ciexyzToSrgb(cielabToCiexyz(triplet));\n}\n\n/**\n * Convert sRGB to CIE LAB (standard illuminant D65).\n *\n * @param {RGB} triplet 'sRGB' triplet as {r,g,b}.\n * @returns {object} CIE LAB triplet as {l,a,b}.\n */\nexport function srgbToCielab(triplet) {\n return ciexyzToCielab(srgbToCiexyz(triplet));\n}\n\n/**\n * Get the hex code of a string colour for a colour used in pre dwv v0.17.\n *\n * @param {string} name The name of a colour.\n * @returns {string} The hex representing the colour.\n */\nexport function colourNameToHex(name) {\n // default colours used in dwv version < 0.17\n const dict = {\n Yellow: '#ffff00',\n Red: '#ff0000',\n White: '#ffffff',\n Green: '#008000',\n Blue: '#0000ff',\n Lime: '#00ff00',\n Fuchsia: '#ff00ff',\n Black: '#000000'\n };\n let res = '#ffff00';\n if (typeof dict[name] !== 'undefined') {\n res = dict[name];\n }\n return res;\n}\n","/**\n * Immutable 3D vector.\n */\nexport class Vector3D {\n\n /**\n * X coordinate.\n *\n * @type {number}\n */\n #x;\n\n /**\n * Y coordinate.\n *\n * @type {number}\n */\n #y;\n\n /**\n * Z coordinate.\n *\n * @type {number}\n */\n #z;\n\n /**\n * @param {number} x The X component of the vector.\n * @param {number} y The Y component of the vector.\n * @param {number} z The Z component of the vector.\n */\n constructor(x, y, z) {\n this.#x = x;\n this.#y = y;\n this.#z = z;\n }\n\n /**\n * Get the X component of the vector.\n *\n * @returns {number} The X component of the vector.\n */\n getX() {\n return this.#x;\n }\n\n /**\n * Get the Y component of the vector.\n *\n * @returns {number} The Y component of the vector.\n */\n getY() {\n return this.#y;\n }\n\n /**\n * Get the Z component of the vector.\n *\n * @returns {number} The Z component of the vector.\n */\n getZ() {\n return this.#z;\n }\n\n /**\n * Check for Vector3D equality.\n *\n * @param {Vector3D} rhs The other vector to compare to.\n * @returns {boolean} True if both vectors are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.#x === rhs.getX() &&\n this.#y === rhs.getY() &&\n this.#z === rhs.getZ();\n }\n\n /**\n * Get a string representation of the Vector3D.\n *\n * @returns {string} The vector as a string.\n */\n toString() {\n return '(' + this.#x +\n ', ' + this.#y +\n ', ' + this.#z + ')';\n }\n\n /**\n * Get the norm of the vector.\n *\n * @returns {number} The norm.\n */\n norm() {\n return Math.sqrt(\n (this.#x * this.#x) +\n (this.#y * this.#y) +\n (this.#z * this.#z)\n );\n }\n\n /**\n * Get the cross product with another Vector3D, ie the\n * vector that is perpendicular to both a and b.\n * If both vectors are parallel, the cross product is a zero vector.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/Cross_product}.\n *\n * @param {Vector3D} vector3D The input vector.\n * @returns {Vector3D} The result vector.\n */\n crossProduct(vector3D) {\n return new Vector3D(\n (this.#y * vector3D.getZ()) - (vector3D.getY() * this.#z),\n (this.#z * vector3D.getX()) - (vector3D.getZ() * this.#x),\n (this.#x * vector3D.getY()) - (vector3D.getX() * this.#y));\n }\n\n /**\n * Get the dot product with another Vector3D.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/Dot_product}.\n *\n * @param {Vector3D} vector3D The input vector.\n * @returns {number} The dot product.\n */\n dotProduct(vector3D) {\n return (this.#x * vector3D.getX()) +\n (this.#y * vector3D.getY()) +\n (this.#z * vector3D.getZ());\n }\n\n /**\n * Is this vector codirectional to an input one.\n *\n * @param {Vector3D} vector3D The vector to test.\n * @returns {boolean} True if codirectional, false is opposite.\n */\n isCodirectional(vector3D) {\n // a.dot(b) = ||a|| * ||b|| * cos(theta)\n // (https://en.wikipedia.org/wiki/Dot_product#Geometric_definition)\n // -> the sign of the dot product depends on the cosinus of\n // the angle between the vectors\n // -> >0 => vectors are codirectional\n // -> <0 => vectors are opposite\n return this.dotProduct(vector3D) > 0;\n }\n\n} // Vector3D class","import {Vector3D} from './vector';\nimport {Point3D} from './point';\nimport {Index} from './index';\nimport {logger} from '../utils/logger';\n\n// Number.EPSILON is difference between 1 and the smallest\n// floating point number greater than 1\n// -> ~2e-16\n// BIG_EPSILON -> ~2e-12\nexport const BIG_EPSILON = Number.EPSILON * 1e4;\n// 'real world', for example when comparing positions\nexport const REAL_WORLD_EPSILON = 1e-4;\n\n/**\n * Check if two numbers are similar.\n *\n * @param {number} a The first number.\n * @param {number} b The second number.\n * @param {number} tol The comparison tolerance,\n * default to Number.EPSILON.\n * @returns {boolean} True if similar.\n */\nexport function isSimilar(a, b, tol) {\n if (typeof tol === 'undefined') {\n tol = Number.EPSILON;\n }\n return Math.abs(a - b) < tol;\n}\n\n/**\n * Immutable 3x3 Matrix.\n */\nexport class Matrix33 {\n\n /**\n * Matrix values.\n *\n * @type {number[]}\n */\n #values;\n\n /**\n * Matrix inverse, calculated at first ask.\n *\n * @type {Matrix33}\n */\n #inverse;\n\n /**\n * @param {number[]} values Row-major ordered 9 values.\n */\n constructor(values) {\n this.#values = values;\n }\n\n /**\n * Get a value of the matrix.\n *\n * @param {number} row The row at wich to get the value.\n * @param {number} col The column at wich to get the value.\n * @returns {number|undefined} The value at the position.\n */\n get(row, col) {\n return this.#values[row * 3 + col];\n }\n\n /**\n * Get the inverse of this matrix.\n *\n * @returns {Matrix33|undefined} The inverse matrix or undefined\n * if the determinant is zero.\n */\n getInverse() {\n if (typeof this.#inverse === 'undefined') {\n this.#inverse = getMatrixInverse(this);\n }\n return this.#inverse;\n }\n\n /**\n * Check for Matrix33 equality.\n *\n * @param {Matrix33} rhs The other matrix to compare to.\n * @param {number} [p] A numeric expression for the precision to use in check\n * (ex: 0.001). Defaults to Number.EPSILON if not provided.\n * @returns {boolean} True if both matrices are equal.\n */\n equals(rhs, p) {\n // TODO: add type check\n // check values\n for (let i = 0; i < 3; ++i) {\n for (let j = 0; j < 3; ++j) {\n if (!isSimilar(this.get(i, j), rhs.get(i, j), p)) {\n return false;\n }\n }\n }\n return true;\n }\n\n /**\n * Get a string representation of the Matrix33.\n *\n * @returns {string} The matrix as a string.\n */\n toString() {\n let str = '[';\n for (let i = 0; i < 3; ++i) {\n if (i !== 0) {\n str += ', \\n ';\n }\n for (let j = 0; j < 3; ++j) {\n if (j !== 0) {\n str += ', ';\n }\n str += this.get(i, j);\n }\n }\n str += ']';\n return str;\n }\n\n /**\n * Multiply this matrix by another.\n *\n * @param {Matrix33} rhs The matrix to multiply by.\n * @returns {Matrix33} The product matrix.\n */\n multiply(rhs) {\n const values = [];\n for (let i = 0; i < 3; ++i) {\n for (let j = 0; j < 3; ++j) {\n let tmp = 0;\n for (let k = 0; k < 3; ++k) {\n tmp += this.get(i, k) * rhs.get(k, j);\n }\n values.push(tmp);\n }\n }\n return new Matrix33(values);\n }\n\n /**\n * Get the absolute value of this matrix.\n *\n * @returns {Matrix33} The result matrix.\n */\n getAbs() {\n const values = [];\n for (let i = 0; i < 3; ++i) {\n for (let j = 0; j < 3; ++j) {\n values.push(Math.abs(this.get(i, j)));\n }\n }\n return new Matrix33(values);\n }\n\n /**\n * Multiply this matrix by a 3D array.\n *\n * @param {number[]} array3D The input 3D array.\n * @returns {number[]} The result 3D array.\n */\n multiplyArray3D(array3D) {\n if (array3D.length !== 3) {\n throw new Error('Cannot multiply 3x3 matrix with non 3D array: ' +\n array3D.length);\n }\n const values = [];\n for (let i = 0; i < 3; ++i) {\n let tmp = 0;\n for (let j = 0; j < 3; ++j) {\n tmp += this.get(i, j) * array3D[j];\n }\n values.push(tmp);\n }\n return values;\n }\n\n /**\n * Multiply this matrix by a 3D vector.\n *\n * @param {Vector3D} vector3D The input 3D vector.\n * @returns {Vector3D} The result 3D vector.\n */\n multiplyVector3D(vector3D) {\n const array3D = this.multiplyArray3D(\n [vector3D.getX(), vector3D.getY(), vector3D.getZ()]\n );\n return new Vector3D(array3D[0], array3D[1], array3D[2]);\n }\n\n /**\n * Multiply this matrix by a 3D point.\n *\n * @param {Point3D} point3D The input 3D point.\n * @returns {Point3D} The result 3D point.\n */\n multiplyPoint3D(point3D) {\n const array3D = this.multiplyArray3D(\n [point3D.getX(), point3D.getY(), point3D.getZ()]\n );\n return new Point3D(array3D[0], array3D[1], array3D[2]);\n }\n\n /**\n * Multiply this matrix by a 3D index.\n *\n * @param {Index} index3D The input 3D index.\n * @returns {Index} The result 3D index.\n */\n multiplyIndex3D(index3D) {\n const array3D = this.multiplyArray3D(index3D.getValues());\n return new Index(array3D);\n }\n\n /**\n * Get the index of the maximum in absolute value of a row.\n *\n * @param {number} row The row to get the maximum from.\n * @returns {object} The {value,index} of the maximum.\n */\n getRowAbsMax(row) {\n const values = [\n Math.abs(this.get(row, 0)),\n Math.abs(this.get(row, 1)),\n Math.abs(this.get(row, 2))\n ];\n const absMax = Math.max.apply(null, values);\n const index = values.indexOf(absMax);\n return {\n value: this.get(row, index),\n index: index\n };\n }\n\n /**\n * Get the index of the maximum in absolute value of a column.\n *\n * @param {number} col The column to get the maximum from.\n * @returns {object} The {value,index} of the maximum.\n */\n getColAbsMax(col) {\n const values = [\n Math.abs(this.get(0, col)),\n Math.abs(this.get(1, col)),\n Math.abs(this.get(2, col))\n ];\n const absMax = Math.max.apply(null, values);\n const index = values.indexOf(absMax);\n return {\n value: this.get(index, col),\n index: index\n };\n }\n\n /**\n * Get this matrix with only zero and +/- ones instead of the maximum.\n *\n * @returns {Matrix33} The simplified matrix.\n */\n asOneAndZeros() {\n const res = [];\n for (let j = 0; j < 3; ++j) {\n const max = this.getRowAbsMax(j);\n const sign = max.value > 0 ? 1 : -1;\n for (let i = 0; i < 3; ++i) {\n if (i === max.index) {\n res.push(1 * sign);\n } else {\n res.push(0);\n }\n }\n }\n return new Matrix33(res);\n }\n\n /**\n * Get the third column direction index of an orientation matrix.\n *\n * @returns {number} The index of the absolute maximum of the last column.\n */\n getThirdColMajorDirection() {\n return this.getColAbsMax(2).index;\n }\n\n} // Matrix33\n\n/**\n * Get the inverse of an input 3*3 matrix.\n *\n * Ref:\n * - {@link https://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3_%C3%97_3_matrices},\n * - {@link https://github.com/willnode/N-Matrix-Programmer}.\n *\n * @param {Matrix33} m The input matrix.\n * @returns {Matrix33|undefined} The inverse matrix or undefined\n * if the determinant is zero.\n */\nfunction getMatrixInverse(m) {\n const m00 = m.get(0, 0);\n const m01 = m.get(0, 1);\n const m02 = m.get(0, 2);\n const m10 = m.get(1, 0);\n const m11 = m.get(1, 1);\n const m12 = m.get(1, 2);\n const m20 = m.get(2, 0);\n const m21 = m.get(2, 1);\n const m22 = m.get(2, 2);\n\n const a1212 = m11 * m22 - m12 * m21;\n const a2012 = m12 * m20 - m10 * m22;\n const a0112 = m10 * m21 - m11 * m20;\n\n let det = m00 * a1212 + m01 * a2012 + m02 * a0112;\n if (det === 0) {\n logger.warn('Cannot invert 3*3 matrix with zero determinant.');\n return undefined;\n }\n det = 1 / det;\n\n const values = [\n det * a1212,\n det * (m02 * m21 - m01 * m22),\n det * (m01 * m12 - m02 * m11),\n det * a2012,\n det * (m00 * m22 - m02 * m20),\n det * (m02 * m10 - m00 * m12),\n det * a0112,\n det * (m01 * m20 - m00 * m21),\n det * (m00 * m11 - m01 * m10)\n ];\n\n return new Matrix33(values);\n}\n\n/**\n * Create a 3x3 identity matrix.\n *\n * @returns {Matrix33} The identity matrix.\n */\nexport function getIdentityMat33() {\n /* eslint-disable @stylistic/js/array-element-newline */\n return new Matrix33([\n 1, 0, 0,\n 0, 1, 0,\n 0, 0, 1\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n}\n\n/**\n * Check if a matrix is a 3x3 identity matrix.\n *\n * @param {Matrix33} mat33 The matrix to test.\n * @returns {boolean} True if identity.\n */\nexport function isIdentityMat33(mat33) {\n return mat33.equals(getIdentityMat33());\n}\n","import {isSimilar} from './matrix';\nimport {Vector3D} from './vector';\n\n/**\n * Immutable 2D point.\n */\nexport class Point2D {\n\n /**\n * X position.\n *\n * @type {number}\n */\n #x;\n\n /**\n * Y position.\n *\n * @type {number}\n */\n #y;\n\n /**\n * @param {number} x The X coordinate for the point.\n * @param {number} y The Y coordinate for the point.\n */\n constructor(x, y) {\n this.#x = x;\n this.#y = y;\n }\n\n /**\n * Get the X position of the point.\n *\n * @returns {number} The X position of the point.\n */\n getX() {\n return this.#x;\n }\n\n /**\n * Get the Y position of the point.\n *\n * @returns {number} The Y position of the point.\n */\n getY() {\n return this.#y;\n }\n\n /**\n * Get the values of this point.\n *\n * @returns {number[]} The array of values.\n */\n getValues() {\n return [this.#x, this.#y];\n }\n\n /**\n * Get the centroid of the point, ie itself.\n *\n * @returns {Point2D} The centroid point.\n */\n getCentroid() {\n return this;\n }\n\n /**\n * Check for Point2D equality.\n *\n * @param {Point2D} rhs The other point to compare to.\n * @returns {boolean} True if both points are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n typeof rhs !== 'undefined' &&\n this.#x === rhs.getX() &&\n this.#y === rhs.getY();\n }\n\n /**\n * Get a string representation of the Point2D.\n *\n * @returns {string} The point as a string.\n */\n toString() {\n return '(' + this.#x + ', ' + this.#y + ')';\n }\n\n /**\n * Get the distance to another Point2D.\n *\n * @param {Point2D} point2D The input point.\n * @returns {number} Ths distance to the input point.\n */\n getDistance(point2D) {\n const dx = this.#x - point2D.getX();\n const dy = this.#y - point2D.getY();\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n} // Point2D class\n\n/**\n * Immutable 3D point.\n */\nexport class Point3D {\n\n /**\n * X position.\n *\n * @type {number}\n */\n #x;\n\n /**\n * Y position.\n *\n * @type {number}\n */\n #y;\n\n /**\n * Z position.\n *\n * @type {number}\n */\n #z;\n\n /**\n * @param {number} x The X coordinate for the point.\n * @param {number} y The Y coordinate for the point.\n * @param {number} z The Z coordinate for the point.\n */\n constructor(x, y, z) {\n this.#x = x;\n this.#y = y;\n this.#z = z;\n }\n\n /**\n * Get the X position of the point.\n *\n * @returns {number} The X position of the point.\n */\n getX() {\n return this.#x;\n }\n\n /**\n * Get the Y position of the point.\n *\n * @returns {number} The Y position of the point.\n */\n getY() {\n return this.#y;\n }\n\n /**\n * Get the Z position of the point.\n *\n * @returns {number} The Z position of the point.\n */\n getZ() {\n return this.#z;\n }\n\n /**\n * Get the values of this point.\n *\n * @returns {number[]} The array of values.\n */\n getValues() {\n return [this.#x, this.#y, this.#z];\n }\n\n /**\n * Check for Point3D equality.\n *\n * @param {Point3D} rhs The other point to compare to.\n * @returns {boolean} True if both points are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.#x === rhs.getX() &&\n this.#y === rhs.getY() &&\n this.#z === rhs.getZ();\n }\n\n /**\n * Check for Point3D similarity.\n *\n * @param {Point3D} rhs The other point to compare to.\n * @param {number} tol Optional comparison tolerance,\n * default to Number.EPSILON.\n * @returns {boolean} True if both points are equal.\n */\n isSimilar(rhs, tol) {\n return rhs !== null &&\n isSimilar(this.#x, rhs.getX(), tol) &&\n isSimilar(this.#y, rhs.getY(), tol) &&\n isSimilar(this.#z, rhs.getZ(), tol);\n }\n\n /**\n * Get a string representation of the Point3D.\n *\n * @returns {string} The point as a string.\n */\n toString() {\n return '(' + this.#x +\n ', ' + this.#y +\n ', ' + this.#z + ')';\n }\n\n /**\n * Get the distance to another Point3D.\n *\n * @param {Point3D} point3D The input point.\n * @returns {number} Ths distance to the input point.\n */\n getDistance(point3D) {\n return Math.sqrt(this.#getSquaredDistance(point3D));\n }\n\n /**\n * Get the square of the distance between this and\n * an input point. Used for sorting.\n *\n * @param {Point3D} point3D The input point.\n * @returns {number} The square of the distance.\n */\n #getSquaredDistance(point3D) {\n const dx = this.#x - point3D.getX();\n const dy = this.#y - point3D.getY();\n const dz = this.#z - point3D.getZ();\n return dx * dx + dy * dy + dz * dz;\n }\n\n /**\n * Get the closest point to this in a Point3D list.\n *\n * @param {Point3D[]} pointList The list to check.\n * @returns {number} The index of the closest point in the input list.\n */\n getClosest(pointList) {\n let minIndex = 0;\n // the order between squared distances and distances is the same\n let minDist = this.#getSquaredDistance(pointList[minIndex]);\n for (let i = 0; i < pointList.length; ++i) {\n const dist = this.#getSquaredDistance(pointList[i]);\n if (dist < minDist) {\n minIndex = i;\n minDist = dist;\n }\n }\n return minIndex;\n }\n\n /**\n * Get the difference to another Point3D.\n *\n * @param {Point3D} point3D The input point.\n * @returns {Vector3D} The 3D vector from the input point to this one.\n */\n minus(point3D) {\n return new Vector3D(\n (this.#x - point3D.getX()),\n (this.#y - point3D.getY()),\n (this.#z - point3D.getZ()));\n }\n\n} // Point3D class\n\n/**\n * Get an array find callback for an equal input point.\n *\n * @param {Point3D} point The point to compare to.\n * @returns {Function} A function that compares, using `equals`,\n * its input point to the one given as input to this function.\n */\nexport function getEqualPoint3DFunction(point) {\n return function (element) {\n return element.equals(point);\n };\n}\n\n/**\n * Immutable point.\n * Warning: the input array is NOT cloned, modifying it will\n * modify the point values.\n */\nexport class Point {\n\n /**\n * Point values.\n *\n * @type {number[]}\n */\n #values;\n\n /**\n * @param {number[]} values The point values.\n */\n constructor(values) {\n if (!values || typeof values === 'undefined') {\n throw new Error('Cannot create point with no values.');\n }\n if (values.length === 0) {\n throw new Error('Cannot create point with empty values.');\n }\n const valueCheck = function (val) {\n return !isNaN(val);\n };\n if (!values.every(valueCheck)) {\n throw new Error('Cannot create point with non number values.');\n }\n this.#values = values;\n }\n\n /**\n * Get the point value at the given array index.\n *\n * @param {number} i The index to get.\n * @returns {number} The value.\n */\n get(i) {\n return this.#values[i];\n }\n\n /**\n * Get the length of the point.\n *\n * @returns {number} The length.\n */\n length() {\n return this.#values.length;\n }\n\n /**\n * Get a string representation of the point.\n *\n * @returns {string} The point as a string.\n */\n toString() {\n return '(' + this.#values.toString() + ')';\n }\n\n /**\n * Get the values of this point.\n *\n * @returns {number[]} The array of values.\n */\n getValues() {\n return this.#values.slice();\n }\n\n /**\n * Check if the input point can be compared to this one.\n *\n * @param {Point} rhs The point to compare to.\n * @returns {boolean} True if both points are comparable.\n */\n canCompare(rhs) {\n // check input\n if (!rhs) {\n return false;\n }\n // check length\n if (this.length() !== rhs.length()) {\n return false;\n }\n // seems ok!\n return true;\n }\n\n /**\n * Check for Point equality.\n *\n * @param {Point} rhs The point to compare to.\n * @returns {boolean} True if both points are equal.\n */\n equals(rhs) {\n // check if can compare\n if (!this.canCompare(rhs)) {\n return false;\n }\n // check values\n for (let i = 0, leni = this.length(); i < leni; ++i) {\n if (this.get(i) !== rhs.get(i)) {\n return false;\n }\n }\n // seems ok!\n return true;\n }\n\n /**\n * Compare points and return different dimensions.\n *\n * @param {Point} rhs The point to compare to.\n * @returns {number[]} The list of different dimensions.\n */\n compare(rhs) {\n // check if can compare\n if (!this.canCompare(rhs)) {\n return null;\n }\n // check values\n const diffDims = [];\n for (let i = 0, leni = this.length(); i < leni; ++i) {\n if (this.get(i) !== rhs.get(i)) {\n diffDims.push(i);\n }\n }\n return diffDims;\n }\n\n /**\n * Get the 3D part of this point.\n *\n * @returns {Point3D} The Point3D.\n */\n get3D() {\n return new Point3D(this.get(0), this.get(1), this.get(2));\n }\n\n /**\n * Add another point to this one.\n *\n * @param {Point} rhs The point to add.\n * @returns {Point} The point representing the sum of both points.\n */\n add(rhs) {\n // check if can compare\n if (!this.canCompare(rhs)) {\n return null;\n }\n const values = [];\n const values0 = this.getValues();\n const values1 = rhs.getValues();\n for (let i = 0; i < values0.length; ++i) {\n values.push(values0[i] + values1[i]);\n }\n return new Point(values);\n }\n\n /**\n * Merge this point with a Point3D to create a new point.\n *\n * @param {Point3D} rhs The Point3D to merge with.\n * @returns {Point} The merge result.\n */\n mergeWith3D(rhs) {\n const values = this.getValues();\n values[0] = rhs.getX();\n values[1] = rhs.getY();\n values[2] = rhs.getZ();\n return new Point(values);\n }\n\n} // Point class\n","/**\n * Namespace for translation function\n * (in a namespace to allow for override from client).\n */\nexport const i18n = {\n\n /**\n * Get the translated text.\n *\n * @param {string} key The key to the text entry.\n * @returns {string|undefined} The translated text.\n */\n t(key) {\n let res = key;\n const props = key.split('.');\n // defaut units look like 'unit.cm2'\n if (props.length === 2 &&\n props[0] === 'unit') {\n const units = {\n mm: 'mm',\n cm2: 'cm²',\n degree: '°'\n };\n res = units[props[1]];\n }\n return res;\n }\n\n};\n","\nimport {i18n} from './i18n';\n\n/**\n * Capitalise the first letter of a string.\n *\n * @param {string} string The string to capitalise the first letter.\n * @returns {string} The new string.\n */\nexport function capitaliseFirstLetter(string) {\n let res = string;\n if (string) {\n res = string.charAt(0).toUpperCase() + string.slice(1);\n }\n return res;\n}\n\n/**\n * Check if a string starts with the input element.\n *\n * @param {string} str The input string.\n * @param {string} search The searched start.\n * @param {number} [rawPos] The position in this string at which to begin\n * searching for searchString. Defaults to 0.\n * @returns {boolean} True if the input string starts with the searched string.\n */\nexport function startsWith(str, search, rawPos) {\n if (typeof str === 'undefined' || str === null ||\n typeof search === 'undefined' || search === null) {\n return false;\n }\n const pos = rawPos > 0 ? rawPos | 0 : 0;\n return str.substring(pos, pos + search.length) === search;\n}\n\n/**\n * Check if a string ends with the input element.\n *\n * @param {string} str The input string.\n * @param {string} search The searched ending.\n * @returns {boolean} True if the input string ends with the searched string.\n */\nexport function endsWith(str, search) {\n if (typeof str === 'undefined' || str === null ||\n typeof search === 'undefined' || search === null) {\n return false;\n }\n return str.substring(str.length - search.length) === search;\n}\n\n/**\n * Split key/value string: `key0=val00&key0=val01&key1=val10\n * will return `{key0 : [val00, val01], key1 : val1}`.\n *\n * @param {string} inputStr The string to split.\n * @returns {object} The split string.\n */\nexport function splitKeyValueString(inputStr) {\n // result\n const result = {};\n // check input string\n if (inputStr) {\n // split key/value pairs\n const pairs = inputStr.split('&');\n for (let i = 0; i < pairs.length; ++i) {\n const pair = pairs[i].split('=');\n // if the key does not exist, create it\n if (!result[pair[0]]) {\n result[pair[0]] = pair[1];\n } else {\n // make it an array\n if (!(result[pair[0]] instanceof Array)) {\n result[pair[0]] = [result[pair[0]]];\n }\n result[pair[0]].push(pair[1]);\n }\n }\n }\n return result;\n}\n\n/**\n * Get flags from an input string. Flags are words surrounded with curly\n * braces.\n *\n * @param {string} inputStr The input string.\n * @returns {string[]} An array of found flags.\n */\nexport function getFlags(inputStr) {\n const flags = [];\n // check input string\n if (inputStr === null || typeof inputStr === 'undefined') {\n return flags;\n }\n\n // word surrounded by curly braces\n const regex = /{(\\w+)}/g;\n\n let match = regex.exec(inputStr);\n while (match) {\n flags.push(match[1]); // first matching group\n match = regex.exec(inputStr);\n }\n return flags;\n}\n\n/**\n * Replace flags in a input string. Flags are keywords surrounded with curly\n * braces.\n *\n * @param {string} inputStr The input string.\n * @param {object} values A object of {value, unit}.\n * @returns {string} The result string.\n */\nexport function replaceFlags(inputStr, values) {\n let res = '';\n // check input string\n if (inputStr === null || typeof inputStr === 'undefined') {\n return res;\n }\n res = inputStr;\n // check values\n if (values === null || typeof values === 'undefined') {\n return res;\n }\n\n // loop through flags\n const keys = getFlags(inputStr);\n for (let i = 0; i < keys.length; ++i) {\n const valueObj = values[keys[i]];\n if (valueObj !== null && typeof valueObj !== 'undefined' &&\n valueObj.value !== null && typeof valueObj.value !== 'undefined') {\n // value string\n let valueStr = valueObj.value.toPrecision(4);\n // add unit if available\n // space or no space? Yes apart from degree...\n // check: https://en.wikipedia.org/wiki/Space_(punctuation)#Spaces_and_unit_symbols\n if (valueObj.unit !== null &&\n typeof valueObj.unit !== 'undefined' &&\n valueObj.unit.length !== 0) {\n if (valueObj.unit !== 'unit.degree') {\n valueStr += ' ';\n }\n valueStr += i18n.t(valueObj.unit);\n }\n // flag to replace\n const flag = '{' + keys[i] + '}';\n // replace\n res = res.replace(flag, valueStr);\n }\n }\n // return\n return res;\n}\n\n/**\n * Get the root of an input path.\n * Splits using `/` as separator.\n *\n * @param {string} path The input path.\n * @returns {string} The input path without its last part.\n */\nexport function getRootPath(path) {\n return path.split('/').slice(0, -1).join('/');\n}\n\n/**\n * Get a file extension: anything after the last dot.\n * File name starting with a dot are discarded.\n * Extensions are expected to contain at least one letter.\n *\n * @param {string} filePath The file path containing the file name.\n * @returns {string} The lower case file extension or null for none.\n */\nexport function getFileExtension(filePath) {\n let ext = null;\n if (typeof filePath !== 'undefined' &&\n filePath !== null &&\n filePath[0] !== '.') {\n const pathSplit = filePath.toLowerCase().split('.');\n if (pathSplit.length !== 1) {\n ext = pathSplit.pop();\n // extension should contain at least one letter and no slash\n const regExp = /[a-z]/;\n if (!regExp.test(ext) || ext.includes('/')) {\n ext = null;\n }\n }\n }\n return ext;\n}\n\n/**\n * Convert a string to a Uint8Array.\n *\n * @param {string} str The string to convert.\n * @returns {Uint8Array} The Uint8Array.\n */\nexport function stringToUint8Array(str) {\n const arr = new Uint8Array(str.length);\n for (let i = 0, leni = str.length; i < leni; i++) {\n arr[i] = str.charCodeAt(i);\n }\n return arr;\n}\n\n/**\n * Round a float number to a given precision.\n *\n * Inspired from {@link https://stackoverflow.com/a/49729715/3639892}.\n *\n * Can be a solution to not have trailing zero as when\n * using toFixed or toPrecision.\n * '+number.toFixed(precision)' does not pass all the tests...\n *\n * @param {number} number The number to round.\n * @param {number} precision The rounding precision.\n * @returns {number} The rounded number.\n */\nexport function precisionRound(number, precision) {\n const factor = Math.pow(10, precision);\n const delta = 0.01 / factor; // fixes precisionRound(1.005, 2)\n return Math.round(number * factor + delta) / factor;\n}\n","import {stringToUint8Array} from './string';\n\n/**\n * Get a string id from array values in the form of: '#0-1_#1-2'.\n *\n * @param {Array} arr The input array.\n * @param {number[]} [dims] Optional list of dimensions to use.\n * @returns {string} The string id.\n */\nexport function toStringId(arr, dims) {\n // use all dims if not as input\n if (typeof dims === 'undefined') {\n dims = [];\n for (let i = 0; i < arr.length; ++i) {\n dims.push(i);\n }\n }\n // check dims\n for (let i = 0; i < dims.length; ++i) {\n if (dims[i] >= arr.length) {\n throw new Error('Non valid dimension for toStringId');\n }\n }\n // build string\n let res = '';\n for (let i = 0; i < dims.length; ++i) {\n if (i !== 0) {\n res += '_';\n }\n res += '#' + dims[i] + '-' + arr[dims[i]];\n }\n return res;\n}\n\n/**\n * Get an array from an id string in the form of: '#0-1_#1-2'\n * (result of toStringId).\n *\n * @param {string} inputStr The input string.\n * @returns {Array} The corresponding array (minimum size is 3D).\n */\nexport function getArrayFromStringId(inputStr) {\n // split ids\n const strIds = inputStr.split('_');\n // get the size of the index (minimum 3)\n let numberOfDims = 3;\n let dim;\n for (let i = 0; i < strIds.length; ++i) {\n // expecting dim < 10\n dim = parseInt(strIds[i].substring(1, 2), 10);\n // dim is zero based\n if (dim + 1 > numberOfDims) {\n numberOfDims = dim + 1;\n }\n }\n // default values\n const values = new Array(numberOfDims);\n values.fill(0);\n // get other values from the input string\n for (let j = 0; j < strIds.length; ++j) {\n // expecting dim < 10\n dim = parseInt(strIds[j].substring(1, 2), 10);\n const value = parseInt(strIds[j].substring(3), 10);\n values[dim] = value;\n }\n\n return values;\n}\n\n/**\n * Check if the first input array contains all the\n * elements of the second input array.\n *\n * @param {string[]} arr0 The test array.\n * @param {string[]} arr1 The elements to check in the first array.\n * @returns {boolean} True if all the elements of arr1 are included in arr0.\n */\nexport function arrayContains(arr0, arr1) {\n // check input\n if (arr0 === null ||\n arr1 === null ||\n typeof arr0 === 'undefined' ||\n typeof arr1 === 'undefined') {\n return false;\n }\n if (arr0.length === 0 ||\n arr1.length === 0 ||\n arr1.length > arr0.length) {\n return false;\n }\n // check values\n for (const itemArr1 of arr1) {\n if (!arr0.includes(itemArr1)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Check for array equality after sorting.\n *\n * @param {Array} arr0 First array.\n * @param {Array} arr1 Second array.\n * @returns {boolean} True if both array are defined and contain same values.\n */\nexport function arraySortEquals(arr0, arr1) {\n if (arr0 === null ||\n arr1 === null ||\n typeof arr0 === 'undefined' ||\n typeof arr1 === 'undefined') {\n return false;\n }\n const arr0sorted = arr0.slice().sort();\n const arr1sorted = arr1.slice().sort();\n return arrayEquals(arr0sorted, arr1sorted);\n}\n\n/**\n * Check for array equality.\n *\n * @param {Array} arr0 First array.\n * @param {Array} arr1 Second array.\n * @returns {boolean} True if both array are defined and contain same values.\n */\nexport function arrayEquals(arr0, arr1) {\n if (arr0 === null ||\n arr1 === null ||\n typeof arr0 === 'undefined' ||\n typeof arr1 === 'undefined') {\n return false;\n }\n if (arr0.length !== arr1.length) {\n return false;\n }\n return arr0.every(function (element, index) {\n return element === arr1[index];\n });\n}\n\n/**\n * Convert a Uint8Array to a string.\n *\n * @param {Uint8Array} arr The array to convert.\n * @returns {string} The array as string.\n */\nexport function uint8ArrayToString(arr) {\n return String.fromCharCode.apply(String, arr);\n}\n\n/**\n * Array find in a subset of the input array.\n * Equivalent to: `arr.slice(start, end).find(callbackFn)`.\n *\n * @param {Uint8Array} arr The input array to search.\n * @param {Function} callbackFn The find function.\n * @param {number|undefined} start The array start index.\n * @param {number|undefined} [end] The array end index.\n * @returns {number|undefined} The index where the element was found.\n */\nexport function findInArraySubset(arr, callbackFn, start, end) {\n // check inputs\n if (typeof start === 'undefined' ||\n start < 0 ||\n start >= arr.length\n ) {\n start = 0;\n }\n if (typeof end === 'undefined' ||\n end <= start ||\n end > arr.length) {\n end = arr.length;\n }\n // run\n for (let i = start; i < end; ++i) {\n if (callbackFn(arr[i], i, arr)) {\n return i;\n }\n }\n return undefined;\n}\n\n/**\n * Get a find in array callback.\n *\n * @param {Uint8Array} arr1 The array to find.\n * @returns {Function} The find callback function.\n */\nexport function getFindArrayInArrayCallback(arr1) {\n return function (element, index, arr0) {\n for (let i = 0; i < arr1.length; ++i) {\n if (arr0[index + i] !== arr1[i]) {\n return false;\n }\n }\n return true;\n };\n}\n\n/**\n * Extract each element of a multipart ArrayBuffer.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/MIME#Multipart_messages}.\n *\n * @param {ArrayBuffer} arr The multipart array.\n * @returns {Array} The multipart parts as an array of object as\n * {'Content-Type', ..., data} (depending on header tags).\n */\nexport function parseMultipart(arr) {\n const u8Array = new Uint8Array(arr);\n\n const parts = [];\n // check input\n if (u8Array.length === 0) {\n return parts;\n }\n\n // \\r\\n\\r\\n\n const doubleReturnNew = new Uint8Array([0x0d, 0x0a, 0x0d, 0x0a]);\n const partHeaderEndCb = getFindArrayInArrayCallback(doubleReturnNew);\n\n // look for boundary in first part header\n let partHeaderEndIndex = findInArraySubset(\n u8Array, partHeaderEndCb, 0\n );\n if (typeof partHeaderEndIndex === 'undefined') {\n throw new Error('Can\\'t find the end of the first multipart header');\n }\n const firstPartHeader = u8Array.slice(0, partHeaderEndIndex);\n // switch to string to use split\n const lines = uint8ArrayToString(firstPartHeader).split('\\r\\n');\n // boundary should start with '--'\n let boundaryStr;\n for (let i = 0; i < lines.length; ++i) {\n if (lines[i][0] === '-' && lines[i][1] === '-') {\n boundaryStr = lines[i];\n break;\n }\n }\n if (typeof boundaryStr === 'undefined') {\n throw new Error('Can\\'t find the boundary between multi-parts');\n }\n const boundary = stringToUint8Array(boundaryStr);\n const boundaryCb = getFindArrayInArrayCallback(boundary);\n const boundaryLen = boundaryStr.length;\n\n // skip mime header\n let nextBoundaryIndex = findInArraySubset(\n u8Array, boundaryCb, 0\n );\n\n // loop through content\n while (typeof partHeaderEndIndex !== 'undefined') {\n const part = {};\n\n // header\n const partHeader = u8Array.slice(\n nextBoundaryIndex + boundaryLen, partHeaderEndIndex);\n // split into object\n const partHeaderLines =\n uint8ArrayToString(partHeader).split('\\r\\n');\n for (let l = 0; l < partHeaderLines.length; ++l) {\n const line = partHeaderLines[l];\n const semiColonIndex = line.indexOf(':');\n if (semiColonIndex !== -1) {\n const key = line.substring(0, semiColonIndex).trim();\n const val = line.substring(semiColonIndex + 1).trim();\n part[key] = val;\n }\n }\n\n // find next boundary\n nextBoundaryIndex = findInArraySubset(\n u8Array, boundaryCb, partHeaderEndIndex\n );\n // exit if none\n if (typeof nextBoundaryIndex === 'undefined') {\n break;\n }\n\n // get part\n // partHeaderEndIndex plus the size of the '\\r\\n\\r\\n' separator\n const dataBeginIndex = partHeaderEndIndex + 4;\n // nextBoundaryIndex minus the previous '\\r\\n'\n const dataEndIndex = nextBoundaryIndex - 2;\n if (dataBeginIndex < dataEndIndex) {\n part.data = u8Array.slice(dataBeginIndex, dataEndIndex).buffer;\n } else {\n part.data = new Uint8Array();\n }\n\n // store part\n parts.push(part);\n\n // find next part header end\n partHeaderEndIndex = findInArraySubset(\n u8Array, partHeaderEndCb,\n nextBoundaryIndex + boundaryLen\n );\n }\n\n return parts;\n}\n\n/**\n * Build a multipart message.\n *\n * Ref:\n * - {@link https://en.wikipedia.org/wiki/MIME#Multipart_messages},\n * - {@link https://hg.orthanc-server.com/orthanc-dicomweb/file/tip/Resources/Samples/JavaScript/stow-rs.js}.\n *\n * @param {Array} parts The message parts as an array of object containing\n * content headers and messages as the data property (as returned by parse).\n * @param {string} boundary The message boundary.\n * @returns {Uint8Array} The full multipart message.\n */\nexport function buildMultipart(parts, boundary) {\n const lineBreak = '\\r\\n';\n // build headers and calculate size\n let partsSize = 0;\n const headers = [];\n for (let i = 0; i < parts.length; ++i) {\n let headerStr = '';\n if (i !== 0) {\n headerStr += lineBreak;\n }\n headerStr += '--' + boundary + lineBreak;\n const partKeys = Object.keys(parts[i]);\n for (let k = 0; k < partKeys.length; ++k) {\n const key = partKeys[k];\n if (key !== 'data') {\n headerStr += key + ': ' + parts[i][key] + lineBreak;\n }\n }\n headerStr += lineBreak;\n const header = stringToUint8Array(headerStr);\n headers.push(header);\n partsSize += header.byteLength + parts[i].data.byteLength;\n }\n // build trailer\n const trailerStr = lineBreak + '--' + boundary + '--' + lineBreak;\n const trailer = stringToUint8Array(trailerStr);\n\n // final buffer\n const buffer = new Uint8Array(partsSize + trailer.byteLength);\n let offset = 0;\n // concatenate parts\n for (let j = 0; j < parts.length; ++j) {\n buffer.set(headers[j], offset);\n offset += headers[j].byteLength;\n buffer.set(new Uint8Array(parts[j].data), offset);\n offset += parts[j].data.byteLength;\n }\n // end buffer with trailer\n buffer.set(trailer, offset);\n\n // return\n return buffer;\n}\n","/* eslint-disable @stylistic/js/quote-props */\n/* eslint @stylistic/js/max-len:0 */\n\n/**\n * DICOM tag dictionary 2022a.\n * Generated using xml standard conversion from {@link https://github.com/ivmartel/dcmStdToJs} v0.1.0.\n *\n * Conversion changes:\n * - (vr) 'See Note' -> 'NONE',\n * - (vr) 'OB or OW' -> 'ox',\n * - (vr) 'US or SS' -> 'xs',\n * - (vr) 'US or OW' -> 'xx',\n * - (vr) 'US or SS or OW' -> 'xs',\n * - added 'GenericGroupLength' element to each group.\n *\n * Local changes:\n * - tag numbers with 'xx' were replaced with '00', 'xxx' with '001' and\n * 'xxxx' with '0004'.\n *\n * @type {Object>}\n */\nexport const dictionary = {\n '0000': {\n '0000': ['UL', '1', 'CommandGroupLength'],\n '0001': ['UL', '1', 'CommandLengthToEnd'],\n '0002': ['UI', '1', 'AffectedSOPClassUID'],\n '0003': ['UI', '1', 'RequestedSOPClassUID'],\n '0010': ['SH', '1', 'CommandRecognitionCode'],\n '0100': ['US', '1', 'CommandField'],\n '0110': ['US', '1', 'MessageID'],\n '0120': ['US', '1', 'MessageIDBeingRespondedTo'],\n '0200': ['AE', '1', 'Initiator'],\n '0300': ['AE', '1', 'Receiver'],\n '0400': ['AE', '1', 'FindLocation'],\n '0600': ['AE', '1', 'MoveDestination'],\n '0700': ['US', '1', 'Priority'],\n '0800': ['US', '1', 'CommandDataSetType'],\n '0850': ['US', '1', 'NumberOfMatches'],\n '0860': ['US', '1', 'ResponseSequenceNumber'],\n '0900': ['US', '1', 'Status'],\n '0901': ['AT', '1-n', 'OffendingElement'],\n '0902': ['LO', '1', 'ErrorComment'],\n '0903': ['US', '1', 'ErrorID'],\n '1000': ['UI', '1', 'AffectedSOPInstanceUID'],\n '1001': ['UI', '1', 'RequestedSOPInstanceUID'],\n '1002': ['US', '1', 'EventTypeID'],\n '1005': ['AT', '1-n', 'AttributeIdentifierList'],\n '1008': ['US', '1', 'ActionTypeID'],\n '1020': ['US', '1', 'NumberOfRemainingSuboperations'],\n '1021': ['US', '1', 'NumberOfCompletedSuboperations'],\n '1022': ['US', '1', 'NumberOfFailedSuboperations'],\n '1023': ['US', '1', 'NumberOfWarningSuboperations'],\n '1030': ['AE', '1', 'MoveOriginatorApplicationEntityTitle'],\n '1031': ['US', '1', 'MoveOriginatorMessageID'],\n '4000': ['LT', '1', 'DialogReceiver'],\n '4010': ['LT', '1', 'TerminalType'],\n '5010': ['SH', '1', 'MessageSetID'],\n '5020': ['SH', '1', 'EndMessageID'],\n '5110': ['LT', '1', 'DisplayFormat'],\n '5120': ['LT', '1', 'PagePositionID'],\n '5130': ['CS', '1', 'TextFormatID'],\n '5140': ['CS', '1', 'NormalReverse'],\n '5150': ['CS', '1', 'AddGrayScale'],\n '5160': ['CS', '1', 'Borders'],\n '5170': ['IS', '1', 'Copies'],\n '5180': ['CS', '1', 'CommandMagnificationType'],\n '5190': ['CS', '1', 'Erase'],\n '51A0': ['CS', '1', 'Print'],\n '51B0': ['US', '1-n', 'Overlays']\n },\n '0002': {\n '0000': ['UL', '1', 'FileMetaInformationGroupLength'],\n '0001': ['OB', '1', 'FileMetaInformationVersion'],\n '0002': ['UI', '1', 'MediaStorageSOPClassUID'],\n '0003': ['UI', '1', 'MediaStorageSOPInstanceUID'],\n '0010': ['UI', '1', 'TransferSyntaxUID'],\n '0012': ['UI', '1', 'ImplementationClassUID'],\n '0013': ['SH', '1', 'ImplementationVersionName'],\n '0016': ['AE', '1', 'SourceApplicationEntityTitle'],\n '0017': ['AE', '1', 'SendingApplicationEntityTitle'],\n '0018': ['AE', '1', 'ReceivingApplicationEntityTitle'],\n '0026': ['UR', '1', 'SourcePresentationAddress'],\n '0027': ['UR', '1', 'SendingPresentationAddress'],\n '0028': ['UR', '1', 'ReceivingPresentationAddress'],\n '0031': ['OB', '1', 'RTVMetaInformationVersion'],\n '0032': ['UI', '1', 'RTVCommunicationSOPClassUID'],\n '0033': ['UI', '1', 'RTVCommunicationSOPInstanceUID'],\n '0035': ['OB', '1', 'RTVSourceIdentifier'],\n '0036': ['OB', '1', 'RTVFlowIdentifier'],\n '0037': ['UL', '1', 'RTVFlowRTPSamplingRate'],\n '0038': ['FD', '1', 'RTVFlowActualFrameDuration'],\n '0100': ['UI', '1', 'PrivateInformationCreatorUID'],\n '0102': ['OB', '1', 'PrivateInformation']\n },\n '0004': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '1130': ['CS', '1', 'FileSetID'],\n '1141': ['CS', '1-8', 'FileSetDescriptorFileID'],\n '1142': ['CS', '1', 'SpecificCharacterSetOfFileSetDescriptorFile'],\n '1200': ['UL', '1', 'OffsetOfTheFirstDirectoryRecordOfTheRootDirectoryEntity'],\n '1202': ['UL', '1', 'OffsetOfTheLastDirectoryRecordOfTheRootDirectoryEntity'],\n '1212': ['US', '1', 'FileSetConsistencyFlag'],\n '1220': ['SQ', '1', 'DirectoryRecordSequence'],\n '1400': ['UL', '1', 'OffsetOfTheNextDirectoryRecord'],\n '1410': ['US', '1', 'RecordInUseFlag'],\n '1420': ['UL', '1', 'OffsetOfReferencedLowerLevelDirectoryEntity'],\n '1430': ['CS', '1', 'DirectoryRecordType'],\n '1432': ['UI', '1', 'PrivateRecordUID'],\n '1500': ['CS', '1-8', 'ReferencedFileID'],\n '1504': ['UL', '1', 'MRDRDirectoryRecordOffset'],\n '1510': ['UI', '1', 'ReferencedSOPClassUIDInFile'],\n '1511': ['UI', '1', 'ReferencedSOPInstanceUIDInFile'],\n '1512': ['UI', '1', 'ReferencedTransferSyntaxUIDInFile'],\n '151A': ['UI', '1-n', 'ReferencedRelatedGeneralSOPClassUIDInFile'],\n '1600': ['UL', '1', 'NumberOfReferences']\n },\n '0008': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['UL', '1', 'LengthToEnd'],\n '0005': ['CS', '1-n', 'SpecificCharacterSet'],\n '0006': ['SQ', '1', 'LanguageCodeSequence'],\n '0008': ['CS', '2-n', 'ImageType'],\n '0010': ['SH', '1', 'RecognitionCode'],\n '0012': ['DA', '1', 'InstanceCreationDate'],\n '0013': ['TM', '1', 'InstanceCreationTime'],\n '0014': ['UI', '1', 'InstanceCreatorUID'],\n '0015': ['DT', '1', 'InstanceCoercionDateTime'],\n '0016': ['UI', '1', 'SOPClassUID'],\n '0018': ['UI', '1', 'SOPInstanceUID'],\n '001A': ['UI', '1-n', 'RelatedGeneralSOPClassUID'],\n '001B': ['UI', '1', 'OriginalSpecializedSOPClassUID'],\n '0020': ['DA', '1', 'StudyDate'],\n '0021': ['DA', '1', 'SeriesDate'],\n '0022': ['DA', '1', 'AcquisitionDate'],\n '0023': ['DA', '1', 'ContentDate'],\n '0024': ['DA', '1', 'OverlayDate'],\n '0025': ['DA', '1', 'CurveDate'],\n '002A': ['DT', '1', 'AcquisitionDateTime'],\n '0030': ['TM', '1', 'StudyTime'],\n '0031': ['TM', '1', 'SeriesTime'],\n '0032': ['TM', '1', 'AcquisitionTime'],\n '0033': ['TM', '1', 'ContentTime'],\n '0034': ['TM', '1', 'OverlayTime'],\n '0035': ['TM', '1', 'CurveTime'],\n '0040': ['US', '1', 'DataSetType'],\n '0041': ['LO', '1', 'DataSetSubtype'],\n '0042': ['CS', '1', 'NuclearMedicineSeriesType'],\n '0050': ['SH', '1', 'AccessionNumber'],\n '0051': ['SQ', '1', 'IssuerOfAccessionNumberSequence'],\n '0052': ['CS', '1', 'QueryRetrieveLevel'],\n '0053': ['CS', '1', 'QueryRetrieveView'],\n '0054': ['AE', '1-n', 'RetrieveAETitle'],\n '0055': ['AE', '1', 'StationAETitle'],\n '0056': ['CS', '1', 'InstanceAvailability'],\n '0058': ['UI', '1-n', 'FailedSOPInstanceUIDList'],\n '0060': ['CS', '1', 'Modality'],\n '0061': ['CS', '1-n', 'ModalitiesInStudy'],\n '0062': ['UI', '1-n', 'SOPClassesInStudy'],\n '0063': ['SQ', '1', 'AnatomicRegionsInStudyCodeSequence'],\n '0064': ['CS', '1', 'ConversionType'],\n '0068': ['CS', '1', 'PresentationIntentType'],\n '0070': ['LO', '1', 'Manufacturer'],\n '0080': ['LO', '1', 'InstitutionName'],\n '0081': ['ST', '1', 'InstitutionAddress'],\n '0082': ['SQ', '1', 'InstitutionCodeSequence'],\n '0090': ['PN', '1', 'ReferringPhysicianName'],\n '0092': ['ST', '1', 'ReferringPhysicianAddress'],\n '0094': ['SH', '1-n', 'ReferringPhysicianTelephoneNumbers'],\n '0096': ['SQ', '1', 'ReferringPhysicianIdentificationSequence'],\n '009C': ['PN', '1-n', 'ConsultingPhysicianName'],\n '009D': ['SQ', '1', 'ConsultingPhysicianIdentificationSequence'],\n '0100': ['SH', '1', 'CodeValue'],\n '0101': ['LO', '1', 'ExtendedCodeValue'],\n '0102': ['SH', '1', 'CodingSchemeDesignator'],\n '0103': ['SH', '1', 'CodingSchemeVersion'],\n '0104': ['LO', '1', 'CodeMeaning'],\n '0105': ['CS', '1', 'MappingResource'],\n '0106': ['DT', '1', 'ContextGroupVersion'],\n '0107': ['DT', '1', 'ContextGroupLocalVersion'],\n '0108': ['LT', '1', 'ExtendedCodeMeaning'],\n '0109': ['SQ', '1', 'CodingSchemeResourcesSequence'],\n '010A': ['CS', '1', 'CodingSchemeURLType'],\n '010B': ['CS', '1', 'ContextGroupExtensionFlag'],\n '010C': ['UI', '1', 'CodingSchemeUID'],\n '010D': ['UI', '1', 'ContextGroupExtensionCreatorUID'],\n '010E': ['UR', '1', 'CodingSchemeURL'],\n '010F': ['CS', '1', 'ContextIdentifier'],\n '0110': ['SQ', '1', 'CodingSchemeIdentificationSequence'],\n '0112': ['LO', '1', 'CodingSchemeRegistry'],\n '0114': ['ST', '1', 'CodingSchemeExternalID'],\n '0115': ['ST', '1', 'CodingSchemeName'],\n '0116': ['ST', '1', 'CodingSchemeResponsibleOrganization'],\n '0117': ['UI', '1', 'ContextUID'],\n '0118': ['UI', '1', 'MappingResourceUID'],\n '0119': ['UC', '1', 'LongCodeValue'],\n '0120': ['UR', '1', 'URNCodeValue'],\n '0121': ['SQ', '1', 'EquivalentCodeSequence'],\n '0122': ['LO', '1', 'MappingResourceName'],\n '0123': ['SQ', '1', 'ContextGroupIdentificationSequence'],\n '0124': ['SQ', '1', 'MappingResourceIdentificationSequence'],\n '0201': ['SH', '1', 'TimezoneOffsetFromUTC'],\n '0202': ['', '', ''],\n '0220': ['SQ', '1', 'ResponsibleGroupCodeSequence'],\n '0221': ['CS', '1', 'EquipmentModality'],\n '0222': ['LO', '1', 'ManufacturerRelatedModelGroup'],\n '0300': ['SQ', '1', 'PrivateDataElementCharacteristicsSequence'],\n '0301': ['US', '1', 'PrivateGroupReference'],\n '0302': ['LO', '1', 'PrivateCreatorReference'],\n '0303': ['CS', '1', 'BlockIdentifyingInformationStatus'],\n '0304': ['US', '1-n', 'NonidentifyingPrivateElements'],\n '0305': ['SQ', '1', 'DeidentificationActionSequence'],\n '0306': ['US', '1-n', 'IdentifyingPrivateElements'],\n '0307': ['CS', '1', 'DeidentificationAction'],\n '0308': ['US', '1', 'PrivateDataElement'],\n '0309': ['UL', '1-3', 'PrivateDataElementValueMultiplicity'],\n '030A': ['CS', '1', 'PrivateDataElementValueRepresentation'],\n '030B': ['UL', '1-2', 'PrivateDataElementNumberOfItems'],\n '030C': ['UC', '1', 'PrivateDataElementName'],\n '030D': ['UC', '1', 'PrivateDataElementKeyword'],\n '030E': ['UT', '1', 'PrivateDataElementDescription'],\n '030F': ['UT', '1', 'PrivateDataElementEncoding'],\n '0310': ['SQ', '1', 'PrivateDataElementDefinitionSequence'],\n '1000': ['AE', '1', 'NetworkID'],\n '1010': ['SH', '1', 'StationName'],\n '1030': ['LO', '1', 'StudyDescription'],\n '1032': ['SQ', '1', 'ProcedureCodeSequence'],\n '103E': ['LO', '1', 'SeriesDescription'],\n '103F': ['SQ', '1', 'SeriesDescriptionCodeSequence'],\n '1040': ['LO', '1', 'InstitutionalDepartmentName'],\n '1041': ['SQ', '1', 'InstitutionalDepartmentTypeCodeSequence'],\n '1048': ['PN', '1-n', 'PhysiciansOfRecord'],\n '1049': ['SQ', '1', 'PhysiciansOfRecordIdentificationSequence'],\n '1050': ['PN', '1-n', 'PerformingPhysicianName'],\n '1052': ['SQ', '1', 'PerformingPhysicianIdentificationSequence'],\n '1060': ['PN', '1-n', 'NameOfPhysiciansReadingStudy'],\n '1062': ['SQ', '1', 'PhysiciansReadingStudyIdentificationSequence'],\n '1070': ['PN', '1-n', 'OperatorsName'],\n '1072': ['SQ', '1', 'OperatorIdentificationSequence'],\n '1080': ['LO', '1-n', 'AdmittingDiagnosesDescription'],\n '1084': ['SQ', '1', 'AdmittingDiagnosesCodeSequence'],\n '1090': ['LO', '1', 'ManufacturerModelName'],\n '1100': ['SQ', '1', 'ReferencedResultsSequence'],\n '1110': ['SQ', '1', 'ReferencedStudySequence'],\n '1111': ['SQ', '1', 'ReferencedPerformedProcedureStepSequence'],\n '1115': ['SQ', '1', 'ReferencedSeriesSequence'],\n '1120': ['SQ', '1', 'ReferencedPatientSequence'],\n '1125': ['SQ', '1', 'ReferencedVisitSequence'],\n '1130': ['SQ', '1', 'ReferencedOverlaySequence'],\n '1134': ['SQ', '1', 'ReferencedStereometricInstanceSequence'],\n '113A': ['SQ', '1', 'ReferencedWaveformSequence'],\n '1140': ['SQ', '1', 'ReferencedImageSequence'],\n '1145': ['SQ', '1', 'ReferencedCurveSequence'],\n '114A': ['SQ', '1', 'ReferencedInstanceSequence'],\n '114B': ['SQ', '1', 'ReferencedRealWorldValueMappingInstanceSequence'],\n '1150': ['UI', '1', 'ReferencedSOPClassUID'],\n '1155': ['UI', '1', 'ReferencedSOPInstanceUID'],\n '1156': ['SQ', '1', 'DefinitionSourceSequence'],\n '115A': ['UI', '1-n', 'SOPClassesSupported'],\n '1160': ['IS', '1-n', 'ReferencedFrameNumber'],\n '1161': ['UL', '1-n', 'SimpleFrameList'],\n '1162': ['UL', '3-3n', 'CalculatedFrameList'],\n '1163': ['FD', '2', 'TimeRange'],\n '1164': ['SQ', '1', 'FrameExtractionSequence'],\n '1167': ['UI', '1', 'MultiFrameSourceSOPInstanceUID'],\n '1190': ['UR', '1', 'RetrieveURL'],\n '1195': ['UI', '1', 'TransactionUID'],\n '1196': ['US', '1', 'WarningReason'],\n '1197': ['US', '1', 'FailureReason'],\n '1198': ['SQ', '1', 'FailedSOPSequence'],\n '1199': ['SQ', '1', 'ReferencedSOPSequence'],\n '119A': ['SQ', '1', 'OtherFailuresSequence'],\n '1200': ['SQ', '1', 'StudiesContainingOtherReferencedInstancesSequence'],\n '1250': ['SQ', '1', 'RelatedSeriesSequence'],\n '2110': ['CS', '1', 'LossyImageCompressionRetired'],\n '2111': ['ST', '1', 'DerivationDescription'],\n '2112': ['SQ', '1', 'SourceImageSequence'],\n '2120': ['SH', '1', 'StageName'],\n '2122': ['IS', '1', 'StageNumber'],\n '2124': ['IS', '1', 'NumberOfStages'],\n '2127': ['SH', '1', 'ViewName'],\n '2128': ['IS', '1', 'ViewNumber'],\n '2129': ['IS', '1', 'NumberOfEventTimers'],\n '212A': ['IS', '1', 'NumberOfViewsInStage'],\n '2130': ['DS', '1-n', 'EventElapsedTimes'],\n '2132': ['LO', '1-n', 'EventTimerNames'],\n '2133': ['SQ', '1', 'EventTimerSequence'],\n '2134': ['FD', '1', 'EventTimeOffset'],\n '2135': ['SQ', '1', 'EventCodeSequence'],\n '2142': ['IS', '1', 'StartTrim'],\n '2143': ['IS', '1', 'StopTrim'],\n '2144': ['IS', '1', 'RecommendedDisplayFrameRate'],\n '2200': ['CS', '1', 'TransducerPosition'],\n '2204': ['CS', '1', 'TransducerOrientation'],\n '2208': ['CS', '1', 'AnatomicStructure'],\n '2218': ['SQ', '1', 'AnatomicRegionSequence'],\n '2220': ['SQ', '1', 'AnatomicRegionModifierSequence'],\n '2228': ['SQ', '1', 'PrimaryAnatomicStructureSequence'],\n '2229': ['SQ', '1', 'AnatomicStructureSpaceOrRegionSequence'],\n '2230': ['SQ', '1', 'PrimaryAnatomicStructureModifierSequence'],\n '2240': ['SQ', '1', 'TransducerPositionSequence'],\n '2242': ['SQ', '1', 'TransducerPositionModifierSequence'],\n '2244': ['SQ', '1', 'TransducerOrientationSequence'],\n '2246': ['SQ', '1', 'TransducerOrientationModifierSequence'],\n '2251': ['SQ', '1', 'AnatomicStructureSpaceOrRegionCodeSequenceTrial'],\n '2253': ['SQ', '1', 'AnatomicPortalOfEntranceCodeSequenceTrial'],\n '2255': ['SQ', '1', 'AnatomicApproachDirectionCodeSequenceTrial'],\n '2256': ['ST', '1', 'AnatomicPerspectiveDescriptionTrial'],\n '2257': ['SQ', '1', 'AnatomicPerspectiveCodeSequenceTrial'],\n '2258': ['ST', '1', 'AnatomicLocationOfExaminingInstrumentDescriptionTrial'],\n '2259': ['SQ', '1', 'AnatomicLocationOfExaminingInstrumentCodeSequenceTrial'],\n '225A': ['SQ', '1', 'AnatomicStructureSpaceOrRegionModifierCodeSequenceTrial'],\n '225C': ['SQ', '1', 'OnAxisBackgroundAnatomicStructureCodeSequenceTrial'],\n '3001': ['SQ', '1', 'AlternateRepresentationSequence'],\n '3002': ['UI', '1-n', 'AvailableTransferSyntaxUID'],\n '3010': ['UI', '1-n', 'IrradiationEventUID'],\n '3011': ['SQ', '1', 'SourceIrradiationEventSequence'],\n '3012': ['UI', '1', 'RadiopharmaceuticalAdministrationEventUID'],\n '4000': ['LT', '1', 'IdentifyingComments'],\n '9007': ['CS', '4', 'FrameType'],\n '9092': ['SQ', '1', 'ReferencedImageEvidenceSequence'],\n '9121': ['SQ', '1', 'ReferencedRawDataSequence'],\n '9123': ['UI', '1', 'CreatorVersionUID'],\n '9124': ['SQ', '1', 'DerivationImageSequence'],\n '9154': ['SQ', '1', 'SourceImageEvidenceSequence'],\n '9205': ['CS', '1', 'PixelPresentation'],\n '9206': ['CS', '1', 'VolumetricProperties'],\n '9207': ['CS', '1', 'VolumeBasedCalculationTechnique'],\n '9208': ['CS', '1', 'ComplexImageComponent'],\n '9209': ['CS', '1', 'AcquisitionContrast'],\n '9215': ['SQ', '1', 'DerivationCodeSequence'],\n '9237': ['SQ', '1', 'ReferencedPresentationStateSequence'],\n '9410': ['SQ', '1', 'ReferencedOtherPlaneSequence'],\n '9458': ['SQ', '1', 'FrameDisplaySequence'],\n '9459': ['FL', '1', 'RecommendedDisplayFrameRateInFloat'],\n '9460': ['CS', '1', 'SkipFrameRangeFlag']\n },\n '0010': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['PN', '1', 'PatientName'],\n '0020': ['LO', '1', 'PatientID'],\n '0021': ['LO', '1', 'IssuerOfPatientID'],\n '0022': ['CS', '1', 'TypeOfPatientID'],\n '0024': ['SQ', '1', 'IssuerOfPatientIDQualifiersSequence'],\n '0026': ['SQ', '1', 'SourcePatientGroupIdentificationSequence'],\n '0027': ['SQ', '1', 'GroupOfPatientsIdentificationSequence'],\n '0028': ['US', '3', 'SubjectRelativePositionInImage'],\n '0030': ['DA', '1', 'PatientBirthDate'],\n '0032': ['TM', '1', 'PatientBirthTime'],\n '0033': ['LO', '1', 'PatientBirthDateInAlternativeCalendar'],\n '0034': ['LO', '1', 'PatientDeathDateInAlternativeCalendar'],\n '0035': ['CS', '1', 'PatientAlternativeCalendar'],\n '0040': ['CS', '1', 'PatientSex'],\n '0050': ['SQ', '1', 'PatientInsurancePlanCodeSequence'],\n '0101': ['SQ', '1', 'PatientPrimaryLanguageCodeSequence'],\n '0102': ['SQ', '1', 'PatientPrimaryLanguageModifierCodeSequence'],\n '0200': ['CS', '1', 'QualityControlSubject'],\n '0201': ['SQ', '1', 'QualityControlSubjectTypeCodeSequence'],\n '0212': ['UC', '1', 'StrainDescription'],\n '0213': ['LO', '1', 'StrainNomenclature'],\n '0214': ['LO', '1', 'StrainStockNumber'],\n '0215': ['SQ', '1', 'StrainSourceRegistryCodeSequence'],\n '0216': ['SQ', '1', 'StrainStockSequence'],\n '0217': ['LO', '1', 'StrainSource'],\n '0218': ['UT', '1', 'StrainAdditionalInformation'],\n '0219': ['SQ', '1', 'StrainCodeSequence'],\n '0221': ['SQ', '1', 'GeneticModificationsSequence'],\n '0222': ['UC', '1', 'GeneticModificationsDescription'],\n '0223': ['LO', '1', 'GeneticModificationsNomenclature'],\n '0229': ['SQ', '1', 'GeneticModificationsCodeSequence'],\n '1000': ['LO', '1-n', 'OtherPatientIDs'],\n '1001': ['PN', '1-n', 'OtherPatientNames'],\n '1002': ['SQ', '1', 'OtherPatientIDsSequence'],\n '1005': ['PN', '1', 'PatientBirthName'],\n '1010': ['AS', '1', 'PatientAge'],\n '1020': ['DS', '1', 'PatientSize'],\n '1021': ['SQ', '1', 'PatientSizeCodeSequence'],\n '1022': ['DS', '1', 'PatientBodyMassIndex'],\n '1023': ['DS', '1', 'MeasuredAPDimension'],\n '1024': ['DS', '1', 'MeasuredLateralDimension'],\n '1030': ['DS', '1', 'PatientWeight'],\n '1040': ['LO', '1', 'PatientAddress'],\n '1050': ['LO', '1-n', 'InsurancePlanIdentification'],\n '1060': ['PN', '1', 'PatientMotherBirthName'],\n '1080': ['LO', '1', 'MilitaryRank'],\n '1081': ['LO', '1', 'BranchOfService'],\n '1090': ['LO', '1', 'MedicalRecordLocator'],\n '1100': ['SQ', '1', 'ReferencedPatientPhotoSequence'],\n '2000': ['LO', '1-n', 'MedicalAlerts'],\n '2110': ['LO', '1-n', 'Allergies'],\n '2150': ['LO', '1', 'CountryOfResidence'],\n '2152': ['LO', '1', 'RegionOfResidence'],\n '2154': ['SH', '1-n', 'PatientTelephoneNumbers'],\n '2155': ['LT', '1', 'PatientTelecomInformation'],\n '2160': ['SH', '1', 'EthnicGroup'],\n '2180': ['SH', '1', 'Occupation'],\n '21A0': ['CS', '1', 'SmokingStatus'],\n '21B0': ['LT', '1', 'AdditionalPatientHistory'],\n '21C0': ['US', '1', 'PregnancyStatus'],\n '21D0': ['DA', '1', 'LastMenstrualDate'],\n '21F0': ['LO', '1', 'PatientReligiousPreference'],\n '2201': ['LO', '1', 'PatientSpeciesDescription'],\n '2202': ['SQ', '1', 'PatientSpeciesCodeSequence'],\n '2203': ['CS', '1', 'PatientSexNeutered'],\n '2210': ['CS', '1', 'AnatomicalOrientationType'],\n '2292': ['LO', '1', 'PatientBreedDescription'],\n '2293': ['SQ', '1', 'PatientBreedCodeSequence'],\n '2294': ['SQ', '1', 'BreedRegistrationSequence'],\n '2295': ['LO', '1', 'BreedRegistrationNumber'],\n '2296': ['SQ', '1', 'BreedRegistryCodeSequence'],\n '2297': ['PN', '1', 'ResponsiblePerson'],\n '2298': ['CS', '1', 'ResponsiblePersonRole'],\n '2299': ['LO', '1', 'ResponsibleOrganization'],\n '4000': ['LT', '1', 'PatientComments'],\n '9431': ['FL', '1', 'ExaminedBodyThickness']\n },\n '0012': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['LO', '1', 'ClinicalTrialSponsorName'],\n '0020': ['LO', '1', 'ClinicalTrialProtocolID'],\n '0021': ['LO', '1', 'ClinicalTrialProtocolName'],\n '0030': ['LO', '1', 'ClinicalTrialSiteID'],\n '0031': ['LO', '1', 'ClinicalTrialSiteName'],\n '0040': ['LO', '1', 'ClinicalTrialSubjectID'],\n '0042': ['LO', '1', 'ClinicalTrialSubjectReadingID'],\n '0050': ['LO', '1', 'ClinicalTrialTimePointID'],\n '0051': ['ST', '1', 'ClinicalTrialTimePointDescription'],\n '0052': ['FD', '1', 'LongitudinalTemporalOffsetFromEvent'],\n '0053': ['CS', '1', 'LongitudinalTemporalEventType'],\n '0060': ['LO', '1', 'ClinicalTrialCoordinatingCenterName'],\n '0062': ['CS', '1', 'PatientIdentityRemoved'],\n '0063': ['LO', '1-n', 'DeidentificationMethod'],\n '0064': ['SQ', '1', 'DeidentificationMethodCodeSequence'],\n '0071': ['LO', '1', 'ClinicalTrialSeriesID'],\n '0072': ['LO', '1', 'ClinicalTrialSeriesDescription'],\n '0081': ['LO', '1', 'ClinicalTrialProtocolEthicsCommitteeName'],\n '0082': ['LO', '1', 'ClinicalTrialProtocolEthicsCommitteeApprovalNumber'],\n '0083': ['SQ', '1', 'ConsentForClinicalTrialUseSequence'],\n '0084': ['CS', '1', 'DistributionType'],\n '0085': ['CS', '1', 'ConsentForDistributionFlag'],\n '0086': ['DA', '1', 'EthicsCommitteeApprovalEffectivenessStartDate'],\n '0087': ['DA', '1', 'EthicsCommitteeApprovalEffectivenessEndDate']\n },\n '0014': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0023': ['ST', '1', 'CADFileFormat'],\n '0024': ['ST', '1', 'ComponentReferenceSystem'],\n '0025': ['ST', '1', 'ComponentManufacturingProcedure'],\n '0028': ['ST', '1', 'ComponentManufacturer'],\n '0030': ['DS', '1-n', 'MaterialThickness'],\n '0032': ['DS', '1-n', 'MaterialPipeDiameter'],\n '0034': ['DS', '1-n', 'MaterialIsolationDiameter'],\n '0042': ['ST', '1', 'MaterialGrade'],\n '0044': ['ST', '1', 'MaterialPropertiesDescription'],\n '0045': ['ST', '1', 'MaterialPropertiesFileFormatRetired'],\n '0046': ['LT', '1', 'MaterialNotes'],\n '0050': ['CS', '1', 'ComponentShape'],\n '0052': ['CS', '1', 'CurvatureType'],\n '0054': ['DS', '1', 'OuterDiameter'],\n '0056': ['DS', '1', 'InnerDiameter'],\n '0100': ['LO', '1-n', 'ComponentWelderIDs'],\n '0101': ['CS', '1', 'SecondaryApprovalStatus'],\n '0102': ['DA', '1', 'SecondaryReviewDate'],\n '0103': ['TM', '1', 'SecondaryReviewTime'],\n '0104': ['PN', '1', 'SecondaryReviewerName'],\n '0105': ['ST', '1', 'RepairID'],\n '0106': ['SQ', '1', 'MultipleComponentApprovalSequence'],\n '0107': ['CS', '1-n', 'OtherApprovalStatus'],\n '0108': ['CS', '1-n', 'OtherSecondaryApprovalStatus'],\n '1010': ['ST', '1', 'ActualEnvironmentalConditions'],\n '1020': ['DA', '1', 'ExpiryDate'],\n '1040': ['ST', '1', 'EnvironmentalConditions'],\n '2002': ['SQ', '1', 'EvaluatorSequence'],\n '2004': ['IS', '1', 'EvaluatorNumber'],\n '2006': ['PN', '1', 'EvaluatorName'],\n '2008': ['IS', '1', 'EvaluationAttempt'],\n '2012': ['SQ', '1', 'IndicationSequence'],\n '2014': ['IS', '1', 'IndicationNumber'],\n '2016': ['SH', '1', 'IndicationLabel'],\n '2018': ['ST', '1', 'IndicationDescription'],\n '201A': ['CS', '1-n', 'IndicationType'],\n '201C': ['CS', '1', 'IndicationDisposition'],\n '201E': ['SQ', '1', 'IndicationROISequence'],\n '2030': ['SQ', '1', 'IndicationPhysicalPropertySequence'],\n '2032': ['SH', '1', 'PropertyLabel'],\n '2202': ['IS', '1', 'CoordinateSystemNumberOfAxes'],\n '2204': ['SQ', '1', 'CoordinateSystemAxesSequence'],\n '2206': ['ST', '1', 'CoordinateSystemAxisDescription'],\n '2208': ['CS', '1', 'CoordinateSystemDataSetMapping'],\n '220A': ['IS', '1', 'CoordinateSystemAxisNumber'],\n '220C': ['CS', '1', 'CoordinateSystemAxisType'],\n '220E': ['CS', '1', 'CoordinateSystemAxisUnits'],\n '2210': ['OB', '1', 'CoordinateSystemAxisValues'],\n '2220': ['SQ', '1', 'CoordinateSystemTransformSequence'],\n '2222': ['ST', '1', 'TransformDescription'],\n '2224': ['IS', '1', 'TransformNumberOfAxes'],\n '2226': ['IS', '1-n', 'TransformOrderOfAxes'],\n '2228': ['CS', '1', 'TransformedAxisUnits'],\n '222A': ['DS', '1-n', 'CoordinateSystemTransformRotationAndScaleMatrix'],\n '222C': ['DS', '1-n', 'CoordinateSystemTransformTranslationMatrix'],\n '3011': ['DS', '1', 'InternalDetectorFrameTime'],\n '3012': ['DS', '1', 'NumberOfFramesIntegrated'],\n '3020': ['SQ', '1', 'DetectorTemperatureSequence'],\n '3022': ['ST', '1', 'SensorName'],\n '3024': ['DS', '1', 'HorizontalOffsetOfSensor'],\n '3026': ['DS', '1', 'VerticalOffsetOfSensor'],\n '3028': ['DS', '1', 'SensorTemperature'],\n '3040': ['SQ', '1', 'DarkCurrentSequence'],\n '3050': ['ox', '1', 'DarkCurrentCounts'],\n '3060': ['SQ', '1', 'GainCorrectionReferenceSequence'],\n '3070': ['ox', '1', 'AirCounts'],\n '3071': ['DS', '1', 'KVUsedInGainCalibration'],\n '3072': ['DS', '1', 'MAUsedInGainCalibration'],\n '3073': ['DS', '1', 'NumberOfFramesUsedForIntegration'],\n '3074': ['LO', '1', 'FilterMaterialUsedInGainCalibration'],\n '3075': ['DS', '1', 'FilterThicknessUsedInGainCalibration'],\n '3076': ['DA', '1', 'DateOfGainCalibration'],\n '3077': ['TM', '1', 'TimeOfGainCalibration'],\n '3080': ['OB', '1', 'BadPixelImage'],\n '3099': ['LT', '1', 'CalibrationNotes'],\n '3100': ['LT', '1', 'LinearityCorrectionTechnique'],\n '3101': ['LT', '1', 'BeamHardeningCorrectionTechnique'],\n '4002': ['SQ', '1', 'PulserEquipmentSequence'],\n '4004': ['CS', '1', 'PulserType'],\n '4006': ['LT', '1', 'PulserNotes'],\n '4008': ['SQ', '1', 'ReceiverEquipmentSequence'],\n '400A': ['CS', '1', 'AmplifierType'],\n '400C': ['LT', '1', 'ReceiverNotes'],\n '400E': ['SQ', '1', 'PreAmplifierEquipmentSequence'],\n '400F': ['LT', '1', 'PreAmplifierNotes'],\n '4010': ['SQ', '1', 'TransmitTransducerSequence'],\n '4011': ['SQ', '1', 'ReceiveTransducerSequence'],\n '4012': ['US', '1', 'NumberOfElements'],\n '4013': ['CS', '1', 'ElementShape'],\n '4014': ['DS', '1', 'ElementDimensionA'],\n '4015': ['DS', '1', 'ElementDimensionB'],\n '4016': ['DS', '1', 'ElementPitchA'],\n '4017': ['DS', '1', 'MeasuredBeamDimensionA'],\n '4018': ['DS', '1', 'MeasuredBeamDimensionB'],\n '4019': ['DS', '1', 'LocationOfMeasuredBeamDiameter'],\n '401A': ['DS', '1', 'NominalFrequency'],\n '401B': ['DS', '1', 'MeasuredCenterFrequency'],\n '401C': ['DS', '1', 'MeasuredBandwidth'],\n '401D': ['DS', '1', 'ElementPitchB'],\n '4020': ['SQ', '1', 'PulserSettingsSequence'],\n '4022': ['DS', '1', 'PulseWidth'],\n '4024': ['DS', '1', 'ExcitationFrequency'],\n '4026': ['CS', '1', 'ModulationType'],\n '4028': ['DS', '1', 'Damping'],\n '4030': ['SQ', '1', 'ReceiverSettingsSequence'],\n '4031': ['DS', '1', 'AcquiredSoundpathLength'],\n '4032': ['CS', '1', 'AcquisitionCompressionType'],\n '4033': ['IS', '1', 'AcquisitionSampleSize'],\n '4034': ['DS', '1', 'RectifierSmoothing'],\n '4035': ['SQ', '1', 'DACSequence'],\n '4036': ['CS', '1', 'DACType'],\n '4038': ['DS', '1-n', 'DACGainPoints'],\n '403A': ['DS', '1-n', 'DACTimePoints'],\n '403C': ['DS', '1-n', 'DACAmplitude'],\n '4040': ['SQ', '1', 'PreAmplifierSettingsSequence'],\n '4050': ['SQ', '1', 'TransmitTransducerSettingsSequence'],\n '4051': ['SQ', '1', 'ReceiveTransducerSettingsSequence'],\n '4052': ['DS', '1', 'IncidentAngle'],\n '4054': ['ST', '1', 'CouplingTechnique'],\n '4056': ['ST', '1', 'CouplingMedium'],\n '4057': ['DS', '1', 'CouplingVelocity'],\n '4058': ['DS', '1', 'ProbeCenterLocationX'],\n '4059': ['DS', '1', 'ProbeCenterLocationZ'],\n '405A': ['DS', '1', 'SoundPathLength'],\n '405C': ['ST', '1', 'DelayLawIdentifier'],\n '4060': ['SQ', '1', 'GateSettingsSequence'],\n '4062': ['DS', '1', 'GateThreshold'],\n '4064': ['DS', '1', 'VelocityOfSound'],\n '4070': ['SQ', '1', 'CalibrationSettingsSequence'],\n '4072': ['ST', '1', 'CalibrationProcedure'],\n '4074': ['SH', '1', 'ProcedureVersion'],\n '4076': ['DA', '1', 'ProcedureCreationDate'],\n '4078': ['DA', '1', 'ProcedureExpirationDate'],\n '407A': ['DA', '1', 'ProcedureLastModifiedDate'],\n '407C': ['TM', '1-n', 'CalibrationTime'],\n '407E': ['DA', '1-n', 'CalibrationDate'],\n '4080': ['SQ', '1', 'ProbeDriveEquipmentSequence'],\n '4081': ['CS', '1', 'DriveType'],\n '4082': ['LT', '1', 'ProbeDriveNotes'],\n '4083': ['SQ', '1', 'DriveProbeSequence'],\n '4084': ['DS', '1', 'ProbeInductance'],\n '4085': ['DS', '1', 'ProbeResistance'],\n '4086': ['SQ', '1', 'ReceiveProbeSequence'],\n '4087': ['SQ', '1', 'ProbeDriveSettingsSequence'],\n '4088': ['DS', '1', 'BridgeResistors'],\n '4089': ['DS', '1', 'ProbeOrientationAngle'],\n '408B': ['DS', '1', 'UserSelectedGainY'],\n '408C': ['DS', '1', 'UserSelectedPhase'],\n '408D': ['DS', '1', 'UserSelectedOffsetX'],\n '408E': ['DS', '1', 'UserSelectedOffsetY'],\n '4091': ['SQ', '1', 'ChannelSettingsSequence'],\n '4092': ['DS', '1', 'ChannelThreshold'],\n '409A': ['SQ', '1', 'ScannerSettingsSequence'],\n '409B': ['ST', '1', 'ScanProcedure'],\n '409C': ['DS', '1', 'TranslationRateX'],\n '409D': ['DS', '1', 'TranslationRateY'],\n '409F': ['DS', '1', 'ChannelOverlap'],\n '40A0': ['LO', '1-n', 'ImageQualityIndicatorType'],\n '40A1': ['LO', '1-n', 'ImageQualityIndicatorMaterial'],\n '40A2': ['LO', '1-n', 'ImageQualityIndicatorSize'],\n '5002': ['IS', '1', 'LINACEnergy'],\n '5004': ['IS', '1', 'LINACOutput'],\n '5100': ['US', '1', 'ActiveAperture'],\n '5101': ['DS', '1', 'TotalAperture'],\n '5102': ['DS', '1', 'ApertureElevation'],\n '5103': ['DS', '1', 'MainLobeAngle'],\n '5104': ['DS', '1', 'MainRoofAngle'],\n '5105': ['CS', '1', 'ConnectorType'],\n '5106': ['SH', '1', 'WedgeModelNumber'],\n '5107': ['DS', '1', 'WedgeAngleFloat'],\n '5108': ['DS', '1', 'WedgeRoofAngle'],\n '5109': ['CS', '1', 'WedgeElement1Position'],\n '510A': ['DS', '1', 'WedgeMaterialVelocity'],\n '510B': ['SH', '1', 'WedgeMaterial'],\n '510C': ['DS', '1', 'WedgeOffsetZ'],\n '510D': ['DS', '1', 'WedgeOriginOffsetX'],\n '510E': ['DS', '1', 'WedgeTimeDelay'],\n '510F': ['SH', '1', 'WedgeName'],\n '5110': ['SH', '1', 'WedgeManufacturerName'],\n '5111': ['LO', '1', 'WedgeDescription'],\n '5112': ['DS', '1', 'NominalBeamAngle'],\n '5113': ['DS', '1', 'WedgeOffsetX'],\n '5114': ['DS', '1', 'WedgeOffsetY'],\n '5115': ['DS', '1', 'WedgeTotalLength'],\n '5116': ['DS', '1', 'WedgeInContactLength'],\n '5117': ['DS', '1', 'WedgeFrontGap'],\n '5118': ['DS', '1', 'WedgeTotalHeight'],\n '5119': ['DS', '1', 'WedgeFrontHeight'],\n '511A': ['DS', '1', 'WedgeRearHeight'],\n '511B': ['DS', '1', 'WedgeTotalWidth'],\n '511C': ['DS', '1', 'WedgeInContactWidth'],\n '511D': ['DS', '1', 'WedgeChamferHeight'],\n '511E': ['CS', '1', 'WedgeCurve'],\n '511F': ['DS', '1', 'RadiusAlongWedge']\n },\n '0016': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['DS', '1', 'WhitePoint'],\n '0002': ['DS', '3', 'PrimaryChromaticities'],\n '0003': ['UT', '1', 'BatteryLevel'],\n '0004': ['DS', '1', 'ExposureTimeInSeconds'],\n '0005': ['DS', '1', 'FNumber'],\n '0006': ['IS', '1', 'OECFRows'],\n '0007': ['IS', '1', 'OECFColumns'],\n '0008': ['UC', '1-n', 'OECFColumnNames'],\n '0009': ['DS', '1-n', 'OECFValues'],\n '000A': ['IS', '1', 'SpatialFrequencyResponseRows'],\n '000B': ['IS', '1', 'SpatialFrequencyResponseColumns'],\n '000C': ['UC', '1-n', 'SpatialFrequencyResponseColumnNames'],\n '000D': ['DS', '1-n', 'SpatialFrequencyResponseValues'],\n '000E': ['IS', '1', 'ColorFilterArrayPatternRows'],\n '000F': ['IS', '1', 'ColorFilterArrayPatternColumns'],\n '0010': ['DS', '1-n', 'ColorFilterArrayPatternValues'],\n '0011': ['US', '1', 'FlashFiringStatus'],\n '0012': ['US', '1', 'FlashReturnStatus'],\n '0013': ['US', '1', 'FlashMode'],\n '0014': ['US', '1', 'FlashFunctionPresent'],\n '0015': ['US', '1', 'FlashRedEyeMode'],\n '0016': ['US', '1', 'ExposureProgram'],\n '0017': ['UT', '1', 'SpectralSensitivity'],\n '0018': ['IS', '1', 'PhotographicSensitivity'],\n '0019': ['IS', '1', 'SelfTimerMode'],\n '001A': ['US', '1', 'SensitivityType'],\n '001B': ['IS', '1', 'StandardOutputSensitivity'],\n '001C': ['IS', '1', 'RecommendedExposureIndex'],\n '001D': ['IS', '1', 'ISOSpeed'],\n '001E': ['IS', '1', 'ISOSpeedLatitudeyyy'],\n '001F': ['IS', '1', 'ISOSpeedLatitudezzz'],\n '0020': ['UT', '1', 'EXIFVersion'],\n '0021': ['DS', '1', 'ShutterSpeedValue'],\n '0022': ['DS', '1', 'ApertureValue'],\n '0023': ['DS', '1', 'BrightnessValue'],\n '0024': ['DS', '1', 'ExposureBiasValue'],\n '0025': ['DS', '1', 'MaxApertureValue'],\n '0026': ['DS', '1', 'SubjectDistance'],\n '0027': ['US', '1', 'MeteringMode'],\n '0028': ['US', '1', 'LightSource'],\n '0029': ['DS', '1', 'FocalLength'],\n '002A': ['IS', '2-4', 'SubjectArea'],\n '002B': ['OB', '1', 'MakerNote'],\n '0030': ['DS', '1', 'Temperature'],\n '0031': ['DS', '1', 'Humidity'],\n '0032': ['DS', '1', 'Pressure'],\n '0033': ['DS', '1', 'WaterDepth'],\n '0034': ['DS', '1', 'Acceleration'],\n '0035': ['DS', '1', 'CameraElevationAngle'],\n '0036': ['DS', '1-2', 'FlashEnergy'],\n '0037': ['IS', '2', 'SubjectLocation'],\n '0038': ['DS', '1', 'PhotographicExposureIndex'],\n '0039': ['US', '1', 'SensingMethod'],\n '003A': ['US', '1', 'FileSource'],\n '003B': ['US', '1', 'SceneType'],\n '0041': ['US', '1', 'CustomRendered'],\n '0042': ['US', '1', 'ExposureMode'],\n '0043': ['US', '1', 'WhiteBalance'],\n '0044': ['DS', '1', 'DigitalZoomRatio'],\n '0045': ['IS', '1', 'FocalLengthIn35mmFilm'],\n '0046': ['US', '1', 'SceneCaptureType'],\n '0047': ['US', '1', 'GainControl'],\n '0048': ['US', '1', 'Contrast'],\n '0049': ['US', '1', 'Saturation'],\n '004A': ['US', '1', 'Sharpness'],\n '004B': ['OB', '1', 'DeviceSettingDescription'],\n '004C': ['US', '1', 'SubjectDistanceRange'],\n '004D': ['UT', '1', 'CameraOwnerName'],\n '004E': ['DS', '4', 'LensSpecification'],\n '004F': ['UT', '1', 'LensMake'],\n '0050': ['UT', '1', 'LensModel'],\n '0051': ['UT', '1', 'LensSerialNumber'],\n '0061': ['CS', '1', 'InteroperabilityIndex'],\n '0062': ['OB', '1', 'InteroperabilityVersion'],\n '0070': ['OB', '1', 'GPSVersionID'],\n '0071': ['CS', '1', 'GPSLatitudeRef'],\n '0072': ['DS', '3', 'GPSLatitude'],\n '0073': ['CS', '1', 'GPSLongitudeRef'],\n '0074': ['DS', '3', 'GPSLongitude'],\n '0075': ['US', '1', 'GPSAltitudeRef'],\n '0076': ['DS', '1', 'GPSAltitude'],\n '0077': ['DT', '1', 'GPSTimeStamp'],\n '0078': ['UT', '1', 'GPSSatellites'],\n '0079': ['CS', '1', 'GPSStatus'],\n '007A': ['CS', '1', 'GPSMeasureMode'],\n '007B': ['DS', '1', 'GPSDOP'],\n '007C': ['CS', '1', 'GPSSpeedRef'],\n '007D': ['DS', '1', 'GPSSpeed'],\n '007E': ['CS', '1', 'GPSTrackRef'],\n '007F': ['DS', '1', 'GPSTrack'],\n '0080': ['CS', '1', 'GPSImgDirectionRef'],\n '0081': ['DS', '1', 'GPSImgDirection'],\n '0082': ['UT', '1', 'GPSMapDatum'],\n '0083': ['CS', '1', 'GPSDestLatitudeRef'],\n '0084': ['DS', '3', 'GPSDestLatitude'],\n '0085': ['CS', '1', 'GPSDestLongitudeRef'],\n '0086': ['DS', '3', 'GPSDestLongitude'],\n '0087': ['CS', '1', 'GPSDestBearingRef'],\n '0088': ['DS', '1', 'GPSDestBearing'],\n '0089': ['CS', '1', 'GPSDestDistanceRef'],\n '008A': ['DS', '1', 'GPSDestDistance'],\n '008B': ['OB', '1', 'GPSProcessingMethod'],\n '008C': ['OB', '1', 'GPSAreaInformation'],\n '008D': ['DT', '1', 'GPSDateStamp'],\n '008E': ['IS', '1', 'GPSDifferential'],\n '1001': ['CS', '1', 'LightSourcePolarization'],\n '1002': ['DS', '1', 'EmitterColorTemperature'],\n '1003': ['CS', '1', 'ContactMethod'],\n '1004': ['CS', '1-n', 'ImmersionMedia'],\n '1005': ['DS', '1', 'OpticalMagnificationFactor']\n },\n '0018': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['LO', '1', 'ContrastBolusAgent'],\n '0012': ['SQ', '1', 'ContrastBolusAgentSequence'],\n '0013': ['FL', '1', 'ContrastBolusT1Relaxivity'],\n '0014': ['SQ', '1', 'ContrastBolusAdministrationRouteSequence'],\n '0015': ['CS', '1', 'BodyPartExamined'],\n '0020': ['CS', '1-n', 'ScanningSequence'],\n '0021': ['CS', '1-n', 'SequenceVariant'],\n '0022': ['CS', '1-n', 'ScanOptions'],\n '0023': ['CS', '1', 'MRAcquisitionType'],\n '0024': ['SH', '1', 'SequenceName'],\n '0025': ['CS', '1', 'AngioFlag'],\n '0026': ['SQ', '1', 'InterventionDrugInformationSequence'],\n '0027': ['TM', '1', 'InterventionDrugStopTime'],\n '0028': ['DS', '1', 'InterventionDrugDose'],\n '0029': ['SQ', '1', 'InterventionDrugCodeSequence'],\n '002A': ['SQ', '1', 'AdditionalDrugSequence'],\n '0030': ['LO', '1-n', 'Radionuclide'],\n '0031': ['LO', '1', 'Radiopharmaceutical'],\n '0032': ['DS', '1', 'EnergyWindowCenterline'],\n '0033': ['DS', '1-n', 'EnergyWindowTotalWidth'],\n '0034': ['LO', '1', 'InterventionDrugName'],\n '0035': ['TM', '1', 'InterventionDrugStartTime'],\n '0036': ['SQ', '1', 'InterventionSequence'],\n '0037': ['CS', '1', 'TherapyType'],\n '0038': ['CS', '1', 'InterventionStatus'],\n '0039': ['CS', '1', 'TherapyDescription'],\n '003A': ['ST', '1', 'InterventionDescription'],\n '0040': ['IS', '1', 'CineRate'],\n '0042': ['CS', '1', 'InitialCineRunState'],\n '0050': ['DS', '1', 'SliceThickness'],\n '0060': ['DS', '1', 'KVP'],\n '0061': ['DS', '1', ''],\n '0070': ['IS', '1', 'CountsAccumulated'],\n '0071': ['CS', '1', 'AcquisitionTerminationCondition'],\n '0072': ['DS', '1', 'EffectiveDuration'],\n '0073': ['CS', '1', 'AcquisitionStartCondition'],\n '0074': ['IS', '1', 'AcquisitionStartConditionData'],\n '0075': ['IS', '1', 'AcquisitionTerminationConditionData'],\n '0080': ['DS', '1', 'RepetitionTime'],\n '0081': ['DS', '1', 'EchoTime'],\n '0082': ['DS', '1', 'InversionTime'],\n '0083': ['DS', '1', 'NumberOfAverages'],\n '0084': ['DS', '1', 'ImagingFrequency'],\n '0085': ['SH', '1', 'ImagedNucleus'],\n '0086': ['IS', '1-n', 'EchoNumbers'],\n '0087': ['DS', '1', 'MagneticFieldStrength'],\n '0088': ['DS', '1', 'SpacingBetweenSlices'],\n '0089': ['IS', '1', 'NumberOfPhaseEncodingSteps'],\n '0090': ['DS', '1', 'DataCollectionDiameter'],\n '0091': ['IS', '1', 'EchoTrainLength'],\n '0093': ['DS', '1', 'PercentSampling'],\n '0094': ['DS', '1', 'PercentPhaseFieldOfView'],\n '0095': ['DS', '1', 'PixelBandwidth'],\n '1000': ['LO', '1', 'DeviceSerialNumber'],\n '1002': ['UI', '1', 'DeviceUID'],\n '1003': ['LO', '1', 'DeviceID'],\n '1004': ['LO', '1', 'PlateID'],\n '1005': ['LO', '1', 'GeneratorID'],\n '1006': ['LO', '1', 'GridID'],\n '1007': ['LO', '1', 'CassetteID'],\n '1008': ['LO', '1', 'GantryID'],\n '1009': ['UT', '1', 'UniqueDeviceIdentifier'],\n '100A': ['SQ', '1', 'UDISequence'],\n '100B': ['UI', '1-n', 'ManufacturerDeviceClassUID'],\n '1010': ['LO', '1', 'SecondaryCaptureDeviceID'],\n '1011': ['LO', '1', 'HardcopyCreationDeviceID'],\n '1012': ['DA', '1', 'DateOfSecondaryCapture'],\n '1014': ['TM', '1', 'TimeOfSecondaryCapture'],\n '1016': ['LO', '1', 'SecondaryCaptureDeviceManufacturer'],\n '1017': ['LO', '1', 'HardcopyDeviceManufacturer'],\n '1018': ['LO', '1', 'SecondaryCaptureDeviceManufacturerModelName'],\n '1019': ['LO', '1-n', 'SecondaryCaptureDeviceSoftwareVersions'],\n '101A': ['LO', '1-n', 'HardcopyDeviceSoftwareVersion'],\n '101B': ['LO', '1', 'HardcopyDeviceManufacturerModelName'],\n '1020': ['LO', '1-n', 'SoftwareVersions'],\n '1022': ['SH', '1', 'VideoImageFormatAcquired'],\n '1023': ['LO', '1', 'DigitalImageFormatAcquired'],\n '1030': ['LO', '1', 'ProtocolName'],\n '1040': ['LO', '1', 'ContrastBolusRoute'],\n '1041': ['DS', '1', 'ContrastBolusVolume'],\n '1042': ['TM', '1', 'ContrastBolusStartTime'],\n '1043': ['TM', '1', 'ContrastBolusStopTime'],\n '1044': ['DS', '1', 'ContrastBolusTotalDose'],\n '1045': ['IS', '1', 'SyringeCounts'],\n '1046': ['DS', '1-n', 'ContrastFlowRate'],\n '1047': ['DS', '1-n', 'ContrastFlowDuration'],\n '1048': ['CS', '1', 'ContrastBolusIngredient'],\n '1049': ['DS', '1', 'ContrastBolusIngredientConcentration'],\n '1050': ['DS', '1', 'SpatialResolution'],\n '1060': ['DS', '1', 'TriggerTime'],\n '1061': ['LO', '1', 'TriggerSourceOrType'],\n '1062': ['IS', '1', 'NominalInterval'],\n '1063': ['DS', '1', 'FrameTime'],\n '1064': ['LO', '1', 'CardiacFramingType'],\n '1065': ['DS', '1-n', 'FrameTimeVector'],\n '1066': ['DS', '1', 'FrameDelay'],\n '1067': ['DS', '1', 'ImageTriggerDelay'],\n '1068': ['DS', '1', 'MultiplexGroupTimeOffset'],\n '1069': ['DS', '1', 'TriggerTimeOffset'],\n '106A': ['CS', '1', 'SynchronizationTrigger'],\n '106C': ['US', '2', 'SynchronizationChannel'],\n '106E': ['UL', '1', 'TriggerSamplePosition'],\n '1070': ['LO', '1', 'RadiopharmaceuticalRoute'],\n '1071': ['DS', '1', 'RadiopharmaceuticalVolume'],\n '1072': ['TM', '1', 'RadiopharmaceuticalStartTime'],\n '1073': ['TM', '1', 'RadiopharmaceuticalStopTime'],\n '1074': ['DS', '1', 'RadionuclideTotalDose'],\n '1075': ['DS', '1', 'RadionuclideHalfLife'],\n '1076': ['DS', '1', 'RadionuclidePositronFraction'],\n '1077': ['DS', '1', 'RadiopharmaceuticalSpecificActivity'],\n '1078': ['DT', '1', 'RadiopharmaceuticalStartDateTime'],\n '1079': ['DT', '1', 'RadiopharmaceuticalStopDateTime'],\n '1080': ['CS', '1', 'BeatRejectionFlag'],\n '1081': ['IS', '1', 'LowRRValue'],\n '1082': ['IS', '1', 'HighRRValue'],\n '1083': ['IS', '1', 'IntervalsAcquired'],\n '1084': ['IS', '1', 'IntervalsRejected'],\n '1085': ['LO', '1', 'PVCRejection'],\n '1086': ['IS', '1', 'SkipBeats'],\n '1088': ['IS', '1', 'HeartRate'],\n '1090': ['IS', '1', 'CardiacNumberOfImages'],\n '1094': ['IS', '1', 'TriggerWindow'],\n '1100': ['DS', '1', 'ReconstructionDiameter'],\n '1110': ['DS', '1', 'DistanceSourceToDetector'],\n '1111': ['DS', '1', 'DistanceSourceToPatient'],\n '1114': ['DS', '1', 'EstimatedRadiographicMagnificationFactor'],\n '1120': ['DS', '1', 'GantryDetectorTilt'],\n '1121': ['DS', '1', 'GantryDetectorSlew'],\n '1130': ['DS', '1', 'TableHeight'],\n '1131': ['DS', '1', 'TableTraverse'],\n '1134': ['CS', '1', 'TableMotion'],\n '1135': ['DS', '1-n', 'TableVerticalIncrement'],\n '1136': ['DS', '1-n', 'TableLateralIncrement'],\n '1137': ['DS', '1-n', 'TableLongitudinalIncrement'],\n '1138': ['DS', '1', 'TableAngle'],\n '113A': ['CS', '1', 'TableType'],\n '1140': ['CS', '1', 'RotationDirection'],\n '1141': ['DS', '1', 'AngularPosition'],\n '1142': ['DS', '1-n', 'RadialPosition'],\n '1143': ['DS', '1', 'ScanArc'],\n '1144': ['DS', '1', 'AngularStep'],\n '1145': ['DS', '1', 'CenterOfRotationOffset'],\n '1146': ['DS', '1-n', 'RotationOffset'],\n '1147': ['CS', '1', 'FieldOfViewShape'],\n '1149': ['IS', '1-2', 'FieldOfViewDimensions'],\n '1150': ['IS', '1', 'ExposureTime'],\n '1151': ['IS', '1', 'XRayTubeCurrent'],\n '1152': ['IS', '1', 'Exposure'],\n '1153': ['IS', '1', 'ExposureInuAs'],\n '1154': ['DS', '1', 'AveragePulseWidth'],\n '1155': ['CS', '1', 'RadiationSetting'],\n '1156': ['CS', '1', 'RectificationType'],\n '115A': ['CS', '1', 'RadiationMode'],\n '115E': ['DS', '1', 'ImageAndFluoroscopyAreaDoseProduct'],\n '1160': ['SH', '1', 'FilterType'],\n '1161': ['LO', '1-n', 'TypeOfFilters'],\n '1162': ['DS', '1', 'IntensifierSize'],\n '1164': ['DS', '2', 'ImagerPixelSpacing'],\n '1166': ['CS', '1-n', 'Grid'],\n '1170': ['IS', '1', 'GeneratorPower'],\n '1180': ['SH', '1', 'CollimatorGridName'],\n '1181': ['CS', '1', 'CollimatorType'],\n '1182': ['IS', '1-2', 'FocalDistance'],\n '1183': ['DS', '1-2', 'XFocusCenter'],\n '1184': ['DS', '1-2', 'YFocusCenter'],\n '1190': ['DS', '1-n', 'FocalSpots'],\n '1191': ['CS', '1', 'AnodeTargetMaterial'],\n '11A0': ['DS', '1', 'BodyPartThickness'],\n '11A2': ['DS', '1', 'CompressionForce'],\n '11A3': ['DS', '1', 'CompressionPressure'],\n '11A4': ['LO', '1', 'PaddleDescription'],\n '11A5': ['DS', '1', 'CompressionContactArea'],\n '11B0': ['LO', '1', 'AcquisitionMode'],\n '11B1': ['LO', '1', 'DoseModeName'],\n '11B2': ['CS', '1', 'AcquiredSubtractionMaskFlag'],\n '11B3': ['CS', '1', 'FluoroscopyPersistenceFlag'],\n '11B4': ['CS', '1', 'FluoroscopyLastImageHoldPersistenceFlag'],\n '11B5': ['IS', '1', 'UpperLimitNumberOfPersistentFluoroscopyFrames'],\n '11B6': ['CS', '1', 'ContrastBolusAutoInjectionTriggerFlag'],\n '11B7': ['FD', '1', 'ContrastBolusInjectionDelay'],\n '11B8': ['SQ', '1', 'XAAcquisitionPhaseDetailsSequence'],\n '11B9': ['FD', '1', 'XAAcquisitionFrameRate'],\n '11BA': ['SQ', '1', 'XAPlaneDetailsSequence'],\n '11BB': ['LO', '1', 'AcquisitionFieldOfViewLabel'],\n '11BC': ['SQ', '1', 'XRayFilterDetailsSequence'],\n '11BD': ['FD', '1', 'XAAcquisitionDuration'],\n '11BE': ['CS', '1', 'ReconstructionPipelineType'],\n '11BF': ['SQ', '1', 'ImageFilterDetailsSequence'],\n '11C0': ['CS', '1', 'AppliedMaskSubtractionFlag'],\n '11C1': ['SQ', '1', 'RequestedSeriesDescriptionCodeSequence'],\n '1200': ['DA', '1-n', 'DateOfLastCalibration'],\n '1201': ['TM', '1-n', 'TimeOfLastCalibration'],\n '1202': ['DT', '1', 'DateTimeOfLastCalibration'],\n '1203': ['DT', '1', 'CalibrationDateTime'],\n '1210': ['SH', '1-n', 'ConvolutionKernel'],\n '1240': ['IS', '1-n', 'UpperLowerPixelValues'],\n '1242': ['IS', '1', 'ActualFrameDuration'],\n '1243': ['IS', '1', 'CountRate'],\n '1244': ['US', '1', 'PreferredPlaybackSequencing'],\n '1250': ['SH', '1', 'ReceiveCoilName'],\n '1251': ['SH', '1', 'TransmitCoilName'],\n '1260': ['SH', '1', 'PlateType'],\n '1261': ['LO', '1', 'PhosphorType'],\n '1271': ['FD', '1', 'WaterEquivalentDiameter'],\n '1272': ['SQ', '1', 'WaterEquivalentDiameterCalculationMethodCodeSequence'],\n '1300': ['DS', '1', 'ScanVelocity'],\n '1301': ['CS', '1-n', 'WholeBodyTechnique'],\n '1302': ['IS', '1', 'ScanLength'],\n '1310': ['US', '4', 'AcquisitionMatrix'],\n '1312': ['CS', '1', 'InPlanePhaseEncodingDirection'],\n '1314': ['DS', '1', 'FlipAngle'],\n '1315': ['CS', '1', 'VariableFlipAngleFlag'],\n '1316': ['DS', '1', 'SAR'],\n '1318': ['DS', '1', 'dBdt'],\n '1320': ['FL', '1', 'B1rms'],\n '1400': ['LO', '1', 'AcquisitionDeviceProcessingDescription'],\n '1401': ['LO', '1', 'AcquisitionDeviceProcessingCode'],\n '1402': ['CS', '1', 'CassetteOrientation'],\n '1403': ['CS', '1', 'CassetteSize'],\n '1404': ['US', '1', 'ExposuresOnPlate'],\n '1405': ['IS', '1', 'RelativeXRayExposure'],\n '1411': ['DS', '1', 'ExposureIndex'],\n '1412': ['DS', '1', 'TargetExposureIndex'],\n '1413': ['DS', '1', 'DeviationIndex'],\n '1450': ['DS', '1', 'ColumnAngulation'],\n '1460': ['DS', '1', 'TomoLayerHeight'],\n '1470': ['DS', '1', 'TomoAngle'],\n '1480': ['DS', '1', 'TomoTime'],\n '1490': ['CS', '1', 'TomoType'],\n '1491': ['CS', '1', 'TomoClass'],\n '1495': ['IS', '1', 'NumberOfTomosynthesisSourceImages'],\n '1500': ['CS', '1', 'PositionerMotion'],\n '1508': ['CS', '1', 'PositionerType'],\n '1510': ['DS', '1', 'PositionerPrimaryAngle'],\n '1511': ['DS', '1', 'PositionerSecondaryAngle'],\n '1520': ['DS', '1-n', 'PositionerPrimaryAngleIncrement'],\n '1521': ['DS', '1-n', 'PositionerSecondaryAngleIncrement'],\n '1530': ['DS', '1', 'DetectorPrimaryAngle'],\n '1531': ['DS', '1', 'DetectorSecondaryAngle'],\n '1600': ['CS', '1-3', 'ShutterShape'],\n '1602': ['IS', '1', 'ShutterLeftVerticalEdge'],\n '1604': ['IS', '1', 'ShutterRightVerticalEdge'],\n '1606': ['IS', '1', 'ShutterUpperHorizontalEdge'],\n '1608': ['IS', '1', 'ShutterLowerHorizontalEdge'],\n '1610': ['IS', '2', 'CenterOfCircularShutter'],\n '1612': ['IS', '1', 'RadiusOfCircularShutter'],\n '1620': ['IS', '2-2n', 'VerticesOfThePolygonalShutter'],\n '1622': ['US', '1', 'ShutterPresentationValue'],\n '1623': ['US', '1', 'ShutterOverlayGroup'],\n '1624': ['US', '3', 'ShutterPresentationColorCIELabValue'],\n '1630': ['CS', '1', 'OutlineShapeType'],\n '1631': ['FD', '1', 'OutlineLeftVerticalEdge'],\n '1632': ['FD', '1', 'OutlineRightVerticalEdge'],\n '1633': ['FD', '1', 'OutlineUpperHorizontalEdge'],\n '1634': ['FD', '1', 'OutlineLowerHorizontalEdge'],\n '1635': ['FD', '2', 'CenterOfCircularOutline'],\n '1636': ['FD', '1', 'DiameterOfCircularOutline'],\n '1637': ['UL', '1', 'NumberOfPolygonalVertices'],\n '1638': ['OF', '1', 'VerticesOfThePolygonalOutline'],\n '1700': ['CS', '1-3', 'CollimatorShape'],\n '1702': ['IS', '1', 'CollimatorLeftVerticalEdge'],\n '1704': ['IS', '1', 'CollimatorRightVerticalEdge'],\n '1706': ['IS', '1', 'CollimatorUpperHorizontalEdge'],\n '1708': ['IS', '1', 'CollimatorLowerHorizontalEdge'],\n '1710': ['IS', '2', 'CenterOfCircularCollimator'],\n '1712': ['IS', '1', 'RadiusOfCircularCollimator'],\n '1720': ['IS', '2-2n', 'VerticesOfThePolygonalCollimator'],\n '1800': ['CS', '1', 'AcquisitionTimeSynchronized'],\n '1801': ['SH', '1', 'TimeSource'],\n '1802': ['CS', '1', 'TimeDistributionProtocol'],\n '1803': ['LO', '1', 'NTPSourceAddress'],\n '2001': ['IS', '1-n', 'PageNumberVector'],\n '2002': ['SH', '1-n', 'FrameLabelVector'],\n '2003': ['DS', '1-n', 'FramePrimaryAngleVector'],\n '2004': ['DS', '1-n', 'FrameSecondaryAngleVector'],\n '2005': ['DS', '1-n', 'SliceLocationVector'],\n '2006': ['SH', '1-n', 'DisplayWindowLabelVector'],\n '2010': ['DS', '2', 'NominalScannedPixelSpacing'],\n '2020': ['CS', '1', 'DigitizingDeviceTransportDirection'],\n '2030': ['DS', '1', 'RotationOfScannedFilm'],\n '2041': ['SQ', '1', 'BiopsyTargetSequence'],\n '2042': ['UI', '1', 'TargetUID'],\n '2043': ['FL', '2', 'LocalizingCursorPosition'],\n '2044': ['FL', '3', 'CalculatedTargetPosition'],\n '2045': ['SH', '1', 'TargetLabel'],\n '2046': ['FL', '1', 'DisplayedZValue'],\n '3100': ['CS', '1', 'IVUSAcquisition'],\n '3101': ['DS', '1', 'IVUSPullbackRate'],\n '3102': ['DS', '1', 'IVUSGatedRate'],\n '3103': ['IS', '1', 'IVUSPullbackStartFrameNumber'],\n '3104': ['IS', '1', 'IVUSPullbackStopFrameNumber'],\n '3105': ['IS', '1-n', 'LesionNumber'],\n '4000': ['LT', '1', 'AcquisitionComments'],\n '5000': ['SH', '1-n', 'OutputPower'],\n '5010': ['LO', '1-n', 'TransducerData'],\n '5011': ['SQ', '1', 'TransducerIdentificationSequence'],\n '5012': ['DS', '1', 'FocusDepth'],\n '5020': ['LO', '1', 'ProcessingFunction'],\n '5021': ['LO', '1', 'PostprocessingFunction'],\n '5022': ['DS', '1', 'MechanicalIndex'],\n '5024': ['DS', '1', 'BoneThermalIndex'],\n '5026': ['DS', '1', 'CranialThermalIndex'],\n '5027': ['DS', '1', 'SoftTissueThermalIndex'],\n '5028': ['DS', '1', 'SoftTissueFocusThermalIndex'],\n '5029': ['DS', '1', 'SoftTissueSurfaceThermalIndex'],\n '5030': ['DS', '1', 'DynamicRange'],\n '5040': ['DS', '1', 'TotalGain'],\n '5050': ['IS', '1', 'DepthOfScanField'],\n '5100': ['CS', '1', 'PatientPosition'],\n '5101': ['CS', '1', 'ViewPosition'],\n '5104': ['SQ', '1', 'ProjectionEponymousNameCodeSequence'],\n '5210': ['DS', '6', 'ImageTransformationMatrix'],\n '5212': ['DS', '3', 'ImageTranslationVector'],\n '6000': ['DS', '1', 'Sensitivity'],\n '6011': ['SQ', '1', 'SequenceOfUltrasoundRegions'],\n '6012': ['US', '1', 'RegionSpatialFormat'],\n '6014': ['US', '1', 'RegionDataType'],\n '6016': ['UL', '1', 'RegionFlags'],\n '6018': ['UL', '1', 'RegionLocationMinX0'],\n '601A': ['UL', '1', 'RegionLocationMinY0'],\n '601C': ['UL', '1', 'RegionLocationMaxX1'],\n '601E': ['UL', '1', 'RegionLocationMaxY1'],\n '6020': ['SL', '1', 'ReferencePixelX0'],\n '6022': ['SL', '1', 'ReferencePixelY0'],\n '6024': ['US', '1', 'PhysicalUnitsXDirection'],\n '6026': ['US', '1', 'PhysicalUnitsYDirection'],\n '6028': ['FD', '1', 'ReferencePixelPhysicalValueX'],\n '602A': ['FD', '1', 'ReferencePixelPhysicalValueY'],\n '602C': ['FD', '1', 'PhysicalDeltaX'],\n '602E': ['FD', '1', 'PhysicalDeltaY'],\n '6030': ['UL', '1', 'TransducerFrequency'],\n '6031': ['CS', '1', 'TransducerType'],\n '6032': ['UL', '1', 'PulseRepetitionFrequency'],\n '6034': ['FD', '1', 'DopplerCorrectionAngle'],\n '6036': ['FD', '1', 'SteeringAngle'],\n '6038': ['UL', '1', 'DopplerSampleVolumeXPositionRetired'],\n '6039': ['SL', '1', 'DopplerSampleVolumeXPosition'],\n '603A': ['UL', '1', 'DopplerSampleVolumeYPositionRetired'],\n '603B': ['SL', '1', 'DopplerSampleVolumeYPosition'],\n '603C': ['UL', '1', 'TMLinePositionX0Retired'],\n '603D': ['SL', '1', 'TMLinePositionX0'],\n '603E': ['UL', '1', 'TMLinePositionY0Retired'],\n '603F': ['SL', '1', 'TMLinePositionY0'],\n '6040': ['UL', '1', 'TMLinePositionX1Retired'],\n '6041': ['SL', '1', 'TMLinePositionX1'],\n '6042': ['UL', '1', 'TMLinePositionY1Retired'],\n '6043': ['SL', '1', 'TMLinePositionY1'],\n '6044': ['US', '1', 'PixelComponentOrganization'],\n '6046': ['UL', '1', 'PixelComponentMask'],\n '6048': ['UL', '1', 'PixelComponentRangeStart'],\n '604A': ['UL', '1', 'PixelComponentRangeStop'],\n '604C': ['US', '1', 'PixelComponentPhysicalUnits'],\n '604E': ['US', '1', 'PixelComponentDataType'],\n '6050': ['UL', '1', 'NumberOfTableBreakPoints'],\n '6052': ['UL', '1-n', 'TableOfXBreakPoints'],\n '6054': ['FD', '1-n', 'TableOfYBreakPoints'],\n '6056': ['UL', '1', 'NumberOfTableEntries'],\n '6058': ['UL', '1-n', 'TableOfPixelValues'],\n '605A': ['FL', '1-n', 'TableOfParameterValues'],\n '6060': ['FL', '1-n', 'RWaveTimeVector'],\n '6070': ['US', '1', 'ActiveImageAreaOverlayGroup'],\n '7000': ['CS', '1', 'DetectorConditionsNominalFlag'],\n '7001': ['DS', '1', 'DetectorTemperature'],\n '7004': ['CS', '1', 'DetectorType'],\n '7005': ['CS', '1', 'DetectorConfiguration'],\n '7006': ['LT', '1', 'DetectorDescription'],\n '7008': ['LT', '1', 'DetectorMode'],\n '700A': ['SH', '1', 'DetectorID'],\n '700C': ['DA', '1', 'DateOfLastDetectorCalibration'],\n '700E': ['TM', '1', 'TimeOfLastDetectorCalibration'],\n '7010': ['IS', '1', 'ExposuresOnDetectorSinceLastCalibration'],\n '7011': ['IS', '1', 'ExposuresOnDetectorSinceManufactured'],\n '7012': ['DS', '1', 'DetectorTimeSinceLastExposure'],\n '7014': ['DS', '1', 'DetectorActiveTime'],\n '7016': ['DS', '1', 'DetectorActivationOffsetFromExposure'],\n '701A': ['DS', '2', 'DetectorBinning'],\n '7020': ['DS', '2', 'DetectorElementPhysicalSize'],\n '7022': ['DS', '2', 'DetectorElementSpacing'],\n '7024': ['CS', '1', 'DetectorActiveShape'],\n '7026': ['DS', '1-2', 'DetectorActiveDimensions'],\n '7028': ['DS', '2', 'DetectorActiveOrigin'],\n '702A': ['LO', '1', 'DetectorManufacturerName'],\n '702B': ['LO', '1', 'DetectorManufacturerModelName'],\n '7030': ['DS', '2', 'FieldOfViewOrigin'],\n '7032': ['DS', '1', 'FieldOfViewRotation'],\n '7034': ['CS', '1', 'FieldOfViewHorizontalFlip'],\n '7036': ['FL', '2', 'PixelDataAreaOriginRelativeToFOV'],\n '7038': ['FL', '1', 'PixelDataAreaRotationAngleRelativeToFOV'],\n '7040': ['LT', '1', 'GridAbsorbingMaterial'],\n '7041': ['LT', '1', 'GridSpacingMaterial'],\n '7042': ['DS', '1', 'GridThickness'],\n '7044': ['DS', '1', 'GridPitch'],\n '7046': ['IS', '2', 'GridAspectRatio'],\n '7048': ['DS', '1', 'GridPeriod'],\n '704C': ['DS', '1', 'GridFocalDistance'],\n '7050': ['CS', '1-n', 'FilterMaterial'],\n '7052': ['DS', '1-n', 'FilterThicknessMinimum'],\n '7054': ['DS', '1-n', 'FilterThicknessMaximum'],\n '7056': ['FL', '1-n', 'FilterBeamPathLengthMinimum'],\n '7058': ['FL', '1-n', 'FilterBeamPathLengthMaximum'],\n '7060': ['CS', '1', 'ExposureControlMode'],\n '7062': ['LT', '1', 'ExposureControlModeDescription'],\n '7064': ['CS', '1', 'ExposureStatus'],\n '7065': ['DS', '1', 'PhototimerSetting'],\n '8150': ['DS', '1', 'ExposureTimeInuS'],\n '8151': ['DS', '1', 'XRayTubeCurrentInuA'],\n '9004': ['CS', '1', 'ContentQualification'],\n '9005': ['SH', '1', 'PulseSequenceName'],\n '9006': ['SQ', '1', 'MRImagingModifierSequence'],\n '9008': ['CS', '1', 'EchoPulseSequence'],\n '9009': ['CS', '1', 'InversionRecovery'],\n '9010': ['CS', '1', 'FlowCompensation'],\n '9011': ['CS', '1', 'MultipleSpinEcho'],\n '9012': ['CS', '1', 'MultiPlanarExcitation'],\n '9014': ['CS', '1', 'PhaseContrast'],\n '9015': ['CS', '1', 'TimeOfFlightContrast'],\n '9016': ['CS', '1', 'Spoiling'],\n '9017': ['CS', '1', 'SteadyStatePulseSequence'],\n '9018': ['CS', '1', 'EchoPlanarPulseSequence'],\n '9019': ['FD', '1', 'TagAngleFirstAxis'],\n '9020': ['CS', '1', 'MagnetizationTransfer'],\n '9021': ['CS', '1', 'T2Preparation'],\n '9022': ['CS', '1', 'BloodSignalNulling'],\n '9024': ['CS', '1', 'SaturationRecovery'],\n '9025': ['CS', '1', 'SpectrallySelectedSuppression'],\n '9026': ['CS', '1', 'SpectrallySelectedExcitation'],\n '9027': ['CS', '1', 'SpatialPresaturation'],\n '9028': ['CS', '1', 'Tagging'],\n '9029': ['CS', '1', 'OversamplingPhase'],\n '9030': ['FD', '1', 'TagSpacingFirstDimension'],\n '9032': ['CS', '1', 'GeometryOfKSpaceTraversal'],\n '9033': ['CS', '1', 'SegmentedKSpaceTraversal'],\n '9034': ['CS', '1', 'RectilinearPhaseEncodeReordering'],\n '9035': ['FD', '1', 'TagThickness'],\n '9036': ['CS', '1', 'PartialFourierDirection'],\n '9037': ['CS', '1', 'CardiacSynchronizationTechnique'],\n '9041': ['LO', '1', 'ReceiveCoilManufacturerName'],\n '9042': ['SQ', '1', 'MRReceiveCoilSequence'],\n '9043': ['CS', '1', 'ReceiveCoilType'],\n '9044': ['CS', '1', 'QuadratureReceiveCoil'],\n '9045': ['SQ', '1', 'MultiCoilDefinitionSequence'],\n '9046': ['LO', '1', 'MultiCoilConfiguration'],\n '9047': ['SH', '1', 'MultiCoilElementName'],\n '9048': ['CS', '1', 'MultiCoilElementUsed'],\n '9049': ['SQ', '1', 'MRTransmitCoilSequence'],\n '9050': ['LO', '1', 'TransmitCoilManufacturerName'],\n '9051': ['CS', '1', 'TransmitCoilType'],\n '9052': ['FD', '1-2', 'SpectralWidth'],\n '9053': ['FD', '1-2', 'ChemicalShiftReference'],\n '9054': ['CS', '1', 'VolumeLocalizationTechnique'],\n '9058': ['US', '1', 'MRAcquisitionFrequencyEncodingSteps'],\n '9059': ['CS', '1', 'Decoupling'],\n '9060': ['CS', '1-2', 'DecoupledNucleus'],\n '9061': ['FD', '1-2', 'DecouplingFrequency'],\n '9062': ['CS', '1', 'DecouplingMethod'],\n '9063': ['FD', '1-2', 'DecouplingChemicalShiftReference'],\n '9064': ['CS', '1', 'KSpaceFiltering'],\n '9065': ['CS', '1-2', 'TimeDomainFiltering'],\n '9066': ['US', '1-2', 'NumberOfZeroFills'],\n '9067': ['CS', '1', 'BaselineCorrection'],\n '9069': ['FD', '1', 'ParallelReductionFactorInPlane'],\n '9070': ['FD', '1', 'CardiacRRIntervalSpecified'],\n '9073': ['FD', '1', 'AcquisitionDuration'],\n '9074': ['DT', '1', 'FrameAcquisitionDateTime'],\n '9075': ['CS', '1', 'DiffusionDirectionality'],\n '9076': ['SQ', '1', 'DiffusionGradientDirectionSequence'],\n '9077': ['CS', '1', 'ParallelAcquisition'],\n '9078': ['CS', '1', 'ParallelAcquisitionTechnique'],\n '9079': ['FD', '1-n', 'InversionTimes'],\n '9080': ['ST', '1', 'MetaboliteMapDescription'],\n '9081': ['CS', '1', 'PartialFourier'],\n '9082': ['FD', '1', 'EffectiveEchoTime'],\n '9083': ['SQ', '1', 'MetaboliteMapCodeSequence'],\n '9084': ['SQ', '1', 'ChemicalShiftSequence'],\n '9085': ['CS', '1', 'CardiacSignalSource'],\n '9087': ['FD', '1', 'DiffusionBValue'],\n '9089': ['FD', '3', 'DiffusionGradientOrientation'],\n '9090': ['FD', '3', 'VelocityEncodingDirection'],\n '9091': ['FD', '1', 'VelocityEncodingMinimumValue'],\n '9092': ['SQ', '1', 'VelocityEncodingAcquisitionSequence'],\n '9093': ['US', '1', 'NumberOfKSpaceTrajectories'],\n '9094': ['CS', '1', 'CoverageOfKSpace'],\n '9095': ['UL', '1', 'SpectroscopyAcquisitionPhaseRows'],\n '9096': ['FD', '1', 'ParallelReductionFactorInPlaneRetired'],\n '9098': ['FD', '1-2', 'TransmitterFrequency'],\n '9100': ['CS', '1-2', 'ResonantNucleus'],\n '9101': ['CS', '1', 'FrequencyCorrection'],\n '9103': ['SQ', '1', 'MRSpectroscopyFOVGeometrySequence'],\n '9104': ['FD', '1', 'SlabThickness'],\n '9105': ['FD', '3', 'SlabOrientation'],\n '9106': ['FD', '3', 'MidSlabPosition'],\n '9107': ['SQ', '1', 'MRSpatialSaturationSequence'],\n '9112': ['SQ', '1', 'MRTimingAndRelatedParametersSequence'],\n '9114': ['SQ', '1', 'MREchoSequence'],\n '9115': ['SQ', '1', 'MRModifierSequence'],\n '9117': ['SQ', '1', 'MRDiffusionSequence'],\n '9118': ['SQ', '1', 'CardiacSynchronizationSequence'],\n '9119': ['SQ', '1', 'MRAveragesSequence'],\n '9125': ['SQ', '1', 'MRFOVGeometrySequence'],\n '9126': ['SQ', '1', 'VolumeLocalizationSequence'],\n '9127': ['UL', '1', 'SpectroscopyAcquisitionDataColumns'],\n '9147': ['CS', '1', 'DiffusionAnisotropyType'],\n '9151': ['DT', '1', 'FrameReferenceDateTime'],\n '9152': ['SQ', '1', 'MRMetaboliteMapSequence'],\n '9155': ['FD', '1', 'ParallelReductionFactorOutOfPlane'],\n '9159': ['UL', '1', 'SpectroscopyAcquisitionOutOfPlanePhaseSteps'],\n '9166': ['CS', '1', 'BulkMotionStatus'],\n '9168': ['FD', '1', 'ParallelReductionFactorSecondInPlane'],\n '9169': ['CS', '1', 'CardiacBeatRejectionTechnique'],\n '9170': ['CS', '1', 'RespiratoryMotionCompensationTechnique'],\n '9171': ['CS', '1', 'RespiratorySignalSource'],\n '9172': ['CS', '1', 'BulkMotionCompensationTechnique'],\n '9173': ['CS', '1', 'BulkMotionSignalSource'],\n '9174': ['CS', '1', 'ApplicableSafetyStandardAgency'],\n '9175': ['LO', '1', 'ApplicableSafetyStandardDescription'],\n '9176': ['SQ', '1', 'OperatingModeSequence'],\n '9177': ['CS', '1', 'OperatingModeType'],\n '9178': ['CS', '1', 'OperatingMode'],\n '9179': ['CS', '1', 'SpecificAbsorptionRateDefinition'],\n '9180': ['CS', '1', 'GradientOutputType'],\n '9181': ['FD', '1', 'SpecificAbsorptionRateValue'],\n '9182': ['FD', '1', 'GradientOutput'],\n '9183': ['CS', '1', 'FlowCompensationDirection'],\n '9184': ['FD', '1', 'TaggingDelay'],\n '9185': ['ST', '1', 'RespiratoryMotionCompensationTechniqueDescription'],\n '9186': ['SH', '1', 'RespiratorySignalSourceID'],\n '9195': ['FD', '1', 'ChemicalShiftMinimumIntegrationLimitInHz'],\n '9196': ['FD', '1', 'ChemicalShiftMaximumIntegrationLimitInHz'],\n '9197': ['SQ', '1', 'MRVelocityEncodingSequence'],\n '9198': ['CS', '1', 'FirstOrderPhaseCorrection'],\n '9199': ['CS', '1', 'WaterReferencedPhaseCorrection'],\n '9200': ['CS', '1', 'MRSpectroscopyAcquisitionType'],\n '9214': ['CS', '1', 'RespiratoryCyclePosition'],\n '9217': ['FD', '1', 'VelocityEncodingMaximumValue'],\n '9218': ['FD', '1', 'TagSpacingSecondDimension'],\n '9219': ['SS', '1', 'TagAngleSecondAxis'],\n '9220': ['FD', '1', 'FrameAcquisitionDuration'],\n '9226': ['SQ', '1', 'MRImageFrameTypeSequence'],\n '9227': ['SQ', '1', 'MRSpectroscopyFrameTypeSequence'],\n '9231': ['US', '1', 'MRAcquisitionPhaseEncodingStepsInPlane'],\n '9232': ['US', '1', 'MRAcquisitionPhaseEncodingStepsOutOfPlane'],\n '9234': ['UL', '1', 'SpectroscopyAcquisitionPhaseColumns'],\n '9236': ['CS', '1', 'CardiacCyclePosition'],\n '9239': ['SQ', '1', 'SpecificAbsorptionRateSequence'],\n '9240': ['US', '1', 'RFEchoTrainLength'],\n '9241': ['US', '1', 'GradientEchoTrainLength'],\n '9250': ['CS', '1', 'ArterialSpinLabelingContrast'],\n '9251': ['SQ', '1', 'MRArterialSpinLabelingSequence'],\n '9252': ['LO', '1', 'ASLTechniqueDescription'],\n '9253': ['US', '1', 'ASLSlabNumber'],\n '9254': ['FD', '1', 'ASLSlabThickness'],\n '9255': ['FD', '3', 'ASLSlabOrientation'],\n '9256': ['FD', '3', 'ASLMidSlabPosition'],\n '9257': ['CS', '1', 'ASLContext'],\n '9258': ['UL', '1', 'ASLPulseTrainDuration'],\n '9259': ['CS', '1', 'ASLCrusherFlag'],\n '925A': ['FD', '1', 'ASLCrusherFlowLimit'],\n '925B': ['LO', '1', 'ASLCrusherDescription'],\n '925C': ['CS', '1', 'ASLBolusCutoffFlag'],\n '925D': ['SQ', '1', 'ASLBolusCutoffTimingSequence'],\n '925E': ['LO', '1', 'ASLBolusCutoffTechnique'],\n '925F': ['UL', '1', 'ASLBolusCutoffDelayTime'],\n '9260': ['SQ', '1', 'ASLSlabSequence'],\n '9295': ['FD', '1', 'ChemicalShiftMinimumIntegrationLimitInppm'],\n '9296': ['FD', '1', 'ChemicalShiftMaximumIntegrationLimitInppm'],\n '9297': ['CS', '1', 'WaterReferenceAcquisition'],\n '9298': ['IS', '1', 'EchoPeakPosition'],\n '9301': ['SQ', '1', 'CTAcquisitionTypeSequence'],\n '9302': ['CS', '1', 'AcquisitionType'],\n '9303': ['FD', '1', 'TubeAngle'],\n '9304': ['SQ', '1', 'CTAcquisitionDetailsSequence'],\n '9305': ['FD', '1', 'RevolutionTime'],\n '9306': ['FD', '1', 'SingleCollimationWidth'],\n '9307': ['FD', '1', 'TotalCollimationWidth'],\n '9308': ['SQ', '1', 'CTTableDynamicsSequence'],\n '9309': ['FD', '1', 'TableSpeed'],\n '9310': ['FD', '1', 'TableFeedPerRotation'],\n '9311': ['FD', '1', 'SpiralPitchFactor'],\n '9312': ['SQ', '1', 'CTGeometrySequence'],\n '9313': ['FD', '3', 'DataCollectionCenterPatient'],\n '9314': ['SQ', '1', 'CTReconstructionSequence'],\n '9315': ['CS', '1', 'ReconstructionAlgorithm'],\n '9316': ['CS', '1', 'ConvolutionKernelGroup'],\n '9317': ['FD', '2', 'ReconstructionFieldOfView'],\n '9318': ['FD', '3', 'ReconstructionTargetCenterPatient'],\n '9319': ['FD', '1', 'ReconstructionAngle'],\n '9320': ['SH', '1', 'ImageFilter'],\n '9321': ['SQ', '1', 'CTExposureSequence'],\n '9322': ['FD', '2', 'ReconstructionPixelSpacing'],\n '9323': ['CS', '1-n', 'ExposureModulationType'],\n '9324': ['FD', '1', 'EstimatedDoseSaving'],\n '9325': ['SQ', '1', 'CTXRayDetailsSequence'],\n '9326': ['SQ', '1', 'CTPositionSequence'],\n '9327': ['FD', '1', 'TablePosition'],\n '9328': ['FD', '1', 'ExposureTimeInms'],\n '9329': ['SQ', '1', 'CTImageFrameTypeSequence'],\n '9330': ['FD', '1', 'XRayTubeCurrentInmA'],\n '9332': ['FD', '1', 'ExposureInmAs'],\n '9333': ['CS', '1', 'ConstantVolumeFlag'],\n '9334': ['CS', '1', 'FluoroscopyFlag'],\n '9335': ['FD', '1', 'DistanceSourceToDataCollectionCenter'],\n '9337': ['US', '1', 'ContrastBolusAgentNumber'],\n '9338': ['SQ', '1', 'ContrastBolusIngredientCodeSequence'],\n '9340': ['SQ', '1', 'ContrastAdministrationProfileSequence'],\n '9341': ['SQ', '1', 'ContrastBolusUsageSequence'],\n '9342': ['CS', '1', 'ContrastBolusAgentAdministered'],\n '9343': ['CS', '1', 'ContrastBolusAgentDetected'],\n '9344': ['CS', '1', 'ContrastBolusAgentPhase'],\n '9345': ['FD', '1', 'CTDIvol'],\n '9346': ['SQ', '1', 'CTDIPhantomTypeCodeSequence'],\n '9351': ['FL', '1', 'CalciumScoringMassFactorPatient'],\n '9352': ['FL', '3', 'CalciumScoringMassFactorDevice'],\n '9353': ['FL', '1', 'EnergyWeightingFactor'],\n '9360': ['SQ', '1', 'CTAdditionalXRaySourceSequence'],\n '9361': ['CS', '1', 'MultienergyCTAcquisition'],\n '9362': ['SQ', '1', 'MultienergyCTAcquisitionSequence'],\n '9363': ['SQ', '1', 'MultienergyCTProcessingSequence'],\n '9364': ['SQ', '1', 'MultienergyCTCharacteristicsSequence'],\n '9365': ['SQ', '1', 'MultienergyCTXRaySourceSequence'],\n '9366': ['US', '1', 'XRaySourceIndex'],\n '9367': ['UC', '1', 'XRaySourceID'],\n '9368': ['CS', '1', 'MultienergySourceTechnique'],\n '9369': ['DT', '1', 'SourceStartDateTime'],\n '936A': ['DT', '1', 'SourceEndDateTime'],\n '936B': ['US', '1', 'SwitchingPhaseNumber'],\n '936C': ['DS', '1', 'SwitchingPhaseNominalDuration'],\n '936D': ['DS', '1', 'SwitchingPhaseTransitionDuration'],\n '936E': ['DS', '1', 'EffectiveBinEnergy'],\n '936F': ['SQ', '1', 'MultienergyCTXRayDetectorSequence'],\n '9370': ['US', '1', 'XRayDetectorIndex'],\n '9371': ['UC', '1', 'XRayDetectorID'],\n '9372': ['CS', '1', 'MultienergyDetectorType'],\n '9373': ['ST', '1', 'XRayDetectorLabel'],\n '9374': ['DS', '1', 'NominalMaxEnergy'],\n '9375': ['DS', '1', 'NominalMinEnergy'],\n '9376': ['US', '1-n', 'ReferencedXRayDetectorIndex'],\n '9377': ['US', '1-n', 'ReferencedXRaySourceIndex'],\n '9378': ['US', '1-n', 'ReferencedPathIndex'],\n '9379': ['SQ', '1', 'MultienergyCTPathSequence'],\n '937A': ['US', '1', 'MultienergyCTPathIndex'],\n '937B': ['UT', '1', 'MultienergyAcquisitionDescription'],\n '937C': ['FD', '1', 'MonoenergeticEnergyEquivalent'],\n '937D': ['SQ', '1', 'MaterialCodeSequence'],\n '937E': ['CS', '1', 'DecompositionMethod'],\n '937F': ['UT', '1', 'DecompositionDescription'],\n '9380': ['SQ', '1', 'DecompositionAlgorithmIdentificationSequence'],\n '9381': ['SQ', '1', 'DecompositionMaterialSequence'],\n '9382': ['SQ', '1', 'MaterialAttenuationSequence'],\n '9383': ['DS', '1', 'PhotonEnergy'],\n '9384': ['DS', '1', 'XRayMassAttenuationCoefficient'],\n '9401': ['SQ', '1', 'ProjectionPixelCalibrationSequence'],\n '9402': ['FL', '1', 'DistanceSourceToIsocenter'],\n '9403': ['FL', '1', 'DistanceObjectToTableTop'],\n '9404': ['FL', '2', 'ObjectPixelSpacingInCenterOfBeam'],\n '9405': ['SQ', '1', 'PositionerPositionSequence'],\n '9406': ['SQ', '1', 'TablePositionSequence'],\n '9407': ['SQ', '1', 'CollimatorShapeSequence'],\n '9410': ['CS', '1', 'PlanesInAcquisition'],\n '9412': ['SQ', '1', 'XAXRFFrameCharacteristicsSequence'],\n '9417': ['SQ', '1', 'FrameAcquisitionSequence'],\n '9420': ['CS', '1', 'XRayReceptorType'],\n '9423': ['LO', '1', 'AcquisitionProtocolName'],\n '9424': ['LT', '1', 'AcquisitionProtocolDescription'],\n '9425': ['CS', '1', 'ContrastBolusIngredientOpaque'],\n '9426': ['FL', '1', 'DistanceReceptorPlaneToDetectorHousing'],\n '9427': ['CS', '1', 'IntensifierActiveShape'],\n '9428': ['FL', '1-2', 'IntensifierActiveDimensions'],\n '9429': ['FL', '2', 'PhysicalDetectorSize'],\n '9430': ['FL', '2', 'PositionOfIsocenterProjection'],\n '9432': ['SQ', '1', 'FieldOfViewSequence'],\n '9433': ['LO', '1', 'FieldOfViewDescription'],\n '9434': ['SQ', '1', 'ExposureControlSensingRegionsSequence'],\n '9435': ['CS', '1', 'ExposureControlSensingRegionShape'],\n '9436': ['SS', '1', 'ExposureControlSensingRegionLeftVerticalEdge'],\n '9437': ['SS', '1', 'ExposureControlSensingRegionRightVerticalEdge'],\n '9438': ['SS', '1', 'ExposureControlSensingRegionUpperHorizontalEdge'],\n '9439': ['SS', '1', 'ExposureControlSensingRegionLowerHorizontalEdge'],\n '9440': ['SS', '2', 'CenterOfCircularExposureControlSensingRegion'],\n '9441': ['US', '1', 'RadiusOfCircularExposureControlSensingRegion'],\n '9442': ['SS', '2-n', 'VerticesOfThePolygonalExposureControlSensingRegion'],\n '9445': ['', '', ''],\n '9447': ['FL', '1', 'ColumnAngulationPatient'],\n '9449': ['FL', '1', 'BeamAngle'],\n '9451': ['SQ', '1', 'FrameDetectorParametersSequence'],\n '9452': ['FL', '1', 'CalculatedAnatomyThickness'],\n '9455': ['SQ', '1', 'CalibrationSequence'],\n '9456': ['SQ', '1', 'ObjectThicknessSequence'],\n '9457': ['CS', '1', 'PlaneIdentification'],\n '9461': ['FL', '1-2', 'FieldOfViewDimensionsInFloat'],\n '9462': ['SQ', '1', 'IsocenterReferenceSystemSequence'],\n '9463': ['FL', '1', 'PositionerIsocenterPrimaryAngle'],\n '9464': ['FL', '1', 'PositionerIsocenterSecondaryAngle'],\n '9465': ['FL', '1', 'PositionerIsocenterDetectorRotationAngle'],\n '9466': ['FL', '1', 'TableXPositionToIsocenter'],\n '9467': ['FL', '1', 'TableYPositionToIsocenter'],\n '9468': ['FL', '1', 'TableZPositionToIsocenter'],\n '9469': ['FL', '1', 'TableHorizontalRotationAngle'],\n '9470': ['FL', '1', 'TableHeadTiltAngle'],\n '9471': ['FL', '1', 'TableCradleTiltAngle'],\n '9472': ['SQ', '1', 'FrameDisplayShutterSequence'],\n '9473': ['FL', '1', 'AcquiredImageAreaDoseProduct'],\n '9474': ['CS', '1', 'CArmPositionerTabletopRelationship'],\n '9476': ['SQ', '1', 'XRayGeometrySequence'],\n '9477': ['SQ', '1', 'IrradiationEventIdentificationSequence'],\n '9504': ['SQ', '1', 'XRay3DFrameTypeSequence'],\n '9506': ['SQ', '1', 'ContributingSourcesSequence'],\n '9507': ['SQ', '1', 'XRay3DAcquisitionSequence'],\n '9508': ['FL', '1', 'PrimaryPositionerScanArc'],\n '9509': ['FL', '1', 'SecondaryPositionerScanArc'],\n '9510': ['FL', '1', 'PrimaryPositionerScanStartAngle'],\n '9511': ['FL', '1', 'SecondaryPositionerScanStartAngle'],\n '9514': ['FL', '1', 'PrimaryPositionerIncrement'],\n '9515': ['FL', '1', 'SecondaryPositionerIncrement'],\n '9516': ['DT', '1', 'StartAcquisitionDateTime'],\n '9517': ['DT', '1', 'EndAcquisitionDateTime'],\n '9518': ['SS', '1', 'PrimaryPositionerIncrementSign'],\n '9519': ['SS', '1', 'SecondaryPositionerIncrementSign'],\n '9524': ['LO', '1', 'ApplicationName'],\n '9525': ['LO', '1', 'ApplicationVersion'],\n '9526': ['LO', '1', 'ApplicationManufacturer'],\n '9527': ['CS', '1', 'AlgorithmType'],\n '9528': ['LO', '1', 'AlgorithmDescription'],\n '9530': ['SQ', '1', 'XRay3DReconstructionSequence'],\n '9531': ['LO', '1', 'ReconstructionDescription'],\n '9538': ['SQ', '1', 'PerProjectionAcquisitionSequence'],\n '9541': ['SQ', '1', 'DetectorPositionSequence'],\n '9542': ['SQ', '1', 'XRayAcquisitionDoseSequence'],\n '9543': ['FD', '1', 'XRaySourceIsocenterPrimaryAngle'],\n '9544': ['FD', '1', 'XRaySourceIsocenterSecondaryAngle'],\n '9545': ['FD', '1', 'BreastSupportIsocenterPrimaryAngle'],\n '9546': ['FD', '1', 'BreastSupportIsocenterSecondaryAngle'],\n '9547': ['FD', '1', 'BreastSupportXPositionToIsocenter'],\n '9548': ['FD', '1', 'BreastSupportYPositionToIsocenter'],\n '9549': ['FD', '1', 'BreastSupportZPositionToIsocenter'],\n '9550': ['FD', '1', 'DetectorIsocenterPrimaryAngle'],\n '9551': ['FD', '1', 'DetectorIsocenterSecondaryAngle'],\n '9552': ['FD', '1', 'DetectorXPositionToIsocenter'],\n '9553': ['FD', '1', 'DetectorYPositionToIsocenter'],\n '9554': ['FD', '1', 'DetectorZPositionToIsocenter'],\n '9555': ['SQ', '1', 'XRayGridSequence'],\n '9556': ['SQ', '1', 'XRayFilterSequence'],\n '9557': ['FD', '3', 'DetectorActiveAreaTLHCPosition'],\n '9558': ['FD', '6', 'DetectorActiveAreaOrientation'],\n '9559': ['CS', '1', 'PositionerPrimaryAngleDirection'],\n '9601': ['SQ', '1', 'DiffusionBMatrixSequence'],\n '9602': ['FD', '1', 'DiffusionBValueXX'],\n '9603': ['FD', '1', 'DiffusionBValueXY'],\n '9604': ['FD', '1', 'DiffusionBValueXZ'],\n '9605': ['FD', '1', 'DiffusionBValueYY'],\n '9606': ['FD', '1', 'DiffusionBValueYZ'],\n '9607': ['FD', '1', 'DiffusionBValueZZ'],\n '9621': ['SQ', '1', 'FunctionalMRSequence'],\n '9622': ['CS', '1', 'FunctionalSettlingPhaseFramesPresent'],\n '9623': ['DT', '1', 'FunctionalSyncPulse'],\n '9624': ['CS', '1', 'SettlingPhaseFrame'],\n '9701': ['DT', '1', 'DecayCorrectionDateTime'],\n '9715': ['FD', '1', 'StartDensityThreshold'],\n '9716': ['FD', '1', 'StartRelativeDensityDifferenceThreshold'],\n '9717': ['FD', '1', 'StartCardiacTriggerCountThreshold'],\n '9718': ['FD', '1', 'StartRespiratoryTriggerCountThreshold'],\n '9719': ['FD', '1', 'TerminationCountsThreshold'],\n '9720': ['FD', '1', 'TerminationDensityThreshold'],\n '9721': ['FD', '1', 'TerminationRelativeDensityThreshold'],\n '9722': ['FD', '1', 'TerminationTimeThreshold'],\n '9723': ['FD', '1', 'TerminationCardiacTriggerCountThreshold'],\n '9724': ['FD', '1', 'TerminationRespiratoryTriggerCountThreshold'],\n '9725': ['CS', '1', 'DetectorGeometry'],\n '9726': ['FD', '1', 'TransverseDetectorSeparation'],\n '9727': ['FD', '1', 'AxialDetectorDimension'],\n '9729': ['US', '1', 'RadiopharmaceuticalAgentNumber'],\n '9732': ['SQ', '1', 'PETFrameAcquisitionSequence'],\n '9733': ['SQ', '1', 'PETDetectorMotionDetailsSequence'],\n '9734': ['SQ', '1', 'PETTableDynamicsSequence'],\n '9735': ['SQ', '1', 'PETPositionSequence'],\n '9736': ['SQ', '1', 'PETFrameCorrectionFactorsSequence'],\n '9737': ['SQ', '1', 'RadiopharmaceuticalUsageSequence'],\n '9738': ['CS', '1', 'AttenuationCorrectionSource'],\n '9739': ['US', '1', 'NumberOfIterations'],\n '9740': ['US', '1', 'NumberOfSubsets'],\n '9749': ['SQ', '1', 'PETReconstructionSequence'],\n '9751': ['SQ', '1', 'PETFrameTypeSequence'],\n '9755': ['CS', '1', 'TimeOfFlightInformationUsed'],\n '9756': ['CS', '1', 'ReconstructionType'],\n '9758': ['CS', '1', 'DecayCorrected'],\n '9759': ['CS', '1', 'AttenuationCorrected'],\n '9760': ['CS', '1', 'ScatterCorrected'],\n '9761': ['CS', '1', 'DeadTimeCorrected'],\n '9762': ['CS', '1', 'GantryMotionCorrected'],\n '9763': ['CS', '1', 'PatientMotionCorrected'],\n '9764': ['CS', '1', 'CountLossNormalizationCorrected'],\n '9765': ['CS', '1', 'RandomsCorrected'],\n '9766': ['CS', '1', 'NonUniformRadialSamplingCorrected'],\n '9767': ['CS', '1', 'SensitivityCalibrated'],\n '9768': ['CS', '1', 'DetectorNormalizationCorrection'],\n '9769': ['CS', '1', 'IterativeReconstructionMethod'],\n '9770': ['CS', '1', 'AttenuationCorrectionTemporalRelationship'],\n '9771': ['SQ', '1', 'PatientPhysiologicalStateSequence'],\n '9772': ['SQ', '1', 'PatientPhysiologicalStateCodeSequence'],\n '9801': ['FD', '1-n', 'DepthsOfFocus'],\n '9803': ['SQ', '1', 'ExcludedIntervalsSequence'],\n '9804': ['DT', '1', 'ExclusionStartDateTime'],\n '9805': ['FD', '1', 'ExclusionDuration'],\n '9806': ['SQ', '1', 'USImageDescriptionSequence'],\n '9807': ['SQ', '1', 'ImageDataTypeSequence'],\n '9808': ['CS', '1', 'DataType'],\n '9809': ['SQ', '1', 'TransducerScanPatternCodeSequence'],\n '980B': ['CS', '1', 'AliasedDataType'],\n '980C': ['CS', '1', 'PositionMeasuringDeviceUsed'],\n '980D': ['SQ', '1', 'TransducerGeometryCodeSequence'],\n '980E': ['SQ', '1', 'TransducerBeamSteeringCodeSequence'],\n '980F': ['SQ', '1', 'TransducerApplicationCodeSequence'],\n '9810': ['xs', '1', 'ZeroVelocityPixelValue'],\n '9900': ['LO', '1', 'ReferenceLocationLabel'],\n '9901': ['UT', '1', 'ReferenceLocationDescription'],\n '9902': ['SQ', '1', 'ReferenceBasisCodeSequence'],\n '9903': ['SQ', '1', 'ReferenceGeometryCodeSequence'],\n '9904': ['DS', '1', 'OffsetDistance'],\n '9905': ['CS', '1', 'OffsetDirection'],\n '9906': ['SQ', '1', 'PotentialScheduledProtocolCodeSequence'],\n '9907': ['SQ', '1', 'PotentialRequestedProcedureCodeSequence'],\n '9908': ['UC', '1-n', 'PotentialReasonsForProcedure'],\n '9909': ['SQ', '1', 'PotentialReasonsForProcedureCodeSequence'],\n '990A': ['UC', '1-n', 'PotentialDiagnosticTasks'],\n '990B': ['SQ', '1', 'ContraindicationsCodeSequence'],\n '990C': ['SQ', '1', 'ReferencedDefinedProtocolSequence'],\n '990D': ['SQ', '1', 'ReferencedPerformedProtocolSequence'],\n '990E': ['SQ', '1', 'PredecessorProtocolSequence'],\n '990F': ['UT', '1', 'ProtocolPlanningInformation'],\n '9910': ['UT', '1', 'ProtocolDesignRationale'],\n '9911': ['SQ', '1', 'PatientSpecificationSequence'],\n '9912': ['SQ', '1', 'ModelSpecificationSequence'],\n '9913': ['SQ', '1', 'ParametersSpecificationSequence'],\n '9914': ['SQ', '1', 'InstructionSequence'],\n '9915': ['US', '1', 'InstructionIndex'],\n '9916': ['LO', '1', 'InstructionText'],\n '9917': ['UT', '1', 'InstructionDescription'],\n '9918': ['CS', '1', 'InstructionPerformedFlag'],\n '9919': ['DT', '1', 'InstructionPerformedDateTime'],\n '991A': ['UT', '1', 'InstructionPerformanceComment'],\n '991B': ['SQ', '1', 'PatientPositioningInstructionSequence'],\n '991C': ['SQ', '1', 'PositioningMethodCodeSequence'],\n '991D': ['SQ', '1', 'PositioningLandmarkSequence'],\n '991E': ['UI', '1', 'TargetFrameOfReferenceUID'],\n '991F': ['SQ', '1', 'AcquisitionProtocolElementSpecificationSequence'],\n '9920': ['SQ', '1', 'AcquisitionProtocolElementSequence'],\n '9921': ['US', '1', 'ProtocolElementNumber'],\n '9922': ['LO', '1', 'ProtocolElementName'],\n '9923': ['UT', '1', 'ProtocolElementCharacteristicsSummary'],\n '9924': ['UT', '1', 'ProtocolElementPurpose'],\n '9930': ['CS', '1', 'AcquisitionMotion'],\n '9931': ['SQ', '1', 'AcquisitionStartLocationSequence'],\n '9932': ['SQ', '1', 'AcquisitionEndLocationSequence'],\n '9933': ['SQ', '1', 'ReconstructionProtocolElementSpecificationSequence'],\n '9934': ['SQ', '1', 'ReconstructionProtocolElementSequence'],\n '9935': ['SQ', '1', 'StorageProtocolElementSpecificationSequence'],\n '9936': ['SQ', '1', 'StorageProtocolElementSequence'],\n '9937': ['LO', '1', 'RequestedSeriesDescription'],\n '9938': ['US', '1-n', 'SourceAcquisitionProtocolElementNumber'],\n '9939': ['US', '1-n', 'SourceAcquisitionBeamNumber'],\n '993A': ['US', '1-n', 'SourceReconstructionProtocolElementNumber'],\n '993B': ['SQ', '1', 'ReconstructionStartLocationSequence'],\n '993C': ['SQ', '1', 'ReconstructionEndLocationSequence'],\n '993D': ['SQ', '1', 'ReconstructionAlgorithmSequence'],\n '993E': ['SQ', '1', 'ReconstructionTargetCenterLocationSequence'],\n '9941': ['UT', '1', 'ImageFilterDescription'],\n '9942': ['FD', '1', 'CTDIvolNotificationTrigger'],\n '9943': ['FD', '1', 'DLPNotificationTrigger'],\n '9944': ['CS', '1', 'AutoKVPSelectionType'],\n '9945': ['FD', '1', 'AutoKVPUpperBound'],\n '9946': ['FD', '1', 'AutoKVPLowerBound'],\n '9947': ['CS', '1', 'ProtocolDefinedPatientPosition'],\n 'A001': ['SQ', '1', 'ContributingEquipmentSequence'],\n 'A002': ['DT', '1', 'ContributionDateTime'],\n 'A003': ['ST', '1', 'ContributionDescription']\n },\n '0020': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '000D': ['UI', '1', 'StudyInstanceUID'],\n '000E': ['UI', '1', 'SeriesInstanceUID'],\n '0010': ['SH', '1', 'StudyID'],\n '0011': ['IS', '1', 'SeriesNumber'],\n '0012': ['IS', '1', 'AcquisitionNumber'],\n '0013': ['IS', '1', 'InstanceNumber'],\n '0014': ['IS', '1', 'IsotopeNumber'],\n '0015': ['IS', '1', 'PhaseNumber'],\n '0016': ['IS', '1', 'IntervalNumber'],\n '0017': ['IS', '1', 'TimeSlotNumber'],\n '0018': ['IS', '1', 'AngleNumber'],\n '0019': ['IS', '1', 'ItemNumber'],\n '0020': ['CS', '2', 'PatientOrientation'],\n '0022': ['IS', '1', 'OverlayNumber'],\n '0024': ['IS', '1', 'CurveNumber'],\n '0026': ['IS', '1', 'LUTNumber'],\n '0030': ['DS', '3', 'ImagePosition'],\n '0032': ['DS', '3', 'ImagePositionPatient'],\n '0035': ['DS', '6', 'ImageOrientation'],\n '0037': ['DS', '6', 'ImageOrientationPatient'],\n '0050': ['DS', '1', 'Location'],\n '0052': ['UI', '1', 'FrameOfReferenceUID'],\n '0060': ['CS', '1', 'Laterality'],\n '0062': ['CS', '1', 'ImageLaterality'],\n '0070': ['LO', '1', 'ImageGeometryType'],\n '0080': ['CS', '1-n', 'MaskingImage'],\n '00AA': ['IS', '1', 'ReportNumber'],\n '0100': ['IS', '1', 'TemporalPositionIdentifier'],\n '0105': ['IS', '1', 'NumberOfTemporalPositions'],\n '0110': ['DS', '1', 'TemporalResolution'],\n '0200': ['UI', '1', 'SynchronizationFrameOfReferenceUID'],\n '0242': ['UI', '1', 'SOPInstanceUIDOfConcatenationSource'],\n '1000': ['IS', '1', 'SeriesInStudy'],\n '1001': ['IS', '1', 'AcquisitionsInSeries'],\n '1002': ['IS', '1', 'ImagesInAcquisition'],\n '1003': ['IS', '1', 'ImagesInSeries'],\n '1004': ['IS', '1', 'AcquisitionsInStudy'],\n '1005': ['IS', '1', 'ImagesInStudy'],\n '1020': ['LO', '1-n', 'Reference'],\n '103F': ['LO', '1', 'TargetPositionReferenceIndicator'],\n '1040': ['LO', '1', 'PositionReferenceIndicator'],\n '1041': ['DS', '1', 'SliceLocation'],\n '1070': ['IS', '1-n', 'OtherStudyNumbers'],\n '1200': ['IS', '1', 'NumberOfPatientRelatedStudies'],\n '1202': ['IS', '1', 'NumberOfPatientRelatedSeries'],\n '1204': ['IS', '1', 'NumberOfPatientRelatedInstances'],\n '1206': ['IS', '1', 'NumberOfStudyRelatedSeries'],\n '1208': ['IS', '1', 'NumberOfStudyRelatedInstances'],\n '1209': ['IS', '1', 'NumberOfSeriesRelatedInstances'],\n '3100': ['CS', '1-n', 'SourceImageIDs'],\n '3401': ['CS', '1', 'ModifyingDeviceID'],\n '3402': ['CS', '1', 'ModifiedImageID'],\n '3403': ['DA', '1', 'ModifiedImageDate'],\n '3404': ['LO', '1', 'ModifyingDeviceManufacturer'],\n '3405': ['TM', '1', 'ModifiedImageTime'],\n '3406': ['LO', '1', 'ModifiedImageDescription'],\n '4000': ['LT', '1', 'ImageComments'],\n '5000': ['AT', '1-n', 'OriginalImageIdentification'],\n '5002': ['LO', '1-n', 'OriginalImageIdentificationNomenclature'],\n '9056': ['SH', '1', 'StackID'],\n '9057': ['UL', '1', 'InStackPositionNumber'],\n '9071': ['SQ', '1', 'FrameAnatomySequence'],\n '9072': ['CS', '1', 'FrameLaterality'],\n '9111': ['SQ', '1', 'FrameContentSequence'],\n '9113': ['SQ', '1', 'PlanePositionSequence'],\n '9116': ['SQ', '1', 'PlaneOrientationSequence'],\n '9128': ['UL', '1', 'TemporalPositionIndex'],\n '9153': ['FD', '1', 'NominalCardiacTriggerDelayTime'],\n '9154': ['FL', '1', 'NominalCardiacTriggerTimePriorToRPeak'],\n '9155': ['FL', '1', 'ActualCardiacTriggerTimePriorToRPeak'],\n '9156': ['US', '1', 'FrameAcquisitionNumber'],\n '9157': ['UL', '1-n', 'DimensionIndexValues'],\n '9158': ['LT', '1', 'FrameComments'],\n '9161': ['UI', '1', 'ConcatenationUID'],\n '9162': ['US', '1', 'InConcatenationNumber'],\n '9163': ['US', '1', 'InConcatenationTotalNumber'],\n '9164': ['UI', '1', 'DimensionOrganizationUID'],\n '9165': ['AT', '1', 'DimensionIndexPointer'],\n '9167': ['AT', '1', 'FunctionalGroupPointer'],\n '9170': ['SQ', '1', 'UnassignedSharedConvertedAttributesSequence'],\n '9171': ['SQ', '1', 'UnassignedPerFrameConvertedAttributesSequence'],\n '9172': ['SQ', '1', 'ConversionSourceAttributesSequence'],\n '9213': ['LO', '1', 'DimensionIndexPrivateCreator'],\n '9221': ['SQ', '1', 'DimensionOrganizationSequence'],\n '9222': ['SQ', '1', 'DimensionIndexSequence'],\n '9228': ['UL', '1', 'ConcatenationFrameOffsetNumber'],\n '9238': ['LO', '1', 'FunctionalGroupPrivateCreator'],\n '9241': ['FL', '1', 'NominalPercentageOfCardiacPhase'],\n '9245': ['FL', '1', 'NominalPercentageOfRespiratoryPhase'],\n '9246': ['FL', '1', 'StartingRespiratoryAmplitude'],\n '9247': ['CS', '1', 'StartingRespiratoryPhase'],\n '9248': ['FL', '1', 'EndingRespiratoryAmplitude'],\n '9249': ['CS', '1', 'EndingRespiratoryPhase'],\n '9250': ['CS', '1', 'RespiratoryTriggerType'],\n '9251': ['FD', '1', 'RRIntervalTimeNominal'],\n '9252': ['FD', '1', 'ActualCardiacTriggerDelayTime'],\n '9253': ['SQ', '1', 'RespiratorySynchronizationSequence'],\n '9254': ['FD', '1', 'RespiratoryIntervalTime'],\n '9255': ['FD', '1', 'NominalRespiratoryTriggerDelayTime'],\n '9256': ['FD', '1', 'RespiratoryTriggerDelayThreshold'],\n '9257': ['FD', '1', 'ActualRespiratoryTriggerDelayTime'],\n '9301': ['FD', '3', 'ImagePositionVolume'],\n '9302': ['FD', '6', 'ImageOrientationVolume'],\n '9307': ['CS', '1', 'UltrasoundAcquisitionGeometry'],\n '9308': ['FD', '3', 'ApexPosition'],\n '9309': ['FD', '16', 'VolumeToTransducerMappingMatrix'],\n '930A': ['FD', '16', 'VolumeToTableMappingMatrix'],\n '930B': ['CS', '1', 'VolumeToTransducerRelationship'],\n '930C': ['CS', '1', 'PatientFrameOfReferenceSource'],\n '930D': ['FD', '1', 'TemporalPositionTimeOffset'],\n '930E': ['SQ', '1', 'PlanePositionVolumeSequence'],\n '930F': ['SQ', '1', 'PlaneOrientationVolumeSequence'],\n '9310': ['SQ', '1', 'TemporalPositionSequence'],\n '9311': ['CS', '1', 'DimensionOrganizationType'],\n '9312': ['UI', '1', 'VolumeFrameOfReferenceUID'],\n '9313': ['UI', '1', 'TableFrameOfReferenceUID'],\n '9421': ['LO', '1', 'DimensionDescriptionLabel'],\n '9450': ['SQ', '1', 'PatientOrientationInFrameSequence'],\n '9453': ['LO', '1', 'FrameLabel'],\n '9518': ['US', '1-n', 'AcquisitionIndex'],\n '9529': ['SQ', '1', 'ContributingSOPInstancesReferenceSequence'],\n '9536': ['US', '1', 'ReconstructionIndex']\n },\n '0022': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['US', '1', 'LightPathFilterPassThroughWavelength'],\n '0002': ['US', '2', 'LightPathFilterPassBand'],\n '0003': ['US', '1', 'ImagePathFilterPassThroughWavelength'],\n '0004': ['US', '2', 'ImagePathFilterPassBand'],\n '0005': ['CS', '1', 'PatientEyeMovementCommanded'],\n '0006': ['SQ', '1', 'PatientEyeMovementCommandCodeSequence'],\n '0007': ['FL', '1', 'SphericalLensPower'],\n '0008': ['FL', '1', 'CylinderLensPower'],\n '0009': ['FL', '1', 'CylinderAxis'],\n '000A': ['FL', '1', 'EmmetropicMagnification'],\n '000B': ['FL', '1', 'IntraOcularPressure'],\n '000C': ['FL', '1', 'HorizontalFieldOfView'],\n '000D': ['CS', '1', 'PupilDilated'],\n '000E': ['FL', '1', 'DegreeOfDilation'],\n '0010': ['FL', '1', 'StereoBaselineAngle'],\n '0011': ['FL', '1', 'StereoBaselineDisplacement'],\n '0012': ['FL', '1', 'StereoHorizontalPixelOffset'],\n '0013': ['FL', '1', 'StereoVerticalPixelOffset'],\n '0014': ['FL', '1', 'StereoRotation'],\n '0015': ['SQ', '1', 'AcquisitionDeviceTypeCodeSequence'],\n '0016': ['SQ', '1', 'IlluminationTypeCodeSequence'],\n '0017': ['SQ', '1', 'LightPathFilterTypeStackCodeSequence'],\n '0018': ['SQ', '1', 'ImagePathFilterTypeStackCodeSequence'],\n '0019': ['SQ', '1', 'LensesCodeSequence'],\n '001A': ['SQ', '1', 'ChannelDescriptionCodeSequence'],\n '001B': ['SQ', '1', 'RefractiveStateSequence'],\n '001C': ['SQ', '1', 'MydriaticAgentCodeSequence'],\n '001D': ['SQ', '1', 'RelativeImagePositionCodeSequence'],\n '001E': ['FL', '1', 'CameraAngleOfView'],\n '0020': ['SQ', '1', 'StereoPairsSequence'],\n '0021': ['SQ', '1', 'LeftImageSequence'],\n '0022': ['SQ', '1', 'RightImageSequence'],\n '0028': ['CS', '1', 'StereoPairsPresent'],\n '0030': ['FL', '1', 'AxialLengthOfTheEye'],\n '0031': ['SQ', '1', 'OphthalmicFrameLocationSequence'],\n '0032': ['FL', '2-2n', 'ReferenceCoordinates'],\n '0035': ['FL', '1', 'DepthSpatialResolution'],\n '0036': ['FL', '1', 'MaximumDepthDistortion'],\n '0037': ['FL', '1', 'AlongScanSpatialResolution'],\n '0038': ['FL', '1', 'MaximumAlongScanDistortion'],\n '0039': ['CS', '1', 'OphthalmicImageOrientation'],\n '0041': ['FL', '1', 'DepthOfTransverseImage'],\n '0042': ['SQ', '1', 'MydriaticAgentConcentrationUnitsSequence'],\n '0048': ['FL', '1', 'AcrossScanSpatialResolution'],\n '0049': ['FL', '1', 'MaximumAcrossScanDistortion'],\n '004E': ['DS', '1', 'MydriaticAgentConcentration'],\n '0055': ['FL', '1', 'IlluminationWaveLength'],\n '0056': ['FL', '1', 'IlluminationPower'],\n '0057': ['FL', '1', 'IlluminationBandwidth'],\n '0058': ['SQ', '1', 'MydriaticAgentSequence'],\n '1007': ['SQ', '1', 'OphthalmicAxialMeasurementsRightEyeSequence'],\n '1008': ['SQ', '1', 'OphthalmicAxialMeasurementsLeftEyeSequence'],\n '1009': ['CS', '1', 'OphthalmicAxialMeasurementsDeviceType'],\n '1010': ['CS', '1', 'OphthalmicAxialLengthMeasurementsType'],\n '1012': ['SQ', '1', 'OphthalmicAxialLengthSequence'],\n '1019': ['FL', '1', 'OphthalmicAxialLength'],\n '1024': ['SQ', '1', 'LensStatusCodeSequence'],\n '1025': ['SQ', '1', 'VitreousStatusCodeSequence'],\n '1028': ['SQ', '1', 'IOLFormulaCodeSequence'],\n '1029': ['LO', '1', 'IOLFormulaDetail'],\n '1033': ['FL', '1', 'KeratometerIndex'],\n '1035': ['SQ', '1', 'SourceOfOphthalmicAxialLengthCodeSequence'],\n '1036': ['SQ', '1', 'SourceOfCornealSizeDataCodeSequence'],\n '1037': ['FL', '1', 'TargetRefraction'],\n '1039': ['CS', '1', 'RefractiveProcedureOccurred'],\n '1040': ['SQ', '1', 'RefractiveSurgeryTypeCodeSequence'],\n '1044': ['SQ', '1', 'OphthalmicUltrasoundMethodCodeSequence'],\n '1045': ['SQ', '1', 'SurgicallyInducedAstigmatismSequence'],\n '1046': ['CS', '1', 'TypeOfOpticalCorrection'],\n '1047': ['SQ', '1', 'ToricIOLPowerSequence'],\n '1048': ['SQ', '1', 'PredictedToricErrorSequence'],\n '1049': ['CS', '1', 'PreSelectedForImplantation'],\n '104A': ['SQ', '1', 'ToricIOLPowerForExactEmmetropiaSequence'],\n '104B': ['SQ', '1', 'ToricIOLPowerForExactTargetRefractionSequence'],\n '1050': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsSequence'],\n '1053': ['FL', '1', 'IOLPower'],\n '1054': ['FL', '1', 'PredictedRefractiveError'],\n '1059': ['FL', '1', 'OphthalmicAxialLengthVelocity'],\n '1065': ['LO', '1', 'LensStatusDescription'],\n '1066': ['LO', '1', 'VitreousStatusDescription'],\n '1090': ['SQ', '1', 'IOLPowerSequence'],\n '1092': ['SQ', '1', 'LensConstantSequence'],\n '1093': ['LO', '1', 'IOLManufacturer'],\n '1094': ['LO', '1', 'LensConstantDescription'],\n '1095': ['LO', '1', 'ImplantName'],\n '1096': ['SQ', '1', 'KeratometryMeasurementTypeCodeSequence'],\n '1097': ['LO', '1', 'ImplantPartNumber'],\n '1100': ['SQ', '1', 'ReferencedOphthalmicAxialMeasurementsSequence'],\n '1101': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsSegmentNameCodeSequence'],\n '1103': ['SQ', '1', 'RefractiveErrorBeforeRefractiveSurgeryCodeSequence'],\n '1121': ['FL', '1', 'IOLPowerForExactEmmetropia'],\n '1122': ['FL', '1', 'IOLPowerForExactTargetRefraction'],\n '1125': ['SQ', '1', 'AnteriorChamberDepthDefinitionCodeSequence'],\n '1127': ['SQ', '1', 'LensThicknessSequence'],\n '1128': ['SQ', '1', 'AnteriorChamberDepthSequence'],\n '112A': ['SQ', '1', 'CalculationCommentSequence'],\n '112B': ['CS', '1', 'CalculationCommentType'],\n '112C': ['LT', '1', 'CalculationComment'],\n '1130': ['FL', '1', 'LensThickness'],\n '1131': ['FL', '1', 'AnteriorChamberDepth'],\n '1132': ['SQ', '1', 'SourceOfLensThicknessDataCodeSequence'],\n '1133': ['SQ', '1', 'SourceOfAnteriorChamberDepthDataCodeSequence'],\n '1134': ['SQ', '1', 'SourceOfRefractiveMeasurementsSequence'],\n '1135': ['SQ', '1', 'SourceOfRefractiveMeasurementsCodeSequence'],\n '1140': ['CS', '1', 'OphthalmicAxialLengthMeasurementModified'],\n '1150': ['SQ', '1', 'OphthalmicAxialLengthDataSourceCodeSequence'],\n '1153': ['SQ', '1', 'OphthalmicAxialLengthAcquisitionMethodCodeSequence'],\n '1155': ['FL', '1', 'SignalToNoiseRatio'],\n '1159': ['LO', '1', 'OphthalmicAxialLengthDataSourceDescription'],\n '1210': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsTotalLengthSequence'],\n '1211': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsSegmentalLengthSequence'],\n '1212': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsLengthSummationSequence'],\n '1220': ['SQ', '1', 'UltrasoundOphthalmicAxialLengthMeasurementsSequence'],\n '1225': ['SQ', '1', 'OpticalOphthalmicAxialLengthMeasurementsSequence'],\n '1230': ['SQ', '1', 'UltrasoundSelectedOphthalmicAxialLengthSequence'],\n '1250': ['SQ', '1', 'OphthalmicAxialLengthSelectionMethodCodeSequence'],\n '1255': ['SQ', '1', 'OpticalSelectedOphthalmicAxialLengthSequence'],\n '1257': ['SQ', '1', 'SelectedSegmentalOphthalmicAxialLengthSequence'],\n '1260': ['SQ', '1', 'SelectedTotalOphthalmicAxialLengthSequence'],\n '1262': ['SQ', '1', 'OphthalmicAxialLengthQualityMetricSequence'],\n '1265': ['SQ', '1', 'OphthalmicAxialLengthQualityMetricTypeCodeSequence'],\n '1273': ['LO', '1', 'OphthalmicAxialLengthQualityMetricTypeDescription'],\n '1300': ['SQ', '1', 'IntraocularLensCalculationsRightEyeSequence'],\n '1310': ['SQ', '1', 'IntraocularLensCalculationsLeftEyeSequence'],\n '1330': ['SQ', '1', 'ReferencedOphthalmicAxialLengthMeasurementQCImageSequence'],\n '1415': ['CS', '1', 'OphthalmicMappingDeviceType'],\n '1420': ['SQ', '1', 'AcquisitionMethodCodeSequence'],\n '1423': ['SQ', '1', 'AcquisitionMethodAlgorithmSequence'],\n '1436': ['SQ', '1', 'OphthalmicThicknessMapTypeCodeSequence'],\n '1443': ['SQ', '1', 'OphthalmicThicknessMappingNormalsSequence'],\n '1445': ['SQ', '1', 'RetinalThicknessDefinitionCodeSequence'],\n '1450': ['SQ', '1', 'PixelValueMappingToCodedConceptSequence'],\n '1452': ['xs', '1', 'MappedPixelValue'],\n '1454': ['LO', '1', 'PixelValueMappingExplanation'],\n '1458': ['SQ', '1', 'OphthalmicThicknessMapQualityThresholdSequence'],\n '1460': ['FL', '1', 'OphthalmicThicknessMapThresholdQualityRating'],\n '1463': ['FL', '2', 'AnatomicStructureReferencePoint'],\n '1465': ['SQ', '1', 'RegistrationToLocalizerSequence'],\n '1466': ['CS', '1', 'RegisteredLocalizerUnits'],\n '1467': ['FL', '2', 'RegisteredLocalizerTopLeftHandCorner'],\n '1468': ['FL', '2', 'RegisteredLocalizerBottomRightHandCorner'],\n '1470': ['SQ', '1', 'OphthalmicThicknessMapQualityRatingSequence'],\n '1472': ['SQ', '1', 'RelevantOPTAttributesSequence'],\n '1512': ['SQ', '1', 'TransformationMethodCodeSequence'],\n '1513': ['SQ', '1', 'TransformationAlgorithmSequence'],\n '1515': ['CS', '1', 'OphthalmicAxialLengthMethod'],\n '1517': ['FL', '1', 'OphthalmicFOV'],\n '1518': ['SQ', '1', 'TwoDimensionalToThreeDimensionalMapSequence'],\n '1525': ['SQ', '1', 'WideFieldOphthalmicPhotographyQualityRatingSequence'],\n '1526': ['SQ', '1', 'WideFieldOphthalmicPhotographyQualityThresholdSequence'],\n '1527': ['FL', '1', 'WideFieldOphthalmicPhotographyThresholdQualityRating'],\n '1528': ['FL', '1', 'XCoordinatesCenterPixelViewAngle'],\n '1529': ['FL', '1', 'YCoordinatesCenterPixelViewAngle'],\n '1530': ['UL', '1', 'NumberOfMapPoints'],\n '1531': ['OF', '1', 'TwoDimensionalToThreeDimensionalMapData'],\n '1612': ['SQ', '1', 'DerivationAlgorithmSequence'],\n '1615': ['SQ', '1', 'OphthalmicImageTypeCodeSequence'],\n '1616': ['LO', '1', 'OphthalmicImageTypeDescription'],\n '1618': ['SQ', '1', 'ScanPatternTypeCodeSequence'],\n '1620': ['SQ', '1', 'ReferencedSurfaceMeshIdentificationSequence'],\n '1622': ['CS', '1', 'OphthalmicVolumetricPropertiesFlag'],\n '1624': ['FL', '1', 'OphthalmicAnatomicReferencePointXCoordinate'],\n '1626': ['FL', '1', 'OphthalmicAnatomicReferencePointYCoordinate'],\n '1628': ['SQ', '1', 'OphthalmicEnFaceImageQualityRatingSequence'],\n '1630': ['DS', '1', 'QualityThreshold'],\n '1640': ['SQ', '1', 'OCTBscanAnalysisAcquisitionParametersSequence'],\n '1642': ['UL', '1', 'NumberOfBscansPerFrame'],\n '1643': ['FL', '1', 'BscanSlabThickness'],\n '1644': ['FL', '1', 'DistanceBetweenBscanSlabs'],\n '1645': ['FL', '1', 'BscanCycleTime'],\n '1646': ['FL', '1-n', 'BscanCycleTimeVector'],\n '1649': ['FL', '1', 'AscanRate'],\n '1650': ['FL', '1', 'BscanRate'],\n '1658': ['UL', '1', 'SurfaceMeshZPixelOffset']\n },\n '0024': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['FL', '1', 'VisualFieldHorizontalExtent'],\n '0011': ['FL', '1', 'VisualFieldVerticalExtent'],\n '0012': ['CS', '1', 'VisualFieldShape'],\n '0016': ['SQ', '1', 'ScreeningTestModeCodeSequence'],\n '0018': ['FL', '1', 'MaximumStimulusLuminance'],\n '0020': ['FL', '1', 'BackgroundLuminance'],\n '0021': ['SQ', '1', 'StimulusColorCodeSequence'],\n '0024': ['SQ', '1', 'BackgroundIlluminationColorCodeSequence'],\n '0025': ['FL', '1', 'StimulusArea'],\n '0028': ['FL', '1', 'StimulusPresentationTime'],\n '0032': ['SQ', '1', 'FixationSequence'],\n '0033': ['SQ', '1', 'FixationMonitoringCodeSequence'],\n '0034': ['SQ', '1', 'VisualFieldCatchTrialSequence'],\n '0035': ['US', '1', 'FixationCheckedQuantity'],\n '0036': ['US', '1', 'PatientNotProperlyFixatedQuantity'],\n '0037': ['CS', '1', 'PresentedVisualStimuliDataFlag'],\n '0038': ['US', '1', 'NumberOfVisualStimuli'],\n '0039': ['CS', '1', 'ExcessiveFixationLossesDataFlag'],\n '0040': ['CS', '1', 'ExcessiveFixationLosses'],\n '0042': ['US', '1', 'StimuliRetestingQuantity'],\n '0044': ['LT', '1', 'CommentsOnPatientPerformanceOfVisualField'],\n '0045': ['CS', '1', 'FalseNegativesEstimateFlag'],\n '0046': ['FL', '1', 'FalseNegativesEstimate'],\n '0048': ['US', '1', 'NegativeCatchTrialsQuantity'],\n '0050': ['US', '1', 'FalseNegativesQuantity'],\n '0051': ['CS', '1', 'ExcessiveFalseNegativesDataFlag'],\n '0052': ['CS', '1', 'ExcessiveFalseNegatives'],\n '0053': ['CS', '1', 'FalsePositivesEstimateFlag'],\n '0054': ['FL', '1', 'FalsePositivesEstimate'],\n '0055': ['CS', '1', 'CatchTrialsDataFlag'],\n '0056': ['US', '1', 'PositiveCatchTrialsQuantity'],\n '0057': ['CS', '1', 'TestPointNormalsDataFlag'],\n '0058': ['SQ', '1', 'TestPointNormalsSequence'],\n '0059': ['CS', '1', 'GlobalDeviationProbabilityNormalsFlag'],\n '0060': ['US', '1', 'FalsePositivesQuantity'],\n '0061': ['CS', '1', 'ExcessiveFalsePositivesDataFlag'],\n '0062': ['CS', '1', 'ExcessiveFalsePositives'],\n '0063': ['CS', '1', 'VisualFieldTestNormalsFlag'],\n '0064': ['SQ', '1', 'ResultsNormalsSequence'],\n '0065': ['SQ', '1', 'AgeCorrectedSensitivityDeviationAlgorithmSequence'],\n '0066': ['FL', '1', 'GlobalDeviationFromNormal'],\n '0067': ['SQ', '1', 'GeneralizedDefectSensitivityDeviationAlgorithmSequence'],\n '0068': ['FL', '1', 'LocalizedDeviationFromNormal'],\n '0069': ['LO', '1', 'PatientReliabilityIndicator'],\n '0070': ['FL', '1', 'VisualFieldMeanSensitivity'],\n '0071': ['FL', '1', 'GlobalDeviationProbability'],\n '0072': ['CS', '1', 'LocalDeviationProbabilityNormalsFlag'],\n '0073': ['FL', '1', 'LocalizedDeviationProbability'],\n '0074': ['CS', '1', 'ShortTermFluctuationCalculated'],\n '0075': ['FL', '1', 'ShortTermFluctuation'],\n '0076': ['CS', '1', 'ShortTermFluctuationProbabilityCalculated'],\n '0077': ['FL', '1', 'ShortTermFluctuationProbability'],\n '0078': ['CS', '1', 'CorrectedLocalizedDeviationFromNormalCalculated'],\n '0079': ['FL', '1', 'CorrectedLocalizedDeviationFromNormal'],\n '0080': ['CS', '1', 'CorrectedLocalizedDeviationFromNormalProbabilityCalculated'],\n '0081': ['FL', '1', 'CorrectedLocalizedDeviationFromNormalProbability'],\n '0083': ['SQ', '1', 'GlobalDeviationProbabilitySequence'],\n '0085': ['SQ', '1', 'LocalizedDeviationProbabilitySequence'],\n '0086': ['CS', '1', 'FovealSensitivityMeasured'],\n '0087': ['FL', '1', 'FovealSensitivity'],\n '0088': ['FL', '1', 'VisualFieldTestDuration'],\n '0089': ['SQ', '1', 'VisualFieldTestPointSequence'],\n '0090': ['FL', '1', 'VisualFieldTestPointXCoordinate'],\n '0091': ['FL', '1', 'VisualFieldTestPointYCoordinate'],\n '0092': ['FL', '1', 'AgeCorrectedSensitivityDeviationValue'],\n '0093': ['CS', '1', 'StimulusResults'],\n '0094': ['FL', '1', 'SensitivityValue'],\n '0095': ['CS', '1', 'RetestStimulusSeen'],\n '0096': ['FL', '1', 'RetestSensitivityValue'],\n '0097': ['SQ', '1', 'VisualFieldTestPointNormalsSequence'],\n '0098': ['FL', '1', 'QuantifiedDefect'],\n '0100': ['FL', '1', 'AgeCorrectedSensitivityDeviationProbabilityValue'],\n '0102': ['CS', '1', 'GeneralizedDefectCorrectedSensitivityDeviationFlag'],\n '0103': ['FL', '1', 'GeneralizedDefectCorrectedSensitivityDeviationValue'],\n '0104': ['FL', '1', 'GeneralizedDefectCorrectedSensitivityDeviationProbabilityValue'],\n '0105': ['FL', '1', 'MinimumSensitivityValue'],\n '0106': ['CS', '1', 'BlindSpotLocalized'],\n '0107': ['FL', '1', 'BlindSpotXCoordinate'],\n '0108': ['FL', '1', 'BlindSpotYCoordinate'],\n '0110': ['SQ', '1', 'VisualAcuityMeasurementSequence'],\n '0112': ['SQ', '1', 'RefractiveParametersUsedOnPatientSequence'],\n '0113': ['CS', '1', 'MeasurementLaterality'],\n '0114': ['SQ', '1', 'OphthalmicPatientClinicalInformationLeftEyeSequence'],\n '0115': ['SQ', '1', 'OphthalmicPatientClinicalInformationRightEyeSequence'],\n '0117': ['CS', '1', 'FovealPointNormativeDataFlag'],\n '0118': ['FL', '1', 'FovealPointProbabilityValue'],\n '0120': ['CS', '1', 'ScreeningBaselineMeasured'],\n '0122': ['SQ', '1', 'ScreeningBaselineMeasuredSequence'],\n '0124': ['CS', '1', 'ScreeningBaselineType'],\n '0126': ['FL', '1', 'ScreeningBaselineValue'],\n '0202': ['LO', '1', 'AlgorithmSource'],\n '0306': ['LO', '1', 'DataSetName'],\n '0307': ['LO', '1', 'DataSetVersion'],\n '0308': ['LO', '1', 'DataSetSource'],\n '0309': ['LO', '1', 'DataSetDescription'],\n '0317': ['SQ', '1', 'VisualFieldTestReliabilityGlobalIndexSequence'],\n '0320': ['SQ', '1', 'VisualFieldGlobalResultsIndexSequence'],\n '0325': ['SQ', '1', 'DataObservationSequence'],\n '0338': ['CS', '1', 'IndexNormalsFlag'],\n '0341': ['FL', '1', 'IndexProbability'],\n '0344': ['SQ', '1', 'IndexProbabilitySequence']\n },\n '0028': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['US', '1', 'SamplesPerPixel'],\n '0003': ['US', '1', 'SamplesPerPixelUsed'],\n '0004': ['CS', '1', 'PhotometricInterpretation'],\n '0005': ['US', '1', 'ImageDimensions'],\n '0006': ['US', '1', 'PlanarConfiguration'],\n '0008': ['IS', '1', 'NumberOfFrames'],\n '0009': ['AT', '1-n', 'FrameIncrementPointer'],\n '000A': ['AT', '1-n', 'FrameDimensionPointer'],\n '0010': ['US', '1', 'Rows'],\n '0011': ['US', '1', 'Columns'],\n '0012': ['US', '1', 'Planes'],\n '0014': ['US', '1', 'UltrasoundColorDataPresent'],\n '0020': ['', '', ''],\n '0030': ['DS', '2', 'PixelSpacing'],\n '0031': ['DS', '2', 'ZoomFactor'],\n '0032': ['DS', '2', 'ZoomCenter'],\n '0034': ['IS', '2', 'PixelAspectRatio'],\n '0040': ['CS', '1', 'ImageFormat'],\n '0050': ['LO', '1-n', 'ManipulatedImage'],\n '0051': ['CS', '1-n', 'CorrectedImage'],\n '005F': ['LO', '1', 'CompressionRecognitionCode'],\n '0060': ['CS', '1', 'CompressionCode'],\n '0061': ['SH', '1', 'CompressionOriginator'],\n '0062': ['LO', '1', 'CompressionLabel'],\n '0063': ['SH', '1', 'CompressionDescription'],\n '0065': ['CS', '1-n', 'CompressionSequence'],\n '0066': ['AT', '1-n', 'CompressionStepPointers'],\n '0068': ['US', '1', 'RepeatInterval'],\n '0069': ['US', '1', 'BitsGrouped'],\n '0070': ['US', '1-n', 'PerimeterTable'],\n '0071': ['xs', '1', 'PerimeterValue'],\n '0080': ['US', '1', 'PredictorRows'],\n '0081': ['US', '1', 'PredictorColumns'],\n '0082': ['US', '1-n', 'PredictorConstants'],\n '0090': ['CS', '1', 'BlockedPixels'],\n '0091': ['US', '1', 'BlockRows'],\n '0092': ['US', '1', 'BlockColumns'],\n '0093': ['US', '1', 'RowOverlap'],\n '0094': ['US', '1', 'ColumnOverlap'],\n '0100': ['US', '1', 'BitsAllocated'],\n '0101': ['US', '1', 'BitsStored'],\n '0102': ['US', '1', 'HighBit'],\n '0103': ['US', '1', 'PixelRepresentation'],\n '0104': ['xs', '1', 'SmallestValidPixelValue'],\n '0105': ['xs', '1', 'LargestValidPixelValue'],\n '0106': ['xs', '1', 'SmallestImagePixelValue'],\n '0107': ['xs', '1', 'LargestImagePixelValue'],\n '0108': ['xs', '1', 'SmallestPixelValueInSeries'],\n '0109': ['xs', '1', 'LargestPixelValueInSeries'],\n '0110': ['xs', '1', 'SmallestImagePixelValueInPlane'],\n '0111': ['xs', '1', 'LargestImagePixelValueInPlane'],\n '0120': ['xs', '1', 'PixelPaddingValue'],\n '0121': ['xs', '1', 'PixelPaddingRangeLimit'],\n '0122': ['FL', '1', 'FloatPixelPaddingValue'],\n '0123': ['FD', '1', 'DoubleFloatPixelPaddingValue'],\n '0124': ['FL', '1', 'FloatPixelPaddingRangeLimit'],\n '0125': ['FD', '1', 'DoubleFloatPixelPaddingRangeLimit'],\n '0200': ['US', '1', 'ImageLocation'],\n '0300': ['CS', '1', 'QualityControlImage'],\n '0301': ['CS', '1', 'BurnedInAnnotation'],\n '0302': ['CS', '1', 'RecognizableVisualFeatures'],\n '0303': ['CS', '1', 'LongitudinalTemporalInformationModified'],\n '0304': ['UI', '1', 'ReferencedColorPaletteInstanceUID'],\n '0400': ['LO', '1', 'TransformLabel'],\n '0401': ['LO', '1', 'TransformVersionNumber'],\n '0402': ['US', '1', 'NumberOfTransformSteps'],\n '0403': ['LO', '1-n', 'SequenceOfCompressedData'],\n '0404': ['AT', '1-n', 'DetailsOfCoefficients'],\n '04x0': ['US', '1', 'RowsForNthOrderCoefficients'],\n '04x1': ['US', '1', 'ColumnsForNthOrderCoefficients'],\n '04x2': ['LO', '1-n', 'CoefficientCoding'],\n '04x3': ['AT', '1-n', 'CoefficientCodingPointers'],\n '0700': ['LO', '1', 'DCTLabel'],\n '0701': ['CS', '1-n', 'DataBlockDescription'],\n '0702': ['AT', '1-n', 'DataBlock'],\n '0710': ['US', '1', 'NormalizationFactorFormat'],\n '0720': ['US', '1', 'ZonalMapNumberFormat'],\n '0721': ['AT', '1-n', 'ZonalMapLocation'],\n '0722': ['US', '1', 'ZonalMapFormat'],\n '0730': ['US', '1', 'AdaptiveMapFormat'],\n '0740': ['US', '1', 'CodeNumberFormat'],\n '08x0': ['CS', '1-n', 'CodeLabel'],\n '08x2': ['US', '1', 'NumberOfTables'],\n '08x3': ['AT', '1-n', 'CodeTableLocation'],\n '08x4': ['US', '1', 'BitsForCodeWord'],\n '08x8': ['AT', '1-n', 'ImageDataLocation'],\n '0A02': ['CS', '1', 'PixelSpacingCalibrationType'],\n '0A04': ['LO', '1', 'PixelSpacingCalibrationDescription'],\n '1040': ['CS', '1', 'PixelIntensityRelationship'],\n '1041': ['SS', '1', 'PixelIntensityRelationshipSign'],\n '1050': ['DS', '1-n', 'WindowCenter'],\n '1051': ['DS', '1-n', 'WindowWidth'],\n '1052': ['DS', '1', 'RescaleIntercept'],\n '1053': ['DS', '1', 'RescaleSlope'],\n '1054': ['LO', '1', 'RescaleType'],\n '1055': ['LO', '1-n', 'WindowCenterWidthExplanation'],\n '1056': ['CS', '1', 'VOILUTFunction'],\n '1080': ['CS', '1', 'GrayScale'],\n '1090': ['CS', '1', 'RecommendedViewingMode'],\n '1100': ['xs', '3', 'GrayLookupTableDescriptor'],\n '1101': ['xs', '3', 'RedPaletteColorLookupTableDescriptor'],\n '1102': ['xs', '3', 'GreenPaletteColorLookupTableDescriptor'],\n '1103': ['xs', '3', 'BluePaletteColorLookupTableDescriptor'],\n '1104': ['US', '3', 'AlphaPaletteColorLookupTableDescriptor'],\n '1111': ['xs', '4', 'LargeRedPaletteColorLookupTableDescriptor'],\n '1112': ['xs', '4', 'LargeGreenPaletteColorLookupTableDescriptor'],\n '1113': ['xs', '4', 'LargeBluePaletteColorLookupTableDescriptor'],\n '1199': ['UI', '1', 'PaletteColorLookupTableUID'],\n '1200': ['xs', '1-n or 1', 'GrayLookupTableData'],\n '1201': ['OW', '1', 'RedPaletteColorLookupTableData'],\n '1202': ['OW', '1', 'GreenPaletteColorLookupTableData'],\n '1203': ['OW', '1', 'BluePaletteColorLookupTableData'],\n '1204': ['OW', '1', 'AlphaPaletteColorLookupTableData'],\n '1211': ['OW', '1', 'LargeRedPaletteColorLookupTableData'],\n '1212': ['OW', '1', 'LargeGreenPaletteColorLookupTableData'],\n '1213': ['OW', '1', 'LargeBluePaletteColorLookupTableData'],\n '1214': ['UI', '1', 'LargePaletteColorLookupTableUID'],\n '1221': ['OW', '1', 'SegmentedRedPaletteColorLookupTableData'],\n '1222': ['OW', '1', 'SegmentedGreenPaletteColorLookupTableData'],\n '1223': ['OW', '1', 'SegmentedBluePaletteColorLookupTableData'],\n '1224': ['OW', '1', 'SegmentedAlphaPaletteColorLookupTableData'],\n '1230': ['SQ', '1', 'StoredValueColorRangeSequence'],\n '1231': ['FD', '1', 'MinimumStoredValueMapped'],\n '1232': ['FD', '1', 'MaximumStoredValueMapped'],\n '1300': ['CS', '1', 'BreastImplantPresent'],\n '1350': ['CS', '1', 'PartialView'],\n '1351': ['ST', '1', 'PartialViewDescription'],\n '1352': ['SQ', '1', 'PartialViewCodeSequence'],\n '135A': ['CS', '1', 'SpatialLocationsPreserved'],\n '1401': ['SQ', '1', 'DataFrameAssignmentSequence'],\n '1402': ['CS', '1', 'DataPathAssignment'],\n '1403': ['US', '1', 'BitsMappedToColorLookupTable'],\n '1404': ['SQ', '1', 'BlendingLUT1Sequence'],\n '1405': ['CS', '1', 'BlendingLUT1TransferFunction'],\n '1406': ['FD', '1', 'BlendingWeightConstant'],\n '1407': ['US', '3', 'BlendingLookupTableDescriptor'],\n '1408': ['OW', '1', 'BlendingLookupTableData'],\n '140B': ['SQ', '1', 'EnhancedPaletteColorLookupTableSequence'],\n '140C': ['SQ', '1', 'BlendingLUT2Sequence'],\n '140D': ['CS', '1', 'BlendingLUT2TransferFunction'],\n '140E': ['CS', '1', 'DataPathID'],\n '140F': ['CS', '1', 'RGBLUTTransferFunction'],\n '1410': ['CS', '1', 'AlphaLUTTransferFunction'],\n '2000': ['OB', '1', 'ICCProfile'],\n '2002': ['CS', '1', 'ColorSpace'],\n '2110': ['CS', '1', 'LossyImageCompression'],\n '2112': ['DS', '1-n', 'LossyImageCompressionRatio'],\n '2114': ['CS', '1-n', 'LossyImageCompressionMethod'],\n '3000': ['SQ', '1', 'ModalityLUTSequence'],\n '3002': ['xs', '3', 'LUTDescriptor'],\n '3003': ['LO', '1', 'LUTExplanation'],\n '3004': ['LO', '1', 'ModalityLUTType'],\n '3006': ['xx', '1-n or 1', 'LUTData'],\n '3010': ['SQ', '1', 'VOILUTSequence'],\n '3110': ['SQ', '1', 'SoftcopyVOILUTSequence'],\n '4000': ['LT', '1', 'ImagePresentationComments'],\n '5000': ['SQ', '1', 'BiPlaneAcquisitionSequence'],\n '6010': ['US', '1', 'RepresentativeFrameNumber'],\n '6020': ['US', '1-n', 'FrameNumbersOfInterest'],\n '6022': ['LO', '1-n', 'FrameOfInterestDescription'],\n '6023': ['CS', '1-n', 'FrameOfInterestType'],\n '6030': ['US', '1-n', 'MaskPointers'],\n '6040': ['US', '1-n', 'RWavePointer'],\n '6100': ['SQ', '1', 'MaskSubtractionSequence'],\n '6101': ['CS', '1', 'MaskOperation'],\n '6102': ['US', '2-2n', 'ApplicableFrameRange'],\n '6110': ['US', '1-n', 'MaskFrameNumbers'],\n '6112': ['US', '1', 'ContrastFrameAveraging'],\n '6114': ['FL', '2', 'MaskSubPixelShift'],\n '6120': ['SS', '1', 'TIDOffset'],\n '6190': ['ST', '1', 'MaskOperationExplanation'],\n '7000': ['SQ', '1', 'EquipmentAdministratorSequence'],\n '7001': ['US', '1', 'NumberOfDisplaySubsystems'],\n '7002': ['US', '1', 'CurrentConfigurationID'],\n '7003': ['US', '1', 'DisplaySubsystemID'],\n '7004': ['SH', '1', 'DisplaySubsystemName'],\n '7005': ['LO', '1', 'DisplaySubsystemDescription'],\n '7006': ['CS', '1', 'SystemStatus'],\n '7007': ['LO', '1', 'SystemStatusComment'],\n '7008': ['SQ', '1', 'TargetLuminanceCharacteristicsSequence'],\n '7009': ['US', '1', 'LuminanceCharacteristicsID'],\n '700A': ['SQ', '1', 'DisplaySubsystemConfigurationSequence'],\n '700B': ['US', '1', 'ConfigurationID'],\n '700C': ['SH', '1', 'ConfigurationName'],\n '700D': ['LO', '1', 'ConfigurationDescription'],\n '700E': ['US', '1', 'ReferencedTargetLuminanceCharacteristicsID'],\n '700F': ['SQ', '1', 'QAResultsSequence'],\n '7010': ['SQ', '1', 'DisplaySubsystemQAResultsSequence'],\n '7011': ['SQ', '1', 'ConfigurationQAResultsSequence'],\n '7012': ['SQ', '1', 'MeasurementEquipmentSequence'],\n '7013': ['CS', '1-n', 'MeasurementFunctions'],\n '7014': ['CS', '1', 'MeasurementEquipmentType'],\n '7015': ['SQ', '1', 'VisualEvaluationResultSequence'],\n '7016': ['SQ', '1', 'DisplayCalibrationResultSequence'],\n '7017': ['US', '1', 'DDLValue'],\n '7018': ['FL', '2', 'CIExyWhitePoint'],\n '7019': ['CS', '1', 'DisplayFunctionType'],\n '701A': ['FL', '1', 'GammaValue'],\n '701B': ['US', '1', 'NumberOfLuminancePoints'],\n '701C': ['SQ', '1', 'LuminanceResponseSequence'],\n '701D': ['FL', '1', 'TargetMinimumLuminance'],\n '701E': ['FL', '1', 'TargetMaximumLuminance'],\n '701F': ['FL', '1', 'LuminanceValue'],\n '7020': ['LO', '1', 'LuminanceResponseDescription'],\n '7021': ['CS', '1', 'WhitePointFlag'],\n '7022': ['SQ', '1', 'DisplayDeviceTypeCodeSequence'],\n '7023': ['SQ', '1', 'DisplaySubsystemSequence'],\n '7024': ['SQ', '1', 'LuminanceResultSequence'],\n '7025': ['CS', '1', 'AmbientLightValueSource'],\n '7026': ['CS', '1-n', 'MeasuredCharacteristics'],\n '7027': ['SQ', '1', 'LuminanceUniformityResultSequence'],\n '7028': ['SQ', '1', 'VisualEvaluationTestSequence'],\n '7029': ['CS', '1', 'TestResult'],\n '702A': ['LO', '1', 'TestResultComment'],\n '702B': ['CS', '1', 'TestImageValidation'],\n '702C': ['SQ', '1', 'TestPatternCodeSequence'],\n '702D': ['SQ', '1', 'MeasurementPatternCodeSequence'],\n '702E': ['SQ', '1', 'VisualEvaluationMethodCodeSequence'],\n '7FE0': ['UR', '1', 'PixelDataProviderURL'],\n '9001': ['UL', '1', 'DataPointRows'],\n '9002': ['UL', '1', 'DataPointColumns'],\n '9003': ['CS', '1', 'SignalDomainColumns'],\n '9099': ['US', '1', 'LargestMonochromePixelValue'],\n '9108': ['CS', '1', 'DataRepresentation'],\n '9110': ['SQ', '1', 'PixelMeasuresSequence'],\n '9132': ['SQ', '1', 'FrameVOILUTSequence'],\n '9145': ['SQ', '1', 'PixelValueTransformationSequence'],\n '9235': ['CS', '1', 'SignalDomainRows'],\n '9411': ['FL', '1', 'DisplayFilterPercentage'],\n '9415': ['SQ', '1', 'FramePixelShiftSequence'],\n '9416': ['US', '1', 'SubtractionItemID'],\n '9422': ['SQ', '1', 'PixelIntensityRelationshipLUTSequence'],\n '9443': ['SQ', '1', 'FramePixelDataPropertiesSequence'],\n '9444': ['CS', '1', 'GeometricalProperties'],\n '9445': ['FL', '1', 'GeometricMaximumDistortion'],\n '9446': ['CS', '1-n', 'ImageProcessingApplied'],\n '9454': ['CS', '1', 'MaskSelectionMode'],\n '9474': ['CS', '1', 'LUTFunction'],\n '9478': ['FL', '1', 'MaskVisibilityPercentage'],\n '9501': ['SQ', '1', 'PixelShiftSequence'],\n '9502': ['SQ', '1', 'RegionPixelShiftSequence'],\n '9503': ['SS', '2-2n', 'VerticesOfTheRegion'],\n '9505': ['SQ', '1', 'MultiFramePresentationSequence'],\n '9506': ['US', '2-2n', 'PixelShiftFrameRange'],\n '9507': ['US', '2-2n', 'LUTFrameRange'],\n '9520': ['DS', '16', 'ImageToEquipmentMappingMatrix'],\n '9537': ['CS', '1', 'EquipmentCoordinateSystemIdentification']\n },\n '0032': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '000A': ['CS', '1', 'StudyStatusID'],\n '000C': ['CS', '1', 'StudyPriorityID'],\n '0012': ['LO', '1', 'StudyIDIssuer'],\n '0032': ['DA', '1', 'StudyVerifiedDate'],\n '0033': ['TM', '1', 'StudyVerifiedTime'],\n '0034': ['DA', '1', 'StudyReadDate'],\n '0035': ['TM', '1', 'StudyReadTime'],\n '1000': ['DA', '1', 'ScheduledStudyStartDate'],\n '1001': ['TM', '1', 'ScheduledStudyStartTime'],\n '1010': ['DA', '1', 'ScheduledStudyStopDate'],\n '1011': ['TM', '1', 'ScheduledStudyStopTime'],\n '1020': ['LO', '1', 'ScheduledStudyLocation'],\n '1021': ['AE', '1-n', 'ScheduledStudyLocationAETitle'],\n '1030': ['LO', '1', 'ReasonForStudy'],\n '1031': ['SQ', '1', 'RequestingPhysicianIdentificationSequence'],\n '1032': ['PN', '1', 'RequestingPhysician'],\n '1033': ['LO', '1', 'RequestingService'],\n '1034': ['SQ', '1', 'RequestingServiceCodeSequence'],\n '1040': ['DA', '1', 'StudyArrivalDate'],\n '1041': ['TM', '1', 'StudyArrivalTime'],\n '1050': ['DA', '1', 'StudyCompletionDate'],\n '1051': ['TM', '1', 'StudyCompletionTime'],\n '1055': ['CS', '1', 'StudyComponentStatusID'],\n '1060': ['LO', '1', 'RequestedProcedureDescription'],\n '1064': ['SQ', '1', 'RequestedProcedureCodeSequence'],\n '1065': ['SQ', '1', 'RequestedLateralityCodeSequence'],\n '1066': ['UT', '1', 'ReasonForVisit'],\n '1067': ['SQ', '1', 'ReasonForVisitCodeSequence'],\n '1070': ['LO', '1', 'RequestedContrastAgent'],\n '4000': ['LT', '1', 'StudyComments']\n },\n '0034': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['SQ', '1', 'FlowIdentifierSequence'],\n '0002': ['OB', '1', 'FlowIdentifier'],\n '0003': ['UI', '1', 'FlowTransferSyntaxUID'],\n '0004': ['UL', '1', 'FlowRTPSamplingRate'],\n '0005': ['OB', '1', 'SourceIdentifier'],\n '0007': ['OB', '1', 'FrameOriginTimestamp'],\n '0008': ['CS', '1', 'IncludesImagingSubject'],\n '0009': ['SQ', '1', 'FrameUsefulnessGroupSequence'],\n '000A': ['SQ', '1', 'RealTimeBulkDataFlowSequence'],\n '000B': ['SQ', '1', 'CameraPositionGroupSequence'],\n '000C': ['CS', '1', 'IncludesInformation'],\n '000D': ['SQ', '1', 'TimeOfFrameGroupSequence']\n },\n '0038': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0004': ['SQ', '1', 'ReferencedPatientAliasSequence'],\n '0008': ['CS', '1', 'VisitStatusID'],\n '0010': ['LO', '1', 'AdmissionID'],\n '0011': ['LO', '1', 'IssuerOfAdmissionID'],\n '0014': ['SQ', '1', 'IssuerOfAdmissionIDSequence'],\n '0016': ['LO', '1', 'RouteOfAdmissions'],\n '001A': ['DA', '1', 'ScheduledAdmissionDate'],\n '001B': ['TM', '1', 'ScheduledAdmissionTime'],\n '001C': ['DA', '1', 'ScheduledDischargeDate'],\n '001D': ['TM', '1', 'ScheduledDischargeTime'],\n '001E': ['LO', '1', 'ScheduledPatientInstitutionResidence'],\n '0020': ['DA', '1', 'AdmittingDate'],\n '0021': ['TM', '1', 'AdmittingTime'],\n '0030': ['DA', '1', 'DischargeDate'],\n '0032': ['TM', '1', 'DischargeTime'],\n '0040': ['LO', '1', 'DischargeDiagnosisDescription'],\n '0044': ['SQ', '1', 'DischargeDiagnosisCodeSequence'],\n '0050': ['LO', '1', 'SpecialNeeds'],\n '0060': ['LO', '1', 'ServiceEpisodeID'],\n '0061': ['LO', '1', 'IssuerOfServiceEpisodeID'],\n '0062': ['LO', '1', 'ServiceEpisodeDescription'],\n '0064': ['SQ', '1', 'IssuerOfServiceEpisodeIDSequence'],\n '0100': ['SQ', '1', 'PertinentDocumentsSequence'],\n '0101': ['SQ', '1', 'PertinentResourcesSequence'],\n '0102': ['LO', '1', 'ResourceDescription'],\n '0300': ['LO', '1', 'CurrentPatientLocation'],\n '0400': ['LO', '1', 'PatientInstitutionResidence'],\n '0500': ['LO', '1', 'PatientState'],\n '0502': ['SQ', '1', 'PatientClinicalTrialParticipationSequence'],\n '4000': ['LT', '1', 'VisitComments']\n },\n '003A': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0004': ['CS', '1', 'WaveformOriginality'],\n '0005': ['US', '1', 'NumberOfWaveformChannels'],\n '0010': ['UL', '1', 'NumberOfWaveformSamples'],\n '001A': ['DS', '1', 'SamplingFrequency'],\n '0020': ['SH', '1', 'MultiplexGroupLabel'],\n '0200': ['SQ', '1', 'ChannelDefinitionSequence'],\n '0202': ['IS', '1', 'WaveformChannelNumber'],\n '0203': ['SH', '1', 'ChannelLabel'],\n '0205': ['CS', '1-n', 'ChannelStatus'],\n '0208': ['SQ', '1', 'ChannelSourceSequence'],\n '0209': ['SQ', '1', 'ChannelSourceModifiersSequence'],\n '020A': ['SQ', '1', 'SourceWaveformSequence'],\n '020C': ['LO', '1', 'ChannelDerivationDescription'],\n '0210': ['DS', '1', 'ChannelSensitivity'],\n '0211': ['SQ', '1', 'ChannelSensitivityUnitsSequence'],\n '0212': ['DS', '1', 'ChannelSensitivityCorrectionFactor'],\n '0213': ['DS', '1', 'ChannelBaseline'],\n '0214': ['DS', '1', 'ChannelTimeSkew'],\n '0215': ['DS', '1', 'ChannelSampleSkew'],\n '0218': ['DS', '1', 'ChannelOffset'],\n '021A': ['US', '1', 'WaveformBitsStored'],\n '0220': ['DS', '1', 'FilterLowFrequency'],\n '0221': ['DS', '1', 'FilterHighFrequency'],\n '0222': ['DS', '1', 'NotchFilterFrequency'],\n '0223': ['DS', '1', 'NotchFilterBandwidth'],\n '0230': ['FL', '1', 'WaveformDataDisplayScale'],\n '0231': ['US', '3', 'WaveformDisplayBackgroundCIELabValue'],\n '0240': ['SQ', '1', 'WaveformPresentationGroupSequence'],\n '0241': ['US', '1', 'PresentationGroupNumber'],\n '0242': ['SQ', '1', 'ChannelDisplaySequence'],\n '0244': ['US', '3', 'ChannelRecommendedDisplayCIELabValue'],\n '0245': ['FL', '1', 'ChannelPosition'],\n '0246': ['CS', '1', 'DisplayShadingFlag'],\n '0247': ['FL', '1', 'FractionalChannelDisplayScale'],\n '0248': ['FL', '1', 'AbsoluteChannelDisplayScale'],\n '0300': ['SQ', '1', 'MultiplexedAudioChannelsDescriptionCodeSequence'],\n '0301': ['IS', '1', 'ChannelIdentificationCode'],\n '0302': ['CS', '1', 'ChannelMode'],\n '0310': ['UI', '1', 'MultiplexGroupUID'],\n '0311': ['DS', '1', 'PowerlineFrequency'],\n '0312': ['SQ', '1', 'ChannelImpedanceSequence'],\n '0313': ['DS', '1', 'ImpedanceValue'],\n '0314': ['DT', '1', 'ImpedanceMeasurementDateTime'],\n '0315': ['DS', '1', 'ImpedanceMeasurementFrequency'],\n '0316': ['CS', '1', 'ImpedanceMeasurementCurrentType']\n },\n '0040': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['AE', '1-n', 'ScheduledStationAETitle'],\n '0002': ['DA', '1', 'ScheduledProcedureStepStartDate'],\n '0003': ['TM', '1', 'ScheduledProcedureStepStartTime'],\n '0004': ['DA', '1', 'ScheduledProcedureStepEndDate'],\n '0005': ['TM', '1', 'ScheduledProcedureStepEndTime'],\n '0006': ['PN', '1', 'ScheduledPerformingPhysicianName'],\n '0007': ['LO', '1', 'ScheduledProcedureStepDescription'],\n '0008': ['SQ', '1', 'ScheduledProtocolCodeSequence'],\n '0009': ['SH', '1', 'ScheduledProcedureStepID'],\n '000A': ['SQ', '1', 'StageCodeSequence'],\n '000B': ['SQ', '1', 'ScheduledPerformingPhysicianIdentificationSequence'],\n '0010': ['SH', '1-n', 'ScheduledStationName'],\n '0011': ['SH', '1', 'ScheduledProcedureStepLocation'],\n '0012': ['LO', '1', 'PreMedication'],\n '0020': ['CS', '1', 'ScheduledProcedureStepStatus'],\n '0026': ['SQ', '1', 'OrderPlacerIdentifierSequence'],\n '0027': ['SQ', '1', 'OrderFillerIdentifierSequence'],\n '0031': ['UT', '1', 'LocalNamespaceEntityID'],\n '0032': ['UT', '1', 'UniversalEntityID'],\n '0033': ['CS', '1', 'UniversalEntityIDType'],\n '0035': ['CS', '1', 'IdentifierTypeCode'],\n '0036': ['SQ', '1', 'AssigningFacilitySequence'],\n '0039': ['SQ', '1', 'AssigningJurisdictionCodeSequence'],\n '003A': ['SQ', '1', 'AssigningAgencyOrDepartmentCodeSequence'],\n '0100': ['SQ', '1', 'ScheduledProcedureStepSequence'],\n '0220': ['SQ', '1', 'ReferencedNonImageCompositeSOPInstanceSequence'],\n '0241': ['AE', '1', 'PerformedStationAETitle'],\n '0242': ['SH', '1', 'PerformedStationName'],\n '0243': ['SH', '1', 'PerformedLocation'],\n '0244': ['DA', '1', 'PerformedProcedureStepStartDate'],\n '0245': ['TM', '1', 'PerformedProcedureStepStartTime'],\n '0250': ['DA', '1', 'PerformedProcedureStepEndDate'],\n '0251': ['TM', '1', 'PerformedProcedureStepEndTime'],\n '0252': ['CS', '1', 'PerformedProcedureStepStatus'],\n '0253': ['SH', '1', 'PerformedProcedureStepID'],\n '0254': ['LO', '1', 'PerformedProcedureStepDescription'],\n '0255': ['LO', '1', 'PerformedProcedureTypeDescription'],\n '0260': ['SQ', '1', 'PerformedProtocolCodeSequence'],\n '0261': ['CS', '1', 'PerformedProtocolType'],\n '0270': ['SQ', '1', 'ScheduledStepAttributesSequence'],\n '0275': ['SQ', '1', 'RequestAttributesSequence'],\n '0280': ['ST', '1', 'CommentsOnThePerformedProcedureStep'],\n '0281': ['SQ', '1', 'PerformedProcedureStepDiscontinuationReasonCodeSequence'],\n '0293': ['SQ', '1', 'QuantitySequence'],\n '0294': ['DS', '1', 'Quantity'],\n '0295': ['SQ', '1', 'MeasuringUnitsSequence'],\n '0296': ['SQ', '1', 'BillingItemSequence'],\n '0300': ['US', '1', 'TotalTimeOfFluoroscopy'],\n '0301': ['US', '1', 'TotalNumberOfExposures'],\n '0302': ['US', '1', 'EntranceDose'],\n '0303': ['US', '1-2', 'ExposedArea'],\n '0306': ['DS', '1', 'DistanceSourceToEntrance'],\n '0307': ['DS', '1', 'DistanceSourceToSupport'],\n '030E': ['SQ', '1', 'ExposureDoseSequence'],\n '0310': ['ST', '1', 'CommentsOnRadiationDose'],\n '0312': ['DS', '1', 'XRayOutput'],\n '0314': ['DS', '1', 'HalfValueLayer'],\n '0316': ['DS', '1', 'OrganDose'],\n '0318': ['CS', '1', 'OrganExposed'],\n '0320': ['SQ', '1', 'BillingProcedureStepSequence'],\n '0321': ['SQ', '1', 'FilmConsumptionSequence'],\n '0324': ['SQ', '1', 'BillingSuppliesAndDevicesSequence'],\n '0330': ['SQ', '1', 'ReferencedProcedureStepSequence'],\n '0340': ['SQ', '1', 'PerformedSeriesSequence'],\n '0400': ['LT', '1', 'CommentsOnTheScheduledProcedureStep'],\n '0440': ['SQ', '1', 'ProtocolContextSequence'],\n '0441': ['SQ', '1', 'ContentItemModifierSequence'],\n '0500': ['SQ', '1', 'ScheduledSpecimenSequence'],\n '050A': ['LO', '1', 'SpecimenAccessionNumber'],\n '0512': ['LO', '1', 'ContainerIdentifier'],\n '0513': ['SQ', '1', 'IssuerOfTheContainerIdentifierSequence'],\n '0515': ['SQ', '1', 'AlternateContainerIdentifierSequence'],\n '0518': ['SQ', '1', 'ContainerTypeCodeSequence'],\n '051A': ['LO', '1', 'ContainerDescription'],\n '0520': ['SQ', '1', 'ContainerComponentSequence'],\n '0550': ['SQ', '1', 'SpecimenSequence'],\n '0551': ['LO', '1', 'SpecimenIdentifier'],\n '0552': ['SQ', '1', 'SpecimenDescriptionSequenceTrial'],\n '0553': ['ST', '1', 'SpecimenDescriptionTrial'],\n '0554': ['UI', '1', 'SpecimenUID'],\n '0555': ['SQ', '1', 'AcquisitionContextSequence'],\n '0556': ['ST', '1', 'AcquisitionContextDescription'],\n '0560': ['SQ', '1', 'SpecimenDescriptionSequence'],\n '0562': ['SQ', '1', 'IssuerOfTheSpecimenIdentifierSequence'],\n '059A': ['SQ', '1', 'SpecimenTypeCodeSequence'],\n '0600': ['LO', '1', 'SpecimenShortDescription'],\n '0602': ['UT', '1', 'SpecimenDetailedDescription'],\n '0610': ['SQ', '1', 'SpecimenPreparationSequence'],\n '0612': ['SQ', '1', 'SpecimenPreparationStepContentItemSequence'],\n '0620': ['SQ', '1', 'SpecimenLocalizationContentItemSequence'],\n '06FA': ['LO', '1', 'SlideIdentifier'],\n '0710': ['SQ', '1', 'WholeSlideMicroscopyImageFrameTypeSequence'],\n '071A': ['SQ', '1', 'ImageCenterPointCoordinatesSequence'],\n '072A': ['DS', '1', 'XOffsetInSlideCoordinateSystem'],\n '073A': ['DS', '1', 'YOffsetInSlideCoordinateSystem'],\n '074A': ['DS', '1', 'ZOffsetInSlideCoordinateSystem'],\n '08D8': ['SQ', '1', 'PixelSpacingSequence'],\n '08DA': ['SQ', '1', 'CoordinateSystemAxisCodeSequence'],\n '08EA': ['SQ', '1', 'MeasurementUnitsCodeSequence'],\n '09F8': ['SQ', '1', 'VitalStainCodeSequenceTrial'],\n '1001': ['SH', '1', 'RequestedProcedureID'],\n '1002': ['LO', '1', 'ReasonForTheRequestedProcedure'],\n '1003': ['SH', '1', 'RequestedProcedurePriority'],\n '1004': ['LO', '1', 'PatientTransportArrangements'],\n '1005': ['LO', '1', 'RequestedProcedureLocation'],\n '1006': ['SH', '1', 'PlacerOrderNumberProcedure'],\n '1007': ['SH', '1', 'FillerOrderNumberProcedure'],\n '1008': ['LO', '1', 'ConfidentialityCode'],\n '1009': ['SH', '1', 'ReportingPriority'],\n '100A': ['SQ', '1', 'ReasonForRequestedProcedureCodeSequence'],\n '1010': ['PN', '1-n', 'NamesOfIntendedRecipientsOfResults'],\n '1011': ['SQ', '1', 'IntendedRecipientsOfResultsIdentificationSequence'],\n '1012': ['SQ', '1', 'ReasonForPerformedProcedureCodeSequence'],\n '1060': ['LO', '1', 'RequestedProcedureDescriptionTrial'],\n '1101': ['SQ', '1', 'PersonIdentificationCodeSequence'],\n '1102': ['ST', '1', 'PersonAddress'],\n '1103': ['LO', '1-n', 'PersonTelephoneNumbers'],\n '1104': ['LT', '1', 'PersonTelecomInformation'],\n '1400': ['LT', '1', 'RequestedProcedureComments'],\n '2001': ['LO', '1', 'ReasonForTheImagingServiceRequest'],\n '2004': ['DA', '1', 'IssueDateOfImagingServiceRequest'],\n '2005': ['TM', '1', 'IssueTimeOfImagingServiceRequest'],\n '2006': ['SH', '1', 'PlacerOrderNumberImagingServiceRequestRetired'],\n '2007': ['SH', '1', 'FillerOrderNumberImagingServiceRequestRetired'],\n '2008': ['PN', '1', 'OrderEnteredBy'],\n '2009': ['SH', '1', 'OrderEntererLocation'],\n '2010': ['SH', '1', 'OrderCallbackPhoneNumber'],\n '2011': ['LT', '1', 'OrderCallbackTelecomInformation'],\n '2016': ['LO', '1', 'PlacerOrderNumberImagingServiceRequest'],\n '2017': ['LO', '1', 'FillerOrderNumberImagingServiceRequest'],\n '2400': ['LT', '1', 'ImagingServiceRequestComments'],\n '3001': ['LO', '1', 'ConfidentialityConstraintOnPatientDataDescription'],\n '4001': ['CS', '1', 'GeneralPurposeScheduledProcedureStepStatus'],\n '4002': ['CS', '1', 'GeneralPurposePerformedProcedureStepStatus'],\n '4003': ['CS', '1', 'GeneralPurposeScheduledProcedureStepPriority'],\n '4004': ['SQ', '1', 'ScheduledProcessingApplicationsCodeSequence'],\n '4005': ['DT', '1', 'ScheduledProcedureStepStartDateTime'],\n '4006': ['CS', '1', 'MultipleCopiesFlag'],\n '4007': ['SQ', '1', 'PerformedProcessingApplicationsCodeSequence'],\n '4008': ['DT', '1', 'ScheduledProcedureStepExpirationDateTime'],\n '4009': ['SQ', '1', 'HumanPerformerCodeSequence'],\n '4010': ['DT', '1', 'ScheduledProcedureStepModificationDateTime'],\n '4011': ['DT', '1', 'ExpectedCompletionDateTime'],\n '4015': ['SQ', '1', 'ResultingGeneralPurposePerformedProcedureStepsSequence'],\n '4016': ['SQ', '1', 'ReferencedGeneralPurposeScheduledProcedureStepSequence'],\n '4018': ['SQ', '1', 'ScheduledWorkitemCodeSequence'],\n '4019': ['SQ', '1', 'PerformedWorkitemCodeSequence'],\n '4020': ['CS', '1', 'InputAvailabilityFlag'],\n '4021': ['SQ', '1', 'InputInformationSequence'],\n '4022': ['SQ', '1', 'RelevantInformationSequence'],\n '4023': ['UI', '1', 'ReferencedGeneralPurposeScheduledProcedureStepTransactionUID'],\n '4025': ['SQ', '1', 'ScheduledStationNameCodeSequence'],\n '4026': ['SQ', '1', 'ScheduledStationClassCodeSequence'],\n '4027': ['SQ', '1', 'ScheduledStationGeographicLocationCodeSequence'],\n '4028': ['SQ', '1', 'PerformedStationNameCodeSequence'],\n '4029': ['SQ', '1', 'PerformedStationClassCodeSequence'],\n '4030': ['SQ', '1', 'PerformedStationGeographicLocationCodeSequence'],\n '4031': ['SQ', '1', 'RequestedSubsequentWorkitemCodeSequence'],\n '4032': ['SQ', '1', 'NonDICOMOutputCodeSequence'],\n '4033': ['SQ', '1', 'OutputInformationSequence'],\n '4034': ['SQ', '1', 'ScheduledHumanPerformersSequence'],\n '4035': ['SQ', '1', 'ActualHumanPerformersSequence'],\n '4036': ['LO', '1', 'HumanPerformerOrganization'],\n '4037': ['PN', '1', 'HumanPerformerName'],\n '4040': ['CS', '1', 'RawDataHandling'],\n '4041': ['CS', '1', 'InputReadinessState'],\n '4050': ['DT', '1', 'PerformedProcedureStepStartDateTime'],\n '4051': ['DT', '1', 'PerformedProcedureStepEndDateTime'],\n '4052': ['DT', '1', 'ProcedureStepCancellationDateTime'],\n '4070': ['SQ', '1', 'OutputDestinationSequence'],\n '4071': ['SQ', '1', 'DICOMStorageSequence'],\n '4072': ['SQ', '1', 'STOWRSStorageSequence'],\n '4073': ['UR', '1', 'StorageURL'],\n '4074': ['SQ', '1', 'XDSStorageSequence'],\n '8302': ['DS', '1', 'EntranceDoseInmGy'],\n '8303': ['CS', '1', 'EntranceDoseDerivation'],\n '9092': ['SQ', '1', 'ParametricMapFrameTypeSequence'],\n '9094': ['SQ', '1', 'ReferencedImageRealWorldValueMappingSequence'],\n '9096': ['SQ', '1', 'RealWorldValueMappingSequence'],\n '9098': ['SQ', '1', 'PixelValueMappingCodeSequence'],\n '9210': ['SH', '1', 'LUTLabel'],\n '9211': ['xs', '1', 'RealWorldValueLastValueMapped'],\n '9212': ['FD', '1-n', 'RealWorldValueLUTData'],\n '9213': ['FD', '1', 'DoubleFloatRealWorldValueLastValueMapped'],\n '9214': ['FD', '1', 'DoubleFloatRealWorldValueFirstValueMapped'],\n '9216': ['xs', '1', 'RealWorldValueFirstValueMapped'],\n '9220': ['SQ', '1', 'QuantityDefinitionSequence'],\n '9224': ['FD', '1', 'RealWorldValueIntercept'],\n '9225': ['FD', '1', 'RealWorldValueSlope'],\n 'A007': ['CS', '1', 'FindingsFlagTrial'],\n 'A010': ['CS', '1', 'RelationshipType'],\n 'A020': ['SQ', '1', 'FindingsSequenceTrial'],\n 'A021': ['UI', '1', 'FindingsGroupUIDTrial'],\n 'A022': ['UI', '1', 'ReferencedFindingsGroupUIDTrial'],\n 'A023': ['DA', '1', 'FindingsGroupRecordingDateTrial'],\n 'A024': ['TM', '1', 'FindingsGroupRecordingTimeTrial'],\n 'A026': ['SQ', '1', 'FindingsSourceCategoryCodeSequenceTrial'],\n 'A027': ['LO', '1', 'VerifyingOrganization'],\n 'A028': ['SQ', '1', 'DocumentingOrganizationIdentifierCodeSequenceTrial'],\n 'A030': ['DT', '1', 'VerificationDateTime'],\n 'A032': ['DT', '1', 'ObservationDateTime'],\n 'A033': ['DT', '1', 'ObservationStartDateTime'],\n 'A040': ['CS', '1', 'ValueType'],\n 'A043': ['SQ', '1', 'ConceptNameCodeSequence'],\n 'A047': ['LO', '1', 'MeasurementPrecisionDescriptionTrial'],\n 'A050': ['CS', '1', 'ContinuityOfContent'],\n 'A057': ['CS', '1-n', 'UrgencyOrPriorityAlertsTrial'],\n 'A060': ['LO', '1', 'SequencingIndicatorTrial'],\n 'A066': ['SQ', '1', 'DocumentIdentifierCodeSequenceTrial'],\n 'A067': ['PN', '1', 'DocumentAuthorTrial'],\n 'A068': ['SQ', '1', 'DocumentAuthorIdentifierCodeSequenceTrial'],\n 'A070': ['SQ', '1', 'IdentifierCodeSequenceTrial'],\n 'A073': ['SQ', '1', 'VerifyingObserverSequence'],\n 'A074': ['OB', '1', 'ObjectBinaryIdentifierTrial'],\n 'A075': ['PN', '1', 'VerifyingObserverName'],\n 'A076': ['SQ', '1', 'DocumentingObserverIdentifierCodeSequenceTrial'],\n 'A078': ['SQ', '1', 'AuthorObserverSequence'],\n 'A07A': ['SQ', '1', 'ParticipantSequence'],\n 'A07C': ['SQ', '1', 'CustodialOrganizationSequence'],\n 'A080': ['CS', '1', 'ParticipationType'],\n 'A082': ['DT', '1', 'ParticipationDateTime'],\n 'A084': ['CS', '1', 'ObserverType'],\n 'A085': ['SQ', '1', 'ProcedureIdentifierCodeSequenceTrial'],\n 'A088': ['SQ', '1', 'VerifyingObserverIdentificationCodeSequence'],\n 'A089': ['OB', '1', 'ObjectDirectoryBinaryIdentifierTrial'],\n 'A090': ['SQ', '1', 'EquivalentCDADocumentSequence'],\n 'A0B0': ['US', '2-2n', 'ReferencedWaveformChannels'],\n 'A110': ['DA', '1', 'DateOfDocumentOrVerbalTransactionTrial'],\n 'A112': ['TM', '1', 'TimeOfDocumentCreationOrVerbalTransactionTrial'],\n 'A120': ['DT', '1', 'DateTime'],\n 'A121': ['DA', '1', 'Date'],\n 'A122': ['TM', '1', 'Time'],\n 'A123': ['PN', '1', 'PersonName'],\n 'A124': ['UI', '1', 'UID'],\n 'A125': ['CS', '2', 'ReportStatusIDTrial'],\n 'A130': ['CS', '1', 'TemporalRangeType'],\n 'A132': ['UL', '1-n', 'ReferencedSamplePositions'],\n 'A136': ['US', '1-n', 'ReferencedFrameNumbers'],\n 'A138': ['DS', '1-n', 'ReferencedTimeOffsets'],\n 'A13A': ['DT', '1-n', 'ReferencedDateTime'],\n 'A160': ['UT', '1', 'TextValue'],\n 'A161': ['FD', '1-n', 'FloatingPointValue'],\n 'A162': ['SL', '1-n', 'RationalNumeratorValue'],\n 'A163': ['UL', '1-n', 'RationalDenominatorValue'],\n 'A167': ['SQ', '1', 'ObservationCategoryCodeSequenceTrial'],\n 'A168': ['SQ', '1', 'ConceptCodeSequence'],\n 'A16A': ['ST', '1', 'BibliographicCitationTrial'],\n 'A170': ['SQ', '1', 'PurposeOfReferenceCodeSequence'],\n 'A171': ['UI', '1', 'ObservationUID'],\n 'A172': ['UI', '1', 'ReferencedObservationUIDTrial'],\n 'A173': ['CS', '1', 'ReferencedObservationClassTrial'],\n 'A174': ['CS', '1', 'ReferencedObjectObservationClassTrial'],\n 'A180': ['US', '1', 'AnnotationGroupNumber'],\n 'A192': ['DA', '1', 'ObservationDateTrial'],\n 'A193': ['TM', '1', 'ObservationTimeTrial'],\n 'A194': ['CS', '1', 'MeasurementAutomationTrial'],\n 'A195': ['SQ', '1', 'ModifierCodeSequence'],\n 'A224': ['ST', '1', 'IdentificationDescriptionTrial'],\n 'A290': ['CS', '1', 'CoordinatesSetGeometricTypeTrial'],\n 'A296': ['SQ', '1', 'AlgorithmCodeSequenceTrial'],\n 'A297': ['ST', '1', 'AlgorithmDescriptionTrial'],\n 'A29A': ['SL', '2-2n', 'PixelCoordinatesSetTrial'],\n 'A300': ['SQ', '1', 'MeasuredValueSequence'],\n 'A301': ['SQ', '1', 'NumericValueQualifierCodeSequence'],\n 'A307': ['PN', '1', 'CurrentObserverTrial'],\n 'A30A': ['DS', '1-n', 'NumericValue'],\n 'A313': ['SQ', '1', 'ReferencedAccessionSequenceTrial'],\n 'A33A': ['ST', '1', 'ReportStatusCommentTrial'],\n 'A340': ['SQ', '1', 'ProcedureContextSequenceTrial'],\n 'A352': ['PN', '1', 'VerbalSourceTrial'],\n 'A353': ['ST', '1', 'AddressTrial'],\n 'A354': ['LO', '1', 'TelephoneNumberTrial'],\n 'A358': ['SQ', '1', 'VerbalSourceIdentifierCodeSequenceTrial'],\n 'A360': ['SQ', '1', 'PredecessorDocumentsSequence'],\n 'A370': ['SQ', '1', 'ReferencedRequestSequence'],\n 'A372': ['SQ', '1', 'PerformedProcedureCodeSequence'],\n 'A375': ['SQ', '1', 'CurrentRequestedProcedureEvidenceSequence'],\n 'A380': ['SQ', '1', 'ReportDetailSequenceTrial'],\n 'A385': ['SQ', '1', 'PertinentOtherEvidenceSequence'],\n 'A390': ['SQ', '1', 'HL7StructuredDocumentReferenceSequence'],\n 'A402': ['UI', '1', 'ObservationSubjectUIDTrial'],\n 'A403': ['CS', '1', 'ObservationSubjectClassTrial'],\n 'A404': ['SQ', '1', 'ObservationSubjectTypeCodeSequenceTrial'],\n 'A491': ['CS', '1', 'CompletionFlag'],\n 'A492': ['LO', '1', 'CompletionFlagDescription'],\n 'A493': ['CS', '1', 'VerificationFlag'],\n 'A494': ['CS', '1', 'ArchiveRequested'],\n 'A496': ['CS', '1', 'PreliminaryFlag'],\n 'A504': ['SQ', '1', 'ContentTemplateSequence'],\n 'A525': ['SQ', '1', 'IdenticalDocumentsSequence'],\n 'A600': ['CS', '1', 'ObservationSubjectContextFlagTrial'],\n 'A601': ['CS', '1', 'ObserverContextFlagTrial'],\n 'A603': ['CS', '1', 'ProcedureContextFlagTrial'],\n 'A730': ['SQ', '1', 'ContentSequence'],\n 'A731': ['SQ', '1', 'RelationshipSequenceTrial'],\n 'A732': ['SQ', '1', 'RelationshipTypeCodeSequenceTrial'],\n 'A744': ['SQ', '1', 'LanguageCodeSequenceTrial'],\n 'A801': ['SQ', '1', 'TabulatedValuesSequence'],\n 'A802': ['UL', '1', 'NumberOfTableRows'],\n 'A803': ['UL', '1', 'NumberOfTableColumns'],\n 'A804': ['UL', '1', 'TableRowNumber'],\n 'A805': ['UL', '1', 'TableColumnNumber'],\n 'A806': ['SQ', '1', 'TableRowDefinitionSequence'],\n 'A807': ['SQ', '1', 'TableColumnDefinitionSequence'],\n 'A808': ['SQ', '1', 'CellValuesSequence'],\n 'A992': ['ST', '1', 'UniformResourceLocatorTrial'],\n 'B020': ['SQ', '1', 'WaveformAnnotationSequence'],\n 'DB00': ['CS', '1', 'TemplateIdentifier'],\n 'DB06': ['DT', '1', 'TemplateVersion'],\n 'DB07': ['DT', '1', 'TemplateLocalVersion'],\n 'DB0B': ['CS', '1', 'TemplateExtensionFlag'],\n 'DB0C': ['UI', '1', 'TemplateExtensionOrganizationUID'],\n 'DB0D': ['UI', '1', 'TemplateExtensionCreatorUID'],\n 'DB73': ['UL', '1-n', 'ReferencedContentItemIdentifier'],\n 'E001': ['ST', '1', 'HL7InstanceIdentifier'],\n 'E004': ['DT', '1', 'HL7DocumentEffectiveTime'],\n 'E006': ['SQ', '1', 'HL7DocumentTypeCodeSequence'],\n 'E008': ['SQ', '1', 'DocumentClassCodeSequence'],\n 'E010': ['UR', '1', 'RetrieveURI'],\n 'E011': ['UI', '1', 'RetrieveLocationUID'],\n 'E020': ['CS', '1', 'TypeOfInstances'],\n 'E021': ['SQ', '1', 'DICOMRetrievalSequence'],\n 'E022': ['SQ', '1', 'DICOMMediaRetrievalSequence'],\n 'E023': ['SQ', '1', 'WADORetrievalSequence'],\n 'E024': ['SQ', '1', 'XDSRetrievalSequence'],\n 'E025': ['SQ', '1', 'WADORSRetrievalSequence'],\n 'E030': ['UI', '1', 'RepositoryUniqueID'],\n 'E031': ['UI', '1', 'HomeCommunityID']\n },\n '0042': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['ST', '1', 'DocumentTitle'],\n '0011': ['OB', '1', 'EncapsulatedDocument'],\n '0012': ['LO', '1', 'MIMETypeOfEncapsulatedDocument'],\n '0013': ['SQ', '1', 'SourceInstanceSequence'],\n '0014': ['LO', '1-n', 'ListOfMIMETypes'],\n '0015': ['UL', '1', 'EncapsulatedDocumentLength']\n },\n '0044': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['ST', '1', 'ProductPackageIdentifier'],\n '0002': ['CS', '1', 'SubstanceAdministrationApproval'],\n '0003': ['LT', '1', 'ApprovalStatusFurtherDescription'],\n '0004': ['DT', '1', 'ApprovalStatusDateTime'],\n '0007': ['SQ', '1', 'ProductTypeCodeSequence'],\n '0008': ['LO', '1-n', 'ProductName'],\n '0009': ['LT', '1', 'ProductDescription'],\n '000A': ['LO', '1', 'ProductLotIdentifier'],\n '000B': ['DT', '1', 'ProductExpirationDateTime'],\n '0010': ['DT', '1', 'SubstanceAdministrationDateTime'],\n '0011': ['LO', '1', 'SubstanceAdministrationNotes'],\n '0012': ['LO', '1', 'SubstanceAdministrationDeviceID'],\n '0013': ['SQ', '1', 'ProductParameterSequence'],\n '0019': ['SQ', '1', 'SubstanceAdministrationParameterSequence'],\n '0100': ['SQ', '1', 'ApprovalSequence'],\n '0101': ['SQ', '1', 'AssertionCodeSequence'],\n '0102': ['UI', '1', 'AssertionUID'],\n '0103': ['SQ', '1', 'AsserterIdentificationSequence'],\n '0104': ['DT', '1', 'AssertionDateTime'],\n '0105': ['DT', '1', 'AssertionExpirationDateTime'],\n '0106': ['UT', '1', 'AssertionComments'],\n '0107': ['SQ', '1', 'RelatedAssertionSequence'],\n '0108': ['UI', '1', 'ReferencedAssertionUID'],\n '0109': ['SQ', '1', 'ApprovalSubjectSequence'],\n '010A': ['SQ', '1', 'OrganizationalRoleCodeSequence']\n },\n '0046': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0012': ['LO', '1', 'LensDescription'],\n '0014': ['SQ', '1', 'RightLensSequence'],\n '0015': ['SQ', '1', 'LeftLensSequence'],\n '0016': ['SQ', '1', 'UnspecifiedLateralityLensSequence'],\n '0018': ['SQ', '1', 'CylinderSequence'],\n '0028': ['SQ', '1', 'PrismSequence'],\n '0030': ['FD', '1', 'HorizontalPrismPower'],\n '0032': ['CS', '1', 'HorizontalPrismBase'],\n '0034': ['FD', '1', 'VerticalPrismPower'],\n '0036': ['CS', '1', 'VerticalPrismBase'],\n '0038': ['CS', '1', 'LensSegmentType'],\n '0040': ['FD', '1', 'OpticalTransmittance'],\n '0042': ['FD', '1', 'ChannelWidth'],\n '0044': ['FD', '1', 'PupilSize'],\n '0046': ['FD', '1', 'CornealSize'],\n '0047': ['SQ', '1', 'CornealSizeSequence'],\n '0050': ['SQ', '1', 'AutorefractionRightEyeSequence'],\n '0052': ['SQ', '1', 'AutorefractionLeftEyeSequence'],\n '0060': ['FD', '1', 'DistancePupillaryDistance'],\n '0062': ['FD', '1', 'NearPupillaryDistance'],\n '0063': ['FD', '1', 'IntermediatePupillaryDistance'],\n '0064': ['FD', '1', 'OtherPupillaryDistance'],\n '0070': ['SQ', '1', 'KeratometryRightEyeSequence'],\n '0071': ['SQ', '1', 'KeratometryLeftEyeSequence'],\n '0074': ['SQ', '1', 'SteepKeratometricAxisSequence'],\n '0075': ['FD', '1', 'RadiusOfCurvature'],\n '0076': ['FD', '1', 'KeratometricPower'],\n '0077': ['FD', '1', 'KeratometricAxis'],\n '0080': ['SQ', '1', 'FlatKeratometricAxisSequence'],\n '0092': ['CS', '1', 'BackgroundColor'],\n '0094': ['CS', '1', 'Optotype'],\n '0095': ['CS', '1', 'OptotypePresentation'],\n '0097': ['SQ', '1', 'SubjectiveRefractionRightEyeSequence'],\n '0098': ['SQ', '1', 'SubjectiveRefractionLeftEyeSequence'],\n '0100': ['SQ', '1', 'AddNearSequence'],\n '0101': ['SQ', '1', 'AddIntermediateSequence'],\n '0102': ['SQ', '1', 'AddOtherSequence'],\n '0104': ['FD', '1', 'AddPower'],\n '0106': ['FD', '1', 'ViewingDistance'],\n '0110': ['SQ', '1', 'CorneaMeasurementsSequence'],\n '0111': ['SQ', '1', 'SourceOfCorneaMeasurementDataCodeSequence'],\n '0112': ['SQ', '1', 'SteepCornealAxisSequence'],\n '0113': ['SQ', '1', 'FlatCornealAxisSequence'],\n '0114': ['FD', '1', 'CornealPower'],\n '0115': ['FD', '1', 'CornealAxis'],\n '0116': ['SQ', '1', 'CorneaMeasurementMethodCodeSequence'],\n '0117': ['FL', '1', 'RefractiveIndexOfCornea'],\n '0118': ['FL', '1', 'RefractiveIndexOfAqueousHumor'],\n '0121': ['SQ', '1', 'VisualAcuityTypeCodeSequence'],\n '0122': ['SQ', '1', 'VisualAcuityRightEyeSequence'],\n '0123': ['SQ', '1', 'VisualAcuityLeftEyeSequence'],\n '0124': ['SQ', '1', 'VisualAcuityBothEyesOpenSequence'],\n '0125': ['CS', '1', 'ViewingDistanceType'],\n '0135': ['SS', '2', 'VisualAcuityModifiers'],\n '0137': ['FD', '1', 'DecimalVisualAcuity'],\n '0139': ['LO', '1', 'OptotypeDetailedDefinition'],\n '0145': ['SQ', '1', 'ReferencedRefractiveMeasurementsSequence'],\n '0146': ['FD', '1', 'SpherePower'],\n '0147': ['FD', '1', 'CylinderPower'],\n '0201': ['CS', '1', 'CornealTopographySurface'],\n '0202': ['FL', '2', 'CornealVertexLocation'],\n '0203': ['FL', '1', 'PupilCentroidXCoordinate'],\n '0204': ['FL', '1', 'PupilCentroidYCoordinate'],\n '0205': ['FL', '1', 'EquivalentPupilRadius'],\n '0207': ['SQ', '1', 'CornealTopographyMapTypeCodeSequence'],\n '0208': ['IS', '2-2n', 'VerticesOfTheOutlineOfPupil'],\n '0210': ['SQ', '1', 'CornealTopographyMappingNormalsSequence'],\n '0211': ['SQ', '1', 'MaximumCornealCurvatureSequence'],\n '0212': ['FL', '1', 'MaximumCornealCurvature'],\n '0213': ['FL', '2', 'MaximumCornealCurvatureLocation'],\n '0215': ['SQ', '1', 'MinimumKeratometricSequence'],\n '0218': ['SQ', '1', 'SimulatedKeratometricCylinderSequence'],\n '0220': ['FL', '1', 'AverageCornealPower'],\n '0224': ['FL', '1', 'CornealISValue'],\n '0227': ['FL', '1', 'AnalyzedArea'],\n '0230': ['FL', '1', 'SurfaceRegularityIndex'],\n '0232': ['FL', '1', 'SurfaceAsymmetryIndex'],\n '0234': ['FL', '1', 'CornealEccentricityIndex'],\n '0236': ['FL', '1', 'KeratoconusPredictionIndex'],\n '0238': ['FL', '1', 'DecimalPotentialVisualAcuity'],\n '0242': ['CS', '1', 'CornealTopographyMapQualityEvaluation'],\n '0244': ['SQ', '1', 'SourceImageCornealProcessedDataSequence'],\n '0247': ['FL', '3', 'CornealPointLocation'],\n '0248': ['CS', '1', 'CornealPointEstimated'],\n '0249': ['FL', '1', 'AxialPower'],\n '0250': ['FL', '1', 'TangentialPower'],\n '0251': ['FL', '1', 'RefractivePower'],\n '0252': ['FL', '1', 'RelativeElevation'],\n '0253': ['FL', '1', 'CornealWavefront']\n },\n '0048': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['FL', '1', 'ImagedVolumeWidth'],\n '0002': ['FL', '1', 'ImagedVolumeHeight'],\n '0003': ['FL', '1', 'ImagedVolumeDepth'],\n '0006': ['UL', '1', 'TotalPixelMatrixColumns'],\n '0007': ['UL', '1', 'TotalPixelMatrixRows'],\n '0008': ['SQ', '1', 'TotalPixelMatrixOriginSequence'],\n '0010': ['CS', '1', 'SpecimenLabelInImage'],\n '0011': ['CS', '1', 'FocusMethod'],\n '0012': ['CS', '1', 'ExtendedDepthOfField'],\n '0013': ['US', '1', 'NumberOfFocalPlanes'],\n '0014': ['FL', '1', 'DistanceBetweenFocalPlanes'],\n '0015': ['US', '3', 'RecommendedAbsentPixelCIELabValue'],\n '0100': ['SQ', '1', 'IlluminatorTypeCodeSequence'],\n '0102': ['DS', '6', 'ImageOrientationSlide'],\n '0105': ['SQ', '1', 'OpticalPathSequence'],\n '0106': ['SH', '1', 'OpticalPathIdentifier'],\n '0107': ['ST', '1', 'OpticalPathDescription'],\n '0108': ['SQ', '1', 'IlluminationColorCodeSequence'],\n '0110': ['SQ', '1', 'SpecimenReferenceSequence'],\n '0111': ['DS', '1', 'CondenserLensPower'],\n '0112': ['DS', '1', 'ObjectiveLensPower'],\n '0113': ['DS', '1', 'ObjectiveLensNumericalAperture'],\n '0120': ['SQ', '1', 'PaletteColorLookupTableSequence'],\n '0200': ['SQ', '1', 'ReferencedImageNavigationSequence'],\n '0201': ['US', '2', 'TopLeftHandCornerOfLocalizerArea'],\n '0202': ['US', '2', 'BottomRightHandCornerOfLocalizerArea'],\n '0207': ['SQ', '1', 'OpticalPathIdentificationSequence'],\n '021A': ['SQ', '1', 'PlanePositionSlideSequence'],\n '021E': ['SL', '1', 'ColumnPositionInTotalImagePixelMatrix'],\n '021F': ['SL', '1', 'RowPositionInTotalImagePixelMatrix'],\n '0301': ['CS', '1', 'PixelOriginInterpretation'],\n '0302': ['UL', '1', 'NumberOfOpticalPaths'],\n '0303': ['UL', '1', 'TotalPixelMatrixFocalPlanes']\n },\n '0050': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0004': ['CS', '1', 'CalibrationImage'],\n '0010': ['SQ', '1', 'DeviceSequence'],\n '0012': ['SQ', '1', 'ContainerComponentTypeCodeSequence'],\n '0013': ['FD', '1', 'ContainerComponentThickness'],\n '0014': ['DS', '1', 'DeviceLength'],\n '0015': ['FD', '1', 'ContainerComponentWidth'],\n '0016': ['DS', '1', 'DeviceDiameter'],\n '0017': ['CS', '1', 'DeviceDiameterUnits'],\n '0018': ['DS', '1', 'DeviceVolume'],\n '0019': ['DS', '1', 'InterMarkerDistance'],\n '001A': ['CS', '1', 'ContainerComponentMaterial'],\n '001B': ['LO', '1', 'ContainerComponentID'],\n '001C': ['FD', '1', 'ContainerComponentLength'],\n '001D': ['FD', '1', 'ContainerComponentDiameter'],\n '001E': ['LO', '1', 'ContainerComponentDescription'],\n '0020': ['LO', '1', 'DeviceDescription'],\n '0021': ['ST', '1', 'LongDeviceDescription']\n },\n '0052': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['FL', '1', 'ContrastBolusIngredientPercentByVolume'],\n '0002': ['FD', '1', 'OCTFocalDistance'],\n '0003': ['FD', '1', 'BeamSpotSize'],\n '0004': ['FD', '1', 'EffectiveRefractiveIndex'],\n '0006': ['CS', '1', 'OCTAcquisitionDomain'],\n '0007': ['FD', '1', 'OCTOpticalCenterWavelength'],\n '0008': ['FD', '1', 'AxialResolution'],\n '0009': ['FD', '1', 'RangingDepth'],\n '0011': ['FD', '1', 'ALineRate'],\n '0012': ['US', '1', 'ALinesPerFrame'],\n '0013': ['FD', '1', 'CatheterRotationalRate'],\n '0014': ['FD', '1', 'ALinePixelSpacing'],\n '0016': ['SQ', '1', 'ModeOfPercutaneousAccessSequence'],\n '0025': ['SQ', '1', 'IntravascularOCTFrameTypeSequence'],\n '0026': ['CS', '1', 'OCTZOffsetApplied'],\n '0027': ['SQ', '1', 'IntravascularFrameContentSequence'],\n '0028': ['FD', '1', 'IntravascularLongitudinalDistance'],\n '0029': ['SQ', '1', 'IntravascularOCTFrameContentSequence'],\n '0030': ['SS', '1', 'OCTZOffsetCorrection'],\n '0031': ['CS', '1', 'CatheterDirectionOfRotation'],\n '0033': ['FD', '1', 'SeamLineLocation'],\n '0034': ['FD', '1', 'FirstALineLocation'],\n '0036': ['US', '1', 'SeamLineIndex'],\n '0038': ['US', '1', 'NumberOfPaddedALines'],\n '0039': ['CS', '1', 'InterpolationType'],\n '003A': ['CS', '1', 'RefractiveIndexApplied']\n },\n '0054': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['US', '1-n', 'EnergyWindowVector'],\n '0011': ['US', '1', 'NumberOfEnergyWindows'],\n '0012': ['SQ', '1', 'EnergyWindowInformationSequence'],\n '0013': ['SQ', '1', 'EnergyWindowRangeSequence'],\n '0014': ['DS', '1', 'EnergyWindowLowerLimit'],\n '0015': ['DS', '1', 'EnergyWindowUpperLimit'],\n '0016': ['SQ', '1', 'RadiopharmaceuticalInformationSequence'],\n '0017': ['IS', '1', 'ResidualSyringeCounts'],\n '0018': ['SH', '1', 'EnergyWindowName'],\n '0020': ['US', '1-n', 'DetectorVector'],\n '0021': ['US', '1', 'NumberOfDetectors'],\n '0022': ['SQ', '1', 'DetectorInformationSequence'],\n '0030': ['US', '1-n', 'PhaseVector'],\n '0031': ['US', '1', 'NumberOfPhases'],\n '0032': ['SQ', '1', 'PhaseInformationSequence'],\n '0033': ['US', '1', 'NumberOfFramesInPhase'],\n '0036': ['IS', '1', 'PhaseDelay'],\n '0038': ['IS', '1', 'PauseBetweenFrames'],\n '0039': ['CS', '1', 'PhaseDescription'],\n '0050': ['US', '1-n', 'RotationVector'],\n '0051': ['US', '1', 'NumberOfRotations'],\n '0052': ['SQ', '1', 'RotationInformationSequence'],\n '0053': ['US', '1', 'NumberOfFramesInRotation'],\n '0060': ['US', '1-n', 'RRIntervalVector'],\n '0061': ['US', '1', 'NumberOfRRIntervals'],\n '0062': ['SQ', '1', 'GatedInformationSequence'],\n '0063': ['SQ', '1', 'DataInformationSequence'],\n '0070': ['US', '1-n', 'TimeSlotVector'],\n '0071': ['US', '1', 'NumberOfTimeSlots'],\n '0072': ['SQ', '1', 'TimeSlotInformationSequence'],\n '0073': ['DS', '1', 'TimeSlotTime'],\n '0080': ['US', '1-n', 'SliceVector'],\n '0081': ['US', '1', 'NumberOfSlices'],\n '0090': ['US', '1-n', 'AngularViewVector'],\n '0100': ['US', '1-n', 'TimeSliceVector'],\n '0101': ['US', '1', 'NumberOfTimeSlices'],\n '0200': ['DS', '1', 'StartAngle'],\n '0202': ['CS', '1', 'TypeOfDetectorMotion'],\n '0210': ['IS', '1-n', 'TriggerVector'],\n '0211': ['US', '1', 'NumberOfTriggersInPhase'],\n '0220': ['SQ', '1', 'ViewCodeSequence'],\n '0222': ['SQ', '1', 'ViewModifierCodeSequence'],\n '0300': ['SQ', '1', 'RadionuclideCodeSequence'],\n '0302': ['SQ', '1', 'AdministrationRouteCodeSequence'],\n '0304': ['SQ', '1', 'RadiopharmaceuticalCodeSequence'],\n '0306': ['SQ', '1', 'CalibrationDataSequence'],\n '0308': ['US', '1', 'EnergyWindowNumber'],\n '0400': ['SH', '1', 'ImageID'],\n '0410': ['SQ', '1', 'PatientOrientationCodeSequence'],\n '0412': ['SQ', '1', 'PatientOrientationModifierCodeSequence'],\n '0414': ['SQ', '1', 'PatientGantryRelationshipCodeSequence'],\n '0500': ['CS', '1', 'SliceProgressionDirection'],\n '0501': ['CS', '1', 'ScanProgressionDirection'],\n '1000': ['CS', '2', 'SeriesType'],\n '1001': ['CS', '1', 'Units'],\n '1002': ['CS', '1', 'CountsSource'],\n '1004': ['CS', '1', 'ReprojectionMethod'],\n '1006': ['CS', '1', 'SUVType'],\n '1100': ['CS', '1', 'RandomsCorrectionMethod'],\n '1101': ['LO', '1', 'AttenuationCorrectionMethod'],\n '1102': ['CS', '1', 'DecayCorrection'],\n '1103': ['LO', '1', 'ReconstructionMethod'],\n '1104': ['LO', '1', 'DetectorLinesOfResponseUsed'],\n '1105': ['LO', '1', 'ScatterCorrectionMethod'],\n '1200': ['DS', '1', 'AxialAcceptance'],\n '1201': ['IS', '2', 'AxialMash'],\n '1202': ['IS', '1', 'TransverseMash'],\n '1203': ['DS', '2', 'DetectorElementSize'],\n '1210': ['DS', '1', 'CoincidenceWindowWidth'],\n '1220': ['CS', '1-n', 'SecondaryCountsType'],\n '1300': ['DS', '1', 'FrameReferenceTime'],\n '1310': ['IS', '1', 'PrimaryPromptsCountsAccumulated'],\n '1311': ['IS', '1-n', 'SecondaryCountsAccumulated'],\n '1320': ['DS', '1', 'SliceSensitivityFactor'],\n '1321': ['DS', '1', 'DecayFactor'],\n '1322': ['DS', '1', 'DoseCalibrationFactor'],\n '1323': ['DS', '1', 'ScatterFractionFactor'],\n '1324': ['DS', '1', 'DeadTimeFactor'],\n '1330': ['US', '1', 'ImageIndex'],\n '1400': ['CS', '1-n', 'CountsIncluded'],\n '1401': ['CS', '1', 'DeadTimeCorrectionFlag']\n },\n '0060': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '3000': ['SQ', '1', 'HistogramSequence'],\n '3002': ['US', '1', 'HistogramNumberOfBins'],\n '3004': ['xs', '1', 'HistogramFirstBinValue'],\n '3006': ['xs', '1', 'HistogramLastBinValue'],\n '3008': ['US', '1', 'HistogramBinWidth'],\n '3010': ['LO', '1', 'HistogramExplanation'],\n '3020': ['UL', '1-n', 'HistogramData']\n },\n '0062': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['CS', '1', 'SegmentationType'],\n '0002': ['SQ', '1', 'SegmentSequence'],\n '0003': ['SQ', '1', 'SegmentedPropertyCategoryCodeSequence'],\n '0004': ['US', '1', 'SegmentNumber'],\n '0005': ['LO', '1', 'SegmentLabel'],\n '0006': ['ST', '1', 'SegmentDescription'],\n '0007': ['SQ', '1', 'SegmentationAlgorithmIdentificationSequence'],\n '0008': ['CS', '1', 'SegmentAlgorithmType'],\n '0009': ['LO', '1-n', 'SegmentAlgorithmName'],\n '000A': ['SQ', '1', 'SegmentIdentificationSequence'],\n '000B': ['US', '1-n', 'ReferencedSegmentNumber'],\n '000C': ['US', '1', 'RecommendedDisplayGrayscaleValue'],\n '000D': ['US', '3', 'RecommendedDisplayCIELabValue'],\n '000E': ['US', '1', 'MaximumFractionalValue'],\n '000F': ['SQ', '1', 'SegmentedPropertyTypeCodeSequence'],\n '0010': ['CS', '1', 'SegmentationFractionalType'],\n '0011': ['SQ', '1', 'SegmentedPropertyTypeModifierCodeSequence'],\n '0012': ['SQ', '1', 'UsedSegmentsSequence'],\n '0013': ['CS', '1', 'SegmentsOverlap'],\n '0020': ['UT', '1', 'TrackingID'],\n '0021': ['UI', '1', 'TrackingUID']\n },\n '0064': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['SQ', '1', 'DeformableRegistrationSequence'],\n '0003': ['UI', '1', 'SourceFrameOfReferenceUID'],\n '0005': ['SQ', '1', 'DeformableRegistrationGridSequence'],\n '0007': ['UL', '3', 'GridDimensions'],\n '0008': ['FD', '3', 'GridResolution'],\n '0009': ['OF', '1', 'VectorGridData'],\n '000F': ['SQ', '1', 'PreDeformationMatrixRegistrationSequence'],\n '0010': ['SQ', '1', 'PostDeformationMatrixRegistrationSequence']\n },\n '0066': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['UL', '1', 'NumberOfSurfaces'],\n '0002': ['SQ', '1', 'SurfaceSequence'],\n '0003': ['UL', '1', 'SurfaceNumber'],\n '0004': ['LT', '1', 'SurfaceComments'],\n '0009': ['CS', '1', 'SurfaceProcessing'],\n '000A': ['FL', '1', 'SurfaceProcessingRatio'],\n '000B': ['LO', '1', 'SurfaceProcessingDescription'],\n '000C': ['FL', '1', 'RecommendedPresentationOpacity'],\n '000D': ['CS', '1', 'RecommendedPresentationType'],\n '000E': ['CS', '1', 'FiniteVolume'],\n '0010': ['CS', '1', 'Manifold'],\n '0011': ['SQ', '1', 'SurfacePointsSequence'],\n '0012': ['SQ', '1', 'SurfacePointsNormalsSequence'],\n '0013': ['SQ', '1', 'SurfaceMeshPrimitivesSequence'],\n '0015': ['UL', '1', 'NumberOfSurfacePoints'],\n '0016': ['OF', '1', 'PointCoordinatesData'],\n '0017': ['FL', '3', 'PointPositionAccuracy'],\n '0018': ['FL', '1', 'MeanPointDistance'],\n '0019': ['FL', '1', 'MaximumPointDistance'],\n '001A': ['FL', '6', 'PointsBoundingBoxCoordinates'],\n '001B': ['FL', '3', 'AxisOfRotation'],\n '001C': ['FL', '3', 'CenterOfRotation'],\n '001E': ['UL', '1', 'NumberOfVectors'],\n '001F': ['US', '1', 'VectorDimensionality'],\n '0020': ['FL', '1-n', 'VectorAccuracy'],\n '0021': ['OF', '1', 'VectorCoordinateData'],\n '0022': ['OD', '1', 'DoublePointCoordinatesData'],\n '0023': ['OW', '1', 'TrianglePointIndexList'],\n '0024': ['OW', '1', 'EdgePointIndexList'],\n '0025': ['OW', '1', 'VertexPointIndexList'],\n '0026': ['SQ', '1', 'TriangleStripSequence'],\n '0027': ['SQ', '1', 'TriangleFanSequence'],\n '0028': ['SQ', '1', 'LineSequence'],\n '0029': ['OW', '1', 'PrimitivePointIndexList'],\n '002A': ['UL', '1', 'SurfaceCount'],\n '002B': ['SQ', '1', 'ReferencedSurfaceSequence'],\n '002C': ['UL', '1', 'ReferencedSurfaceNumber'],\n '002D': ['SQ', '1', 'SegmentSurfaceGenerationAlgorithmIdentificationSequence'],\n '002E': ['SQ', '1', 'SegmentSurfaceSourceInstanceSequence'],\n '002F': ['SQ', '1', 'AlgorithmFamilyCodeSequence'],\n '0030': ['SQ', '1', 'AlgorithmNameCodeSequence'],\n '0031': ['LO', '1', 'AlgorithmVersion'],\n '0032': ['LT', '1', 'AlgorithmParameters'],\n '0034': ['SQ', '1', 'FacetSequence'],\n '0035': ['SQ', '1', 'SurfaceProcessingAlgorithmIdentificationSequence'],\n '0036': ['LO', '1', 'AlgorithmName'],\n '0037': ['FL', '1', 'RecommendedPointRadius'],\n '0038': ['FL', '1', 'RecommendedLineThickness'],\n '0040': ['OL', '1', 'LongPrimitivePointIndexList'],\n '0041': ['OL', '1', 'LongTrianglePointIndexList'],\n '0042': ['OL', '1', 'LongEdgePointIndexList'],\n '0043': ['OL', '1', 'LongVertexPointIndexList'],\n '0101': ['SQ', '1', 'TrackSetSequence'],\n '0102': ['SQ', '1', 'TrackSequence'],\n '0103': ['OW', '1', 'RecommendedDisplayCIELabValueList'],\n '0104': ['SQ', '1', 'TrackingAlgorithmIdentificationSequence'],\n '0105': ['UL', '1', 'TrackSetNumber'],\n '0106': ['LO', '1', 'TrackSetLabel'],\n '0107': ['UT', '1', 'TrackSetDescription'],\n '0108': ['SQ', '1', 'TrackSetAnatomicalTypeCodeSequence'],\n '0121': ['SQ', '1', 'MeasurementsSequence'],\n '0124': ['SQ', '1', 'TrackSetStatisticsSequence'],\n '0125': ['OF', '1', 'FloatingPointValues'],\n '0129': ['OL', '1', 'TrackPointIndexList'],\n '0130': ['SQ', '1', 'TrackStatisticsSequence'],\n '0132': ['SQ', '1', 'MeasurementValuesSequence'],\n '0133': ['SQ', '1', 'DiffusionAcquisitionCodeSequence'],\n '0134': ['SQ', '1', 'DiffusionModelCodeSequence']\n },\n '0068': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '6210': ['LO', '1', 'ImplantSize'],\n '6221': ['LO', '1', 'ImplantTemplateVersion'],\n '6222': ['SQ', '1', 'ReplacedImplantTemplateSequence'],\n '6223': ['CS', '1', 'ImplantType'],\n '6224': ['SQ', '1', 'DerivationImplantTemplateSequence'],\n '6225': ['SQ', '1', 'OriginalImplantTemplateSequence'],\n '6226': ['DT', '1', 'EffectiveDateTime'],\n '6230': ['SQ', '1', 'ImplantTargetAnatomySequence'],\n '6260': ['SQ', '1', 'InformationFromManufacturerSequence'],\n '6265': ['SQ', '1', 'NotificationFromManufacturerSequence'],\n '6270': ['DT', '1', 'InformationIssueDateTime'],\n '6280': ['ST', '1', 'InformationSummary'],\n '62A0': ['SQ', '1', 'ImplantRegulatoryDisapprovalCodeSequence'],\n '62A5': ['FD', '1', 'OverallTemplateSpatialTolerance'],\n '62C0': ['SQ', '1', 'HPGLDocumentSequence'],\n '62D0': ['US', '1', 'HPGLDocumentID'],\n '62D5': ['LO', '1', 'HPGLDocumentLabel'],\n '62E0': ['SQ', '1', 'ViewOrientationCodeSequence'],\n '62F0': ['SQ', '1', 'ViewOrientationModifierCodeSequence'],\n '62F2': ['FD', '1', 'HPGLDocumentScaling'],\n '6300': ['OB', '1', 'HPGLDocument'],\n '6310': ['US', '1', 'HPGLContourPenNumber'],\n '6320': ['SQ', '1', 'HPGLPenSequence'],\n '6330': ['US', '1', 'HPGLPenNumber'],\n '6340': ['LO', '1', 'HPGLPenLabel'],\n '6345': ['ST', '1', 'HPGLPenDescription'],\n '6346': ['FD', '2', 'RecommendedRotationPoint'],\n '6347': ['FD', '4', 'BoundingRectangle'],\n '6350': ['US', '1-n', 'ImplantTemplate3DModelSurfaceNumber'],\n '6360': ['SQ', '1', 'SurfaceModelDescriptionSequence'],\n '6380': ['LO', '1', 'SurfaceModelLabel'],\n '6390': ['FD', '1', 'SurfaceModelScalingFactor'],\n '63A0': ['SQ', '1', 'MaterialsCodeSequence'],\n '63A4': ['SQ', '1', 'CoatingMaterialsCodeSequence'],\n '63A8': ['SQ', '1', 'ImplantTypeCodeSequence'],\n '63AC': ['SQ', '1', 'FixationMethodCodeSequence'],\n '63B0': ['SQ', '1', 'MatingFeatureSetsSequence'],\n '63C0': ['US', '1', 'MatingFeatureSetID'],\n '63D0': ['LO', '1', 'MatingFeatureSetLabel'],\n '63E0': ['SQ', '1', 'MatingFeatureSequence'],\n '63F0': ['US', '1', 'MatingFeatureID'],\n '6400': ['SQ', '1', 'MatingFeatureDegreeOfFreedomSequence'],\n '6410': ['US', '1', 'DegreeOfFreedomID'],\n '6420': ['CS', '1', 'DegreeOfFreedomType'],\n '6430': ['SQ', '1', 'TwoDMatingFeatureCoordinatesSequence'],\n '6440': ['US', '1', 'ReferencedHPGLDocumentID'],\n '6450': ['FD', '2', 'TwoDMatingPoint'],\n '6460': ['FD', '4', 'TwoDMatingAxes'],\n '6470': ['SQ', '1', 'TwoDDegreeOfFreedomSequence'],\n '6490': ['FD', '3', 'ThreeDDegreeOfFreedomAxis'],\n '64A0': ['FD', '2', 'RangeOfFreedom'],\n '64C0': ['FD', '3', 'ThreeDMatingPoint'],\n '64D0': ['FD', '9', 'ThreeDMatingAxes'],\n '64F0': ['FD', '3', 'TwoDDegreeOfFreedomAxis'],\n '6500': ['SQ', '1', 'PlanningLandmarkPointSequence'],\n '6510': ['SQ', '1', 'PlanningLandmarkLineSequence'],\n '6520': ['SQ', '1', 'PlanningLandmarkPlaneSequence'],\n '6530': ['US', '1', 'PlanningLandmarkID'],\n '6540': ['LO', '1', 'PlanningLandmarkDescription'],\n '6545': ['SQ', '1', 'PlanningLandmarkIdentificationCodeSequence'],\n '6550': ['SQ', '1', 'TwoDPointCoordinatesSequence'],\n '6560': ['FD', '2', 'TwoDPointCoordinates'],\n '6590': ['FD', '3', 'ThreeDPointCoordinates'],\n '65A0': ['SQ', '1', 'TwoDLineCoordinatesSequence'],\n '65B0': ['FD', '4', 'TwoDLineCoordinates'],\n '65D0': ['FD', '6', 'ThreeDLineCoordinates'],\n '65E0': ['SQ', '1', 'TwoDPlaneCoordinatesSequence'],\n '65F0': ['FD', '4', 'TwoDPlaneIntersection'],\n '6610': ['FD', '3', 'ThreeDPlaneOrigin'],\n '6620': ['FD', '3', 'ThreeDPlaneNormal'],\n '7001': ['CS', '1', 'ModelModification'],\n '7002': ['CS', '1', 'ModelMirroring'],\n '7003': ['SQ', '1', 'ModelUsageCodeSequence'],\n '7004': ['UI', '1', 'ModelGroupUID'],\n '7005': ['UR', '1', 'RelativeURIReferenceWithinEncapsulatedDocument']\n },\n '006A': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['CS', '1', 'AnnotationCoordinateType'],\n '0002': ['SQ', '1', 'AnnotationGroupSequence'],\n '0003': ['UI', '1', 'AnnotationGroupUID'],\n '0005': ['LO', '1', 'AnnotationGroupLabel'],\n '0006': ['UT', '1', 'AnnotationGroupDescription'],\n '0007': ['CS', '1', 'AnnotationGroupGenerationType'],\n '0008': ['SQ', '1', 'AnnotationGroupAlgorithmIdentificationSequence'],\n '0009': ['SQ', '1', 'AnnotationPropertyCategoryCodeSequence'],\n '000A': ['SQ', '1', 'AnnotationPropertyTypeCodeSequence'],\n '000B': ['SQ', '1', 'AnnotationPropertyTypeModifierCodeSequence'],\n '000C': ['UL', '1', 'NumberOfAnnotations'],\n '000D': ['CS', '1', 'AnnotationAppliesToAllOpticalPaths'],\n '000E': ['SH', '1-n', 'ReferencedOpticalPathIdentifier'],\n '000F': ['CS', '1', 'AnnotationAppliesToAllZPlanes'],\n '0010': ['FD', '1-n', 'CommonZCoordinateValue'],\n '0011': ['OL', '1', 'AnnotationIndexList']\n },\n '0070': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['SQ', '1', 'GraphicAnnotationSequence'],\n '0002': ['CS', '1', 'GraphicLayer'],\n '0003': ['CS', '1', 'BoundingBoxAnnotationUnits'],\n '0004': ['CS', '1', 'AnchorPointAnnotationUnits'],\n '0005': ['CS', '1', 'GraphicAnnotationUnits'],\n '0006': ['ST', '1', 'UnformattedTextValue'],\n '0008': ['SQ', '1', 'TextObjectSequence'],\n '0009': ['SQ', '1', 'GraphicObjectSequence'],\n '0010': ['FL', '2', 'BoundingBoxTopLeftHandCorner'],\n '0011': ['FL', '2', 'BoundingBoxBottomRightHandCorner'],\n '0012': ['CS', '1', 'BoundingBoxTextHorizontalJustification'],\n '0014': ['FL', '2', 'AnchorPoint'],\n '0015': ['CS', '1', 'AnchorPointVisibility'],\n '0020': ['US', '1', 'GraphicDimensions'],\n '0021': ['US', '1', 'NumberOfGraphicPoints'],\n '0022': ['FL', '2-n', 'GraphicData'],\n '0023': ['CS', '1', 'GraphicType'],\n '0024': ['CS', '1', 'GraphicFilled'],\n '0040': ['IS', '1', 'ImageRotationRetired'],\n '0041': ['CS', '1', 'ImageHorizontalFlip'],\n '0042': ['US', '1', 'ImageRotation'],\n '0050': ['US', '2', 'DisplayedAreaTopLeftHandCornerTrial'],\n '0051': ['US', '2', 'DisplayedAreaBottomRightHandCornerTrial'],\n '0052': ['SL', '2', 'DisplayedAreaTopLeftHandCorner'],\n '0053': ['SL', '2', 'DisplayedAreaBottomRightHandCorner'],\n '005A': ['SQ', '1', 'DisplayedAreaSelectionSequence'],\n '0060': ['SQ', '1', 'GraphicLayerSequence'],\n '0062': ['IS', '1', 'GraphicLayerOrder'],\n '0066': ['US', '1', 'GraphicLayerRecommendedDisplayGrayscaleValue'],\n '0067': ['US', '3', 'GraphicLayerRecommendedDisplayRGBValue'],\n '0068': ['LO', '1', 'GraphicLayerDescription'],\n '0080': ['CS', '1', 'ContentLabel'],\n '0081': ['LO', '1', 'ContentDescription'],\n '0082': ['DA', '1', 'PresentationCreationDate'],\n '0083': ['TM', '1', 'PresentationCreationTime'],\n '0084': ['PN', '1', 'ContentCreatorName'],\n '0086': ['SQ', '1', 'ContentCreatorIdentificationCodeSequence'],\n '0087': ['SQ', '1', 'AlternateContentDescriptionSequence'],\n '0100': ['CS', '1', 'PresentationSizeMode'],\n '0101': ['DS', '2', 'PresentationPixelSpacing'],\n '0102': ['IS', '2', 'PresentationPixelAspectRatio'],\n '0103': ['FL', '1', 'PresentationPixelMagnificationRatio'],\n '0207': ['LO', '1', 'GraphicGroupLabel'],\n '0208': ['ST', '1', 'GraphicGroupDescription'],\n '0209': ['SQ', '1', 'CompoundGraphicSequence'],\n '0226': ['UL', '1', 'CompoundGraphicInstanceID'],\n '0227': ['LO', '1', 'FontName'],\n '0228': ['CS', '1', 'FontNameType'],\n '0229': ['LO', '1', 'CSSFontName'],\n '0230': ['FD', '1', 'RotationAngle'],\n '0231': ['SQ', '1', 'TextStyleSequence'],\n '0232': ['SQ', '1', 'LineStyleSequence'],\n '0233': ['SQ', '1', 'FillStyleSequence'],\n '0234': ['SQ', '1', 'GraphicGroupSequence'],\n '0241': ['US', '3', 'TextColorCIELabValue'],\n '0242': ['CS', '1', 'HorizontalAlignment'],\n '0243': ['CS', '1', 'VerticalAlignment'],\n '0244': ['CS', '1', 'ShadowStyle'],\n '0245': ['FL', '1', 'ShadowOffsetX'],\n '0246': ['FL', '1', 'ShadowOffsetY'],\n '0247': ['US', '3', 'ShadowColorCIELabValue'],\n '0248': ['CS', '1', 'Underlined'],\n '0249': ['CS', '1', 'Bold'],\n '0250': ['CS', '1', 'Italic'],\n '0251': ['US', '3', 'PatternOnColorCIELabValue'],\n '0252': ['US', '3', 'PatternOffColorCIELabValue'],\n '0253': ['FL', '1', 'LineThickness'],\n '0254': ['CS', '1', 'LineDashingStyle'],\n '0255': ['UL', '1', 'LinePattern'],\n '0256': ['OB', '1', 'FillPattern'],\n '0257': ['CS', '1', 'FillMode'],\n '0258': ['FL', '1', 'ShadowOpacity'],\n '0261': ['FL', '1', 'GapLength'],\n '0262': ['FL', '1', 'DiameterOfVisibility'],\n '0273': ['FL', '2', 'RotationPoint'],\n '0274': ['CS', '1', 'TickAlignment'],\n '0278': ['CS', '1', 'ShowTickLabel'],\n '0279': ['CS', '1', 'TickLabelAlignment'],\n '0282': ['CS', '1', 'CompoundGraphicUnits'],\n '0284': ['FL', '1', 'PatternOnOpacity'],\n '0285': ['FL', '1', 'PatternOffOpacity'],\n '0287': ['SQ', '1', 'MajorTicksSequence'],\n '0288': ['FL', '1', 'TickPosition'],\n '0289': ['SH', '1', 'TickLabel'],\n '0294': ['CS', '1', 'CompoundGraphicType'],\n '0295': ['UL', '1', 'GraphicGroupID'],\n '0306': ['CS', '1', 'ShapeType'],\n '0308': ['SQ', '1', 'RegistrationSequence'],\n '0309': ['SQ', '1', 'MatrixRegistrationSequence'],\n '030A': ['SQ', '1', 'MatrixSequence'],\n '030B': ['FD', '16', 'FrameOfReferenceToDisplayedCoordinateSystemTransformationMatrix'],\n '030C': ['CS', '1', 'FrameOfReferenceTransformationMatrixType'],\n '030D': ['SQ', '1', 'RegistrationTypeCodeSequence'],\n '030F': ['ST', '1', 'FiducialDescription'],\n '0310': ['SH', '1', 'FiducialIdentifier'],\n '0311': ['SQ', '1', 'FiducialIdentifierCodeSequence'],\n '0312': ['FD', '1', 'ContourUncertaintyRadius'],\n '0314': ['SQ', '1', 'UsedFiducialsSequence'],\n '0318': ['SQ', '1', 'GraphicCoordinatesDataSequence'],\n '031A': ['UI', '1', 'FiducialUID'],\n '031B': ['UI', '1', 'ReferencedFiducialUID'],\n '031C': ['SQ', '1', 'FiducialSetSequence'],\n '031E': ['SQ', '1', 'FiducialSequence'],\n '031F': ['SQ', '1', 'FiducialsPropertyCategoryCodeSequence'],\n '0401': ['US', '3', 'GraphicLayerRecommendedDisplayCIELabValue'],\n '0402': ['SQ', '1', 'BlendingSequence'],\n '0403': ['FL', '1', 'RelativeOpacity'],\n '0404': ['SQ', '1', 'ReferencedSpatialRegistrationSequence'],\n '0405': ['CS', '1', 'BlendingPosition'],\n '1101': ['UI', '1', 'PresentationDisplayCollectionUID'],\n '1102': ['UI', '1', 'PresentationSequenceCollectionUID'],\n '1103': ['US', '1', 'PresentationSequencePositionIndex'],\n '1104': ['SQ', '1', 'RenderedImageReferenceSequence'],\n '1201': ['SQ', '1', 'VolumetricPresentationStateInputSequence'],\n '1202': ['CS', '1', 'PresentationInputType'],\n '1203': ['US', '1', 'InputSequencePositionIndex'],\n '1204': ['CS', '1', 'Crop'],\n '1205': ['US', '1-n', 'CroppingSpecificationIndex'],\n '1206': ['CS', '1', 'CompositingMethod'],\n '1207': ['US', '1', 'VolumetricPresentationInputNumber'],\n '1208': ['CS', '1', 'ImageVolumeGeometry'],\n '1209': ['UI', '1', 'VolumetricPresentationInputSetUID'],\n '120A': ['SQ', '1', 'VolumetricPresentationInputSetSequence'],\n '120B': ['CS', '1', 'GlobalCrop'],\n '120C': ['US', '1-n', 'GlobalCroppingSpecificationIndex'],\n '120D': ['CS', '1', 'RenderingMethod'],\n '1301': ['SQ', '1', 'VolumeCroppingSequence'],\n '1302': ['CS', '1', 'VolumeCroppingMethod'],\n '1303': ['FD', '6', 'BoundingBoxCrop'],\n '1304': ['SQ', '1', 'ObliqueCroppingPlaneSequence'],\n '1305': ['FD', '4', 'Plane'],\n '1306': ['FD', '3', 'PlaneNormal'],\n '1309': ['US', '1', 'CroppingSpecificationNumber'],\n '1501': ['CS', '1', 'MultiPlanarReconstructionStyle'],\n '1502': ['CS', '1', 'MPRThicknessType'],\n '1503': ['FD', '1', 'MPRSlabThickness'],\n '1505': ['FD', '3', 'MPRTopLeftHandCorner'],\n '1507': ['FD', '3', 'MPRViewWidthDirection'],\n '1508': ['FD', '1', 'MPRViewWidth'],\n '150C': ['UL', '1', 'NumberOfVolumetricCurvePoints'],\n '150D': ['OD', '1', 'VolumetricCurvePoints'],\n '1511': ['FD', '3', 'MPRViewHeightDirection'],\n '1512': ['FD', '1', 'MPRViewHeight'],\n '1602': ['CS', '1', 'RenderProjection'],\n '1603': ['FD', '3', 'ViewpointPosition'],\n '1604': ['FD', '3', 'ViewpointLookAtPoint'],\n '1605': ['FD', '3', 'ViewpointUpDirection'],\n '1606': ['FD', '6', 'RenderFieldOfView'],\n '1607': ['FD', '1', 'SamplingStepSize'],\n '1701': ['CS', '1', 'ShadingStyle'],\n '1702': ['FD', '1', 'AmbientReflectionIntensity'],\n '1703': ['FD', '3', 'LightDirection'],\n '1704': ['FD', '1', 'DiffuseReflectionIntensity'],\n '1705': ['FD', '1', 'SpecularReflectionIntensity'],\n '1706': ['FD', '1', 'Shininess'],\n '1801': ['SQ', '1', 'PresentationStateClassificationComponentSequence'],\n '1802': ['CS', '1', 'ComponentType'],\n '1803': ['SQ', '1', 'ComponentInputSequence'],\n '1804': ['US', '1', 'VolumetricPresentationInputIndex'],\n '1805': ['SQ', '1', 'PresentationStateCompositorComponentSequence'],\n '1806': ['SQ', '1', 'WeightingTransferFunctionSequence'],\n '1807': ['US', '3', 'WeightingLookupTableDescriptor'],\n '1808': ['OB', '1', 'WeightingLookupTableData'],\n '1901': ['SQ', '1', 'VolumetricAnnotationSequence'],\n '1903': ['SQ', '1', 'ReferencedStructuredContextSequence'],\n '1904': ['UI', '1', 'ReferencedContentItem'],\n '1905': ['SQ', '1', 'VolumetricPresentationInputAnnotationSequence'],\n '1907': ['CS', '1', 'AnnotationClipping'],\n '1A01': ['CS', '1', 'PresentationAnimationStyle'],\n '1A03': ['FD', '1', 'RecommendedAnimationRate'],\n '1A04': ['SQ', '1', 'AnimationCurveSequence'],\n '1A05': ['FD', '1', 'AnimationStepSize'],\n '1A06': ['FD', '1', 'SwivelRange'],\n '1A07': ['OD', '1', 'VolumetricCurveUpDirections'],\n '1A08': ['SQ', '1', 'VolumeStreamSequence'],\n '1A09': ['LO', '1', 'RGBATransferFunctionDescription'],\n '1B01': ['SQ', '1', 'AdvancedBlendingSequence'],\n '1B02': ['US', '1', 'BlendingInputNumber'],\n '1B03': ['SQ', '1', 'BlendingDisplayInputSequence'],\n '1B04': ['SQ', '1', 'BlendingDisplaySequence'],\n '1B06': ['CS', '1', 'BlendingMode'],\n '1B07': ['CS', '1', 'TimeSeriesBlending'],\n '1B08': ['CS', '1', 'GeometryForDisplay'],\n '1B11': ['SQ', '1', 'ThresholdSequence'],\n '1B12': ['SQ', '1', 'ThresholdValueSequence'],\n '1B13': ['CS', '1', 'ThresholdType'],\n '1B14': ['FD', '1', 'ThresholdValue']\n },\n '0072': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['SH', '1', 'HangingProtocolName'],\n '0004': ['LO', '1', 'HangingProtocolDescription'],\n '0006': ['CS', '1', 'HangingProtocolLevel'],\n '0008': ['LO', '1', 'HangingProtocolCreator'],\n '000A': ['DT', '1', 'HangingProtocolCreationDateTime'],\n '000C': ['SQ', '1', 'HangingProtocolDefinitionSequence'],\n '000E': ['SQ', '1', 'HangingProtocolUserIdentificationCodeSequence'],\n '0010': ['LO', '1', 'HangingProtocolUserGroupName'],\n '0012': ['SQ', '1', 'SourceHangingProtocolSequence'],\n '0014': ['US', '1', 'NumberOfPriorsReferenced'],\n '0020': ['SQ', '1', 'ImageSetsSequence'],\n '0022': ['SQ', '1', 'ImageSetSelectorSequence'],\n '0024': ['CS', '1', 'ImageSetSelectorUsageFlag'],\n '0026': ['AT', '1', 'SelectorAttribute'],\n '0028': ['US', '1', 'SelectorValueNumber'],\n '0030': ['SQ', '1', 'TimeBasedImageSetsSequence'],\n '0032': ['US', '1', 'ImageSetNumber'],\n '0034': ['CS', '1', 'ImageSetSelectorCategory'],\n '0038': ['US', '2', 'RelativeTime'],\n '003A': ['CS', '1', 'RelativeTimeUnits'],\n '003C': ['SS', '2', 'AbstractPriorValue'],\n '003E': ['SQ', '1', 'AbstractPriorCodeSequence'],\n '0040': ['LO', '1', 'ImageSetLabel'],\n '0050': ['CS', '1', 'SelectorAttributeVR'],\n '0052': ['AT', '1-n', 'SelectorSequencePointer'],\n '0054': ['LO', '1-n', 'SelectorSequencePointerPrivateCreator'],\n '0056': ['LO', '1', 'SelectorAttributePrivateCreator'],\n '005E': ['AE', '1-n', 'SelectorAEValue'],\n '005F': ['AS', '1-n', 'SelectorASValue'],\n '0060': ['AT', '1-n', 'SelectorATValue'],\n '0061': ['DA', '1-n', 'SelectorDAValue'],\n '0062': ['CS', '1-n', 'SelectorCSValue'],\n '0063': ['DT', '1-n', 'SelectorDTValue'],\n '0064': ['IS', '1-n', 'SelectorISValue'],\n '0065': ['OB', '1', 'SelectorOBValue'],\n '0066': ['LO', '1-n', 'SelectorLOValue'],\n '0067': ['OF', '1', 'SelectorOFValue'],\n '0068': ['LT', '1', 'SelectorLTValue'],\n '0069': ['OW', '1', 'SelectorOWValue'],\n '006A': ['PN', '1-n', 'SelectorPNValue'],\n '006B': ['TM', '1-n', 'SelectorTMValue'],\n '006C': ['SH', '1-n', 'SelectorSHValue'],\n '006D': ['UN', '1', 'SelectorUNValue'],\n '006E': ['ST', '1', 'SelectorSTValue'],\n '006F': ['UC', '1-n', 'SelectorUCValue'],\n '0070': ['UT', '1', 'SelectorUTValue'],\n '0071': ['UR', '1', 'SelectorURValue'],\n '0072': ['DS', '1-n', 'SelectorDSValue'],\n '0073': ['OD', '1', 'SelectorODValue'],\n '0074': ['FD', '1-n', 'SelectorFDValue'],\n '0075': ['OL', '1', 'SelectorOLValue'],\n '0076': ['FL', '1-n', 'SelectorFLValue'],\n '0078': ['UL', '1-n', 'SelectorULValue'],\n '007A': ['US', '1-n', 'SelectorUSValue'],\n '007C': ['SL', '1-n', 'SelectorSLValue'],\n '007E': ['SS', '1-n', 'SelectorSSValue'],\n '007F': ['UI', '1-n', 'SelectorUIValue'],\n '0080': ['SQ', '1', 'SelectorCodeSequenceValue'],\n '0081': ['OV', '1', 'SelectorOVValue'],\n '0082': ['SV', '1-n', 'SelectorSVValue'],\n '0083': ['UV', '1-n', 'SelectorUVValue'],\n '0100': ['US', '1', 'NumberOfScreens'],\n '0102': ['SQ', '1', 'NominalScreenDefinitionSequence'],\n '0104': ['US', '1', 'NumberOfVerticalPixels'],\n '0106': ['US', '1', 'NumberOfHorizontalPixels'],\n '0108': ['FD', '4', 'DisplayEnvironmentSpatialPosition'],\n '010A': ['US', '1', 'ScreenMinimumGrayscaleBitDepth'],\n '010C': ['US', '1', 'ScreenMinimumColorBitDepth'],\n '010E': ['US', '1', 'ApplicationMaximumRepaintTime'],\n '0200': ['SQ', '1', 'DisplaySetsSequence'],\n '0202': ['US', '1', 'DisplaySetNumber'],\n '0203': ['LO', '1', 'DisplaySetLabel'],\n '0204': ['US', '1', 'DisplaySetPresentationGroup'],\n '0206': ['LO', '1', 'DisplaySetPresentationGroupDescription'],\n '0208': ['CS', '1', 'PartialDataDisplayHandling'],\n '0210': ['SQ', '1', 'SynchronizedScrollingSequence'],\n '0212': ['US', '2-n', 'DisplaySetScrollingGroup'],\n '0214': ['SQ', '1', 'NavigationIndicatorSequence'],\n '0216': ['US', '1', 'NavigationDisplaySet'],\n '0218': ['US', '1-n', 'ReferenceDisplaySets'],\n '0300': ['SQ', '1', 'ImageBoxesSequence'],\n '0302': ['US', '1', 'ImageBoxNumber'],\n '0304': ['CS', '1', 'ImageBoxLayoutType'],\n '0306': ['US', '1', 'ImageBoxTileHorizontalDimension'],\n '0308': ['US', '1', 'ImageBoxTileVerticalDimension'],\n '0310': ['CS', '1', 'ImageBoxScrollDirection'],\n '0312': ['CS', '1', 'ImageBoxSmallScrollType'],\n '0314': ['US', '1', 'ImageBoxSmallScrollAmount'],\n '0316': ['CS', '1', 'ImageBoxLargeScrollType'],\n '0318': ['US', '1', 'ImageBoxLargeScrollAmount'],\n '0320': ['US', '1', 'ImageBoxOverlapPriority'],\n '0330': ['FD', '1', 'CineRelativeToRealTime'],\n '0400': ['SQ', '1', 'FilterOperationsSequence'],\n '0402': ['CS', '1', 'FilterByCategory'],\n '0404': ['CS', '1', 'FilterByAttributePresence'],\n '0406': ['CS', '1', 'FilterByOperator'],\n '0420': ['US', '3', 'StructuredDisplayBackgroundCIELabValue'],\n '0421': ['US', '3', 'EmptyImageBoxCIELabValue'],\n '0422': ['SQ', '1', 'StructuredDisplayImageBoxSequence'],\n '0424': ['SQ', '1', 'StructuredDisplayTextBoxSequence'],\n '0427': ['SQ', '1', 'ReferencedFirstFrameSequence'],\n '0430': ['SQ', '1', 'ImageBoxSynchronizationSequence'],\n '0432': ['US', '2-n', 'SynchronizedImageBoxList'],\n '0434': ['CS', '1', 'TypeOfSynchronization'],\n '0500': ['CS', '1', 'BlendingOperationType'],\n '0510': ['CS', '1', 'ReformattingOperationType'],\n '0512': ['FD', '1', 'ReformattingThickness'],\n '0514': ['FD', '1', 'ReformattingInterval'],\n '0516': ['CS', '1', 'ReformattingOperationInitialViewDirection'],\n '0520': ['CS', '1-n', 'ThreeDRenderingType'],\n '0600': ['SQ', '1', 'SortingOperationsSequence'],\n '0602': ['CS', '1', 'SortByCategory'],\n '0604': ['CS', '1', 'SortingDirection'],\n '0700': ['CS', '2', 'DisplaySetPatientOrientation'],\n '0702': ['CS', '1', 'VOIType'],\n '0704': ['CS', '1', 'PseudoColorType'],\n '0705': ['SQ', '1', 'PseudoColorPaletteInstanceReferenceSequence'],\n '0706': ['CS', '1', 'ShowGrayscaleInverted'],\n '0710': ['CS', '1', 'ShowImageTrueSizeFlag'],\n '0712': ['CS', '1', 'ShowGraphicAnnotationFlag'],\n '0714': ['CS', '1', 'ShowPatientDemographicsFlag'],\n '0716': ['CS', '1', 'ShowAcquisitionTechniquesFlag'],\n '0717': ['CS', '1', 'DisplaySetHorizontalJustification'],\n '0718': ['CS', '1', 'DisplaySetVerticalJustification']\n },\n '0074': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0120': ['FD', '1', 'ContinuationStartMeterset'],\n '0121': ['FD', '1', 'ContinuationEndMeterset'],\n '1000': ['CS', '1', 'ProcedureStepState'],\n '1002': ['SQ', '1', 'ProcedureStepProgressInformationSequence'],\n '1004': ['DS', '1', 'ProcedureStepProgress'],\n '1006': ['ST', '1', 'ProcedureStepProgressDescription'],\n '1007': ['SQ', '1', 'ProcedureStepProgressParametersSequence'],\n '1008': ['SQ', '1', 'ProcedureStepCommunicationsURISequence'],\n '100A': ['UR', '1', 'ContactURI'],\n '100C': ['LO', '1', 'ContactDisplayName'],\n '100E': ['SQ', '1', 'ProcedureStepDiscontinuationReasonCodeSequence'],\n '1020': ['SQ', '1', 'BeamTaskSequence'],\n '1022': ['CS', '1', 'BeamTaskType'],\n '1024': ['IS', '1', 'BeamOrderIndexTrial'],\n '1025': ['CS', '1', 'AutosequenceFlag'],\n '1026': ['FD', '1', 'TableTopVerticalAdjustedPosition'],\n '1027': ['FD', '1', 'TableTopLongitudinalAdjustedPosition'],\n '1028': ['FD', '1', 'TableTopLateralAdjustedPosition'],\n '102A': ['FD', '1', 'PatientSupportAdjustedAngle'],\n '102B': ['FD', '1', 'TableTopEccentricAdjustedAngle'],\n '102C': ['FD', '1', 'TableTopPitchAdjustedAngle'],\n '102D': ['FD', '1', 'TableTopRollAdjustedAngle'],\n '1030': ['SQ', '1', 'DeliveryVerificationImageSequence'],\n '1032': ['CS', '1', 'VerificationImageTiming'],\n '1034': ['CS', '1', 'DoubleExposureFlag'],\n '1036': ['CS', '1', 'DoubleExposureOrdering'],\n '1038': ['DS', '1', 'DoubleExposureMetersetTrial'],\n '103A': ['DS', '4', 'DoubleExposureFieldDeltaTrial'],\n '1040': ['SQ', '1', 'RelatedReferenceRTImageSequence'],\n '1042': ['SQ', '1', 'GeneralMachineVerificationSequence'],\n '1044': ['SQ', '1', 'ConventionalMachineVerificationSequence'],\n '1046': ['SQ', '1', 'IonMachineVerificationSequence'],\n '1048': ['SQ', '1', 'FailedAttributesSequence'],\n '104A': ['SQ', '1', 'OverriddenAttributesSequence'],\n '104C': ['SQ', '1', 'ConventionalControlPointVerificationSequence'],\n '104E': ['SQ', '1', 'IonControlPointVerificationSequence'],\n '1050': ['SQ', '1', 'AttributeOccurrenceSequence'],\n '1052': ['AT', '1', 'AttributeOccurrencePointer'],\n '1054': ['UL', '1', 'AttributeItemSelector'],\n '1056': ['LO', '1', 'AttributeOccurrencePrivateCreator'],\n '1057': ['IS', '1-n', 'SelectorSequencePointerItems'],\n '1200': ['CS', '1', 'ScheduledProcedureStepPriority'],\n '1202': ['LO', '1', 'WorklistLabel'],\n '1204': ['LO', '1', 'ProcedureStepLabel'],\n '1210': ['SQ', '1', 'ScheduledProcessingParametersSequence'],\n '1212': ['SQ', '1', 'PerformedProcessingParametersSequence'],\n '1216': ['SQ', '1', 'UnifiedProcedureStepPerformedProcedureSequence'],\n '1220': ['SQ', '1', 'RelatedProcedureStepSequence'],\n '1222': ['LO', '1', 'ProcedureStepRelationshipType'],\n '1224': ['SQ', '1', 'ReplacedProcedureStepSequence'],\n '1230': ['LO', '1', 'DeletionLock'],\n '1234': ['AE', '1', 'ReceivingAE'],\n '1236': ['AE', '1', 'RequestingAE'],\n '1238': ['LT', '1', 'ReasonForCancellation'],\n '1242': ['CS', '1', 'SCPStatus'],\n '1244': ['CS', '1', 'SubscriptionListStatus'],\n '1246': ['CS', '1', 'UnifiedProcedureStepListStatus'],\n '1324': ['UL', '1', 'BeamOrderIndex'],\n '1338': ['FD', '1', 'DoubleExposureMeterset'],\n '133A': ['FD', '4', 'DoubleExposureFieldDelta'],\n '1401': ['SQ', '1', 'BrachyTaskSequence'],\n '1402': ['DS', '1', 'ContinuationStartTotalReferenceAirKerma'],\n '1403': ['DS', '1', 'ContinuationEndTotalReferenceAirKerma'],\n '1404': ['IS', '1', 'ContinuationPulseNumber'],\n '1405': ['SQ', '1', 'ChannelDeliveryOrderSequence'],\n '1406': ['IS', '1', 'ReferencedChannelNumber'],\n '1407': ['DS', '1', 'StartCumulativeTimeWeight'],\n '1408': ['DS', '1', 'EndCumulativeTimeWeight'],\n '1409': ['SQ', '1', 'OmittedChannelSequence'],\n '140A': ['CS', '1', 'ReasonForChannelOmission'],\n '140B': ['LO', '1', 'ReasonForChannelOmissionDescription'],\n '140C': ['IS', '1', 'ChannelDeliveryOrderIndex'],\n '140D': ['SQ', '1', 'ChannelDeliveryContinuationSequence'],\n '140E': ['SQ', '1', 'OmittedApplicationSetupSequence']\n },\n '0076': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['LO', '1', 'ImplantAssemblyTemplateName'],\n '0003': ['LO', '1', 'ImplantAssemblyTemplateIssuer'],\n '0006': ['LO', '1', 'ImplantAssemblyTemplateVersion'],\n '0008': ['SQ', '1', 'ReplacedImplantAssemblyTemplateSequence'],\n '000A': ['CS', '1', 'ImplantAssemblyTemplateType'],\n '000C': ['SQ', '1', 'OriginalImplantAssemblyTemplateSequence'],\n '000E': ['SQ', '1', 'DerivationImplantAssemblyTemplateSequence'],\n '0010': ['SQ', '1', 'ImplantAssemblyTemplateTargetAnatomySequence'],\n '0020': ['SQ', '1', 'ProcedureTypeCodeSequence'],\n '0030': ['LO', '1', 'SurgicalTechnique'],\n '0032': ['SQ', '1', 'ComponentTypesSequence'],\n '0034': ['SQ', '1', 'ComponentTypeCodeSequence'],\n '0036': ['CS', '1', 'ExclusiveComponentType'],\n '0038': ['CS', '1', 'MandatoryComponentType'],\n '0040': ['SQ', '1', 'ComponentSequence'],\n '0055': ['US', '1', 'ComponentID'],\n '0060': ['SQ', '1', 'ComponentAssemblySequence'],\n '0070': ['US', '1', 'Component1ReferencedID'],\n '0080': ['US', '1', 'Component1ReferencedMatingFeatureSetID'],\n '0090': ['US', '1', 'Component1ReferencedMatingFeatureID'],\n '00A0': ['US', '1', 'Component2ReferencedID'],\n '00B0': ['US', '1', 'Component2ReferencedMatingFeatureSetID'],\n '00C0': ['US', '1', 'Component2ReferencedMatingFeatureID']\n },\n '0078': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['LO', '1', 'ImplantTemplateGroupName'],\n '0010': ['ST', '1', 'ImplantTemplateGroupDescription'],\n '0020': ['LO', '1', 'ImplantTemplateGroupIssuer'],\n '0024': ['LO', '1', 'ImplantTemplateGroupVersion'],\n '0026': ['SQ', '1', 'ReplacedImplantTemplateGroupSequence'],\n '0028': ['SQ', '1', 'ImplantTemplateGroupTargetAnatomySequence'],\n '002A': ['SQ', '1', 'ImplantTemplateGroupMembersSequence'],\n '002E': ['US', '1', 'ImplantTemplateGroupMemberID'],\n '0050': ['FD', '3', 'ThreeDImplantTemplateGroupMemberMatchingPoint'],\n '0060': ['FD', '9', 'ThreeDImplantTemplateGroupMemberMatchingAxes'],\n '0070': ['SQ', '1', 'ImplantTemplateGroupMemberMatching2DCoordinatesSequence'],\n '0090': ['FD', '2', 'TwoDImplantTemplateGroupMemberMatchingPoint'],\n '00A0': ['FD', '4', 'TwoDImplantTemplateGroupMemberMatchingAxes'],\n '00B0': ['SQ', '1', 'ImplantTemplateGroupVariationDimensionSequence'],\n '00B2': ['LO', '1', 'ImplantTemplateGroupVariationDimensionName'],\n '00B4': ['SQ', '1', 'ImplantTemplateGroupVariationDimensionRankSequence'],\n '00B6': ['US', '1', 'ReferencedImplantTemplateGroupMemberID'],\n '00B8': ['US', '1', 'ImplantTemplateGroupVariationDimensionRank']\n },\n '0080': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['SQ', '1', 'SurfaceScanAcquisitionTypeCodeSequence'],\n '0002': ['SQ', '1', 'SurfaceScanModeCodeSequence'],\n '0003': ['SQ', '1', 'RegistrationMethodCodeSequence'],\n '0004': ['FD', '1', 'ShotDurationTime'],\n '0005': ['FD', '1', 'ShotOffsetTime'],\n '0006': ['US', '1-n', 'SurfacePointPresentationValueData'],\n '0007': ['US', '3-3n', 'SurfacePointColorCIELabValueData'],\n '0008': ['SQ', '1', 'UVMappingSequence'],\n '0009': ['SH', '1', 'TextureLabel'],\n '0010': ['OF', '1', 'UValueData'],\n '0011': ['OF', '1', 'VValueData'],\n '0012': ['SQ', '1', 'ReferencedTextureSequence'],\n '0013': ['SQ', '1', 'ReferencedSurfaceDataSequence']\n },\n '0082': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['CS', '1', 'AssessmentSummary'],\n '0003': ['UT', '1', 'AssessmentSummaryDescription'],\n '0004': ['SQ', '1', 'AssessedSOPInstanceSequence'],\n '0005': ['SQ', '1', 'ReferencedComparisonSOPInstanceSequence'],\n '0006': ['UL', '1', 'NumberOfAssessmentObservations'],\n '0007': ['SQ', '1', 'AssessmentObservationsSequence'],\n '0008': ['CS', '1', 'ObservationSignificance'],\n '000A': ['UT', '1', 'ObservationDescription'],\n '000C': ['SQ', '1', 'StructuredConstraintObservationSequence'],\n '0010': ['SQ', '1', 'AssessedAttributeValueSequence'],\n '0016': ['LO', '1', 'AssessmentSetID'],\n '0017': ['SQ', '1', 'AssessmentRequesterSequence'],\n '0018': ['LO', '1', 'SelectorAttributeName'],\n '0019': ['LO', '1', 'SelectorAttributeKeyword'],\n '0021': ['SQ', '1', 'AssessmentTypeCodeSequence'],\n '0022': ['SQ', '1', 'ObservationBasisCodeSequence'],\n '0023': ['LO', '1', 'AssessmentLabel'],\n '0032': ['CS', '1', 'ConstraintType'],\n '0033': ['UT', '1', 'SpecificationSelectionGuidance'],\n '0034': ['SQ', '1', 'ConstraintValueSequence'],\n '0035': ['SQ', '1', 'RecommendedDefaultValueSequence'],\n '0036': ['CS', '1', 'ConstraintViolationSignificance'],\n '0037': ['UT', '1', 'ConstraintViolationCondition'],\n '0038': ['CS', '1', 'ModifiableConstraintFlag']\n },\n '0088': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0130': ['SH', '1', 'StorageMediaFileSetID'],\n '0140': ['UI', '1', 'StorageMediaFileSetUID'],\n '0200': ['SQ', '1', 'IconImageSequence'],\n '0904': ['LO', '1', 'TopicTitle'],\n '0906': ['ST', '1', 'TopicSubject'],\n '0910': ['LO', '1', 'TopicAuthor'],\n '0912': ['LO', '1-32', 'TopicKeywords']\n },\n '0100': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0410': ['CS', '1', 'SOPInstanceStatus'],\n '0420': ['DT', '1', 'SOPAuthorizationDateTime'],\n '0424': ['LT', '1', 'SOPAuthorizationComment'],\n '0426': ['LO', '1', 'AuthorizationEquipmentCertificationNumber']\n },\n '0400': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0005': ['US', '1', 'MACIDNumber'],\n '0010': ['UI', '1', 'MACCalculationTransferSyntaxUID'],\n '0015': ['CS', '1', 'MACAlgorithm'],\n '0020': ['AT', '1-n', 'DataElementsSigned'],\n '0100': ['UI', '1', 'DigitalSignatureUID'],\n '0105': ['DT', '1', 'DigitalSignatureDateTime'],\n '0110': ['CS', '1', 'CertificateType'],\n '0115': ['OB', '1', 'CertificateOfSigner'],\n '0120': ['OB', '1', 'Signature'],\n '0305': ['CS', '1', 'CertifiedTimestampType'],\n '0310': ['OB', '1', 'CertifiedTimestamp'],\n '0315': ['FL', '1', ''],\n '0401': ['SQ', '1', 'DigitalSignaturePurposeCodeSequence'],\n '0402': ['SQ', '1', 'ReferencedDigitalSignatureSequence'],\n '0403': ['SQ', '1', 'ReferencedSOPInstanceMACSequence'],\n '0404': ['OB', '1', 'MAC'],\n '0500': ['SQ', '1', 'EncryptedAttributesSequence'],\n '0510': ['UI', '1', 'EncryptedContentTransferSyntaxUID'],\n '0520': ['OB', '1', 'EncryptedContent'],\n '0550': ['SQ', '1', 'ModifiedAttributesSequence'],\n '0551': ['SQ', '1', 'NonconformingModifiedAttributesSequence'],\n '0552': ['OB', '1', 'NonconformingDataElementValue'],\n '0561': ['SQ', '1', 'OriginalAttributesSequence'],\n '0562': ['DT', '1', 'AttributeModificationDateTime'],\n '0563': ['LO', '1', 'ModifyingSystem'],\n '0564': ['LO', '1', 'SourceOfPreviousValues'],\n '0565': ['CS', '1', 'ReasonForTheAttributeModification'],\n '0600': ['CS', '1', 'InstanceOriginStatus']\n },\n '1000': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['US', '3', 'EscapeTriplet'],\n '0011': ['US', '3', 'RunLengthTriplet'],\n '0012': ['US', '1', 'HuffmanTableSize'],\n '0013': ['US', '3', 'HuffmanTableTriplet'],\n '0014': ['US', '1', 'ShiftTableSize'],\n '0015': ['US', '3', 'ShiftTableTriplet']\n },\n '1010': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0004': ['US', '1-n', 'ZonalMap']\n },\n '2000': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['IS', '1', 'NumberOfCopies'],\n '001E': ['SQ', '1', 'PrinterConfigurationSequence'],\n '0020': ['CS', '1', 'PrintPriority'],\n '0030': ['CS', '1', 'MediumType'],\n '0040': ['CS', '1', 'FilmDestination'],\n '0050': ['LO', '1', 'FilmSessionLabel'],\n '0060': ['IS', '1', 'MemoryAllocation'],\n '0061': ['IS', '1', 'MaximumMemoryAllocation'],\n '0062': ['CS', '1', 'ColorImagePrintingFlag'],\n '0063': ['CS', '1', 'CollationFlag'],\n '0065': ['CS', '1', 'AnnotationFlag'],\n '0067': ['CS', '1', 'ImageOverlayFlag'],\n '0069': ['CS', '1', 'PresentationLUTFlag'],\n '006A': ['CS', '1', 'ImageBoxPresentationLUTFlag'],\n '00A0': ['US', '1', 'MemoryBitDepth'],\n '00A1': ['US', '1', 'PrintingBitDepth'],\n '00A2': ['SQ', '1', 'MediaInstalledSequence'],\n '00A4': ['SQ', '1', 'OtherMediaAvailableSequence'],\n '00A8': ['SQ', '1', 'SupportedImageDisplayFormatsSequence'],\n '0500': ['SQ', '1', 'ReferencedFilmBoxSequence'],\n '0510': ['SQ', '1', 'ReferencedStoredPrintSequence']\n },\n '2010': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['ST', '1', 'ImageDisplayFormat'],\n '0030': ['CS', '1', 'AnnotationDisplayFormatID'],\n '0040': ['CS', '1', 'FilmOrientation'],\n '0050': ['CS', '1', 'FilmSizeID'],\n '0052': ['CS', '1', 'PrinterResolutionID'],\n '0054': ['CS', '1', 'DefaultPrinterResolutionID'],\n '0060': ['CS', '1', 'MagnificationType'],\n '0080': ['CS', '1', 'SmoothingType'],\n '00A6': ['CS', '1', 'DefaultMagnificationType'],\n '00A7': ['CS', '1-n', 'OtherMagnificationTypesAvailable'],\n '00A8': ['CS', '1', 'DefaultSmoothingType'],\n '00A9': ['CS', '1-n', 'OtherSmoothingTypesAvailable'],\n '0100': ['CS', '1', 'BorderDensity'],\n '0110': ['CS', '1', 'EmptyImageDensity'],\n '0120': ['US', '1', 'MinDensity'],\n '0130': ['US', '1', 'MaxDensity'],\n '0140': ['CS', '1', 'Trim'],\n '0150': ['ST', '1', 'ConfigurationInformation'],\n '0152': ['LT', '1', 'ConfigurationInformationDescription'],\n '0154': ['IS', '1', 'MaximumCollatedFilms'],\n '015E': ['US', '1', 'Illumination'],\n '0160': ['US', '1', 'ReflectedAmbientLight'],\n '0376': ['DS', '2', 'PrinterPixelSpacing'],\n '0500': ['SQ', '1', 'ReferencedFilmSessionSequence'],\n '0510': ['SQ', '1', 'ReferencedImageBoxSequence'],\n '0520': ['SQ', '1', 'ReferencedBasicAnnotationBoxSequence']\n },\n '2020': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['US', '1', 'ImageBoxPosition'],\n '0020': ['CS', '1', 'Polarity'],\n '0030': ['DS', '1', 'RequestedImageSize'],\n '0040': ['CS', '1', 'RequestedDecimateCropBehavior'],\n '0050': ['CS', '1', 'RequestedResolutionID'],\n '00A0': ['CS', '1', 'RequestedImageSizeFlag'],\n '00A2': ['CS', '1', 'DecimateCropResult'],\n '0110': ['SQ', '1', 'BasicGrayscaleImageSequence'],\n '0111': ['SQ', '1', 'BasicColorImageSequence'],\n '0130': ['SQ', '1', 'ReferencedImageOverlayBoxSequence'],\n '0140': ['SQ', '1', 'ReferencedVOILUTBoxSequence']\n },\n '2030': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['US', '1', 'AnnotationPosition'],\n '0020': ['LO', '1', 'TextString']\n },\n '2040': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['SQ', '1', 'ReferencedOverlayPlaneSequence'],\n '0011': ['US', '1-99', 'ReferencedOverlayPlaneGroups'],\n '0020': ['SQ', '1', 'OverlayPixelDataSequence'],\n '0060': ['CS', '1', 'OverlayMagnificationType'],\n '0070': ['CS', '1', 'OverlaySmoothingType'],\n '0072': ['CS', '1', 'OverlayOrImageMagnification'],\n '0074': ['US', '1', 'MagnifyToNumberOfColumns'],\n '0080': ['CS', '1', 'OverlayForegroundDensity'],\n '0082': ['CS', '1', 'OverlayBackgroundDensity'],\n '0090': ['CS', '1', 'OverlayMode'],\n '0100': ['CS', '1', 'ThresholdDensity'],\n '0500': ['SQ', '1', 'ReferencedImageBoxSequenceRetired']\n },\n '2050': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['SQ', '1', 'PresentationLUTSequence'],\n '0020': ['CS', '1', 'PresentationLUTShape'],\n '0500': ['SQ', '1', 'ReferencedPresentationLUTSequence']\n },\n '2100': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['SH', '1', 'PrintJobID'],\n '0020': ['CS', '1', 'ExecutionStatus'],\n '0030': ['CS', '1', 'ExecutionStatusInfo'],\n '0040': ['DA', '1', 'CreationDate'],\n '0050': ['TM', '1', 'CreationTime'],\n '0070': ['AE', '1', 'Originator'],\n '0140': ['AE', '1', 'DestinationAE'],\n '0160': ['SH', '1', 'OwnerID'],\n '0170': ['IS', '1', 'NumberOfFilms'],\n '0500': ['SQ', '1', 'ReferencedPrintJobSequencePullStoredPrint']\n },\n '2110': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['CS', '1', 'PrinterStatus'],\n '0020': ['CS', '1', 'PrinterStatusInfo'],\n '0030': ['LO', '1', 'PrinterName'],\n '0099': ['SH', '1', 'PrintQueueID']\n },\n '2120': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['CS', '1', 'QueueStatus'],\n '0050': ['SQ', '1', 'PrintJobDescriptionSequence'],\n '0070': ['SQ', '1', 'ReferencedPrintJobSequence']\n },\n '2130': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['SQ', '1', 'PrintManagementCapabilitiesSequence'],\n '0015': ['SQ', '1', 'PrinterCharacteristicsSequence'],\n '0030': ['SQ', '1', 'FilmBoxContentSequence'],\n '0040': ['SQ', '1', 'ImageBoxContentSequence'],\n '0050': ['SQ', '1', 'AnnotationContentSequence'],\n '0060': ['SQ', '1', 'ImageOverlayBoxContentSequence'],\n '0080': ['SQ', '1', 'PresentationLUTContentSequence'],\n '00A0': ['SQ', '1', 'ProposedStudySequence'],\n '00C0': ['SQ', '1', 'OriginalImageSequence']\n },\n '2200': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['CS', '1', 'LabelUsingInformationExtractedFromInstances'],\n '0002': ['UT', '1', 'LabelText'],\n '0003': ['CS', '1', 'LabelStyleSelection'],\n '0004': ['LT', '1', 'MediaDisposition'],\n '0005': ['LT', '1', 'BarcodeValue'],\n '0006': ['CS', '1', 'BarcodeSymbology'],\n '0007': ['CS', '1', 'AllowMediaSplitting'],\n '0008': ['CS', '1', 'IncludeNonDICOMObjects'],\n '0009': ['CS', '1', 'IncludeDisplayApplication'],\n '000A': ['CS', '1', 'PreserveCompositeInstancesAfterMediaCreation'],\n '000B': ['US', '1', 'TotalNumberOfPiecesOfMediaCreated'],\n '000C': ['LO', '1', 'RequestedMediaApplicationProfile'],\n '000D': ['SQ', '1', 'ReferencedStorageMediaSequence'],\n '000E': ['AT', '1-n', 'FailureAttributes'],\n '000F': ['CS', '1', 'AllowLossyCompression'],\n '0020': ['CS', '1', 'RequestPriority']\n },\n '3002': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['SH', '1', 'RTImageLabel'],\n '0003': ['LO', '1', 'RTImageName'],\n '0004': ['ST', '1', 'RTImageDescription'],\n '000A': ['CS', '1', 'ReportedValuesOrigin'],\n '000C': ['CS', '1', 'RTImagePlane'],\n '000D': ['DS', '3', 'XRayImageReceptorTranslation'],\n '000E': ['DS', '1', 'XRayImageReceptorAngle'],\n '0010': ['DS', '6', 'RTImageOrientation'],\n '0011': ['DS', '2', 'ImagePlanePixelSpacing'],\n '0012': ['DS', '2', 'RTImagePosition'],\n '0020': ['SH', '1', 'RadiationMachineName'],\n '0022': ['DS', '1', 'RadiationMachineSAD'],\n '0024': ['DS', '1', 'RadiationMachineSSD'],\n '0026': ['DS', '1', 'RTImageSID'],\n '0028': ['DS', '1', 'SourceToReferenceObjectDistance'],\n '0029': ['IS', '1', 'FractionNumber'],\n '0030': ['SQ', '1', 'ExposureSequence'],\n '0032': ['DS', '1', 'MetersetExposure'],\n '0034': ['DS', '4', 'DiaphragmPosition'],\n '0040': ['SQ', '1', 'FluenceMapSequence'],\n '0041': ['CS', '1', 'FluenceDataSource'],\n '0042': ['DS', '1', 'FluenceDataScale'],\n '0050': ['SQ', '1', 'PrimaryFluenceModeSequence'],\n '0051': ['CS', '1', 'FluenceMode'],\n '0052': ['SH', '1', 'FluenceModeID']\n },\n '3004': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['CS', '1', 'DVHType'],\n '0002': ['CS', '1', 'DoseUnits'],\n '0004': ['CS', '1', 'DoseType'],\n '0005': ['CS', '1', 'SpatialTransformOfDose'],\n '0006': ['LO', '1', 'DoseComment'],\n '0008': ['DS', '3', 'NormalizationPoint'],\n '000A': ['CS', '1', 'DoseSummationType'],\n '000C': ['DS', '2-n', 'GridFrameOffsetVector'],\n '000E': ['DS', '1', 'DoseGridScaling'],\n '0010': ['SQ', '1', 'RTDoseROISequence'],\n '0012': ['DS', '1', 'DoseValue'],\n '0014': ['CS', '1-3', 'TissueHeterogeneityCorrection'],\n '0040': ['DS', '3', 'DVHNormalizationPoint'],\n '0042': ['DS', '1', 'DVHNormalizationDoseValue'],\n '0050': ['SQ', '1', 'DVHSequence'],\n '0052': ['DS', '1', 'DVHDoseScaling'],\n '0054': ['CS', '1', 'DVHVolumeUnits'],\n '0056': ['IS', '1', 'DVHNumberOfBins'],\n '0058': ['DS', '2-2n', 'DVHData'],\n '0060': ['SQ', '1', 'DVHReferencedROISequence'],\n '0062': ['CS', '1', 'DVHROIContributionType'],\n '0070': ['DS', '1', 'DVHMinimumDose'],\n '0072': ['DS', '1', 'DVHMaximumDose'],\n '0074': ['DS', '1', 'DVHMeanDose']\n },\n '3006': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['SH', '1', 'StructureSetLabel'],\n '0004': ['LO', '1', 'StructureSetName'],\n '0006': ['ST', '1', 'StructureSetDescription'],\n '0008': ['DA', '1', 'StructureSetDate'],\n '0009': ['TM', '1', 'StructureSetTime'],\n '0010': ['SQ', '1', 'ReferencedFrameOfReferenceSequence'],\n '0012': ['SQ', '1', 'RTReferencedStudySequence'],\n '0014': ['SQ', '1', 'RTReferencedSeriesSequence'],\n '0016': ['SQ', '1', 'ContourImageSequence'],\n '0018': ['SQ', '1', 'PredecessorStructureSetSequence'],\n '0020': ['SQ', '1', 'StructureSetROISequence'],\n '0022': ['IS', '1', 'ROINumber'],\n '0024': ['UI', '1', 'ReferencedFrameOfReferenceUID'],\n '0026': ['LO', '1', 'ROIName'],\n '0028': ['ST', '1', 'ROIDescription'],\n '002A': ['IS', '3', 'ROIDisplayColor'],\n '002C': ['DS', '1', 'ROIVolume'],\n '0030': ['SQ', '1', 'RTRelatedROISequence'],\n '0033': ['CS', '1', 'RTROIRelationship'],\n '0036': ['CS', '1', 'ROIGenerationAlgorithm'],\n '0037': ['SQ', '1', 'ROIDerivationAlgorithmIdentificationSequence'],\n '0038': ['LO', '1', 'ROIGenerationDescription'],\n '0039': ['SQ', '1', 'ROIContourSequence'],\n '0040': ['SQ', '1', 'ContourSequence'],\n '0042': ['CS', '1', 'ContourGeometricType'],\n '0044': ['DS', '1', 'ContourSlabThickness'],\n '0045': ['DS', '3', 'ContourOffsetVector'],\n '0046': ['IS', '1', 'NumberOfContourPoints'],\n '0048': ['IS', '1', 'ContourNumber'],\n '0049': ['IS', '1-n', 'AttachedContours'],\n '004A': ['SQ', '1', 'SourcePixelPlanesCharacteristicsSequence'],\n '0050': ['DS', '3-3n', 'ContourData'],\n '0080': ['SQ', '1', 'RTROIObservationsSequence'],\n '0082': ['IS', '1', 'ObservationNumber'],\n '0084': ['IS', '1', 'ReferencedROINumber'],\n '0085': ['SH', '1', 'ROIObservationLabel'],\n '0086': ['SQ', '1', 'RTROIIdentificationCodeSequence'],\n '0088': ['ST', '1', 'ROIObservationDescription'],\n '00A0': ['SQ', '1', 'RelatedRTROIObservationsSequence'],\n '00A4': ['CS', '1', 'RTROIInterpretedType'],\n '00A6': ['PN', '1', 'ROIInterpreter'],\n '00B0': ['SQ', '1', 'ROIPhysicalPropertiesSequence'],\n '00B2': ['CS', '1', 'ROIPhysicalProperty'],\n '00B4': ['DS', '1', 'ROIPhysicalPropertyValue'],\n '00B6': ['SQ', '1', 'ROIElementalCompositionSequence'],\n '00B7': ['US', '1', 'ROIElementalCompositionAtomicNumber'],\n '00B8': ['FL', '1', 'ROIElementalCompositionAtomicMassFraction'],\n '00B9': ['SQ', '1', 'AdditionalRTROIIdentificationCodeSequence'],\n '00C0': ['SQ', '1', 'FrameOfReferenceRelationshipSequence'],\n '00C2': ['UI', '1', 'RelatedFrameOfReferenceUID'],\n '00C4': ['CS', '1', 'FrameOfReferenceTransformationType'],\n '00C6': ['DS', '16', 'FrameOfReferenceTransformationMatrix'],\n '00C8': ['LO', '1', 'FrameOfReferenceTransformationComment'],\n '00C9': ['SQ', '1', 'PatientLocationCoordinatesSequence'],\n '00CA': ['SQ', '1', 'PatientLocationCoordinatesCodeSequence'],\n '00CB': ['SQ', '1', 'PatientSupportPositionSequence']\n },\n '3008': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['SQ', '1', 'MeasuredDoseReferenceSequence'],\n '0012': ['ST', '1', 'MeasuredDoseDescription'],\n '0014': ['CS', '1', 'MeasuredDoseType'],\n '0016': ['DS', '1', 'MeasuredDoseValue'],\n '0020': ['SQ', '1', 'TreatmentSessionBeamSequence'],\n '0021': ['SQ', '1', 'TreatmentSessionIonBeamSequence'],\n '0022': ['IS', '1', 'CurrentFractionNumber'],\n '0024': ['DA', '1', 'TreatmentControlPointDate'],\n '0025': ['TM', '1', 'TreatmentControlPointTime'],\n '002A': ['CS', '1', 'TreatmentTerminationStatus'],\n '002B': ['SH', '1', 'TreatmentTerminationCode'],\n '002C': ['CS', '1', 'TreatmentVerificationStatus'],\n '0030': ['SQ', '1', 'ReferencedTreatmentRecordSequence'],\n '0032': ['DS', '1', 'SpecifiedPrimaryMeterset'],\n '0033': ['DS', '1', 'SpecifiedSecondaryMeterset'],\n '0036': ['DS', '1', 'DeliveredPrimaryMeterset'],\n '0037': ['DS', '1', 'DeliveredSecondaryMeterset'],\n '003A': ['DS', '1', 'SpecifiedTreatmentTime'],\n '003B': ['DS', '1', 'DeliveredTreatmentTime'],\n '0040': ['SQ', '1', 'ControlPointDeliverySequence'],\n '0041': ['SQ', '1', 'IonControlPointDeliverySequence'],\n '0042': ['DS', '1', 'SpecifiedMeterset'],\n '0044': ['DS', '1', 'DeliveredMeterset'],\n '0045': ['FL', '1', 'MetersetRateSet'],\n '0046': ['FL', '1', 'MetersetRateDelivered'],\n '0047': ['FL', '1-n', 'ScanSpotMetersetsDelivered'],\n '0048': ['DS', '1', 'DoseRateDelivered'],\n '0050': ['SQ', '1', 'TreatmentSummaryCalculatedDoseReferenceSequence'],\n '0052': ['DS', '1', 'CumulativeDoseToDoseReference'],\n '0054': ['DA', '1', 'FirstTreatmentDate'],\n '0056': ['DA', '1', 'MostRecentTreatmentDate'],\n '005A': ['IS', '1', 'NumberOfFractionsDelivered'],\n '0060': ['SQ', '1', 'OverrideSequence'],\n '0061': ['AT', '1', 'ParameterSequencePointer'],\n '0062': ['AT', '1', 'OverrideParameterPointer'],\n '0063': ['IS', '1', 'ParameterItemIndex'],\n '0064': ['IS', '1', 'MeasuredDoseReferenceNumber'],\n '0065': ['AT', '1', 'ParameterPointer'],\n '0066': ['ST', '1', 'OverrideReason'],\n '0067': ['US', '1', 'ParameterValueNumber'],\n '0068': ['SQ', '1', 'CorrectedParameterSequence'],\n '006A': ['FL', '1', 'CorrectionValue'],\n '0070': ['SQ', '1', 'CalculatedDoseReferenceSequence'],\n '0072': ['IS', '1', 'CalculatedDoseReferenceNumber'],\n '0074': ['ST', '1', 'CalculatedDoseReferenceDescription'],\n '0076': ['DS', '1', 'CalculatedDoseReferenceDoseValue'],\n '0078': ['DS', '1', 'StartMeterset'],\n '007A': ['DS', '1', 'EndMeterset'],\n '0080': ['SQ', '1', 'ReferencedMeasuredDoseReferenceSequence'],\n '0082': ['IS', '1', 'ReferencedMeasuredDoseReferenceNumber'],\n '0090': ['SQ', '1', 'ReferencedCalculatedDoseReferenceSequence'],\n '0092': ['IS', '1', 'ReferencedCalculatedDoseReferenceNumber'],\n '00A0': ['SQ', '1', 'BeamLimitingDeviceLeafPairsSequence'],\n '00B0': ['SQ', '1', 'RecordedWedgeSequence'],\n '00C0': ['SQ', '1', 'RecordedCompensatorSequence'],\n '00D0': ['SQ', '1', 'RecordedBlockSequence'],\n '00D1': ['SQ', '1', 'RecordedBlockSlabSequence'],\n '00E0': ['SQ', '1', 'TreatmentSummaryMeasuredDoseReferenceSequence'],\n '00F0': ['SQ', '1', 'RecordedSnoutSequence'],\n '00F2': ['SQ', '1', 'RecordedRangeShifterSequence'],\n '00F4': ['SQ', '1', 'RecordedLateralSpreadingDeviceSequence'],\n '00F6': ['SQ', '1', 'RecordedRangeModulatorSequence'],\n '0100': ['SQ', '1', 'RecordedSourceSequence'],\n '0105': ['LO', '1', 'SourceSerialNumber'],\n '0110': ['SQ', '1', 'TreatmentSessionApplicationSetupSequence'],\n '0116': ['CS', '1', 'ApplicationSetupCheck'],\n '0120': ['SQ', '1', 'RecordedBrachyAccessoryDeviceSequence'],\n '0122': ['IS', '1', 'ReferencedBrachyAccessoryDeviceNumber'],\n '0130': ['SQ', '1', 'RecordedChannelSequence'],\n '0132': ['DS', '1', 'SpecifiedChannelTotalTime'],\n '0134': ['DS', '1', 'DeliveredChannelTotalTime'],\n '0136': ['IS', '1', 'SpecifiedNumberOfPulses'],\n '0138': ['IS', '1', 'DeliveredNumberOfPulses'],\n '013A': ['DS', '1', 'SpecifiedPulseRepetitionInterval'],\n '013C': ['DS', '1', 'DeliveredPulseRepetitionInterval'],\n '0140': ['SQ', '1', 'RecordedSourceApplicatorSequence'],\n '0142': ['IS', '1', 'ReferencedSourceApplicatorNumber'],\n '0150': ['SQ', '1', 'RecordedChannelShieldSequence'],\n '0152': ['IS', '1', 'ReferencedChannelShieldNumber'],\n '0160': ['SQ', '1', 'BrachyControlPointDeliveredSequence'],\n '0162': ['DA', '1', 'SafePositionExitDate'],\n '0164': ['TM', '1', 'SafePositionExitTime'],\n '0166': ['DA', '1', 'SafePositionReturnDate'],\n '0168': ['TM', '1', 'SafePositionReturnTime'],\n '0171': ['SQ', '1', 'PulseSpecificBrachyControlPointDeliveredSequence'],\n '0172': ['US', '1', 'PulseNumber'],\n '0173': ['SQ', '1', 'BrachyPulseControlPointDeliveredSequence'],\n '0200': ['CS', '1', 'CurrentTreatmentStatus'],\n '0202': ['ST', '1', 'TreatmentStatusComment'],\n '0220': ['SQ', '1', 'FractionGroupSummarySequence'],\n '0223': ['IS', '1', 'ReferencedFractionNumber'],\n '0224': ['CS', '1', 'FractionGroupType'],\n '0230': ['CS', '1', 'BeamStopperPosition'],\n '0240': ['SQ', '1', 'FractionStatusSummarySequence'],\n '0250': ['DA', '1', 'TreatmentDate'],\n '0251': ['TM', '1', 'TreatmentTime']\n },\n '300A': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['SH', '1', 'RTPlanLabel'],\n '0003': ['LO', '1', 'RTPlanName'],\n '0004': ['ST', '1', 'RTPlanDescription'],\n '0006': ['DA', '1', 'RTPlanDate'],\n '0007': ['TM', '1', 'RTPlanTime'],\n '0009': ['LO', '1-n', 'TreatmentProtocols'],\n '000A': ['CS', '1', 'PlanIntent'],\n '000B': ['LO', '1-n', 'TreatmentSites'],\n '000C': ['CS', '1', 'RTPlanGeometry'],\n '000E': ['ST', '1', 'PrescriptionDescription'],\n '0010': ['SQ', '1', 'DoseReferenceSequence'],\n '0012': ['IS', '1', 'DoseReferenceNumber'],\n '0013': ['UI', '1', 'DoseReferenceUID'],\n '0014': ['CS', '1', 'DoseReferenceStructureType'],\n '0015': ['CS', '1', 'NominalBeamEnergyUnit'],\n '0016': ['LO', '1', 'DoseReferenceDescription'],\n '0018': ['DS', '3', 'DoseReferencePointCoordinates'],\n '001A': ['DS', '1', 'NominalPriorDose'],\n '0020': ['CS', '1', 'DoseReferenceType'],\n '0021': ['DS', '1', 'ConstraintWeight'],\n '0022': ['DS', '1', 'DeliveryWarningDose'],\n '0023': ['DS', '1', 'DeliveryMaximumDose'],\n '0025': ['DS', '1', 'TargetMinimumDose'],\n '0026': ['DS', '1', 'TargetPrescriptionDose'],\n '0027': ['DS', '1', 'TargetMaximumDose'],\n '0028': ['DS', '1', 'TargetUnderdoseVolumeFraction'],\n '002A': ['DS', '1', 'OrganAtRiskFullVolumeDose'],\n '002B': ['DS', '1', 'OrganAtRiskLimitDose'],\n '002C': ['DS', '1', 'OrganAtRiskMaximumDose'],\n '002D': ['DS', '1', 'OrganAtRiskOverdoseVolumeFraction'],\n '0040': ['SQ', '1', 'ToleranceTableSequence'],\n '0042': ['IS', '1', 'ToleranceTableNumber'],\n '0043': ['SH', '1', 'ToleranceTableLabel'],\n '0044': ['DS', '1', 'GantryAngleTolerance'],\n '0046': ['DS', '1', 'BeamLimitingDeviceAngleTolerance'],\n '0048': ['SQ', '1', 'BeamLimitingDeviceToleranceSequence'],\n '004A': ['DS', '1', 'BeamLimitingDevicePositionTolerance'],\n '004B': ['FL', '1', 'SnoutPositionTolerance'],\n '004C': ['DS', '1', 'PatientSupportAngleTolerance'],\n '004E': ['DS', '1', 'TableTopEccentricAngleTolerance'],\n '004F': ['FL', '1', 'TableTopPitchAngleTolerance'],\n '0050': ['FL', '1', 'TableTopRollAngleTolerance'],\n '0051': ['DS', '1', 'TableTopVerticalPositionTolerance'],\n '0052': ['DS', '1', 'TableTopLongitudinalPositionTolerance'],\n '0053': ['DS', '1', 'TableTopLateralPositionTolerance'],\n '0055': ['CS', '1', 'RTPlanRelationship'],\n '0070': ['SQ', '1', 'FractionGroupSequence'],\n '0071': ['IS', '1', 'FractionGroupNumber'],\n '0072': ['LO', '1', 'FractionGroupDescription'],\n '0078': ['IS', '1', 'NumberOfFractionsPlanned'],\n '0079': ['IS', '1', 'NumberOfFractionPatternDigitsPerDay'],\n '007A': ['IS', '1', 'RepeatFractionCycleLength'],\n '007B': ['LT', '1', 'FractionPattern'],\n '0080': ['IS', '1', 'NumberOfBeams'],\n '0082': ['DS', '3', 'BeamDoseSpecificationPoint'],\n '0083': ['UI', '1', 'ReferencedDoseReferenceUID'],\n '0084': ['DS', '1', 'BeamDose'],\n '0086': ['DS', '1', 'BeamMeterset'],\n '0088': ['FL', '1', 'BeamDosePointDepth'],\n '0089': ['FL', '1', 'BeamDosePointEquivalentDepth'],\n '008A': ['FL', '1', 'BeamDosePointSSD'],\n '008B': ['CS', '1', 'BeamDoseMeaning'],\n '008C': ['SQ', '1', 'BeamDoseVerificationControlPointSequence'],\n '008D': ['FL', '1', 'AverageBeamDosePointDepth'],\n '008E': ['FL', '1', 'AverageBeamDosePointEquivalentDepth'],\n '008F': ['FL', '1', 'AverageBeamDosePointSSD'],\n '0090': ['CS', '1', 'BeamDoseType'],\n '0091': ['DS', '1', 'AlternateBeamDose'],\n '0092': ['CS', '1', 'AlternateBeamDoseType'],\n '0093': ['CS', '1', 'DepthValueAveragingFlag'],\n '0094': ['DS', '1', 'BeamDosePointSourceToExternalContourDistance'],\n '00A0': ['IS', '1', 'NumberOfBrachyApplicationSetups'],\n '00A2': ['DS', '3', 'BrachyApplicationSetupDoseSpecificationPoint'],\n '00A4': ['DS', '1', 'BrachyApplicationSetupDose'],\n '00B0': ['SQ', '1', 'BeamSequence'],\n '00B2': ['SH', '1', 'TreatmentMachineName'],\n '00B3': ['CS', '1', 'PrimaryDosimeterUnit'],\n '00B4': ['DS', '1', 'SourceAxisDistance'],\n '00B6': ['SQ', '1', 'BeamLimitingDeviceSequence'],\n '00B8': ['CS', '1', 'RTBeamLimitingDeviceType'],\n '00BA': ['DS', '1', 'SourceToBeamLimitingDeviceDistance'],\n '00BB': ['FL', '1', 'IsocenterToBeamLimitingDeviceDistance'],\n '00BC': ['IS', '1', 'NumberOfLeafJawPairs'],\n '00BE': ['DS', '3-n', 'LeafPositionBoundaries'],\n '00C0': ['IS', '1', 'BeamNumber'],\n '00C2': ['LO', '1', 'BeamName'],\n '00C3': ['ST', '1', 'BeamDescription'],\n '00C4': ['CS', '1', 'BeamType'],\n '00C5': ['FD', '1', 'BeamDeliveryDurationLimit'],\n '00C6': ['CS', '1', 'RadiationType'],\n '00C7': ['CS', '1', 'HighDoseTechniqueType'],\n '00C8': ['IS', '1', 'ReferenceImageNumber'],\n '00CA': ['SQ', '1', 'PlannedVerificationImageSequence'],\n '00CC': ['LO', '1-n', 'ImagingDeviceSpecificAcquisitionParameters'],\n '00CE': ['CS', '1', 'TreatmentDeliveryType'],\n '00D0': ['IS', '1', 'NumberOfWedges'],\n '00D1': ['SQ', '1', 'WedgeSequence'],\n '00D2': ['IS', '1', 'WedgeNumber'],\n '00D3': ['CS', '1', 'WedgeType'],\n '00D4': ['SH', '1', 'WedgeID'],\n '00D5': ['IS', '1', 'WedgeAngle'],\n '00D6': ['DS', '1', 'WedgeFactor'],\n '00D7': ['FL', '1', 'TotalWedgeTrayWaterEquivalentThickness'],\n '00D8': ['DS', '1', 'WedgeOrientation'],\n '00D9': ['FL', '1', 'IsocenterToWedgeTrayDistance'],\n '00DA': ['DS', '1', 'SourceToWedgeTrayDistance'],\n '00DB': ['FL', '1', 'WedgeThinEdgePosition'],\n '00DC': ['SH', '1', 'BolusID'],\n '00DD': ['ST', '1', 'BolusDescription'],\n '00DE': ['DS', '1', 'EffectiveWedgeAngle'],\n '00E0': ['IS', '1', 'NumberOfCompensators'],\n '00E1': ['SH', '1', 'MaterialID'],\n '00E2': ['DS', '1', 'TotalCompensatorTrayFactor'],\n '00E3': ['SQ', '1', 'CompensatorSequence'],\n '00E4': ['IS', '1', 'CompensatorNumber'],\n '00E5': ['SH', '1', 'CompensatorID'],\n '00E6': ['DS', '1', 'SourceToCompensatorTrayDistance'],\n '00E7': ['IS', '1', 'CompensatorRows'],\n '00E8': ['IS', '1', 'CompensatorColumns'],\n '00E9': ['DS', '2', 'CompensatorPixelSpacing'],\n '00EA': ['DS', '2', 'CompensatorPosition'],\n '00EB': ['DS', '1-n', 'CompensatorTransmissionData'],\n '00EC': ['DS', '1-n', 'CompensatorThicknessData'],\n '00ED': ['IS', '1', 'NumberOfBoli'],\n '00EE': ['CS', '1', 'CompensatorType'],\n '00EF': ['SH', '1', 'CompensatorTrayID'],\n '00F0': ['IS', '1', 'NumberOfBlocks'],\n '00F2': ['DS', '1', 'TotalBlockTrayFactor'],\n '00F3': ['FL', '1', 'TotalBlockTrayWaterEquivalentThickness'],\n '00F4': ['SQ', '1', 'BlockSequence'],\n '00F5': ['SH', '1', 'BlockTrayID'],\n '00F6': ['DS', '1', 'SourceToBlockTrayDistance'],\n '00F7': ['FL', '1', 'IsocenterToBlockTrayDistance'],\n '00F8': ['CS', '1', 'BlockType'],\n '00F9': ['LO', '1', 'AccessoryCode'],\n '00FA': ['CS', '1', 'BlockDivergence'],\n '00FB': ['CS', '1', 'BlockMountingPosition'],\n '00FC': ['IS', '1', 'BlockNumber'],\n '00FE': ['LO', '1', 'BlockName'],\n '0100': ['DS', '1', 'BlockThickness'],\n '0102': ['DS', '1', 'BlockTransmission'],\n '0104': ['IS', '1', 'BlockNumberOfPoints'],\n '0106': ['DS', '2-2n', 'BlockData'],\n '0107': ['SQ', '1', 'ApplicatorSequence'],\n '0108': ['SH', '1', 'ApplicatorID'],\n '0109': ['CS', '1', 'ApplicatorType'],\n '010A': ['LO', '1', 'ApplicatorDescription'],\n '010C': ['DS', '1', 'CumulativeDoseReferenceCoefficient'],\n '010E': ['DS', '1', 'FinalCumulativeMetersetWeight'],\n '0110': ['IS', '1', 'NumberOfControlPoints'],\n '0111': ['SQ', '1', 'ControlPointSequence'],\n '0112': ['IS', '1', 'ControlPointIndex'],\n '0114': ['DS', '1', 'NominalBeamEnergy'],\n '0115': ['DS', '1', 'DoseRateSet'],\n '0116': ['SQ', '1', 'WedgePositionSequence'],\n '0118': ['CS', '1', 'WedgePosition'],\n '011A': ['SQ', '1', 'BeamLimitingDevicePositionSequence'],\n '011C': ['DS', '2-2n', 'LeafJawPositions'],\n '011E': ['DS', '1', 'GantryAngle'],\n '011F': ['CS', '1', 'GantryRotationDirection'],\n '0120': ['DS', '1', 'BeamLimitingDeviceAngle'],\n '0121': ['CS', '1', 'BeamLimitingDeviceRotationDirection'],\n '0122': ['DS', '1', 'PatientSupportAngle'],\n '0123': ['CS', '1', 'PatientSupportRotationDirection'],\n '0124': ['DS', '1', 'TableTopEccentricAxisDistance'],\n '0125': ['DS', '1', 'TableTopEccentricAngle'],\n '0126': ['CS', '1', 'TableTopEccentricRotationDirection'],\n '0128': ['DS', '1', 'TableTopVerticalPosition'],\n '0129': ['DS', '1', 'TableTopLongitudinalPosition'],\n '012A': ['DS', '1', 'TableTopLateralPosition'],\n '012C': ['DS', '3', 'IsocenterPosition'],\n '012E': ['DS', '3', 'SurfaceEntryPoint'],\n '0130': ['DS', '1', 'SourceToSurfaceDistance'],\n '0131': ['FL', '1', 'AverageBeamDosePointSourceToExternalContourDistance'],\n '0132': ['FL', '1', 'SourceToExternalContourDistance'],\n '0133': ['FL', '3', 'ExternalContourEntryPoint'],\n '0134': ['DS', '1', 'CumulativeMetersetWeight'],\n '0140': ['FL', '1', 'TableTopPitchAngle'],\n '0142': ['CS', '1', 'TableTopPitchRotationDirection'],\n '0144': ['FL', '1', 'TableTopRollAngle'],\n '0146': ['CS', '1', 'TableTopRollRotationDirection'],\n '0148': ['FL', '1', 'HeadFixationAngle'],\n '014A': ['FL', '1', 'GantryPitchAngle'],\n '014C': ['CS', '1', 'GantryPitchRotationDirection'],\n '014E': ['FL', '1', 'GantryPitchAngleTolerance'],\n '0150': ['CS', '1', 'FixationEye'],\n '0151': ['DS', '1', 'ChairHeadFramePosition'],\n '0152': ['DS', '1', 'HeadFixationAngleTolerance'],\n '0153': ['DS', '1', 'ChairHeadFramePositionTolerance'],\n '0154': ['DS', '1', 'FixationLightAzimuthalAngleTolerance'],\n '0155': ['DS', '1', 'FixationLightPolarAngleTolerance'],\n '0180': ['SQ', '1', 'PatientSetupSequence'],\n '0182': ['IS', '1', 'PatientSetupNumber'],\n '0183': ['LO', '1', 'PatientSetupLabel'],\n '0184': ['LO', '1', 'PatientAdditionalPosition'],\n '0190': ['SQ', '1', 'FixationDeviceSequence'],\n '0192': ['CS', '1', 'FixationDeviceType'],\n '0194': ['SH', '1', 'FixationDeviceLabel'],\n '0196': ['ST', '1', 'FixationDeviceDescription'],\n '0198': ['SH', '1', 'FixationDevicePosition'],\n '0199': ['FL', '1', 'FixationDevicePitchAngle'],\n '019A': ['FL', '1', 'FixationDeviceRollAngle'],\n '01A0': ['SQ', '1', 'ShieldingDeviceSequence'],\n '01A2': ['CS', '1', 'ShieldingDeviceType'],\n '01A4': ['SH', '1', 'ShieldingDeviceLabel'],\n '01A6': ['ST', '1', 'ShieldingDeviceDescription'],\n '01A8': ['SH', '1', 'ShieldingDevicePosition'],\n '01B0': ['CS', '1', 'SetupTechnique'],\n '01B2': ['ST', '1', 'SetupTechniqueDescription'],\n '01B4': ['SQ', '1', 'SetupDeviceSequence'],\n '01B6': ['CS', '1', 'SetupDeviceType'],\n '01B8': ['SH', '1', 'SetupDeviceLabel'],\n '01BA': ['ST', '1', 'SetupDeviceDescription'],\n '01BC': ['DS', '1', 'SetupDeviceParameter'],\n '01D0': ['ST', '1', 'SetupReferenceDescription'],\n '01D2': ['DS', '1', 'TableTopVerticalSetupDisplacement'],\n '01D4': ['DS', '1', 'TableTopLongitudinalSetupDisplacement'],\n '01D6': ['DS', '1', 'TableTopLateralSetupDisplacement'],\n '0200': ['CS', '1', 'BrachyTreatmentTechnique'],\n '0202': ['CS', '1', 'BrachyTreatmentType'],\n '0206': ['SQ', '1', 'TreatmentMachineSequence'],\n '0210': ['SQ', '1', 'SourceSequence'],\n '0212': ['IS', '1', 'SourceNumber'],\n '0214': ['CS', '1', 'SourceType'],\n '0216': ['LO', '1', 'SourceManufacturer'],\n '0218': ['DS', '1', 'ActiveSourceDiameter'],\n '021A': ['DS', '1', 'ActiveSourceLength'],\n '021B': ['SH', '1', 'SourceModelID'],\n '021C': ['LO', '1', 'SourceDescription'],\n '0222': ['DS', '1', 'SourceEncapsulationNominalThickness'],\n '0224': ['DS', '1', 'SourceEncapsulationNominalTransmission'],\n '0226': ['LO', '1', 'SourceIsotopeName'],\n '0228': ['DS', '1', 'SourceIsotopeHalfLife'],\n '0229': ['CS', '1', 'SourceStrengthUnits'],\n '022A': ['DS', '1', 'ReferenceAirKermaRate'],\n '022B': ['DS', '1', 'SourceStrength'],\n '022C': ['DA', '1', 'SourceStrengthReferenceDate'],\n '022E': ['TM', '1', 'SourceStrengthReferenceTime'],\n '0230': ['SQ', '1', 'ApplicationSetupSequence'],\n '0232': ['CS', '1', 'ApplicationSetupType'],\n '0234': ['IS', '1', 'ApplicationSetupNumber'],\n '0236': ['LO', '1', 'ApplicationSetupName'],\n '0238': ['LO', '1', 'ApplicationSetupManufacturer'],\n '0240': ['IS', '1', 'TemplateNumber'],\n '0242': ['SH', '1', 'TemplateType'],\n '0244': ['LO', '1', 'TemplateName'],\n '0250': ['DS', '1', 'TotalReferenceAirKerma'],\n '0260': ['SQ', '1', 'BrachyAccessoryDeviceSequence'],\n '0262': ['IS', '1', 'BrachyAccessoryDeviceNumber'],\n '0263': ['SH', '1', 'BrachyAccessoryDeviceID'],\n '0264': ['CS', '1', 'BrachyAccessoryDeviceType'],\n '0266': ['LO', '1', 'BrachyAccessoryDeviceName'],\n '026A': ['DS', '1', 'BrachyAccessoryDeviceNominalThickness'],\n '026C': ['DS', '1', 'BrachyAccessoryDeviceNominalTransmission'],\n '0271': ['DS', '1', 'ChannelEffectiveLength'],\n '0272': ['DS', '1', 'ChannelInnerLength'],\n '0273': ['SH', '1', 'AfterloaderChannelID'],\n '0274': ['DS', '1', 'SourceApplicatorTipLength'],\n '0280': ['SQ', '1', 'ChannelSequence'],\n '0282': ['IS', '1', 'ChannelNumber'],\n '0284': ['DS', '1', 'ChannelLength'],\n '0286': ['DS', '1', 'ChannelTotalTime'],\n '0288': ['CS', '1', 'SourceMovementType'],\n '028A': ['IS', '1', 'NumberOfPulses'],\n '028C': ['DS', '1', 'PulseRepetitionInterval'],\n '0290': ['IS', '1', 'SourceApplicatorNumber'],\n '0291': ['SH', '1', 'SourceApplicatorID'],\n '0292': ['CS', '1', 'SourceApplicatorType'],\n '0294': ['LO', '1', 'SourceApplicatorName'],\n '0296': ['DS', '1', 'SourceApplicatorLength'],\n '0298': ['LO', '1', 'SourceApplicatorManufacturer'],\n '029C': ['DS', '1', 'SourceApplicatorWallNominalThickness'],\n '029E': ['DS', '1', 'SourceApplicatorWallNominalTransmission'],\n '02A0': ['DS', '1', 'SourceApplicatorStepSize'],\n '02A1': ['IS', '1', 'ApplicatorShapeReferencedROINumber'],\n '02A2': ['IS', '1', 'TransferTubeNumber'],\n '02A4': ['DS', '1', 'TransferTubeLength'],\n '02B0': ['SQ', '1', 'ChannelShieldSequence'],\n '02B2': ['IS', '1', 'ChannelShieldNumber'],\n '02B3': ['SH', '1', 'ChannelShieldID'],\n '02B4': ['LO', '1', 'ChannelShieldName'],\n '02B8': ['DS', '1', 'ChannelShieldNominalThickness'],\n '02BA': ['DS', '1', 'ChannelShieldNominalTransmission'],\n '02C8': ['DS', '1', 'FinalCumulativeTimeWeight'],\n '02D0': ['SQ', '1', 'BrachyControlPointSequence'],\n '02D2': ['DS', '1', 'ControlPointRelativePosition'],\n '02D4': ['DS', '3', 'ControlPoint3DPosition'],\n '02D6': ['DS', '1', 'CumulativeTimeWeight'],\n '02E0': ['CS', '1', 'CompensatorDivergence'],\n '02E1': ['CS', '1', 'CompensatorMountingPosition'],\n '02E2': ['DS', '1-n', 'SourceToCompensatorDistance'],\n '02E3': ['FL', '1', 'TotalCompensatorTrayWaterEquivalentThickness'],\n '02E4': ['FL', '1', 'IsocenterToCompensatorTrayDistance'],\n '02E5': ['FL', '1', 'CompensatorColumnOffset'],\n '02E6': ['FL', '1-n', 'IsocenterToCompensatorDistances'],\n '02E7': ['FL', '1', 'CompensatorRelativeStoppingPowerRatio'],\n '02E8': ['FL', '1', 'CompensatorMillingToolDiameter'],\n '02EA': ['SQ', '1', 'IonRangeCompensatorSequence'],\n '02EB': ['LT', '1', 'CompensatorDescription'],\n '0302': ['IS', '1', 'RadiationMassNumber'],\n '0304': ['IS', '1', 'RadiationAtomicNumber'],\n '0306': ['SS', '1', 'RadiationChargeState'],\n '0308': ['CS', '1', 'ScanMode'],\n '0309': ['CS', '1', 'ModulatedScanModeType'],\n '030A': ['FL', '2', 'VirtualSourceAxisDistances'],\n '030C': ['SQ', '1', 'SnoutSequence'],\n '030D': ['FL', '1', 'SnoutPosition'],\n '030F': ['SH', '1', 'SnoutID'],\n '0312': ['IS', '1', 'NumberOfRangeShifters'],\n '0314': ['SQ', '1', 'RangeShifterSequence'],\n '0316': ['IS', '1', 'RangeShifterNumber'],\n '0318': ['SH', '1', 'RangeShifterID'],\n '0320': ['CS', '1', 'RangeShifterType'],\n '0322': ['LO', '1', 'RangeShifterDescription'],\n '0330': ['IS', '1', 'NumberOfLateralSpreadingDevices'],\n '0332': ['SQ', '1', 'LateralSpreadingDeviceSequence'],\n '0334': ['IS', '1', 'LateralSpreadingDeviceNumber'],\n '0336': ['SH', '1', 'LateralSpreadingDeviceID'],\n '0338': ['CS', '1', 'LateralSpreadingDeviceType'],\n '033A': ['LO', '1', 'LateralSpreadingDeviceDescription'],\n '033C': ['FL', '1', 'LateralSpreadingDeviceWaterEquivalentThickness'],\n '0340': ['IS', '1', 'NumberOfRangeModulators'],\n '0342': ['SQ', '1', 'RangeModulatorSequence'],\n '0344': ['IS', '1', 'RangeModulatorNumber'],\n '0346': ['SH', '1', 'RangeModulatorID'],\n '0348': ['CS', '1', 'RangeModulatorType'],\n '034A': ['LO', '1', 'RangeModulatorDescription'],\n '034C': ['SH', '1', 'BeamCurrentModulationID'],\n '0350': ['CS', '1', 'PatientSupportType'],\n '0352': ['SH', '1', 'PatientSupportID'],\n '0354': ['LO', '1', 'PatientSupportAccessoryCode'],\n '0355': ['LO', '1', 'TrayAccessoryCode'],\n '0356': ['FL', '1', 'FixationLightAzimuthalAngle'],\n '0358': ['FL', '1', 'FixationLightPolarAngle'],\n '035A': ['FL', '1', 'MetersetRate'],\n '0360': ['SQ', '1', 'RangeShifterSettingsSequence'],\n '0362': ['LO', '1', 'RangeShifterSetting'],\n '0364': ['FL', '1', 'IsocenterToRangeShifterDistance'],\n '0366': ['FL', '1', 'RangeShifterWaterEquivalentThickness'],\n '0370': ['SQ', '1', 'LateralSpreadingDeviceSettingsSequence'],\n '0372': ['LO', '1', 'LateralSpreadingDeviceSetting'],\n '0374': ['FL', '1', 'IsocenterToLateralSpreadingDeviceDistance'],\n '0380': ['SQ', '1', 'RangeModulatorSettingsSequence'],\n '0382': ['FL', '1', 'RangeModulatorGatingStartValue'],\n '0384': ['FL', '1', 'RangeModulatorGatingStopValue'],\n '0386': ['FL', '1', 'RangeModulatorGatingStartWaterEquivalentThickness'],\n '0388': ['FL', '1', 'RangeModulatorGatingStopWaterEquivalentThickness'],\n '038A': ['FL', '1', 'IsocenterToRangeModulatorDistance'],\n '038F': ['FL', '1-n', 'ScanSpotTimeOffset'],\n '0390': ['SH', '1', 'ScanSpotTuneID'],\n '0391': ['IS', '1-n', 'ScanSpotPrescribedIndices'],\n '0392': ['IS', '1', 'NumberOfScanSpotPositions'],\n '0393': ['CS', '1', 'ScanSpotReordered'],\n '0394': ['FL', '1-n', 'ScanSpotPositionMap'],\n '0395': ['CS', '1', 'ScanSpotReorderingAllowed'],\n '0396': ['FL', '1-n', 'ScanSpotMetersetWeights'],\n '0398': ['FL', '2', 'ScanningSpotSize'],\n '0399': ['FL', '2-2n', 'ScanSpotSizesDelivered'],\n '039A': ['IS', '1', 'NumberOfPaintings'],\n '03A0': ['SQ', '1', 'IonToleranceTableSequence'],\n '03A2': ['SQ', '1', 'IonBeamSequence'],\n '03A4': ['SQ', '1', 'IonBeamLimitingDeviceSequence'],\n '03A6': ['SQ', '1', 'IonBlockSequence'],\n '03A8': ['SQ', '1', 'IonControlPointSequence'],\n '03AA': ['SQ', '1', 'IonWedgeSequence'],\n '03AC': ['SQ', '1', 'IonWedgePositionSequence'],\n '0401': ['SQ', '1', 'ReferencedSetupImageSequence'],\n '0402': ['ST', '1', 'SetupImageComment'],\n '0410': ['SQ', '1', 'MotionSynchronizationSequence'],\n '0412': ['FL', '3', 'ControlPointOrientation'],\n '0420': ['SQ', '1', 'GeneralAccessorySequence'],\n '0421': ['SH', '1', 'GeneralAccessoryID'],\n '0422': ['ST', '1', 'GeneralAccessoryDescription'],\n '0423': ['CS', '1', 'GeneralAccessoryType'],\n '0424': ['IS', '1', 'GeneralAccessoryNumber'],\n '0425': ['FL', '1', 'SourceToGeneralAccessoryDistance'],\n '0426': ['DS', '1', 'IsocenterToGeneralAccessoryDistance'],\n '0431': ['SQ', '1', 'ApplicatorGeometrySequence'],\n '0432': ['CS', '1', 'ApplicatorApertureShape'],\n '0433': ['FL', '1', 'ApplicatorOpening'],\n '0434': ['FL', '1', 'ApplicatorOpeningX'],\n '0435': ['FL', '1', 'ApplicatorOpeningY'],\n '0436': ['FL', '1', 'SourceToApplicatorMountingPositionDistance'],\n '0440': ['IS', '1', 'NumberOfBlockSlabItems'],\n '0441': ['SQ', '1', 'BlockSlabSequence'],\n '0442': ['DS', '1', 'BlockSlabThickness'],\n '0443': ['US', '1', 'BlockSlabNumber'],\n '0450': ['SQ', '1', 'DeviceMotionControlSequence'],\n '0451': ['CS', '1', 'DeviceMotionExecutionMode'],\n '0452': ['CS', '1', 'DeviceMotionObservationMode'],\n '0453': ['SQ', '1', 'DeviceMotionParameterCodeSequence'],\n '0501': ['FL', '1', 'DistalDepthFraction'],\n '0502': ['FL', '1', 'DistalDepth'],\n '0503': ['FL', '2', 'NominalRangeModulationFractions'],\n '0504': ['FL', '2', 'NominalRangeModulatedRegionDepths'],\n '0505': ['SQ', '1', 'DepthDoseParametersSequence'],\n '0506': ['SQ', '1', 'DeliveredDepthDoseParametersSequence'],\n '0507': ['FL', '1', 'DeliveredDistalDepthFraction'],\n '0508': ['FL', '1', 'DeliveredDistalDepth'],\n '0509': ['FL', '2', 'DeliveredNominalRangeModulationFractions'],\n '0510': ['FL', '2', 'DeliveredNominalRangeModulatedRegionDepths'],\n '0511': ['CS', '1', 'DeliveredReferenceDoseDefinition'],\n '0512': ['CS', '1', 'ReferenceDoseDefinition'],\n '0600': ['US', '1', 'RTControlPointIndex'],\n '0601': ['US', '1', 'RadiationGenerationModeIndex'],\n '0602': ['US', '1', 'ReferencedDefinedDeviceIndex'],\n '0603': ['US', '1', 'RadiationDoseIdentificationIndex'],\n '0604': ['US', '1', 'NumberOfRTControlPoints'],\n '0605': ['US', '1', 'ReferencedRadiationGenerationModeIndex'],\n '0606': ['US', '1', 'TreatmentPositionIndex'],\n '0607': ['US', '1', 'ReferencedDeviceIndex'],\n '0608': ['LO', '1', 'TreatmentPositionGroupLabel'],\n '0609': ['UI', '1', 'TreatmentPositionGroupUID'],\n '060A': ['SQ', '1', 'TreatmentPositionGroupSequence'],\n '060B': ['US', '1', 'ReferencedTreatmentPositionIndex'],\n '060C': ['US', '1', 'ReferencedRadiationDoseIdentificationIndex'],\n '060D': ['FD', '1', 'RTAccessoryHolderWaterEquivalentThickness'],\n '060E': ['US', '1', 'ReferencedRTAccessoryHolderDeviceIndex'],\n '060F': ['CS', '1', 'RTAccessoryHolderSlotExistenceFlag'],\n '0610': ['SQ', '1', 'RTAccessoryHolderSlotSequence'],\n '0611': ['LO', '1', 'RTAccessoryHolderSlotID'],\n '0612': ['FD', '1', 'RTAccessoryHolderSlotDistance'],\n '0613': ['FD', '1', 'RTAccessorySlotDistance'],\n '0614': ['SQ', '1', 'RTAccessoryHolderDefinitionSequence'],\n '0615': ['LO', '1', 'RTAccessoryDeviceSlotID'],\n '0616': ['SQ', '1', 'RTRadiationSequence'],\n '0617': ['SQ', '1', 'RadiationDoseSequence'],\n '0618': ['SQ', '1', 'RadiationDoseIdentificationSequence'],\n '0619': ['LO', '1', 'RadiationDoseIdentificationLabel'],\n '061A': ['CS', '1', 'ReferenceDoseType'],\n '061B': ['CS', '1', 'PrimaryDoseValueIndicator'],\n '061C': ['SQ', '1', 'DoseValuesSequence'],\n '061D': ['CS', '1-n', 'DoseValuePurpose'],\n '061E': ['FD', '3', 'ReferenceDosePointCoordinates'],\n '061F': ['SQ', '1', 'RadiationDoseValuesParametersSequence'],\n '0620': ['SQ', '1', 'MetersetToDoseMappingSequence'],\n '0621': ['SQ', '1', 'ExpectedInVivoMeasurementValuesSequence'],\n '0622': ['US', '1', 'ExpectedInVivoMeasurementValueIndex'],\n '0623': ['LO', '1', 'RadiationDoseInVivoMeasurementLabel'],\n '0624': ['FD', '2', 'RadiationDoseCentralAxisDisplacement'],\n '0625': ['FD', '1', 'RadiationDoseValue'],\n '0626': ['FD', '1', 'RadiationDoseSourceToSkinDistance'],\n '0627': ['FD', '3', 'RadiationDoseMeasurementPointCoordinates'],\n '0628': ['FD', '1', 'RadiationDoseSourceToExternalContourDistance'],\n '0629': ['SQ', '1', 'RTToleranceSetSequence'],\n '062A': ['LO', '1', 'RTToleranceSetLabel'],\n '062B': ['SQ', '1', 'AttributeToleranceValuesSequence'],\n '062C': ['FD', '1', 'ToleranceValue'],\n '062D': ['SQ', '1', 'PatientSupportPositionToleranceSequence'],\n '062E': ['FD', '1', 'TreatmentTimeLimit'],\n '062F': ['SQ', '1', 'CArmPhotonElectronControlPointSequence'],\n '0630': ['SQ', '1', 'ReferencedRTRadiationSequence'],\n '0631': ['SQ', '1', 'ReferencedRTInstanceSequence'],\n '0632': ['SQ', '1', 'ReferencedRTPatientSetupSequence'],\n '0634': ['FD', '1', 'SourceToPatientSurfaceDistance'],\n '0635': ['SQ', '1', 'TreatmentMachineSpecialModeCodeSequence'],\n '0636': ['US', '1', 'IntendedNumberOfFractions'],\n '0637': ['CS', '1', 'RTRadiationSetIntent'],\n '0638': ['CS', '1', 'RTRadiationPhysicalAndGeometricContentDetailFlag'],\n '0639': ['CS', '1', 'RTRecordFlag'],\n '063A': ['SQ', '1', 'TreatmentDeviceIdentificationSequence'],\n '063B': ['SQ', '1', 'ReferencedRTPhysicianIntentSequence'],\n '063C': ['FD', '1', 'CumulativeMeterset'],\n '063D': ['FD', '1', 'DeliveryRate'],\n '063E': ['SQ', '1', 'DeliveryRateUnitSequence'],\n '063F': ['SQ', '1', 'TreatmentPositionSequence'],\n '0640': ['FD', '1', 'RadiationSourceAxisDistance'],\n '0641': ['US', '1', 'NumberOfRTBeamLimitingDevices'],\n '0642': ['FD', '1', 'RTBeamLimitingDeviceProximalDistance'],\n '0643': ['FD', '1', 'RTBeamLimitingDeviceDistalDistance'],\n '0644': ['SQ', '1', 'ParallelRTBeamDelimiterDeviceOrientationLabelCodeSequence'],\n '0645': ['FD', '1', 'BeamModifierOrientationAngle'],\n '0646': ['SQ', '1', 'FixedRTBeamDelimiterDeviceSequence'],\n '0647': ['SQ', '1', 'ParallelRTBeamDelimiterDeviceSequence'],\n '0648': ['US', '1', 'NumberOfParallelRTBeamDelimiters'],\n '0649': ['FD', '2-n', 'ParallelRTBeamDelimiterBoundaries'],\n '064A': ['FD', '2-n', 'ParallelRTBeamDelimiterPositions'],\n '064B': ['FD', '2', 'RTBeamLimitingDeviceOffset'],\n '064C': ['SQ', '1', 'RTBeamDelimiterGeometrySequence'],\n '064D': ['SQ', '1', 'RTBeamLimitingDeviceDefinitionSequence'],\n '064E': ['CS', '1', 'ParallelRTBeamDelimiterOpeningMode'],\n '064F': ['CS', '1-n', 'ParallelRTBeamDelimiterLeafMountingSide'],\n '0650': ['UI', '1', 'PatientSetupUID'],\n '0651': ['SQ', '1', 'WedgeDefinitionSequence'],\n '0652': ['FD', '1', 'RadiationBeamWedgeAngle'],\n '0653': ['FD', '1', 'RadiationBeamWedgeThinEdgeDistance'],\n '0654': ['FD', '1', 'RadiationBeamEffectiveWedgeAngle'],\n '0655': ['US', '1', 'NumberOfWedgePositions'],\n '0656': ['SQ', '1', 'RTBeamLimitingDeviceOpeningSequence'],\n '0657': ['US', '1', 'NumberOfRTBeamLimitingDeviceOpenings'],\n '0658': ['SQ', '1', 'RadiationDosimeterUnitSequence'],\n '0659': ['SQ', '1', 'RTDeviceDistanceReferenceLocationCodeSequence'],\n '065A': ['SQ', '1', 'RadiationDeviceConfigurationAndCommissioningKeySequence'],\n '065B': ['SQ', '1', 'PatientSupportPositionParameterSequence'],\n '065C': ['CS', '1', 'PatientSupportPositionSpecificationMethod'],\n '065D': ['SQ', '1', 'PatientSupportPositionDeviceParameterSequence'],\n '065E': ['US', '1', 'DeviceOrderIndex'],\n '065F': ['US', '1', 'PatientSupportPositionParameterOrderIndex'],\n '0660': ['SQ', '1', 'PatientSupportPositionDeviceToleranceSequence'],\n '0661': ['US', '1', 'PatientSupportPositionToleranceOrderIndex'],\n '0662': ['SQ', '1', 'CompensatorDefinitionSequence'],\n '0663': ['CS', '1', 'CompensatorMapOrientation'],\n '0664': ['OF', '1', 'CompensatorProximalThicknessMap'],\n '0665': ['OF', '1', 'CompensatorDistalThicknessMap'],\n '0666': ['FD', '1', 'CompensatorBasePlaneOffset'],\n '0667': ['SQ', '1', 'CompensatorShapeFabricationCodeSequence'],\n '0668': ['SQ', '1', 'CompensatorShapeSequence'],\n '0669': ['FD', '1', 'RadiationBeamCompensatorMillingToolDiameter'],\n '066A': ['SQ', '1', 'BlockDefinitionSequence'],\n '066B': ['OF', '1', 'BlockEdgeData'],\n '066C': ['CS', '1', 'BlockOrientation'],\n '066D': ['FD', '1', 'RadiationBeamBlockThickness'],\n '066E': ['FD', '1', 'RadiationBeamBlockSlabThickness'],\n '066F': ['SQ', '1', 'BlockEdgeDataSequence'],\n '0670': ['US', '1', 'NumberOfRTAccessoryHolders'],\n '0671': ['SQ', '1', 'GeneralAccessoryDefinitionSequence'],\n '0672': ['US', '1', 'NumberOfGeneralAccessories'],\n '0673': ['SQ', '1', 'BolusDefinitionSequence'],\n '0674': ['US', '1', 'NumberOfBoluses'],\n '0675': ['UI', '1', 'EquipmentFrameOfReferenceUID'],\n '0676': ['ST', '1', 'EquipmentFrameOfReferenceDescription'],\n '0677': ['SQ', '1', 'EquipmentReferencePointCoordinatesSequence'],\n '0678': ['SQ', '1', 'EquipmentReferencePointCodeSequence'],\n '0679': ['FD', '1', 'RTBeamLimitingDeviceAngle'],\n '067A': ['FD', '1', 'SourceRollAngle'],\n '067B': ['SQ', '1', 'RadiationGenerationModeSequence'],\n '067C': ['SH', '1', 'RadiationGenerationModeLabel'],\n '067D': ['ST', '1', 'RadiationGenerationModeDescription'],\n '067E': ['SQ', '1', 'RadiationGenerationModeMachineCodeSequence'],\n '067F': ['SQ', '1', 'RadiationTypeCodeSequence'],\n '0680': ['DS', '1', 'NominalEnergy'],\n '0681': ['DS', '1', 'MinimumNominalEnergy'],\n '0682': ['DS', '1', 'MaximumNominalEnergy'],\n '0683': ['SQ', '1', 'RadiationFluenceModifierCodeSequence'],\n '0684': ['SQ', '1', 'EnergyUnitCodeSequence'],\n '0685': ['US', '1', 'NumberOfRadiationGenerationModes'],\n '0686': ['SQ', '1', 'PatientSupportDevicesSequence'],\n '0687': ['US', '1', 'NumberOfPatientSupportDevices'],\n '0688': ['FD', '1', 'RTBeamModifierDefinitionDistance'],\n '0689': ['SQ', '1', 'BeamAreaLimitSequence'],\n '068A': ['SQ', '1', 'ReferencedRTPrescriptionSequence'],\n '0700': ['UI', '1', 'TreatmentSessionUID'],\n '0701': ['CS', '1', 'RTRadiationUsage'],\n '0702': ['SQ', '1', 'ReferencedRTRadiationSetSequence'],\n '0703': ['SQ', '1', 'ReferencedRTRadiationRecordSequence'],\n '0704': ['US', '1', 'RTRadiationSetDeliveryNumber'],\n '0705': ['US', '1', 'ClinicalFractionNumber'],\n '0706': ['CS', '1', 'RTTreatmentFractionCompletionStatus'],\n '0707': ['CS', '1', 'RTRadiationSetUsage'],\n '0708': ['CS', '1', 'TreatmentDeliveryContinuationFlag'],\n '0709': ['CS', '1', 'TreatmentRecordContentOrigin'],\n '0714': ['CS', '1', 'RTTreatmentTerminationStatus'],\n '0715': ['SQ', '1', 'RTTreatmentTerminationReasonCodeSequence'],\n '0716': ['SQ', '1', 'MachineSpecificTreatmentTerminationCodeSequence'],\n '0722': ['SQ', '1', 'RTRadiationSalvageRecordControlPointSequence'],\n '0723': ['CS', '1', 'StartingMetersetValueKnownFlag'],\n '0730': ['ST', '1', 'TreatmentTerminationDescription'],\n '0731': ['SQ', '1', 'TreatmentToleranceViolationSequence'],\n '0732': ['CS', '1', 'TreatmentToleranceViolationCategory'],\n '0733': ['SQ', '1', 'TreatmentToleranceViolationAttributeSequence'],\n '0734': ['ST', '1', 'TreatmentToleranceViolationDescription'],\n '0735': ['ST', '1', 'TreatmentToleranceViolationIdentification'],\n '0736': ['DT', '1', 'TreatmentToleranceViolationDateTime'],\n '073A': ['DT', '1', 'RecordedRTControlPointDateTime'],\n '073B': ['US', '1', 'ReferencedRadiationRTControlPointIndex'],\n '073E': ['SQ', '1', 'AlternateValueSequence'],\n '073F': ['SQ', '1', 'ConfirmationSequence'],\n '0740': ['SQ', '1', 'InterlockSequence'],\n '0741': ['DT', '1', 'InterlockDateTime'],\n '0742': ['ST', '1', 'InterlockDescription'],\n '0743': ['SQ', '1', 'InterlockOriginatingDeviceSequence'],\n '0744': ['SQ', '1', 'InterlockCodeSequence'],\n '0745': ['SQ', '1', 'InterlockResolutionCodeSequence'],\n '0746': ['SQ', '1', 'InterlockResolutionUserSequence'],\n '0760': ['DT', '1', 'OverrideDateTime'],\n '0761': ['SQ', '1', 'TreatmentToleranceViolationTypeCodeSequence'],\n '0762': ['SQ', '1', 'TreatmentToleranceViolationCauseCodeSequence'],\n '0772': ['SQ', '1', 'MeasuredMetersetToDoseMappingSequence'],\n '0773': ['US', '1', 'ReferencedExpectedInVivoMeasurementValueIndex'],\n '0774': ['SQ', '1', 'DoseMeasurementDeviceCodeSequence'],\n '0780': ['SQ', '1', 'AdditionalParameterRecordingInstanceSequence'],\n '0782': ['US', '1', ''],\n '0783': ['ST', '1', 'InterlockOriginDescription'],\n '0784': ['SQ', '1', 'RTPatientPositionScopeSequence'],\n '0785': ['UI', '1', 'ReferencedTreatmentPositionGroupUID'],\n '0786': ['US', '1', 'RadiationOrderIndex'],\n '0787': ['SQ', '1', 'OmittedRadiationSequence'],\n '0788': ['SQ', '1', 'ReasonForOmissionCodeSequence'],\n '0789': ['SQ', '1', 'RTDeliveryStartPatientPositionSequence'],\n '078A': ['SQ', '1', 'RTTreatmentPreparationPatientPositionSequence'],\n '078B': ['SQ', '1', 'ReferencedRTTreatmentPreparationSequence'],\n '078C': ['SQ', '1', 'ReferencedPatientSetupPhotoSequence'],\n '078D': ['SQ', '1', 'PatientTreatmentPreparationMethodCodeSequence'],\n '078E': ['LT', '1', 'PatientTreatmentPreparationProcedureParameterDescription'],\n '078F': ['SQ', '1', 'PatientTreatmentPreparationDeviceSequence'],\n '0790': ['SQ', '1', 'PatientTreatmentPreparationProcedureSequence'],\n '0791': ['SQ', '1', 'PatientTreatmentPreparationProcedureCodeSequence'],\n '0792': ['LT', '1', 'PatientTreatmentPreparationMethodDescription'],\n '0793': ['SQ', '1', 'PatientTreatmentPreparationProcedureParameterSequence'],\n '0794': ['LT', '1', 'PatientSetupPhotoDescription'],\n '0795': ['US', '1', 'PatientTreatmentPreparationProcedureIndex'],\n '0796': ['US', '1', 'ReferencedPatientSetupProcedureIndex'],\n '0797': ['SQ', '1', 'RTRadiationTaskSequence'],\n '0798': ['SQ', '1', 'RTPatientPositionDisplacementSequence'],\n '0799': ['SQ', '1', 'RTPatientPositionSequence'],\n '079A': ['LO', '1', 'DisplacementReferenceLabel'],\n '079B': ['FD', '16', 'DisplacementMatrix'],\n '079C': ['SQ', '1', 'PatientSupportDisplacementSequence'],\n '079D': ['SQ', '1', 'DisplacementReferenceLocationCodeSequence'],\n '079E': ['CS', '1', 'RTRadiationSetDeliveryUsage']\n },\n '300C': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['SQ', '1', 'ReferencedRTPlanSequence'],\n '0004': ['SQ', '1', 'ReferencedBeamSequence'],\n '0006': ['IS', '1', 'ReferencedBeamNumber'],\n '0007': ['IS', '1', 'ReferencedReferenceImageNumber'],\n '0008': ['DS', '1', 'StartCumulativeMetersetWeight'],\n '0009': ['DS', '1', 'EndCumulativeMetersetWeight'],\n '000A': ['SQ', '1', 'ReferencedBrachyApplicationSetupSequence'],\n '000C': ['IS', '1', 'ReferencedBrachyApplicationSetupNumber'],\n '000E': ['IS', '1', 'ReferencedSourceNumber'],\n '0020': ['SQ', '1', 'ReferencedFractionGroupSequence'],\n '0022': ['IS', '1', 'ReferencedFractionGroupNumber'],\n '0040': ['SQ', '1', 'ReferencedVerificationImageSequence'],\n '0042': ['SQ', '1', 'ReferencedReferenceImageSequence'],\n '0050': ['SQ', '1', 'ReferencedDoseReferenceSequence'],\n '0051': ['IS', '1', 'ReferencedDoseReferenceNumber'],\n '0055': ['SQ', '1', 'BrachyReferencedDoseReferenceSequence'],\n '0060': ['SQ', '1', 'ReferencedStructureSetSequence'],\n '006A': ['IS', '1', 'ReferencedPatientSetupNumber'],\n '0080': ['SQ', '1', 'ReferencedDoseSequence'],\n '00A0': ['IS', '1', 'ReferencedToleranceTableNumber'],\n '00B0': ['SQ', '1', 'ReferencedBolusSequence'],\n '00C0': ['IS', '1', 'ReferencedWedgeNumber'],\n '00D0': ['IS', '1', 'ReferencedCompensatorNumber'],\n '00E0': ['IS', '1', 'ReferencedBlockNumber'],\n '00F0': ['IS', '1', 'ReferencedControlPointIndex'],\n '00F2': ['SQ', '1', 'ReferencedControlPointSequence'],\n '00F4': ['IS', '1', 'ReferencedStartControlPointIndex'],\n '00F6': ['IS', '1', 'ReferencedStopControlPointIndex'],\n '0100': ['IS', '1', 'ReferencedRangeShifterNumber'],\n '0102': ['IS', '1', 'ReferencedLateralSpreadingDeviceNumber'],\n '0104': ['IS', '1', 'ReferencedRangeModulatorNumber'],\n '0111': ['SQ', '1', 'OmittedBeamTaskSequence'],\n '0112': ['CS', '1', 'ReasonForOmission'],\n '0113': ['LO', '1', 'ReasonForOmissionDescription'],\n '0114': ['SQ', '1', 'PrescriptionOverviewSequence'],\n '0115': ['FL', '1', 'TotalPrescriptionDose'],\n '0116': ['SQ', '1', 'PlanOverviewSequence'],\n '0117': ['US', '1', 'PlanOverviewIndex'],\n '0118': ['US', '1', 'ReferencedPlanOverviewIndex'],\n '0119': ['US', '1', 'NumberOfFractionsIncluded'],\n '0120': ['SQ', '1', 'DoseCalibrationConditionsSequence'],\n '0121': ['FD', '1', 'AbsorbedDoseToMetersetRatio'],\n '0122': ['FD', '2', 'DelineatedRadiationFieldSize'],\n '0123': ['CS', '1', 'DoseCalibrationConditionsVerifiedFlag'],\n '0124': ['FD', '1', 'CalibrationReferencePointDepth'],\n '0125': ['SQ', '1', 'GatingBeamHoldTransitionSequence'],\n '0126': ['CS', '1', 'BeamHoldTransition'],\n '0127': ['DT', '1', 'BeamHoldTransitionDateTime'],\n '0128': ['SQ', '1', 'BeamHoldOriginatingDeviceSequence']\n },\n '300E': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['CS', '1', 'ApprovalStatus'],\n '0004': ['DA', '1', 'ReviewDate'],\n '0005': ['TM', '1', 'ReviewTime'],\n '0008': ['PN', '1', 'ReviewerName']\n },\n '3010': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['SQ', '1', 'RadiobiologicalDoseEffectSequence'],\n '0002': ['CS', '1', 'RadiobiologicalDoseEffectFlag'],\n '0003': ['SQ', '1', 'EffectiveDoseCalculationMethodCategoryCodeSequence'],\n '0004': ['SQ', '1', 'EffectiveDoseCalculationMethodCodeSequence'],\n '0005': ['LO', '1', 'EffectiveDoseCalculationMethodDescription'],\n '0006': ['UI', '1', 'ConceptualVolumeUID'],\n '0007': ['SQ', '1', 'OriginatingSOPInstanceReferenceSequence'],\n '0008': ['SQ', '1', 'ConceptualVolumeConstituentSequence'],\n '0009': ['SQ', '1', 'EquivalentConceptualVolumeInstanceReferenceSequence'],\n '000A': ['SQ', '1', 'EquivalentConceptualVolumesSequence'],\n '000B': ['UI', '1', 'ReferencedConceptualVolumeUID'],\n '000C': ['UT', '1', 'ConceptualVolumeCombinationExpression'],\n '000D': ['US', '1', 'ConceptualVolumeConstituentIndex'],\n '000E': ['CS', '1', 'ConceptualVolumeCombinationFlag'],\n '000F': ['ST', '1', 'ConceptualVolumeCombinationDescription'],\n '0010': ['CS', '1', 'ConceptualVolumeSegmentationDefinedFlag'],\n '0011': ['SQ', '1', 'ConceptualVolumeSegmentationReferenceSequence'],\n '0012': ['SQ', '1', 'ConceptualVolumeConstituentSegmentationReferenceSequence'],\n '0013': ['UI', '1', 'ConstituentConceptualVolumeUID'],\n '0014': ['SQ', '1', 'DerivationConceptualVolumeSequence'],\n '0015': ['UI', '1', 'SourceConceptualVolumeUID'],\n '0016': ['SQ', '1', 'ConceptualVolumeDerivationAlgorithmSequence'],\n '0017': ['ST', '1', 'ConceptualVolumeDescription'],\n '0018': ['SQ', '1', 'SourceConceptualVolumeSequence'],\n '0019': ['SQ', '1', 'AuthorIdentificationSequence'],\n '001A': ['LO', '1', 'ManufacturerModelVersion'],\n '001B': ['UC', '1', 'DeviceAlternateIdentifier'],\n '001C': ['CS', '1', 'DeviceAlternateIdentifierType'],\n '001D': ['LT', '1', 'DeviceAlternateIdentifierFormat'],\n '001E': ['LO', '1', 'SegmentationCreationTemplateLabel'],\n '001F': ['UI', '1', 'SegmentationTemplateUID'],\n '0020': ['US', '1', 'ReferencedSegmentReferenceIndex'],\n '0021': ['SQ', '1', 'SegmentReferenceSequence'],\n '0022': ['US', '1', 'SegmentReferenceIndex'],\n '0023': ['SQ', '1', 'DirectSegmentReferenceSequence'],\n '0024': ['SQ', '1', 'CombinationSegmentReferenceSequence'],\n '0025': ['SQ', '1', 'ConceptualVolumeSequence'],\n '0026': ['SQ', '1', 'SegmentedRTAccessoryDeviceSequence'],\n '0027': ['SQ', '1', 'SegmentCharacteristicsSequence'],\n '0028': ['SQ', '1', 'RelatedSegmentCharacteristicsSequence'],\n '0029': ['US', '1', 'SegmentCharacteristicsPrecedence'],\n '002A': ['SQ', '1', 'RTSegmentAnnotationSequence'],\n '002B': ['SQ', '1', 'SegmentAnnotationCategoryCodeSequence'],\n '002C': ['SQ', '1', 'SegmentAnnotationTypeCodeSequence'],\n '002D': ['LO', '1', 'DeviceLabel'],\n '002E': ['SQ', '1', 'DeviceTypeCodeSequence'],\n '002F': ['SQ', '1', 'SegmentAnnotationTypeModifierCodeSequence'],\n '0030': ['SQ', '1', 'PatientEquipmentRelationshipCodeSequence'],\n '0031': ['UI', '1', 'ReferencedFiducialsUID'],\n '0032': ['SQ', '1', 'PatientTreatmentOrientationSequence'],\n '0033': ['SH', '1', 'UserContentLabel'],\n '0034': ['LO', '1', 'UserContentLongLabel'],\n '0035': ['SH', '1', 'EntityLabel'],\n '0036': ['LO', '1', 'EntityName'],\n '0037': ['ST', '1', 'EntityDescription'],\n '0038': ['LO', '1', 'EntityLongLabel'],\n '0039': ['US', '1', 'DeviceIndex'],\n '003A': ['US', '1', 'RTTreatmentPhaseIndex'],\n '003B': ['UI', '1', 'RTTreatmentPhaseUID'],\n '003C': ['US', '1', 'RTPrescriptionIndex'],\n '003D': ['US', '1', 'RTSegmentAnnotationIndex'],\n '003E': ['US', '1', 'BasisRTTreatmentPhaseIndex'],\n '003F': ['US', '1', 'RelatedRTTreatmentPhaseIndex'],\n '0040': ['US', '1', 'ReferencedRTTreatmentPhaseIndex'],\n '0041': ['US', '1', 'ReferencedRTPrescriptionIndex'],\n '0042': ['US', '1', 'ReferencedParentRTPrescriptionIndex'],\n '0043': ['ST', '1', 'ManufacturerDeviceIdentifier'],\n '0044': ['SQ', '1', 'InstanceLevelReferencedPerformedProcedureStepSequence'],\n '0045': ['CS', '1', 'RTTreatmentPhaseIntentPresenceFlag'],\n '0046': ['CS', '1', 'RadiotherapyTreatmentType'],\n '0047': ['CS', '1-n', 'TeletherapyRadiationType'],\n '0048': ['CS', '1-n', 'BrachytherapySourceType'],\n '0049': ['SQ', '1', 'ReferencedRTTreatmentPhaseSequence'],\n '004A': ['SQ', '1', 'ReferencedDirectSegmentInstanceSequence'],\n '004B': ['SQ', '1', 'IntendedRTTreatmentPhaseSequence'],\n '004C': ['DA', '1', 'IntendedPhaseStartDate'],\n '004D': ['DA', '1', 'IntendedPhaseEndDate'],\n '004E': ['SQ', '1', 'RTTreatmentPhaseIntervalSequence'],\n '004F': ['CS', '1', 'TemporalRelationshipIntervalAnchor'],\n '0050': ['FD', '1', 'MinimumNumberOfIntervalDays'],\n '0051': ['FD', '1', 'MaximumNumberOfIntervalDays'],\n '0052': ['UI', '1-n', 'PertinentSOPClassesInStudy'],\n '0053': ['UI', '1-n', 'PertinentSOPClassesInSeries'],\n '0054': ['LO', '1', 'RTPrescriptionLabel'],\n '0055': ['SQ', '1', 'RTPhysicianIntentPredecessorSequence'],\n '0056': ['LO', '1', 'RTTreatmentApproachLabel'],\n '0057': ['SQ', '1', 'RTPhysicianIntentSequence'],\n '0058': ['US', '1', 'RTPhysicianIntentIndex'],\n '0059': ['CS', '1', 'RTTreatmentIntentType'],\n '005A': ['UT', '1', 'RTPhysicianIntentNarrative'],\n '005B': ['SQ', '1', 'RTProtocolCodeSequence'],\n '005C': ['ST', '1', 'ReasonForSuperseding'],\n '005D': ['SQ', '1', 'RTDiagnosisCodeSequence'],\n '005E': ['US', '1', 'ReferencedRTPhysicianIntentIndex'],\n '005F': ['SQ', '1', 'RTPhysicianIntentInputInstanceSequence'],\n '0060': ['SQ', '1', 'RTAnatomicPrescriptionSequence'],\n '0061': ['UT', '1', 'PriorTreatmentDoseDescription'],\n '0062': ['SQ', '1', 'PriorTreatmentReferenceSequence'],\n '0063': ['CS', '1', 'DosimetricObjectiveEvaluationScope'],\n '0064': ['SQ', '1', 'TherapeuticRoleCategoryCodeSequence'],\n '0065': ['SQ', '1', 'TherapeuticRoleTypeCodeSequence'],\n '0066': ['US', '1', 'ConceptualVolumeOptimizationPrecedence'],\n '0067': ['SQ', '1', 'ConceptualVolumeCategoryCodeSequence'],\n '0068': ['CS', '1', 'ConceptualVolumeBlockingConstraint'],\n '0069': ['SQ', '1', 'ConceptualVolumeTypeCodeSequence'],\n '006A': ['SQ', '1', 'ConceptualVolumeTypeModifierCodeSequence'],\n '006B': ['SQ', '1', 'RTPrescriptionSequence'],\n '006C': ['SQ', '1', 'DosimetricObjectiveSequence'],\n '006D': ['SQ', '1', 'DosimetricObjectiveTypeCodeSequence'],\n '006E': ['UI', '1', 'DosimetricObjectiveUID'],\n '006F': ['UI', '1', 'ReferencedDosimetricObjectiveUID'],\n '0070': ['SQ', '1', 'DosimetricObjectiveParameterSequence'],\n '0071': ['SQ', '1', 'ReferencedDosimetricObjectivesSequence'],\n '0073': ['CS', '1', 'AbsoluteDosimetricObjectiveFlag'],\n '0074': ['FD', '1', 'DosimetricObjectiveWeight'],\n '0075': ['CS', '1', 'DosimetricObjectivePurpose'],\n '0076': ['SQ', '1', 'PlanningInputInformationSequence'],\n '0077': ['LO', '1', 'TreatmentSite'],\n '0078': ['SQ', '1', 'TreatmentSiteCodeSequence'],\n '0079': ['SQ', '1', 'FractionPatternSequence'],\n '007A': ['UT', '1', 'TreatmentTechniqueNotes'],\n '007B': ['UT', '1', 'PrescriptionNotes'],\n '007C': ['IS', '1', 'NumberOfIntervalFractions'],\n '007D': ['US', '1', 'NumberOfFractions'],\n '007E': ['US', '1', 'IntendedDeliveryDuration'],\n '007F': ['UT', '1', 'FractionationNotes'],\n '0080': ['SQ', '1', 'RTTreatmentTechniqueCodeSequence'],\n '0081': ['SQ', '1', 'PrescriptionNotesSequence'],\n '0082': ['SQ', '1', 'FractionBasedRelationshipSequence'],\n '0083': ['CS', '1', 'FractionBasedRelationshipIntervalAnchor'],\n '0084': ['FD', '1', 'MinimumHoursBetweenFractions'],\n '0085': ['TM', '1-n', 'IntendedFractionStartTime'],\n '0086': ['LT', '1', 'IntendedStartDayOfWeek'],\n '0087': ['SQ', '1', 'WeekdayFractionPatternSequence'],\n '0088': ['SQ', '1', 'DeliveryTimeStructureCodeSequence'],\n '0089': ['SQ', '1', 'TreatmentSiteModifierCodeSequence'],\n '0090': ['CS', '1', 'RoboticBaseLocationIndicator'],\n '0091': ['SQ', '1', 'RoboticPathNodeSetCodeSequence'],\n '0092': ['UL', '1', 'RoboticNodeIdentifier'],\n '0093': ['FD', '3', 'RTTreatmentSourceCoordinates'],\n '0094': ['FD', '1', 'RadiationSourceCoordinateSystemYawAngle'],\n '0095': ['FD', '1', 'RadiationSourceCoordinateSystemRollAngle'],\n '0096': ['FD', '1', 'RadiationSourceCoordinateSystemPitchAngle'],\n '0097': ['SQ', '1', 'RoboticPathControlPointSequence'],\n '0098': ['SQ', '1', 'TomotherapeuticControlPointSequence'],\n '0099': ['FD', '1-n', 'TomotherapeuticLeafOpenDurations'],\n '009A': ['FD', '1-n', 'TomotherapeuticLeafInitialClosedDurations']\n },\n '4000': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['LT', '1', 'Arbitrary'],\n '4000': ['LT', '1', 'TextComments']\n },\n '4008': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0040': ['SH', '1', 'ResultsID'],\n '0042': ['LO', '1', 'ResultsIDIssuer'],\n '0050': ['SQ', '1', 'ReferencedInterpretationSequence'],\n '00FF': ['CS', '1', 'ReportProductionStatusTrial'],\n '0100': ['DA', '1', 'InterpretationRecordedDate'],\n '0101': ['TM', '1', 'InterpretationRecordedTime'],\n '0102': ['PN', '1', 'InterpretationRecorder'],\n '0103': ['LO', '1', 'ReferenceToRecordedSound'],\n '0108': ['DA', '1', 'InterpretationTranscriptionDate'],\n '0109': ['TM', '1', 'InterpretationTranscriptionTime'],\n '010A': ['PN', '1', 'InterpretationTranscriber'],\n '010B': ['ST', '1', 'InterpretationText'],\n '010C': ['PN', '1', 'InterpretationAuthor'],\n '0111': ['SQ', '1', 'InterpretationApproverSequence'],\n '0112': ['DA', '1', 'InterpretationApprovalDate'],\n '0113': ['TM', '1', 'InterpretationApprovalTime'],\n '0114': ['PN', '1', 'PhysicianApprovingInterpretation'],\n '0115': ['LT', '1', 'InterpretationDiagnosisDescription'],\n '0117': ['SQ', '1', 'InterpretationDiagnosisCodeSequence'],\n '0118': ['SQ', '1', 'ResultsDistributionListSequence'],\n '0119': ['PN', '1', 'DistributionName'],\n '011A': ['LO', '1', 'DistributionAddress'],\n '0200': ['SH', '1', 'InterpretationID'],\n '0202': ['LO', '1', 'InterpretationIDIssuer'],\n '0210': ['CS', '1', 'InterpretationTypeID'],\n '0212': ['CS', '1', 'InterpretationStatusID'],\n '0300': ['ST', '1', 'Impressions'],\n '4000': ['ST', '1', 'ResultsComments']\n },\n '4010': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['CS', '1', 'LowEnergyDetectors'],\n '0002': ['CS', '1', 'HighEnergyDetectors'],\n '0004': ['SQ', '1', 'DetectorGeometrySequence'],\n '1001': ['SQ', '1', 'ThreatROIVoxelSequence'],\n '1004': ['FL', '3', 'ThreatROIBase'],\n '1005': ['FL', '3', 'ThreatROIExtents'],\n '1006': ['OB', '1', 'ThreatROIBitmap'],\n '1007': ['SH', '1', 'RouteSegmentID'],\n '1008': ['CS', '1', 'GantryType'],\n '1009': ['CS', '1', 'OOIOwnerType'],\n '100A': ['SQ', '1', 'RouteSegmentSequence'],\n '1010': ['US', '1', 'PotentialThreatObjectID'],\n '1011': ['SQ', '1', 'ThreatSequence'],\n '1012': ['CS', '1', 'ThreatCategory'],\n '1013': ['LT', '1', 'ThreatCategoryDescription'],\n '1014': ['CS', '1', 'ATDAbilityAssessment'],\n '1015': ['CS', '1', 'ATDAssessmentFlag'],\n '1016': ['FL', '1', 'ATDAssessmentProbability'],\n '1017': ['FL', '1', 'Mass'],\n '1018': ['FL', '1', 'Density'],\n '1019': ['FL', '1', 'ZEffective'],\n '101A': ['SH', '1', 'BoardingPassID'],\n '101B': ['FL', '3', 'CenterOfMass'],\n '101C': ['FL', '3', 'CenterOfPTO'],\n '101D': ['FL', '6-n', 'BoundingPolygon'],\n '101E': ['SH', '1', 'RouteSegmentStartLocationID'],\n '101F': ['SH', '1', 'RouteSegmentEndLocationID'],\n '1020': ['CS', '1', 'RouteSegmentLocationIDType'],\n '1021': ['CS', '1-n', 'AbortReason'],\n '1023': ['FL', '1', 'VolumeOfPTO'],\n '1024': ['CS', '1', 'AbortFlag'],\n '1025': ['DT', '1', 'RouteSegmentStartTime'],\n '1026': ['DT', '1', 'RouteSegmentEndTime'],\n '1027': ['CS', '1', 'TDRType'],\n '1028': ['CS', '1', 'InternationalRouteSegment'],\n '1029': ['LO', '1-n', 'ThreatDetectionAlgorithmAndVersion'],\n '102A': ['SH', '1', 'AssignedLocation'],\n '102B': ['DT', '1', 'AlarmDecisionTime'],\n '1031': ['CS', '1', 'AlarmDecision'],\n '1033': ['US', '1', 'NumberOfTotalObjects'],\n '1034': ['US', '1', 'NumberOfAlarmObjects'],\n '1037': ['SQ', '1', 'PTORepresentationSequence'],\n '1038': ['SQ', '1', 'ATDAssessmentSequence'],\n '1039': ['CS', '1', 'TIPType'],\n '103A': ['CS', '1', 'DICOSVersion'],\n '1041': ['DT', '1', 'OOIOwnerCreationTime'],\n '1042': ['CS', '1', 'OOIType'],\n '1043': ['FL', '3', 'OOISize'],\n '1044': ['CS', '1', 'AcquisitionStatus'],\n '1045': ['SQ', '1', 'BasisMaterialsCodeSequence'],\n '1046': ['CS', '1', 'PhantomType'],\n '1047': ['SQ', '1', 'OOIOwnerSequence'],\n '1048': ['CS', '1', 'ScanType'],\n '1051': ['LO', '1', 'ItineraryID'],\n '1052': ['SH', '1', 'ItineraryIDType'],\n '1053': ['LO', '1', 'ItineraryIDAssigningAuthority'],\n '1054': ['SH', '1', 'RouteID'],\n '1055': ['SH', '1', 'RouteIDAssigningAuthority'],\n '1056': ['CS', '1', 'InboundArrivalType'],\n '1058': ['SH', '1', 'CarrierID'],\n '1059': ['CS', '1', 'CarrierIDAssigningAuthority'],\n '1060': ['FL', '3', 'SourceOrientation'],\n '1061': ['FL', '3', 'SourcePosition'],\n '1062': ['FL', '1', 'BeltHeight'],\n '1064': ['SQ', '1', 'AlgorithmRoutingCodeSequence'],\n '1067': ['CS', '1', 'TransportClassification'],\n '1068': ['LT', '1', 'OOITypeDescriptor'],\n '1069': ['FL', '1', 'TotalProcessingTime'],\n '106C': ['OB', '1', 'DetectorCalibrationData'],\n '106D': ['CS', '1', 'AdditionalScreeningPerformed'],\n '106E': ['CS', '1', 'AdditionalInspectionSelectionCriteria'],\n '106F': ['SQ', '1', 'AdditionalInspectionMethodSequence'],\n '1070': ['CS', '1', 'AITDeviceType'],\n '1071': ['SQ', '1', 'QRMeasurementsSequence'],\n '1072': ['SQ', '1', 'TargetMaterialSequence'],\n '1073': ['FD', '1', 'SNRThreshold'],\n '1075': ['DS', '1', 'ImageScaleRepresentation'],\n '1076': ['SQ', '1', 'ReferencedPTOSequence'],\n '1077': ['SQ', '1', 'ReferencedTDRInstanceSequence'],\n '1078': ['ST', '1', 'PTOLocationDescription'],\n '1079': ['SQ', '1', 'AnomalyLocatorIndicatorSequence'],\n '107A': ['FL', '3', 'AnomalyLocatorIndicator'],\n '107B': ['SQ', '1', 'PTORegionSequence'],\n '107C': ['CS', '1', 'InspectionSelectionCriteria'],\n '107D': ['SQ', '1', 'SecondaryInspectionMethodSequence'],\n '107E': ['DS', '6', 'PRCSToRCSOrientation']\n },\n '4FFE': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['SQ', '1', 'MACParametersSequence']\n },\n '5000': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0005': ['US', '1', 'CurveDimensions'],\n '0010': ['US', '1', 'NumberOfPoints'],\n '0020': ['CS', '1', 'TypeOfData'],\n '0022': ['LO', '1', 'CurveDescription'],\n '0030': ['SH', '1-n', 'AxisUnits'],\n '0040': ['SH', '1-n', 'AxisLabels'],\n '0103': ['US', '1', 'DataValueRepresentation'],\n '0104': ['US', '1-n', 'MinimumCoordinateValue'],\n '0105': ['US', '1-n', 'MaximumCoordinateValue'],\n '0106': ['SH', '1-n', 'CurveRange'],\n '0110': ['US', '1-n', 'CurveDataDescriptor'],\n '0112': ['US', '1-n', 'CoordinateStartValue'],\n '0114': ['US', '1-n', 'CoordinateStepValue'],\n '1001': ['CS', '1', 'CurveActivationLayer'],\n '2000': ['US', '1', 'AudioType'],\n '2002': ['US', '1', 'AudioSampleFormat'],\n '2004': ['US', '1', 'NumberOfChannels'],\n '2006': ['UL', '1', 'NumberOfSamples'],\n '2008': ['UL', '1', 'SampleRate'],\n '200A': ['UL', '1', 'TotalTime'],\n '200C': ['ox', '1', 'AudioSampleData'],\n '200E': ['LT', '1', 'AudioComments'],\n '2500': ['LO', '1', 'CurveLabel'],\n '2600': ['SQ', '1', 'CurveReferencedOverlaySequence'],\n '2610': ['US', '1', 'CurveReferencedOverlayGroup'],\n '3000': ['ox', '1', 'CurveData']\n },\n '5200': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '9229': ['SQ', '1', 'SharedFunctionalGroupsSequence'],\n '9230': ['SQ', '1', 'PerFrameFunctionalGroupsSequence']\n },\n '5400': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0100': ['SQ', '1', 'WaveformSequence'],\n '0110': ['ox', '1', 'ChannelMinimumValue'],\n '0112': ['ox', '1', 'ChannelMaximumValue'],\n '1004': ['US', '1', 'WaveformBitsAllocated'],\n '1006': ['CS', '1', 'WaveformSampleInterpretation'],\n '100A': ['ox', '1', 'WaveformPaddingValue'],\n '1010': ['ox', '1', 'WaveformData']\n },\n '5600': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['OF', '1', 'FirstOrderPhaseCorrectionAngle'],\n '0020': ['OF', '1', 'SpectroscopyData']\n },\n '6000': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['US', '1', 'OverlayRows'],\n '0011': ['US', '1', 'OverlayColumns'],\n '0012': ['US', '1', 'OverlayPlanes'],\n '0015': ['IS', '1', 'NumberOfFramesInOverlay'],\n '0022': ['LO', '1', 'OverlayDescription'],\n '0040': ['CS', '1', 'OverlayType'],\n '0045': ['LO', '1', 'OverlaySubtype'],\n '0050': ['SS', '2', 'OverlayOrigin'],\n '0051': ['US', '1', 'ImageFrameOrigin'],\n '0052': ['US', '1', 'OverlayPlaneOrigin'],\n '0060': ['CS', '1', 'OverlayCompressionCode'],\n '0061': ['SH', '1', 'OverlayCompressionOriginator'],\n '0062': ['SH', '1', 'OverlayCompressionLabel'],\n '0063': ['CS', '1', 'OverlayCompressionDescription'],\n '0066': ['AT', '1-n', 'OverlayCompressionStepPointers'],\n '0068': ['US', '1', 'OverlayRepeatInterval'],\n '0069': ['US', '1', 'OverlayBitsGrouped'],\n '0100': ['US', '1', 'OverlayBitsAllocated'],\n '0102': ['US', '1', 'OverlayBitPosition'],\n '0110': ['CS', '1', 'OverlayFormat'],\n '0200': ['US', '1', 'OverlayLocation'],\n '0800': ['CS', '1-n', 'OverlayCodeLabel'],\n '0802': ['US', '1', 'OverlayNumberOfTables'],\n '0803': ['AT', '1-n', 'OverlayCodeTableLocation'],\n '0804': ['US', '1', 'OverlayBitsForCodeWord'],\n '1001': ['CS', '1', 'OverlayActivationLayer'],\n '1100': ['US', '1', 'OverlayDescriptorGray'],\n '1101': ['US', '1', 'OverlayDescriptorRed'],\n '1102': ['US', '1', 'OverlayDescriptorGreen'],\n '1103': ['US', '1', 'OverlayDescriptorBlue'],\n '1200': ['US', '1-n', 'OverlaysGray'],\n '1201': ['US', '1-n', 'OverlaysRed'],\n '1202': ['US', '1-n', 'OverlaysGreen'],\n '1203': ['US', '1-n', 'OverlaysBlue'],\n '1301': ['IS', '1', 'ROIArea'],\n '1302': ['DS', '1', 'ROIMean'],\n '1303': ['DS', '1', 'ROIStandardDeviation'],\n '1500': ['LO', '1', 'OverlayLabel'],\n '3000': ['ox', '1', 'OverlayData'],\n '4000': ['LT', '1', 'OverlayComments']\n },\n '7F00': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['ox', '1', 'VariablePixelData'],\n '0011': ['US', '1', 'VariableNextDataGroup'],\n '0020': ['OW', '1', 'VariableCoefficientsSDVN'],\n '0030': ['OW', '1', 'VariableCoefficientsSDHN'],\n '0040': ['OW', '1', 'VariableCoefficientsSDDN']\n },\n '7FE0': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['OV', '1', 'ExtendedOffsetTable'],\n '0002': ['OV', '1', 'ExtendedOffsetTableLengths'],\n '0008': ['OF', '1', 'FloatPixelData'],\n '0009': ['OD', '1', 'DoubleFloatPixelData'],\n '0010': ['ox', '1', 'PixelData'],\n '0020': ['OW', '1', 'CoefficientsSDVN'],\n '0030': ['OW', '1', 'CoefficientsSDHN'],\n '0040': ['OW', '1', 'CoefficientsSDDN']\n },\n 'FFFA': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n 'FFFA': ['SQ', '1', 'DigitalSignaturesSequence']\n },\n 'FFFC': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n 'FFFC': ['OB', '1', 'DataSetTrailingPadding']\n },\n 'FFFE': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n 'E000': ['NONE', '1', 'Item'],\n 'E00D': ['NONE', '1', 'ItemDelimitationItem'],\n 'E0DD': ['NONE', '1', 'SequenceDelimitationItem']\n }\n}; // Dictionary\n\n/**\n * Add tags to the dictionary.\n *\n * @param {string} group The group key.\n * @param {Object} tags The tags to add as an\n * object indexed by element key with values as:\n * [VR, multiplicity, TagName] (all strings).\n */\nexport function addTagsToDictionary(group, tags) {\n // TODO: add checks!\n dictionary[group] = tags;\n}\n\n/**\n * Tag groups: key to name pairs.\n * Copied from gdcm-2.6.1\\Source\\DataDictionary\\GroupName.dic\n * -> removed duplicates (commented).\n *\n * @type {Object}\n */\nexport const tagGroups = {\n '0000': 'Command',\n '0002': 'Meta Element',\n '0004': 'File Set',\n //'0004': 'Directory',\n '0008': 'Identifying',\n '0009': 'SPI Identifying',\n '0010': 'Patient',\n '0012': 'Clinical Trial',\n '0018': 'Acquisition',\n '0019': 'SPI Acquisition',\n '0020': 'Image',\n '0021': 'SPI Image',\n '0022': 'Ophtalmology',\n '0028': 'Image Presentation',\n '0032': 'Study',\n '0038': 'Visit',\n '003A': 'Waveform',\n '0040': 'Procedure',\n //'0040': ''Modality Worklist',\n '0042': 'Encapsulated Document',\n '0050': 'Device Informations',\n //'0050': 'XRay Angio Device',\n '0054': 'Nuclear Medicine',\n '0060': 'Histogram',\n '0070': 'Presentation State',\n '0072': 'Hanging Protocol',\n '0088': 'Storage',\n //'0088': 'Medicine',\n '0100': 'Authorization',\n '0400': 'Digital Signature',\n '1000': 'Code Table',\n '1010': 'Zonal Map',\n '2000': 'Film Session',\n '2010': 'Film Box',\n '2020': 'Image Box',\n '2030': 'Annotation',\n '2040': 'Overlay Box',\n '2050': 'Presentation LUT',\n '2100': 'Print Job',\n '2110': 'Printer',\n '2120': 'Queue',\n '2130': 'Print Content',\n '2200': 'Media Creation',\n '3002': 'RT Image',\n '3004': 'RT Dose',\n '3006': 'RT StructureSet',\n '3008': 'RT Treatment',\n '300A': 'RT Plan',\n '300C': 'RT Relationship',\n '300E': 'RT Approval',\n '4000': 'Text',\n '4008': 'Results',\n '4FFE': 'MAC Parameters',\n '5000': 'Curve',\n '5002': 'Curve',\n '5004': 'Curve',\n '5006': 'Curve',\n '5008': 'Curve',\n '500A': 'Curve',\n '500C': 'Curve',\n '500E': 'Curve',\n '5400': 'Waveform Data',\n '6000': 'Overlays',\n '6002': 'Overlays',\n '6004': 'Overlays',\n '6008': 'Overlays',\n '600A': 'Overlays',\n '600C': 'Overlays',\n '600E': 'Overlays',\n 'FFFC': 'Generic',\n '7FE0': 'Pixel Data',\n 'FFFF': 'Unknown'\n};\n\n/**\n * List of Value Representation (VR) with 32bit Value Length (VL).\n *\n * Added locally used 'ox'.\n * See {@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/chapter_7.html#table_7.1-1}.\n *\n * @type {Object}\n */\nconst vr32bitVL = {\n OB: true,\n OD: true,\n OF: true,\n OL: true,\n OV: true,\n OW: true,\n SQ: true,\n SV: true,\n UC: true,\n UN: true,\n UR: true,\n UT: true,\n UV: true,\n ox: true\n};\n\n/**\n * Does the input Value Representation (VR) have a 32bit Value Length (VL).\n *\n * @param {string} vr The data Value Representation (VR).\n * @returns {boolean} True if this VR has a 32-bit VL.\n */\nexport function is32bitVLVR(vr) {\n return typeof vr32bitVL[vr] !== 'undefined';\n}\n\n/**\n * List of string VR with extended or replaced default character repertoire defined in\n * Specific Character Set (0008,0005).\n *\n * See {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/chapter_6.html#sect_6.1.2.2}.\n *\n * @type {Object}\n */\nconst vrCharSetString = {\n SH: true,\n LO: true,\n UC: true,\n ST: true,\n LT: true,\n UT: true,\n PN: true\n};\n\n/**\n * Does the input Value Representation (VR) have an special character repertoire.\n *\n * @param {string} vr The data VR.\n * @returns {boolean} True if this VR has a special char set.\n */\nexport function isCharSetStringVR(vr) {\n return typeof vrCharSetString[vr] !== 'undefined';\n}\n\n/**\n * VR equivalent javascript types.\n *\n * See {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_6.2.html#table_6.2-1}.\n *\n * @type {Object}\n */\nexport const vrTypes = {\n AE: 'string',\n AS: 'string',\n AT: undefined,\n CS: 'string',\n DA: 'string',\n DS: 'string',\n DT: 'string',\n FL: 'Float32',\n FD: 'Float64',\n IS: 'string',\n LO: 'string',\n LT: 'string',\n OB: 'Uint8',\n OD: 'Uint64',\n OF: 'Uint32',\n OL: 'Uint32',\n OV: 'Uint64',\n OW: 'Uint16',\n PN: 'string',\n SH: 'string',\n SL: 'Int32',\n SQ: undefined,\n SS: 'Int16',\n ST: 'string',\n SV: 'Int64',\n TM: 'string',\n UC: 'string',\n UI: 'string',\n UL: 'Uint32',\n UN: 'Uint8',\n UR: 'string',\n US: 'Uint16',\n UT: 'string',\n UV: 'Uint64'\n};\n\n/**\n * Transfer syntaxes.\n *\n * See {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part06/chapter_A.html#table_A-1}.\n *\n * @type {Object}\n */\nexport const transferSyntaxes = {\n '1.2.840.10008.1.2': 'Implicit VR Little Endian',\n '1.2.840.10008.1.2.1': 'Explicit VR Little Endian',\n '1.2.840.10008.1.2.1.98': 'Encapsulated Uncompressed Explicit VR Little Endian',\n '1.2.840.10008.1.2.1.99': 'Deflated Explicit VR Little Endian',\n '1.2.840.10008.1.2.2': 'Explicit VR Big Endian (Retired)',\n '1.2.840.10008.1.2.4.50': 'JPEG Baseline (Process 1)',\n '1.2.840.10008.1.2.4.51': 'JPEG Extended (Process 2 & 4)',\n '1.2.840.10008.1.2.4.52': 'JPEG Extended (Process 3 & 5) (Retired)',\n '1.2.840.10008.1.2.4.53': 'JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8) (Retired)',\n '1.2.840.10008.1.2.4.54': 'JPEG Spectral Selection, Non-Hierarchical (Process 7 & 9) (Retired)',\n '1.2.840.10008.1.2.4.55': 'JPEG Full Progression, Non-Hierarchical (Process 10 & 12) (Retired)',\n '1.2.840.10008.1.2.4.56': 'JPEG Full Progression, Non-Hierarchical (Process 11 & 13) (Retired)',\n '1.2.840.10008.1.2.4.57': 'JPEG Lossless, Non-Hierarchical (Process 14)',\n '1.2.840.10008.1.2.4.58': 'JPEG Lossless, Non-Hierarchical (Process 15) (Retired)',\n '1.2.840.10008.1.2.4.59': 'JPEG Extended, Hierarchical (Process 16 & 18) (Retired)',\n '1.2.840.10008.1.2.4.60': 'JPEG Extended, Hierarchical (Process 17 & 19) (Retired)',\n '1.2.840.10008.1.2.4.61': 'JPEG Spectral Selection, Hierarchical (Process 20 & 22) (Retired)',\n '1.2.840.10008.1.2.4.62': 'JPEG Spectral Selection, Hierarchical (Process 21 & 23) (Retired)',\n '1.2.840.10008.1.2.4.63': 'JPEG Full Progression, Hierarchical (Process 24 & 26) (Retired)',\n '1.2.840.10008.1.2.4.64': 'JPEG Full Progression, Hierarchical (Process 25 & 27) (Retired)',\n '1.2.840.10008.1.2.4.65': 'JPEG Lossless, Hierarchical (Process 28) (Retired)',\n '1.2.840.10008.1.2.4.66': 'JPEG Lossless, Hierarchical (Process 29) (Retired)',\n '1.2.840.10008.1.2.4.70': 'JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14 [Selection Value 1])',\n '1.2.840.10008.1.2.4.80': 'JPEG-LS Lossless Image Compression',\n '1.2.840.10008.1.2.4.81': 'JPEG-LS Lossy (Near-Lossless) Image Compression',\n '1.2.840.10008.1.2.4.90': 'JPEG 2000 Image Compression (Lossless Only)',\n '1.2.840.10008.1.2.4.91': 'JPEG 2000 Image Compression',\n '1.2.840.10008.1.2.4.92': 'JPEG 2000 Part 2 Multi-component Image Compression (Lossless Only)',\n '1.2.840.10008.1.2.4.93': 'JPEG 2000 Part 2 Multi-component Image Compression',\n '1.2.840.10008.1.2.4.94': 'JPIP Referenced',\n '1.2.840.10008.1.2.4.95': 'JPIP Referenced Deflate',\n '1.2.840.10008.1.2.4.100': 'MPEG2 Main Profile / Main Level',\n '1.2.840.10008.1.2.4.101': 'MPEG2 Main Profile / High Level',\n '1.2.840.10008.1.2.4.102': 'MPEG-4 AVC/H.264 High Profile / Level 4.1',\n '1.2.840.10008.1.2.4.103': 'MPEG-4 AVC/H.264 BD-compatible High Profile / Level 4.1',\n '1.2.840.10008.1.2.4.104': 'MPEG-4 AVC/H.264 High Profile / Level 4.2 For 2D Video',\n '1.2.840.10008.1.2.4.105': 'MPEG-4 AVC/H.264 High Profile / Level 4.2 For 3D Video',\n '1.2.840.10008.1.2.4.106': 'MPEG-4 AVC/H.264 Stereo High Profile / Level 4.2',\n '1.2.840.10008.1.2.4.107': 'HEVC/H.265 Main Profile / Level 5.1',\n '1.2.840.10008.1.2.4.108': 'HEVC/H.265 Main 10 Profile / Level 5.1',\n '1.2.840.10008.1.2.5': 'RLE Lossless',\n '1.2.840.10008.1.2.6.1': 'RFC 2557 MIME encapsulation (Retired)',\n '1.2.840.10008.1.2.6.2': 'XML Encoding (Retired)',\n '1.2.840.10008.1.2.7.1': 'SMPTE ST 2110-20 Uncompressed Progressive Active Video',\n '1.2.840.10008.1.2.7.2': 'SMPTE ST 2110-20 Uncompressed Interlaced Active Video',\n '1.2.840.10008.1.2.7.3': 'SMPTE ST 2110-30 PCM Digital Audio',\n '1.2.840.10008.1.20': 'Papyrus 3 Implicit VR Little Endian (Retired)'\n};\n\n/**\n * Transfer syntaxes indexed by keyword.\n *\n * @type {Object}\n */\nexport const transferSyntaxKeywords = {\n ImplicitVRLittleEndian: '1.2.840.10008.1.2',\n ExplicitVRLittleEndian: '1.2.840.10008.1.2.1',\n EncapsulatedUncompressedExplicitVRLittleEndian: '1.2.840.10008.1.2.1.98',\n DeflatedExplicitVRLittleEndian: '1.2.840.10008.1.2.1.99',\n ExplicitVRBigEndian: '1.2.840.10008.1.2.2',\n JPEGBaseline8Bit: '1.2.840.10008.1.2.4.50',\n JPEGExtended12Bit: '1.2.840.10008.1.2.4.51',\n JPEGExtended35: '1.2.840.10008.1.2.4.52',\n JPEGSpectralSelectionNonHierarchical68: '1.2.840.10008.1.2.4.53',\n JPEGSpectralSelectionNonHierarchical79: '1.2.840.10008.1.2.4.54',\n JPEGFullProgressionNonHierarchical1012: '1.2.840.10008.1.2.4.55',\n JPEGFullProgressionNonHierarchical1113: '1.2.840.10008.1.2.4.56',\n JPEGLossless: '1.2.840.10008.1.2.4.57',\n JPEGLosslessNonHierarchical15: '1.2.840.10008.1.2.4.58',\n JPEGExtendedHierarchical1618: '1.2.840.10008.1.2.4.59',\n JPEGExtendedHierarchical1719: '1.2.840.10008.1.2.4.60',\n JPEGSpectralSelectionHierarchical2022: '1.2.840.10008.1.2.4.61',\n JPEGSpectralSelectionHierarchical2123: '1.2.840.10008.1.2.4.62',\n JPEGFullProgressionHierarchical2426: '1.2.840.10008.1.2.4.63',\n JPEGFullProgressionHierarchical2527: '1.2.840.10008.1.2.4.64',\n JPEGLosslessHierarchical28: '1.2.840.10008.1.2.4.65',\n JPEGLosslessHierarchical29: '1.2.840.10008.1.2.4.66',\n JPEGLosslessSV1: '1.2.840.10008.1.2.4.70',\n JPEGLSLossless: '1.2.840.10008.1.2.4.80',\n JPEGLSNearLossless: '1.2.840.10008.1.2.4.81',\n JPEG2000Lossless: '1.2.840.10008.1.2.4.90',\n JPEG2000: '1.2.840.10008.1.2.4.91',\n JPEG2000MCLossless: '1.2.840.10008.1.2.4.92',\n JPEG2000MC: '1.2.840.10008.1.2.4.93',\n JPIPReferenced: '1.2.840.10008.1.2.4.94',\n JPIPReferencedDeflate: '1.2.840.10008.1.2.4.95',\n MPEG2MPML: '1.2.840.10008.1.2.4.100',\n MPEG2MPHL: '1.2.840.10008.1.2.4.101',\n MPEG4HP41: '1.2.840.10008.1.2.4.102',\n MPEG4HP41BD: '1.2.840.10008.1.2.4.103',\n MPEG4HP422D: '1.2.840.10008.1.2.4.104',\n MPEG4HP423D: '1.2.840.10008.1.2.4.105',\n MPEG4HP42STEREO: '1.2.840.10008.1.2.4.106',\n HEVCMP51: '1.2.840.10008.1.2.4.107',\n HEVCM10P51: '1.2.840.10008.1.2.4.108',\n RLELossless: '1.2.840.10008.1.2.5',\n RFC2557MIMEEncapsulation: '1.2.840.10008.1.2.6.1',\n XMLEncoding: '1.2.840.10008.1.2.6.2',\n SMPTEST211020UncompressedProgressiveActiveVideo: '1.2.840.10008.1.2.7.1',\n SMPTEST211020UncompressedInterlacedActiveVideo: '1.2.840.10008.1.2.7.2',\n SMPTEST211030PCMDigitalAudio: '1.2.840.10008.1.2.7.3',\n Papyrus3ImplicitVRLittleEndian: '1.2.840.10008.1.20'\n};\n","import {\n dictionary,\n tagGroups\n} from './dictionary';\n\n/**\n * Immutable tag.\n */\nexport class Tag {\n\n /**\n * The tag group.\n *\n * @type {string}\n */\n #group;\n\n /**\n * The tag element.\n *\n * @type {string}\n */\n #element;\n\n /**\n * @param {string} group The tag group as '####'.\n * @param {string} element The tag element as '####'.\n */\n constructor(group, element) {\n if (!group || typeof group === 'undefined') {\n throw new Error('Cannot create tag with no group.');\n }\n if (group.length !== 4) {\n throw new Error('Cannot create tag with badly sized group: ' + group);\n }\n if (!element || typeof element === 'undefined') {\n throw new Error('Cannot create tag with no element.');\n }\n if (element.length !== 4) {\n throw new Error('Cannot create tag with badly sized element: ' + element);\n }\n this.#group = group;\n this.#element = element;\n }\n\n /**\n * Get the tag group.\n *\n * @returns {string} The tag group.\n */\n getGroup() {\n return this.#group;\n }\n\n /**\n * Get the tag element.\n *\n * @returns {string} The tag element.\n */\n getElement() {\n return this.#element;\n }\n\n /**\n * Get as string representation of the tag: 'key: name'.\n *\n * @returns {string} A string representing the tag.\n */\n toString() {\n return this.getKey() + ': ' + this.getNameFromDictionary();\n }\n\n /**\n * Check for Tag equality.\n *\n * @param {Tag} rhs The other tag to compare to.\n * @returns {boolean} True if both tags are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n typeof rhs !== 'undefined' &&\n this.#group === rhs.getGroup() &&\n this.#element === rhs.getElement();\n }\n\n /**\n * Get the group-element key used to store DICOM elements.\n *\n * @returns {string} The key as '########'.\n */\n getKey() {\n return this.#group + this.#element;\n }\n\n /**\n * Get the group name as defined in TagGroups.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return tagGroups[this.#group];\n }\n\n /**\n * Does this tag have a VR.\n * Basically not the Item, ItemDelimitationItem nor\n * SequenceDelimitationItem tags.\n *\n * @returns {boolean} True if this tag has a VR.\n */\n isWithVR() {\n return !(this.#group === 'FFFE' &&\n (this.#element === 'E000' ||\n this.#element === 'E00D' ||\n this.#element === 'E0DD')\n );\n }\n\n /**\n * Is the tag group a private tag group ?\n *\n * See: {@link http://dicom.nema.org/medical/dicom/2022a/output/html/part05.html#sect_7.8}.\n *\n * @returns {boolean} True if the tag group is private,\n * ie if its group is an odd number.\n */\n isPrivate() {\n return parseInt(this.#group, 16) % 2 === 1;\n }\n\n /**\n * Get the tag info from the dicom dictionary.\n *\n * @returns {string[]|undefined} The info as [vr, multiplicity, name].\n */\n #getInfoFromDictionary() {\n let info;\n if (typeof dictionary[this.#group] !== 'undefined' &&\n typeof dictionary[this.#group][this.#element] !==\n 'undefined') {\n info = dictionary[this.#group][this.#element];\n }\n return info;\n }\n\n /**\n * Get the tag Value Representation (VR) from the dicom dictionary.\n *\n * @returns {string|undefined} The VR.\n */\n getVrFromDictionary() {\n let vr;\n const info = this.#getInfoFromDictionary();\n if (typeof info !== 'undefined') {\n vr = info[0];\n }\n return vr;\n }\n\n /**\n * Get the tag name from the dicom dictionary.\n *\n * @returns {string|undefined} The VR.\n */\n getNameFromDictionary() {\n let name;\n const info = this.#getInfoFromDictionary();\n if (typeof info !== 'undefined') {\n name = info[2];\n }\n return name;\n }\n\n} // Tag class\n\n/**\n * Tag compare function.\n *\n * @param {Tag} a The first tag.\n * @param {Tag} b The second tag.\n * @returns {number} The result of the tag comparison,\n * positive for b before a, negative for a before b and\n * zero to keep same order.\n */\nexport function tagCompareFunction(a, b) {\n // first by group\n let res = parseInt(a.getGroup(), 16) - parseInt(b.getGroup(), 16);\n if (res === 0) {\n // by element if same group\n res = parseInt(a.getElement(), 16) - parseInt(b.getElement(), 16);\n }\n return res;\n}\n\n/**\n * Split a group-element key used to store DICOM elements.\n *\n * @param {string} key The key in form \"00280102\" as generated by tag::getKey.\n * @returns {Tag} The DICOM tag.\n */\nexport function getTagFromKey(key) {\n if (!key || typeof key === 'undefined') {\n throw new Error('Cannot create tag with no key.');\n }\n if (key.length !== 8) {\n throw new Error('Cannot create tag with badly sized key: ' + key);\n }\n return new Tag(key.substring(0, 4), key.substring(4, 8));\n}\n\n/**\n * Get the TransferSyntaxUID Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getTransferSyntaxUIDTag() {\n return new Tag('0002', '0010');\n}\n\n/**\n * Get the FileMetaInformationGroupLength Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getFileMetaInformationGroupLengthTag() {\n return new Tag('0002', '0000');\n}\n\n/**\n * Is the input tag the FileMetaInformationGroupLength Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isFileMetaInformationGroupLengthTag(tag) {\n return tag.equals(getFileMetaInformationGroupLengthTag());\n}\n\n/**\n * Get the Item Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getItemTag() {\n return new Tag('FFFE', 'E000');\n}\n\n/**\n * Is the input tag the Item Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isItemTag(tag) {\n // faster than tag.equals(getItemTag());\n return tag.getKey() === 'FFFEE000';\n}\n\n/**\n * Get the ItemDelimitationItem Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getItemDelimitationItemTag() {\n return new Tag('FFFE', 'E00D');\n}\n\n/**\n * Is the input tag the ItemDelimitationItem Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isItemDelimitationItemTag(tag) {\n // faster than tag.equals(getItemDelimitationItemTag());\n return tag.getKey() === 'FFFEE00D';\n}\n\n/**\n * Get the SequenceDelimitationItem Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getSequenceDelimitationItemTag() {\n return new Tag('FFFE', 'E0DD');\n}\n\n/**\n * Is the input tag the SequenceDelimitationItem Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isSequenceDelimitationItemTag(tag) {\n // faster than tag.equals(getSequenceDelimitationItemTag());\n return tag.getKey() === 'FFFEE0DD';\n}\n\n/**\n * Get the PixelData Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getPixelDataTag() {\n return new Tag('7FE0', '0010');\n}\n\n/**\n * Is the input tag the PixelData Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isPixelDataTag(tag) {\n // faster than tag.equals(getPixelDataTag());\n return tag.getKey() === '7FE00010';\n}\n\n/**\n * Get a tag from the dictionary using a tag string name.\n *\n * @param {string} tagName The tag string name.\n * @returns {Tag|undefined} The tag object or null if not found.\n */\nexport function getTagFromDictionary(tagName) {\n if (typeof tagName === 'undefined' || tagName === null) {\n return null;\n }\n let group = null;\n let element = null;\n const dict = dictionary;\n const keys0 = Object.keys(dict);\n let keys1 = null;\n let foundTag = false;\n // search through dictionary\n for (let k0 = 0, lenK0 = keys0.length; k0 < lenK0; ++k0) {\n group = keys0[k0];\n keys1 = Object.keys(dict[group]);\n for (let k1 = 0, lenK1 = keys1.length; k1 < lenK1; ++k1) {\n element = keys1[k1];\n if (dict[group][element][2] === tagName) {\n foundTag = true;\n break;\n }\n }\n if (foundTag) {\n break;\n }\n }\n let tag;\n if (foundTag) {\n tag = new Tag(group, element);\n }\n return tag;\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Tag} from './dicomTag';\n/* eslint-enable no-unused-vars */\n\n/**\n * DICOM data element.\n */\nexport class DataElement {\n /**\n * The element Value Representation.\n *\n * @type {string}\n */\n vr;\n /**\n * The element value.\n *\n * @type {Array}\n */\n value;\n\n // [start] internal values\n // only present during parsing or writing otherwise not set\n\n /**\n * The element dicom tag.\n *\n * @type {Tag}\n */\n tag;\n\n /**\n * The element Value Length.\n *\n * @type {number}\n */\n vl;\n\n /**\n * Flag to know if defined or undefined sequence length.\n *\n * @type {boolean}\n */\n undefinedLength;\n\n /**\n * The element start offset.\n *\n * @type {number}\n */\n startOffset;\n\n /**\n * The element end offset.\n *\n * @type {number}\n */\n endOffset;\n\n /**\n * The sequence items.\n *\n * @type {Array}\n */\n items;\n\n // [end] internal values\n\n /**\n * @param {string} vr The element VR (Value Representation).\n */\n constructor(vr) {\n this.vr = vr;\n }\n}","/**\n * Is the Native endianness Little Endian.\n *\n * @returns {boolean} True if little endian.\n */\nexport function isNativeLittleEndian() {\n return new Int8Array(new Int16Array([1]).buffer)[0] > 0;\n}\n\n/**\n * Flip an array's endianness.\n * Inspired from [DataStream.js]{@link https://github.com/kig/DataStream.js}.\n *\n * @param {object} array The array to flip (modified).\n */\nfunction flipArrayEndianness(array) {\n const blen = array.byteLength;\n const u8 = new Uint8Array(array.buffer, array.byteOffset, blen);\n const bpe = array.BYTES_PER_ELEMENT;\n let tmp;\n for (let i = 0; i < blen; i += bpe) {\n for (let j = i + bpe - 1, k = i; j > k; j--, k++) {\n tmp = u8[k];\n u8[k] = u8[j];\n u8[j] = tmp;\n }\n }\n}\n\n/**\n * Data reader.\n */\nexport class DataReader {\n\n /**\n * The input buffer.\n *\n * @type {ArrayBuffer}\n */\n #buffer;\n\n /**\n * Is the endianness Little Endian.\n *\n * @type {boolean}\n */\n #isLittleEndian = true;\n\n /**\n * Is the Native endianness Little Endian.\n *\n * @type {boolean}\n */\n #isNativeLittleEndian = isNativeLittleEndian();\n\n /**\n * Flag to know if the TypedArray data needs flipping.\n *\n * @type {boolean}\n */\n #needFlip;\n\n /**\n * The main data view.\n *\n * @type {DataView}\n */\n #view;\n\n /**\n * @param {ArrayBuffer} buffer The input array buffer.\n * @param {boolean} [isLittleEndian] Flag to tell if the data is little\n * or big endian (default: true).\n */\n constructor(buffer, isLittleEndian) {\n this.#buffer = buffer;\n // Set endian flag if not defined.\n if (typeof isLittleEndian !== 'undefined') {\n this.#isLittleEndian = isLittleEndian;\n }\n this.#needFlip = (this.#isLittleEndian !== this.#isNativeLittleEndian);\n this.#view = new DataView(buffer);\n }\n\n /**\n * Read Uint16 (2 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {number} The read data.\n */\n readUint16(byteOffset) {\n return this.#view.getUint16(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read Int16 (2 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {number} The read data.\n */\n readInt16(byteOffset) {\n return this.#view.getInt16(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read Uint32 (4 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {number} The read data.\n */\n readUint32(byteOffset) {\n return this.#view.getUint32(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read BigUint64 (8 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {bigint} The read data.\n */\n readBigUint64(byteOffset) {\n return this.#view.getBigUint64(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read Int32 (4 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {number} The read data.\n */\n readInt32(byteOffset) {\n return this.#view.getInt32(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read BigInt64 (8 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {bigint} The read data.\n */\n readBigInt64(byteOffset) {\n return this.#view.getBigInt64(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read Float32 (4 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {number} The read data.\n */\n readFloat32(byteOffset) {\n return this.#view.getFloat32(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read Float64 (8 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {number} The read data.\n */\n readFloat64(byteOffset) {\n return this.#view.getFloat64(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read binary (0/1) array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Uint8Array} The read data.\n */\n readBinaryArray(byteOffset, size) {\n // input\n const bitArray = new Uint8Array(this.#buffer, byteOffset, size);\n // result\n const byteArrayLength = 8 * bitArray.length;\n const data = new Uint8Array(byteArrayLength);\n let bitNumber = 0;\n let bitIndex = 0;\n for (let i = 0; i < byteArrayLength; ++i) {\n bitNumber = i % 8;\n bitIndex = Math.floor(i / 8);\n // see https://stackoverflow.com/questions/4854207/get-a-specific-bit-from-byte/4854257\n // @ts-ignore\n data[i] = 255 * ((bitArray[bitIndex] & (1 << bitNumber)) !== 0);\n }\n return data;\n }\n\n /**\n * Read Uint8 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Uint8Array} The read data.\n */\n readUint8Array(byteOffset, size) {\n return new Uint8Array(this.#buffer, byteOffset, size);\n }\n\n /**\n * Read Int8 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Int8Array} The read data.\n */\n readInt8Array(byteOffset, size) {\n return new Int8Array(this.#buffer, byteOffset, size);\n }\n\n /**\n * Read Uint16 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Uint16Array} The read data.\n */\n readUint16Array(byteOffset, size) {\n const bpe = Uint16Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of Uint16Array.BYTES_PER_ELEMENT (=2)\n if (byteOffset % bpe === 0) {\n data = new Uint16Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new Uint16Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readUint16(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Int16 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Int16Array} The read data.\n */\n readInt16Array(byteOffset, size) {\n const bpe = Int16Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of Int16Array.BYTES_PER_ELEMENT (=2)\n if (byteOffset % bpe === 0) {\n data = new Int16Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new Int16Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readInt16(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Uint32 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Uint32Array} The read data.\n */\n readUint32Array(byteOffset, size) {\n const bpe = Uint32Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of Uint32Array.BYTES_PER_ELEMENT (=4)\n if (byteOffset % bpe === 0) {\n data = new Uint32Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new Uint32Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readUint32(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Uint64 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {BigUint64Array} The read data.\n */\n readUint64Array(byteOffset, size) {\n const bpe = BigUint64Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of BigUint64Array.BYTES_PER_ELEMENT (=8)\n if (byteOffset % bpe === 0) {\n data = new BigUint64Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new BigUint64Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readBigUint64(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Int32 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Int32Array} The read data.\n */\n readInt32Array(byteOffset, size) {\n const bpe = Int32Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of Int32Array.BYTES_PER_ELEMENT (=4)\n if (byteOffset % bpe === 0) {\n data = new Int32Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new Int32Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readInt32(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Int64 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {BigInt64Array} The read data.\n */\n readInt64Array(byteOffset, size) {\n const bpe = BigInt64Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of BigInt64Array.BYTES_PER_ELEMENT (=8)\n if (byteOffset % bpe === 0) {\n data = new BigInt64Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new BigInt64Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readBigInt64(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Float32 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Float32Array} The read data.\n */\n readFloat32Array(byteOffset, size) {\n const bpe = Float32Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of Float32Array.BYTES_PER_ELEMENT (=4)\n if (byteOffset % bpe === 0) {\n data = new Float32Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new Float32Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readFloat32(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Float64 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Float64Array} The read data.\n */\n readFloat64Array(byteOffset, size) {\n const bpe = Float64Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of Float64Array.BYTES_PER_ELEMENT (=8)\n if (byteOffset % bpe === 0) {\n data = new Float64Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new Float64Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readFloat64(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read data as an hexadecimal string of length 4 (no '0x' prefix).\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {string} The read data ('####').\n */\n readHex(byteOffset) {\n // read and convert to hex string\n const str = this.readUint16(byteOffset).toString(16);\n // return padded\n return '0000'.substring(0, 4 - str.length) + str.toUpperCase();\n }\n\n} // class DataReader\n","import {\n Tag,\n getTransferSyntaxUIDTag,\n isSequenceDelimitationItemTag,\n isItemDelimitationItemTag,\n isPixelDataTag\n} from './dicomTag';\nimport {\n is32bitVLVR,\n isCharSetStringVR,\n transferSyntaxes,\n transferSyntaxKeywords,\n vrTypes,\n} from './dictionary';\nimport {DataElement} from './dataElement';\nimport {DataReader} from './dataReader';\nimport {logger} from '../utils/logger';\n\n/**\n * List of DICOM data elements indexed via a 8 character string formed from\n * the group and element numbers.\n *\n * @typedef {Object} DataElements\n */\n\n/**\n * Get the version of the library.\n *\n * @returns {string} The version of the library.\n */\nexport function getDwvVersion() {\n return '0.35.0-beta.2';\n}\n\n/**\n * Check that an input buffer includes the DICOM prefix 'DICM'\n * after the 128 bytes preamble.\n *\n * Ref: [DICOM File Meta]{@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part10/chapter_7.html#sect_7.1}.\n *\n * @param {ArrayBuffer} buffer The buffer to check.\n * @returns {boolean} True if the buffer includes the prefix.\n */\nexport function hasDicomPrefix(buffer) {\n // check size: typed array constructor will throw RangeError if\n // byteOffset + length * TypedArray.BYTES_PER_ELEMENT > buffer.byteLength\n if (buffer.byteLength < 132) {\n return false;\n }\n const prefixArray = new Uint8Array(buffer, 128, 4);\n const stringReducer = function (previous, current) {\n return previous += String.fromCharCode(current);\n };\n return prefixArray.reduce(stringReducer, '') === 'DICM';\n}\n\n// Zero-width space (u200B)\n// @ts-ignore\nconst ZWS = String.fromCharCode('u200B');\n\n/**\n * Clean string: remove zero-width space ending and trim.\n * Warning: no tests are done on the input, will fail if\n * null or undefined or not string.\n * Exported for tests only.\n *\n * @param {string} inputStr The string to clean.\n * @returns {string} The cleaned string.\n */\nexport function cleanString(inputStr) {\n let res = inputStr;\n // get rid of ending zero-width space\n const lastIndex = inputStr.length - 1;\n if (inputStr[lastIndex] === ZWS) {\n res = inputStr.substring(0, lastIndex);\n }\n // trim spaces\n res = res.trim();\n // return\n return res;\n}\n\n/**\n * Get the utfLabel (used by the TextDecoder) from a character set term.\n *\n * References:\n * - DICOM [Value Encoding]{@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/chapter_6.html},\n * - DICOM [Specific Character Set]{@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.12.html#sect_C.12.1.1.2},\n * - [TextDecoder#Parameters]{@link https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder/TextDecoder#Parameters}.\n *\n * @param {string} charSetTerm The DICOM character set.\n * @returns {string} The corresponding UTF label.\n */\nfunction getUtfLabel(charSetTerm) {\n let label = 'utf-8';\n if (charSetTerm === 'ISO_IR 100') {\n label = 'iso-8859-1';\n } else if (charSetTerm === 'ISO_IR 101') {\n label = 'iso-8859-2';\n } else if (charSetTerm === 'ISO_IR 109') {\n label = 'iso-8859-3';\n } else if (charSetTerm === 'ISO_IR 110') {\n label = 'iso-8859-4';\n } else if (charSetTerm === 'ISO_IR 144') {\n label = 'iso-8859-5';\n } else if (charSetTerm === 'ISO_IR 127') {\n label = 'iso-8859-6';\n } else if (charSetTerm === 'ISO_IR 126') {\n label = 'iso-8859-7';\n } else if (charSetTerm === 'ISO_IR 138') {\n label = 'iso-8859-8';\n } else if (charSetTerm === 'ISO_IR 148') {\n label = 'iso-8859-9';\n } else if (charSetTerm === 'ISO_IR 13') {\n label = 'shift-jis';\n } else if (charSetTerm === 'ISO_IR 166') {\n label = 'iso-8859-11';\n } else if (charSetTerm === 'ISO 2022 IR 87') {\n label = 'iso-2022-jp';\n } else if (charSetTerm === 'ISO 2022 IR 149') {\n // not supported by TextDecoder when it says it should...\n //label = \"iso-2022-kr\";\n } else if (charSetTerm === 'ISO 2022 IR 58') {\n // not supported by TextDecoder...\n //label = \"iso-2022-cn\";\n } else if (charSetTerm === 'ISO_IR 192') {\n label = 'utf-8';\n } else if (charSetTerm === 'GB18030') {\n label = 'gb18030';\n } else if (charSetTerm === 'GB2312') {\n label = 'gb2312';\n } else if (charSetTerm === 'GBK') {\n label = 'chinese';\n }\n return label;\n}\n\n/**\n * Default text decoder.\n */\nclass DefaultTextDecoder {\n /**\n * Decode an input string buffer.\n *\n * @param {Uint8Array} buffer The buffer to decode.\n * @returns {string} The decoded string.\n */\n decode(buffer) {\n let result = '';\n for (let i = 0, leni = buffer.length; i < leni; ++i) {\n result += String.fromCharCode(buffer[i]);\n }\n return result;\n }\n}\n\n/**\n * Get patient orientation label in the reverse direction.\n *\n * @param {string} ori Patient Orientation value.\n * @returns {string} Reverse Orientation Label.\n */\nexport function getReverseOrientation(ori) {\n if (!ori) {\n return null;\n }\n // reverse labels\n const rlabels = {\n L: 'R',\n R: 'L',\n A: 'P',\n P: 'A',\n H: 'F',\n F: 'H'\n };\n\n let rori = '';\n for (let n = 0; n < ori.length; n++) {\n const o = ori.substring(n, n + 1);\n const r = rlabels[o];\n if (r) {\n rori += r;\n }\n }\n // return\n return rori;\n}\n\n/**\n * Tell if a given syntax is an implicit one (element with no VR).\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if an implicit syntax.\n */\nexport function isImplicitTransferSyntax(syntax) {\n return syntax === transferSyntaxKeywords.ImplicitVRLittleEndian;\n}\n\n/**\n * Tell if a given syntax is a big endian syntax.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a big endian syntax.\n */\nexport function isBigEndianTransferSyntax(syntax) {\n return syntax === transferSyntaxKeywords.ExplicitVRBigEndian;\n}\n\n/**\n * Tell if a given syntax is a JPEG baseline one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a jpeg baseline syntax.\n */\nexport function isJpegBaselineTransferSyntax(syntax) {\n return syntax === transferSyntaxKeywords.JPEGBaseline8Bit ||\n syntax === transferSyntaxKeywords.JPEGExtended12Bit;\n}\n\n/**\n * Tell if a given syntax is a JPEG Lossless one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a jpeg lossless syntax.\n */\nexport function isJpegLosslessTransferSyntax(syntax) {\n return syntax === transferSyntaxKeywords.JPEGLossless ||\n syntax === transferSyntaxKeywords.JPEGLosslessSV1;\n}\n\n/**\n * Tell if a given syntax is a JPEG 2000 one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a jpeg 2000 syntax.\n */\nexport function isJpeg2000TransferSyntax(syntax) {\n return syntax.match(/1.2.840.10008.1.2.4.9/) !== null;\n}\n\n/**\n * Tell if a given syntax is a RLE (Run-length encoding) one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a RLE syntax.\n */\nfunction isRleTransferSyntax(syntax) {\n return syntax === transferSyntaxKeywords.RLELossless;\n}\n\n/**\n * Tell if a given syntax needs decompression.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {string|undefined} The name of the decompression algorithm.\n */\nexport function getSyntaxDecompressionName(syntax) {\n let algo;\n if (isJpeg2000TransferSyntax(syntax)) {\n algo = 'jpeg2000';\n } else if (isJpegBaselineTransferSyntax(syntax)) {\n algo = 'jpeg-baseline';\n } else if (isJpegLosslessTransferSyntax(syntax)) {\n algo = 'jpeg-lossless';\n } else if (isRleTransferSyntax(syntax)) {\n algo = 'rle';\n }\n return algo;\n}\n\n/**\n * Tell if a given syntax is supported for reading.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a supported syntax.\n */\nfunction isReadSupportedTransferSyntax(syntax) {\n return (syntax === transferSyntaxKeywords.ImplicitVRLittleEndian ||\n syntax === transferSyntaxKeywords.ExplicitVRLittleEndian ||\n syntax === transferSyntaxKeywords.ExplicitVRBigEndian ||\n isJpegBaselineTransferSyntax(syntax) ||\n isJpegLosslessTransferSyntax(syntax) ||\n isJpeg2000TransferSyntax(syntax) ||\n isRleTransferSyntax(syntax));\n}\n\n/**\n * Get a transfer syntax name from its UID.\n *\n * @param {string} syntax The transfer syntax UID value.\n * @returns {string} The transfer syntax name.\n */\nexport function getTransferSyntaxName(syntax) {\n let name = 'Unknown';\n if (typeof transferSyntaxes[syntax] !== 'undefined') {\n name = transferSyntaxes[syntax];\n }\n return name;\n}\n\n/**\n * Guess the transfer syntax from the first data element.\n *\n * See {@link https://github.com/ivmartel/dwv/issues/188}\n * (Allow to load DICOM with no DICM preamble) for more details.\n *\n * @param {DataElement} firstDataElement The first data element\n * of the DICOM header.\n * @returns {DataElement} The transfer syntax data element.\n */\nfunction guessTransferSyntax(firstDataElement) {\n const oEightGroupBigEndian = '0800';\n const oEightGroupLittleEndian = '0008';\n // check that group is 0008\n const group = firstDataElement.tag.getGroup();\n if (group !== oEightGroupBigEndian &&\n group !== oEightGroupLittleEndian) {\n throw new Error(\n 'Not a valid DICOM file (no magic DICM word found' +\n ' and first element not in 0008 group)'\n );\n }\n // reasonable assumption: 2 uppercase characters => explicit vr\n const vr = firstDataElement.vr;\n const vr0 = vr.charCodeAt(0);\n const vr1 = vr.charCodeAt(1);\n const implicit = (vr0 >= 65 && vr0 <= 90 && vr1 >= 65 && vr1 <= 90)\n ? false : true;\n // guess transfer syntax\n let syntax = null;\n if (group === oEightGroupLittleEndian) {\n if (implicit) {\n syntax = transferSyntaxKeywords.ImplicitVRLittleEndian;\n } else {\n syntax = transferSyntaxKeywords.ExplicitVRLittleEndian;\n }\n } else {\n if (implicit) {\n // ImplicitVRBigEndian: impossible\n throw new Error(\n 'Not a valid DICOM file (no magic DICM word found' +\n 'and implicit VR big endian detected)'\n );\n } else {\n syntax = transferSyntaxKeywords.ExplicitVRBigEndian;\n }\n }\n // set transfer syntax data element\n const dataElement = new DataElement('UI');\n dataElement.tag = getTransferSyntaxUIDTag();\n dataElement.value = [syntax];\n dataElement.vl = dataElement.value[0].length;\n dataElement.startOffset = firstDataElement.startOffset;\n dataElement.endOffset = dataElement.startOffset + dataElement.vl;\n\n return dataElement;\n}\n\n/**\n * Get the appropriate TypedArray in function of arguments.\n *\n * @param {number} bitsAllocated The number of bites used to store\n * the data: [8, 16, 32].\n * @param {number} pixelRepresentation The pixel representation,\n * 0:unsigned;1:signed.\n * @param {number} size The size of the new array.\n * @returns {Uint8Array|Int8Array|Uint16Array|Int16Array|Uint32Array|Int32Array}\n * The good typed array.\n */\nexport function getTypedArray(bitsAllocated, pixelRepresentation, size) {\n let res = null;\n try {\n if (bitsAllocated === 1 || bitsAllocated === 8) {\n if (pixelRepresentation === 0) {\n res = new Uint8Array(size);\n } else {\n res = new Int8Array(size);\n }\n } else if (bitsAllocated === 16) {\n if (pixelRepresentation === 0) {\n res = new Uint16Array(size);\n } else {\n res = new Int16Array(size);\n }\n } else if (bitsAllocated === 32) {\n if (pixelRepresentation === 0) {\n res = new Uint32Array(size);\n } else {\n res = new Int32Array(size);\n }\n }\n } catch (error) {\n if (error instanceof RangeError) {\n const powerOf2 = Math.floor(Math.log(size) / Math.log(2));\n logger.error('Cannot allocate array of size: ' +\n size + ' (>2^' + powerOf2 + ').');\n }\n }\n return res;\n}\n\n/**\n * Get the number of bytes occupied by a data element prefix,\n * (without its value).\n *\n * WARNING: this is valid for tags with a VR, if not sure use\n * the 'isTagWithVR' function first.\n *\n * Reference:\n * - [Data Element explicit]{@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/chapter_7.html#table_7.1-1},\n * - [Data Element implicit]{@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_7.5.2.html#table_7.5-1}.\n *\n * ```\n * | Tag | VR | VL | Value |\n * | 4 | 2 | 2 | X | -> regular explicit: 8 + X\n * | 4 | 2+2 | 4 | X | -> 32bit VL: 12 + X\n *\n * | Tag | VL | Value |\n * | 4 | 4 | X | -> implicit (32bit VL): 8 + X\n *\n * | Tag | Len | Value |\n * | 4 | 4 | X | -> item: 8 + X\n * ```\n *\n * @param {string} vr The Value Representation of the element.\n * @param {boolean} isImplicit Does the data use implicit VR?\n * @returns {number} The size of the element prefix.\n */\nexport function getDataElementPrefixByteSize(vr, isImplicit) {\n return isImplicit ? 8 : is32bitVLVR(vr) ? 12 : 8;\n}\n\n/**\n * Is the input VR a known VR.\n *\n * @param {string} vr The vr to test.\n * @returns {boolean} True if known.\n */\nfunction isKnownVR(vr) {\n const extraVrTypes = ['NONE', 'ox', 'xx', 'xs'];\n const knownTypes = Object.keys(vrTypes).concat(extraVrTypes);\n return knownTypes.includes(vr);\n}\n\n/**\n * Small list of used tag keys.\n */\nconst TagKeys = {\n TransferSyntax: '00020010',\n SpecificCharacterSet: '00080005',\n NumberOfFrames: '00280008',\n BitsAllocated: '00280100',\n PixelRepresentation: '00280103',\n PixelData: '7FE00010'\n};\n\n/**\n * DicomParser class.\n *\n * @example\n * // XMLHttpRequest onload callback\n * const onload = function (event) {\n * // setup the dicom parser\n * const dicomParser = new dwv.DicomParser();\n * // parse the buffer\n * dicomParser.parse(event.target.response);\n * // get the dicom tags\n * const tags = dicomParser.getDicomElements();\n * // display the modality\n * const div = document.getElementById('dwv');\n * div.appendChild(document.createTextNode(\n * 'Modality: ' + tags['00080060'].value[0]\n * ));\n * };\n * // DICOM file request\n * const request = new XMLHttpRequest();\n * const url = 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm';\n * request.open('GET', url);\n * request.responseType = 'arraybuffer';\n * request.onload = onload;\n * request.send();\n */\nexport class DicomParser {\n\n /**\n * The list of DICOM elements.\n *\n * @type {DataElements}\n */\n #dataElements = {};\n\n /**\n * Default character set (optional).\n *\n * @type {string}\n */\n #defaultCharacterSet;\n\n /**\n * Default text decoder.\n *\n * @type {DefaultTextDecoder}\n */\n #defaultTextDecoder = new DefaultTextDecoder();\n\n /**\n * Special text decoder.\n *\n * @type {DefaultTextDecoder|TextDecoder}\n */\n #textDecoder = this.#defaultTextDecoder;\n\n /**\n * Decode an input string buffer using the default text decoder.\n *\n * @param {Uint8Array} buffer The buffer to decode.\n * @returns {string} The decoded string.\n */\n #decodeString(buffer) {\n return this.#defaultTextDecoder.decode(buffer);\n }\n\n /**\n * Decode an input string buffer using the 'special' text decoder.\n *\n * @param {Uint8Array} buffer The buffer to decode.\n * @returns {string} The decoded string.\n */\n #decodeSpecialString(buffer) {\n return this.#textDecoder.decode(buffer);\n }\n\n /**\n * Get the default character set.\n *\n * @returns {string} The default character set.\n */\n getDefaultCharacterSet() {\n return this.#defaultCharacterSet;\n }\n\n /**\n * Set the default character set.\n *\n * @param {string} characterSet The input character set.\n */\n setDefaultCharacterSet(characterSet) {\n this.#defaultCharacterSet = characterSet;\n }\n\n /**\n * Set the text decoder character set.\n *\n * @param {string} characterSet The input character set.\n */\n setDecoderCharacterSet(characterSet) {\n /**\n * The text decoder.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder}.\n *\n * @external TextDecoder\n */\n this.#textDecoder = new TextDecoder(characterSet);\n }\n\n // not using type DataElements since the typedef is not exported with the API\n\n /**\n * Get the DICOM data elements.\n *\n * @returns {Object} The data elements.\n */\n getDicomElements() {\n return this.#dataElements;\n }\n\n /**\n * Read a DICOM tag.\n *\n * @param {DataReader} reader The raw data reader.\n * @param {number} offset The offset where to start to read.\n * @returns {object} An object containing the tag and the end offset.\n */\n #readTag(reader, offset) {\n // group\n const group = reader.readHex(offset);\n offset += Uint16Array.BYTES_PER_ELEMENT;\n // element\n const element = reader.readHex(offset);\n offset += Uint16Array.BYTES_PER_ELEMENT;\n // return\n return {\n tag: new Tag(group, element),\n endOffset: offset\n };\n }\n\n /**\n * Read an item data element.\n *\n * @param {DataReader} reader The raw data reader.\n * @param {number} offset The offset where to start to read.\n * @param {boolean} implicit Is the DICOM VR implicit?\n * @returns {object} The item data as a list of data elements.\n */\n #readItemDataElement(reader, offset, implicit) {\n const itemData = {};\n\n // read the first item\n let item = this.#readDataElement(reader, offset, implicit);\n offset = item.endOffset;\n\n // exit if it is a sequence delimitation item\n if (isSequenceDelimitationItemTag(item.tag)) {\n return {\n data: itemData,\n endOffset: item.endOffset,\n isSeqDelim: true\n };\n }\n\n // store item (mainly to keep vl)\n itemData[item.tag.getKey()] = {\n tag: item.tag,\n vr: 'NONE',\n vl: item.vl,\n undefinedLength: item.undefinedLength\n };\n\n if (!item.undefinedLength) {\n // explicit VR item: read until the end offset\n const endOffset = offset;\n offset -= item.vl;\n while (offset < endOffset) {\n item = this.#readDataElement(reader, offset, implicit);\n offset = item.endOffset;\n itemData[item.tag.getKey()] = item;\n }\n } else {\n // implicit VR item: read until the item delimitation item\n let isItemDelim = false;\n while (!isItemDelim) {\n item = this.#readDataElement(reader, offset, implicit);\n offset = item.endOffset;\n isItemDelim = isItemDelimitationItemTag(item.tag);\n if (!isItemDelim) {\n itemData[item.tag.getKey()] = item;\n }\n }\n }\n\n return {\n data: itemData,\n endOffset: offset,\n isSeqDelim: false\n };\n }\n\n /**\n * Read the pixel item data element.\n * Ref: [Single frame fragments]{@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_A.4.html#table_A.4-1}.\n *\n * @param {DataReader} reader The raw data reader.\n * @param {number} offset The offset where to start to read.\n * @param {boolean} implicit Is the DICOM VR implicit?\n * @returns {object} The item data as an array of data elements.\n */\n #readPixelItemDataElement(\n reader, offset, implicit) {\n const itemData = [];\n\n // first item: basic offset table\n let item = this.#readDataElement(reader, offset, implicit);\n const offsetTableVl = item.vl;\n offset = item.endOffset;\n\n // read until the sequence delimitation item\n let isSeqDelim = false;\n while (!isSeqDelim) {\n item = this.#readDataElement(reader, offset, implicit);\n offset = item.endOffset;\n isSeqDelim = isSequenceDelimitationItemTag(item.tag);\n if (!isSeqDelim) {\n // force pixel item vr to OB\n item.vr = 'OB';\n itemData.push(item);\n }\n }\n\n return {\n data: itemData,\n endOffset: offset,\n offsetTableVl: offsetTableVl\n };\n }\n\n /**\n * Read a DICOM data element.\n *\n * Reference: [DICOM VRs]{@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_6.2.html#table_6.2-1}.\n *\n * @param {DataReader} reader The raw data reader.\n * @param {number} offset The offset where to start to read.\n * @param {boolean} implicit Is the DICOM VR implicit?\n * @returns {DataElement} The data element.\n */\n #readDataElement(reader, offset, implicit) {\n // Tag: group, element\n const readTagRes = this.#readTag(reader, offset);\n const tag = readTagRes.tag;\n offset = readTagRes.endOffset;\n\n // Value Representation (VR)\n let vr = null;\n let is32bitVL = false;\n if (tag.isWithVR()) {\n // implicit VR\n if (implicit) {\n vr = tag.getVrFromDictionary();\n if (typeof vr === 'undefined') {\n vr = 'UN';\n }\n is32bitVL = true;\n } else {\n vr = this.#decodeString(reader.readUint8Array(offset, 2));\n offset += 2 * Uint8Array.BYTES_PER_ELEMENT;\n is32bitVL = is32bitVLVR(vr);\n // reserved 2 bytes\n if (is32bitVL) {\n offset += 2 * Uint8Array.BYTES_PER_ELEMENT;\n }\n }\n } else {\n vr = 'NONE';\n is32bitVL = true;\n }\n\n // check vr\n if (!isKnownVR(vr)) {\n logger.warn('Unknown VR: ' + vr +\n ' (for tag ' + tag.getKey() + '), treating as \\'UN\\'');\n vr = 'UN';\n }\n\n // Value Length (VL)\n let vl = 0;\n if (is32bitVL) {\n vl = reader.readUint32(offset);\n offset += Uint32Array.BYTES_PER_ELEMENT;\n } else {\n vl = reader.readUint16(offset);\n offset += Uint16Array.BYTES_PER_ELEMENT;\n }\n\n // check the value of VL\n let undefinedLength = false;\n if (vl === 0xffffffff) {\n undefinedLength = true;\n vl = 0;\n }\n\n // treat private tag with unknown VR and zero VL as a sequence (see #799)\n if (tag.isPrivate() && vr === 'UN' && vl === 0) {\n vr = 'SQ';\n }\n\n let startOffset = offset;\n let endOffset = startOffset + vl;\n\n // read sequence elements\n let data;\n if (isPixelDataTag(tag) && undefinedLength) {\n // pixel data sequence (implicit)\n const pixItemData =\n this.#readPixelItemDataElement(reader, offset, implicit);\n offset = pixItemData.endOffset;\n startOffset += pixItemData.offsetTableVl;\n data = pixItemData.data;\n endOffset = offset;\n vl = offset - startOffset;\n } else if (vr === 'SQ') {\n // sequence\n data = [];\n let itemData;\n if (!undefinedLength) {\n if (vl !== 0) {\n // explicit VR sequence: read until the end offset\n const sqEndOffset = offset + vl;\n while (offset < sqEndOffset) {\n itemData = this.#readItemDataElement(reader, offset, implicit);\n data.push(itemData.data);\n offset = itemData.endOffset;\n }\n endOffset = offset;\n vl = offset - startOffset;\n }\n } else {\n // implicit VR sequence: read until the sequence delimitation item\n let isSeqDelim = false;\n while (!isSeqDelim) {\n itemData = this.#readItemDataElement(reader, offset, implicit);\n isSeqDelim = itemData.isSeqDelim;\n offset = itemData.endOffset;\n // do not store the delimitation item\n if (!isSeqDelim) {\n data.push(itemData.data);\n }\n }\n endOffset = offset;\n vl = offset - startOffset;\n }\n }\n\n // return\n const element = new DataElement(vr);\n element.tag = tag;\n element.vl = vl;\n element.startOffset = startOffset;\n element.endOffset = endOffset;\n // only set if true (only for sequences and items)\n if (undefinedLength) {\n element.undefinedLength = undefinedLength;\n }\n if (data) {\n element.items = data;\n }\n return element;\n }\n\n /**\n * Interpret the data of an element.\n *\n * @param {DataElement} element The data element.\n * @param {DataReader} reader The raw data reader.\n * @param {number} [pixelRepresentation] PixelRepresentation 0->unsigned,\n * 1->signed (needed for pixel data or VR=xs).\n * @param {number} [bitsAllocated] Bits allocated (needed for pixel data).\n * @returns {object} The interpreted data.\n */\n #interpretElement(\n element, reader, pixelRepresentation, bitsAllocated) {\n\n const tag = element.tag;\n const vl = element.vl;\n const vr = element.vr;\n const offset = element.startOffset;\n\n // data\n let data = null;\n const vrType = vrTypes[vr];\n if (isPixelDataTag(tag)) {\n if (element.undefinedLength) {\n // implicit pixel data sequence\n data = [];\n for (let j = 0; j < element.items.length; ++j) {\n data.push(this.#interpretElement(\n element.items[j], reader,\n pixelRepresentation, bitsAllocated));\n }\n // remove non parsed items\n delete element.items;\n } else {\n // check bits allocated and VR\n // https://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_A.2.html\n if (bitsAllocated > 8 && vr === 'OB') {\n logger.warn(\n 'Reading DICOM pixel data with bitsAllocated>8 and OB VR' +\n ', treating as OW'\n );\n element.vr = 'OW';\n }\n // read\n data = [];\n if (bitsAllocated === 1) {\n data.push(reader.readBinaryArray(offset, vl));\n } else if (bitsAllocated === 8) {\n if (pixelRepresentation === 0) {\n data.push(reader.readUint8Array(offset, vl));\n } else {\n data.push(reader.readInt8Array(offset, vl));\n }\n } else if (bitsAllocated === 16) {\n if (pixelRepresentation === 0) {\n data.push(reader.readUint16Array(offset, vl));\n } else {\n data.push(reader.readInt16Array(offset, vl));\n }\n } else {\n throw new Error('Unsupported bits allocated: ' + bitsAllocated);\n }\n }\n } else if (typeof vrType !== 'undefined') {\n if (vrType === 'Uint8') {\n data = reader.readUint8Array(offset, vl);\n } else if (vrType === 'Uint16') {\n data = reader.readUint16Array(offset, vl);\n // keep as binary for 'O*' VR\n if (vr[0] !== 'O') {\n data = Array.from(data);\n }\n } else if (vrType === 'Uint32') {\n data = reader.readUint32Array(offset, vl);\n // keep as binary for 'O*' VR\n if (vr[0] !== 'O') {\n data = Array.from(data);\n }\n } else if (vrType === 'Uint64') {\n data = reader.readUint64Array(offset, vl);\n } else if (vrType === 'Int16') {\n data = Array.from(reader.readInt16Array(offset, vl));\n } else if (vrType === 'Int32') {\n data = Array.from(reader.readInt32Array(offset, vl));\n } else if (vrType === 'Int64') {\n data = reader.readInt64Array(offset, vl);\n } else if (vrType === 'Float32') {\n data = Array.from(reader.readFloat32Array(offset, vl));\n } else if (vrType === 'Float64') {\n data = Array.from(reader.readFloat64Array(offset, vl));\n } else if (vrType === 'string') {\n const stream = reader.readUint8Array(offset, vl);\n if (isCharSetStringVR(vr)) {\n data = this.#decodeSpecialString(stream);\n } else {\n data = this.#decodeString(stream);\n }\n data = cleanString(data).split('\\\\');\n } else {\n throw new Error('Unknown VR type: ' + vrType);\n }\n } else if (vr === 'xx') {\n // US or OW\n data = Array.from(reader.readUint16Array(offset, vl));\n } else if (vr === 'ox') {\n // OB or OW\n if (bitsAllocated === 8) {\n if (pixelRepresentation === 0) {\n data = Array.from(reader.readUint8Array(offset, vl));\n } else {\n data = Array.from(reader.readInt8Array(offset, vl));\n }\n } else {\n if (pixelRepresentation === 0) {\n data = Array.from(reader.readUint16Array(offset, vl));\n } else {\n data = Array.from(reader.readInt16Array(offset, vl));\n }\n }\n } else if (vr === 'xs') {\n // (US or SS) or (US or SS or OW)\n if (pixelRepresentation === 0) {\n data = Array.from(reader.readUint16Array(offset, vl));\n } else {\n data = Array.from(reader.readInt16Array(offset, vl));\n }\n } else if (vr === 'AT') {\n // attribute\n const raw = reader.readUint16Array(offset, vl);\n data = [];\n for (let i = 0, leni = raw.length; i < leni; i += 2) {\n const stri = raw[i].toString(16);\n const stri1 = raw[i + 1].toString(16);\n let str = '(';\n str += '0000'.substring(0, 4 - stri.length) + stri.toUpperCase();\n str += ',';\n str += '0000'.substring(0, 4 - stri1.length) + stri1.toUpperCase();\n str += ')';\n data.push(str);\n }\n } else if (vr === 'SQ') {\n // sequence\n data = [];\n for (let k = 0; k < element.items.length; ++k) {\n const item = element.items[k];\n const itemData = {};\n const keys = Object.keys(item);\n let sqBitsAllocated = bitsAllocated;\n let sqPixelRepresentation = pixelRepresentation;\n for (let l = 0; l < keys.length; ++l) {\n // check if local bitsAllocated\n // (inside item loop to get interpreted value)\n let dataElement = item[TagKeys.BitsAllocated];\n if (typeof dataElement !== 'undefined' &&\n typeof dataElement.value !== 'undefined') {\n sqBitsAllocated = dataElement.value[0];\n }\n // check if local pixelRepresentation\n // (inside item loop to get interpreted value)\n dataElement = item[TagKeys.PixelRepresentation];\n if (typeof dataElement !== 'undefined' &&\n typeof dataElement.value !== 'undefined') {\n sqPixelRepresentation = dataElement.value[0];\n }\n const subElement = item[keys[l]];\n subElement.value = this.#interpretElement(\n subElement, reader,\n sqPixelRepresentation, sqBitsAllocated);\n delete subElement.tag;\n delete subElement.vl;\n delete subElement.startOffset;\n delete subElement.endOffset;\n itemData[keys[l]] = subElement;\n }\n data.push(itemData);\n }\n // remove non parsed elements\n delete element.items;\n } else if (vr === 'NONE') {\n // no VR -> no data\n data = [];\n } else {\n logger.warn('Unknown VR: ' + vr +\n ' (for tag ' + element.tag.getKey() + ')');\n // empty data...\n data = [];\n }\n\n return data;\n }\n\n /**\n * Interpret the data of a list of elements.\n *\n * @param {DataElements} elements A list of data elements.\n * @param {DataReader} reader The raw data reader.\n * @param {number} pixelRepresentation PixelRepresentation 0->unsigned,\n * 1->signed.\n * @param {number} bitsAllocated Bits allocated.\n */\n #interpret(\n elements, reader,\n pixelRepresentation, bitsAllocated) {\n\n const keys = Object.keys(elements);\n for (let i = 0; i < keys.length; ++i) {\n const element = elements[keys[i]];\n if (typeof element.value === 'undefined') {\n element.value = this.#interpretElement(\n element, reader, pixelRepresentation, bitsAllocated);\n }\n // delete interpretation specific properties\n delete element.tag;\n delete element.vl;\n delete element.startOffset;\n delete element.endOffset;\n }\n }\n\n /**\n * Parse the complete DICOM file (given as input to the class).\n * Fills in the member object 'dataElements'.\n *\n * @param {ArrayBuffer} buffer The input array buffer.\n */\n parse(buffer) {\n let offset = 0;\n let syntax = '';\n let dataElement = null;\n // default readers\n const metaReader = new DataReader(buffer);\n let dataReader = new DataReader(buffer);\n\n // 128 -> 132: magic word\n offset = 128;\n const magicword = this.#decodeString(metaReader.readUint8Array(offset, 4));\n offset += 4 * Uint8Array.BYTES_PER_ELEMENT;\n if (magicword === 'DICM') {\n // 0002, 0000: FileMetaInformationGroupLength (vr='UL')\n dataElement = this.#readDataElement(metaReader, offset, false);\n dataElement.value = this.#interpretElement(dataElement, metaReader);\n // increment offset\n offset = dataElement.endOffset;\n // store the data element\n this.#dataElements[dataElement.tag.getKey()] = dataElement;\n // get meta length\n const metaLength = dataElement.value[0];\n\n // meta elements\n const metaEnd = offset + metaLength;\n while (offset < metaEnd) {\n // get the data element\n dataElement = this.#readDataElement(metaReader, offset, false);\n offset = dataElement.endOffset;\n // store the data element\n this.#dataElements[dataElement.tag.getKey()] = dataElement;\n }\n\n // check the TransferSyntaxUID (has to be there!)\n dataElement = this.#dataElements[TagKeys.TransferSyntax];\n if (typeof dataElement === 'undefined') {\n throw new Error('Not a valid DICOM file (no TransferSyntaxUID found)');\n }\n dataElement.value = this.#interpretElement(dataElement, metaReader);\n syntax = dataElement.value[0];\n\n } else {\n logger.warn('No DICM prefix, trying to guess tansfer syntax.');\n // read first element\n dataElement = this.#readDataElement(dataReader, 0, false);\n // guess transfer syntax\n const tsElement = guessTransferSyntax(dataElement);\n // store\n this.#dataElements[tsElement.tag.getKey()] = tsElement;\n syntax = tsElement.value[0];\n // reset offset\n offset = 0;\n }\n\n // check transfer syntax support\n if (!isReadSupportedTransferSyntax(syntax)) {\n throw new Error('Unsupported DICOM transfer syntax: \\'' + syntax +\n '\\' (' + getTransferSyntaxName(syntax) + ')');\n }\n\n // set implicit flag\n let implicit = false;\n if (isImplicitTransferSyntax(syntax)) {\n implicit = true;\n }\n\n // Big Endian\n if (isBigEndianTransferSyntax(syntax)) {\n dataReader = new DataReader(buffer, false);\n }\n\n // DICOM data elements\n while (offset < buffer.byteLength) {\n // get the data element\n dataElement = this.#readDataElement(dataReader, offset, implicit);\n // increment offset\n offset = dataElement.endOffset;\n // store the data element\n const key = dataElement.tag.getKey();\n if (typeof this.#dataElements[key] === 'undefined') {\n this.#dataElements[key] = dataElement;\n } else {\n logger.warn('Not saving duplicate tag: ' + key);\n }\n }\n\n // safety checks...\n if (isNaN(offset)) {\n throw new Error('Problem while parsing, bad offset');\n }\n if (buffer.byteLength !== offset) {\n logger.warn('Did not reach the end of the buffer: ' +\n offset + ' != ' + buffer.byteLength);\n }\n\n //-------------------------------------------------\n // values needed for data interpretation\n\n // pixel specific\n let pixelRepresentation = 0;\n let bitsAllocated = 16;\n if (typeof this.#dataElements[TagKeys.PixelData] !== 'undefined') {\n // PixelRepresentation 0->unsigned, 1->signed\n dataElement = this.#dataElements[TagKeys.PixelRepresentation];\n if (typeof dataElement !== 'undefined') {\n dataElement.value = this.#interpretElement(dataElement, dataReader);\n pixelRepresentation = dataElement.value[0];\n } else {\n logger.warn(\n 'Reading DICOM pixel data with default pixelRepresentation.');\n }\n\n // BitsAllocated\n dataElement = this.#dataElements[TagKeys.BitsAllocated];\n if (typeof dataElement !== 'undefined') {\n dataElement.value = this.#interpretElement(dataElement, dataReader);\n bitsAllocated = dataElement.value[0];\n } else {\n logger.warn('Reading DICOM pixel data with default bitsAllocated.');\n }\n }\n\n // default character set\n if (typeof this.#defaultCharacterSet !== 'undefined') {\n this.setDecoderCharacterSet(this.#defaultCharacterSet);\n }\n\n // SpecificCharacterSet\n dataElement = this.#dataElements[TagKeys.SpecificCharacterSet];\n if (typeof dataElement !== 'undefined') {\n dataElement.value = this.#interpretElement(dataElement, dataReader);\n let charSetTerm;\n if (dataElement.value.length === 1) {\n charSetTerm = dataElement.value[0];\n } else {\n charSetTerm = dataElement.value[1];\n logger.warn('Unsupported character set with code extensions: \\'' +\n charSetTerm + '\\'.');\n }\n this.setDecoderCharacterSet(getUtfLabel(charSetTerm));\n }\n\n // interpret the dicom elements\n this.#interpret(\n this.#dataElements, dataReader,\n pixelRepresentation, bitsAllocated\n );\n\n // handle fragmented pixel buffer\n // Reference: http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_8.2.html\n // (third note, \"Depending on the transfer syntax...\")\n dataElement = this.#dataElements[TagKeys.PixelData];\n if (typeof dataElement !== 'undefined') {\n if (dataElement.undefinedLength) {\n let numberOfFrames = 1;\n if (typeof this.#dataElements[TagKeys.NumberOfFrames] !== 'undefined') {\n numberOfFrames = Number(\n this.#dataElements[TagKeys.NumberOfFrames].value[0]\n );\n }\n const pixItems = dataElement.value;\n if (pixItems.length > 1 && pixItems.length > numberOfFrames) {\n // concatenate pixel data items\n // concat does not work on typed arrays\n //this.pixelBuffer = this.pixelBuffer.concat( dataElement.data );\n // manual concat...\n const nItemPerFrame = pixItems.length / numberOfFrames;\n const newPixItems = [];\n let index = 0;\n for (let f = 0; f < numberOfFrames; ++f) {\n index = f * nItemPerFrame;\n // calculate the size of a frame\n let size = 0;\n for (let i = 0; i < nItemPerFrame; ++i) {\n size += pixItems[index + i].length;\n }\n // create new buffer\n const newBuffer = new pixItems[0].constructor(size);\n // fill new buffer\n let fragOffset = 0;\n for (let j = 0; j < nItemPerFrame; ++j) {\n newBuffer.set(pixItems[index + j], fragOffset);\n fragOffset += pixItems[index + j].length;\n }\n newPixItems[f] = newBuffer;\n }\n // store as pixel data\n dataElement.value = newPixItems;\n }\n }\n }\n }\n\n} // class DicomParser\n","import {logger} from './logger';\n\n/**\n * ListenerHandler class: handles add/removing and firing listeners.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget#example}.\n */\nexport class ListenerHandler {\n /**\n * Listeners.\n *\n * @type {object}\n */\n #listeners = {};\n\n /**\n * Add an event listener.\n *\n * @param {string} type The event type.\n * @param {object} callback The method associated with the provided\n * event type, will be called with the fired event.\n */\n add(type, callback) {\n // create array if not present\n if (typeof this.#listeners[type] === 'undefined') {\n this.#listeners[type] = [];\n }\n // add callback to listeners array\n this.#listeners[type].push(callback);\n }\n\n /**\n * Remove an event listener.\n *\n * @param {string} type The event type.\n * @param {object} callback The method associated with the provided\n * event type.\n */\n remove(type, callback) {\n // check if the type is present\n if (typeof this.#listeners[type] === 'undefined') {\n return;\n }\n // remove from listeners array\n let nFound = 0;\n for (let i = 0; i < this.#listeners[type].length; ++i) {\n if (this.#listeners[type][i] === callback) {\n ++nFound;\n this.#listeners[type].splice(i, 1);\n }\n }\n if (nFound === 0) {\n logger.debug('No callback found on remove listener for type ' + type);\n }\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n fireEvent = (event) => {\n // check if they are listeners for the event type\n if (typeof this.#listeners[event.type] === 'undefined') {\n return;\n }\n // fire events from a copy of the listeners array\n // to avoid interference from possible add/remove\n const stack = this.#listeners[event.type].slice();\n for (let i = 0; i < stack.length; ++i) {\n stack[i](event);\n }\n };\n}\n","import {Index} from '../math/index';\nimport {Point2D} from '../math/point';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {Point} from '../math/point';\nimport {Matrix33} from '../math/matrix';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get an simple iterator for a given range for a one component data.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols}.\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start The start of the range (included).\n * @param {number} end The end of the range (excluded).\n * @param {number} [increment] The increment between indicies (default=1).\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function simpleRange(dataAccessor, start, end, increment) {\n if (typeof increment === 'undefined') {\n increment = 1;\n }\n let nextIndex = start;\n // result\n return {\n next: function () {\n if (nextIndex < end) {\n const result = {\n value: dataAccessor(nextIndex),\n done: false,\n index: nextIndex\n };\n nextIndex += increment;\n return result;\n }\n return {\n done: true,\n index: end\n };\n }\n };\n}\n\n/**\n * Get an iterator for a given range for a one component data.\n *\n * Using 'maxIter' and not an 'end' index since it fails in some edge cases\n * (for ex coronal2, ie zxy).\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start Zero-based index at which to start the iteration.\n * @param {number} maxIter The maximum number of iterations.\n * @param {number} increment Increment between indicies.\n * @param {number} blockMaxIter Number of applied increment after which\n * blockIncrement is applied.\n * @param {number} blockIncrement Increment after blockMaxIter is reached,\n * the value is from block start to the next block start.\n * @param {boolean} reverse1 If true, loop from end to start.\n * WARN: don't forget to set the value of start as the last index!\n * @param {boolean} reverse2 If true, loop from block end to block start.\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function range(dataAccessor, start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2) {\n if (typeof reverse1 === 'undefined') {\n reverse1 = false;\n }\n if (typeof reverse2 === 'undefined') {\n reverse2 = false;\n }\n\n // first index of the iteration\n let nextIndex = start;\n // adapt first index and increments to reverse values\n if (reverse1) {\n blockIncrement *= -1;\n if (reverse2) {\n // start at end of line\n nextIndex -= (blockMaxIter - 1) * increment;\n } else {\n increment *= -1;\n }\n } else {\n if (reverse2) {\n // start at end of line\n nextIndex += (blockMaxIter - 1) * increment;\n increment *= -1;\n }\n }\n const finalBlockIncrement = blockIncrement - blockMaxIter * increment;\n\n // counters\n let mainCount = 0;\n let blockCount = 0;\n // result\n return {\n next: function () {\n if (mainCount < maxIter) {\n const result = {\n value: dataAccessor(nextIndex),\n done: false,\n index: nextIndex\n };\n nextIndex += increment;\n ++mainCount;\n ++blockCount;\n if (blockCount === blockMaxIter) {\n blockCount = 0;\n nextIndex += finalBlockIncrement;\n }\n return result;\n }\n return {\n done: true,\n index: nextIndex\n };\n }\n };\n}\n\n/**\n * Get an iterator for a given range with bounds (for a one component data).\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols}.\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start The start of the range (included).\n * @param {number} end The end of the range (excluded).\n * @param {number} increment The increment between indicies.\n * @param {number} regionSize The size of the region to iterate through.\n * @param {number} regionOffset The offset between regions.\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function rangeRegion(\n dataAccessor, start, end, increment, regionSize, regionOffset) {\n let nextIndex = start;\n let regionElementCount = 0;\n // result\n return {\n next: function () {\n if (nextIndex < end) {\n const result = {\n value: dataAccessor(nextIndex),\n done: false,\n index: nextIndex\n };\n regionElementCount += 1;\n nextIndex += increment;\n if (regionElementCount === regionSize) {\n regionElementCount = 0;\n nextIndex += regionOffset;\n }\n return result;\n }\n return {\n done: true,\n index: end\n };\n }\n };\n}\n\n/**\n * Get an iterator for a given range with bounds (for a one component data).\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols}.\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start The start of the range (included).\n * @param {number} end The end of the range (excluded).\n * @param {number} increment The increment between indicies.\n * @param {number[][]} regions An array of regions: [off0, size, off1].\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function rangeRegions(\n dataAccessor, start, end, increment, regions) {\n let nextIndex = start;\n let regionCount = 0;\n let regionElementCount = 0;\n // result\n return {\n next: function () {\n if (nextIndex < end) {\n const result = {\n value: dataAccessor(nextIndex),\n done: false,\n index: nextIndex\n };\n regionElementCount += 1;\n nextIndex += increment;\n if (regionElementCount === regions[regionCount][1]) {\n regionElementCount = 0;\n // off1 of current group\n nextIndex += regions[regionCount][2];\n regionCount += 1;\n // off0 of next group\n if (regionCount < regions.length) {\n nextIndex += regions[regionCount][0];\n }\n }\n return result;\n }\n return {\n done: true,\n index: end\n };\n }\n };\n}\n\n/**\n * Get an iterator for a given range for a 3 components data.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols}.\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start The start of the range (included).\n * @param {number} end The end of the range (excluded).\n * (end - start) needs to be a multiple of 3...\n * @param {number} increment The increment between indicies (default=1).\n * @param {boolean} isPlanar A flag to know if the data is planar\n * (RRRR...GGGG...BBBB...) or not (RGBRGBRGBRGB...), defaults to false.\n * @returns {object} A 3 components iterator folowing the iterator and iterable\n * protocol, the value is an array of size 3 with each component.\n */\nexport function simpleRange3d(\n dataAccessor, start, end, increment, isPlanar) {\n if (typeof increment === 'undefined') {\n increment = 1;\n }\n if (typeof isPlanar === 'undefined') {\n isPlanar = false;\n }\n let nextIndex = start;\n let componentIncrement = 1;\n if (isPlanar) {\n componentIncrement = (end - start) / 3;\n } else {\n increment *= 3;\n }\n let nextIndex1 = nextIndex + componentIncrement;\n let nextIndex2 = nextIndex + 2 * componentIncrement;\n\n // result\n return {\n next: function () {\n if (nextIndex < end) {\n const result = {\n value: [\n dataAccessor(nextIndex),\n dataAccessor(nextIndex1),\n dataAccessor(nextIndex2)\n ],\n done: false,\n index: [nextIndex, nextIndex1, nextIndex2]\n };\n nextIndex += increment;\n nextIndex1 += increment;\n nextIndex2 += increment;\n return result;\n }\n return {\n done: true,\n index: [end]\n };\n }\n };\n}\n\n/**\n * Get an iterator for a given range for a 3 components data.\n *\n * Using 'maxIter' and not an 'end' index since it fails in some edge cases\n * (for ex coronal2, ie zxy).\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start Zero-based index at which to start the iteration.\n * @param {number} maxIter The maximum number of iterations.\n * @param {number} increment Increment between indicies.\n * @param {number} blockMaxIter Number of applied increment after which\n * blockIncrement is applied.\n * @param {number} blockIncrement Increment after blockMaxIter is reached,\n * the value is from block start to the next block start.\n * @param {boolean} reverse1 If true, loop from end to start.\n * WARN: don't forget to set the value of start as the last index!\n * @param {boolean} reverse2 If true, loop from block end to block start.\n * @param {boolean} isPlanar A flag to know if the data is planar\n * (RRRR...GGGG...BBBB...) or not (RGBRGBRGBRGB...), defaults to false.\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function range3d(dataAccessor, start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2, isPlanar) {\n const iters = [];\n if (isPlanar) {\n iters.push(range(\n dataAccessor, start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2\n ));\n iters.push(range(\n dataAccessor, start + maxIter * increment, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2\n ));\n iters.push(range(\n dataAccessor, start + 2 * maxIter * increment, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2\n ));\n } else {\n increment *= 3;\n blockIncrement *= 3;\n iters.push(range(\n dataAccessor, start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2\n ));\n iters.push(range(\n dataAccessor, start + 1, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2\n ));\n iters.push(range(\n dataAccessor, start + 2, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2\n ));\n }\n\n // result\n return {\n next: function () {\n const r0 = iters[0].next();\n const r1 = iters[1].next();\n const r2 = iters[2].next();\n if (!r0.done) {\n return {\n value: [\n r0.value,\n r1.value,\n r2.value\n ],\n done: false,\n index: [\n r0.index,\n r1.index,\n r2.index\n ]\n };\n }\n return {\n done: true,\n index: r2.index\n };\n }\n };\n}\n\n/**\n * Get a list of values for a given iterator.\n *\n * @param {object} iterator The iterator to use to loop through data.\n * @returns {Array} The list of values.\n */\nexport function getIteratorValues(iterator) {\n const values = [];\n let ival = iterator.next();\n while (!ival.done) {\n values.push(ival.value);\n ival = iterator.next();\n }\n return values;\n}\n\n/**\n * Get a slice index iterator.\n *\n * @param {Image} image The image to parse.\n * @param {Index} position The current position.\n * @param {boolean} isRescaled Flag for rescaled values (default false).\n * @param {Matrix33} viewOrientation The view orientation.\n * @returns {object} The slice iterator.\n */\nexport function getSliceIterator(\n image, position, isRescaled, viewOrientation) {\n const size = image.getGeometry().getSize();\n // zero-ify non direction index\n let dirMax2Index = 2;\n if (viewOrientation && typeof viewOrientation !== 'undefined') {\n dirMax2Index = viewOrientation.getColAbsMax(2).index;\n }\n const posValues = position.getValues();\n // keep the main direction and any other than 3D\n const indexFilter = function (element, index) {\n return (index === dirMax2Index || index > 2) ? element : 0;\n };\n const posStart = new Index(posValues.map(indexFilter));\n let start = size.indexToOffset(posStart);\n\n // default to non rescaled data\n if (typeof isRescaled === 'undefined') {\n isRescaled = false;\n }\n let dataAccessor = null;\n if (isRescaled) {\n dataAccessor = function (offset) {\n return image.getRescaledValueAtOffset(offset);\n };\n } else {\n dataAccessor = function (offset) {\n return image.getValueAtOffset(offset);\n };\n }\n\n const ncols = size.get(0);\n const nrows = size.get(1);\n const nslices = size.get(2);\n let sliceSize = size.getDimSize(2);\n\n const ncomp = image.getNumberOfComponents();\n const isPlanar = image.getPlanarConfiguration() === 1;\n const getRange = function (\n dataAccessor, start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2) {\n if (ncomp === 1) {\n return range(dataAccessor, start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2);\n } else if (ncomp === 3) {\n return range3d(dataAccessor, 3 * start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2, isPlanar);\n }\n };\n\n let rangeObj = null;\n if (viewOrientation && typeof viewOrientation !== 'undefined') {\n const dirMax0 = viewOrientation.getColAbsMax(0);\n const dirMax2 = viewOrientation.getColAbsMax(2);\n\n // default reverse\n const reverse1 = false;\n const reverse2 = false;\n\n let maxIter = null;\n if (dirMax2.index === 2) {\n // axial\n maxIter = ncols * nrows;\n if (dirMax0.index === 0) {\n // xyz\n rangeObj = getRange(dataAccessor,\n start, maxIter, 1, ncols, ncols, reverse1, reverse2);\n } else {\n // yxz\n rangeObj = getRange(dataAccessor,\n start, maxIter, ncols, nrows, 1, reverse1, reverse2);\n }\n } else if (dirMax2.index === 0) {\n // sagittal\n maxIter = nslices * nrows;\n if (dirMax0.index === 1) {\n // yzx\n rangeObj = getRange(dataAccessor,\n start, maxIter, ncols, nrows, sliceSize, reverse1, reverse2);\n } else {\n // zyx\n rangeObj = getRange(dataAccessor,\n start, maxIter, sliceSize, nslices, ncols, reverse1, reverse2);\n }\n } else if (dirMax2.index === 1) {\n // coronal\n maxIter = nslices * ncols;\n if (dirMax0.index === 0) {\n // xzy\n rangeObj = getRange(dataAccessor,\n start, maxIter, 1, ncols, sliceSize, reverse1, reverse2);\n } else {\n // zxy\n rangeObj = getRange(dataAccessor,\n start, maxIter, sliceSize, nslices, 1, reverse1, reverse2);\n }\n } else {\n throw new Error('Unknown direction: ' + dirMax2.index);\n }\n } else {\n if (image.getNumberOfComponents() === 1) {\n rangeObj = simpleRange(dataAccessor, start, start + sliceSize);\n } else if (image.getNumberOfComponents() === 3) {\n // 3 times bigger...\n start *= 3;\n sliceSize *= 3;\n rangeObj = simpleRange3d(\n dataAccessor, start, start + sliceSize, 1, isPlanar);\n } else {\n throw new Error('Unsupported number of components: ' +\n image.getNumberOfComponents());\n }\n }\n\n return rangeObj;\n}\n\n/**\n * Get a slice index iterator for a rectangular region.\n *\n * @param {Image} image The image to parse.\n * @param {Index} index The current position.\n * @param {boolean} isRescaled Flag for rescaled values (default false).\n * @param {Point2D} min The minimum position (optional).\n * @param {Point2D} max The maximum position (optional).\n * @returns {object} The slice iterator.\n */\nexport function getRegionSliceIterator(\n image, index, isRescaled, min, max) {\n if (image.getNumberOfComponents() !== 1) {\n throw new Error('Unsupported number of components for region iterator: ' +\n image.getNumberOfComponents());\n }\n\n // default to non rescaled data\n if (typeof isRescaled === 'undefined') {\n isRescaled = false;\n }\n let dataAccessor = null;\n if (isRescaled) {\n dataAccessor = function (offset) {\n return image.getRescaledValueAtOffset(offset);\n };\n } else {\n dataAccessor = function (offset) {\n return image.getValueAtOffset(offset);\n };\n }\n\n const size = image.getGeometry().getSize();\n if (typeof min === 'undefined') {\n min = new Point2D(0, 0);\n }\n if (typeof max === 'undefined') {\n max = new Point2D(\n size.get(0) - 1,\n size.get(1)\n );\n }\n // position to pixel for max: extra X is ok, remove extra Y\n const startOffset = size.indexToOffset(index.getWithNew2D(\n min.getX(), min.getY()\n ));\n const endOffset = size.indexToOffset(index.getWithNew2D(\n max.getX(), max.getY() - 1\n ));\n\n // minimum 1 column\n const rangeNumberOfColumns = Math.max(1, max.getX() - min.getX());\n const rowIncrement = size.get(0) - rangeNumberOfColumns;\n\n return rangeRegion(\n dataAccessor, startOffset, endOffset + 1,\n 1, rangeNumberOfColumns, rowIncrement);\n}\n\n/**\n * Get a slice index iterator for a rectangular region.\n *\n * @param {Image} image The image to parse.\n * @param {Index} index The current position.\n * @param {boolean} isRescaled Flag for rescaled values (default false).\n * @param {number[][][]} regions An array of [x, y] pairs (min, max).\n * @returns {object|undefined} The slice iterator.\n */\nexport function getVariableRegionSliceIterator(\n image, index, isRescaled, regions) {\n if (image.getNumberOfComponents() !== 1) {\n throw new Error('Unsupported number of components for region iterator: ' +\n image.getNumberOfComponents());\n }\n\n // default to non rescaled data\n if (typeof isRescaled === 'undefined') {\n isRescaled = false;\n }\n let dataAccessor = null;\n if (isRescaled) {\n dataAccessor = function (offset) {\n return image.getRescaledValueAtOffset(offset);\n };\n } else {\n dataAccessor = function (offset) {\n return image.getValueAtOffset(offset);\n };\n }\n\n const size = image.getGeometry().getSize();\n\n const offsetRegions = [];\n let region;\n let min = null;\n let max = null;\n let regionIndex = null;\n for (let i = 0; i < regions.length; ++i) {\n region = regions[i];\n const width = region[1][0] - region[0][0];\n if (width !== 0) {\n regionIndex = i;\n if (!min) {\n min = region[0];\n }\n offsetRegions.push([\n region[0][0],\n width,\n size.get(0) - region[1][0]\n ]);\n }\n }\n if (regionIndex !== null) {\n max = regions[regionIndex][1];\n }\n\n // exit if no offsets\n if (offsetRegions.length === 0) {\n return undefined;\n }\n\n const startOffset = size.indexToOffset(index.getWithNew2D(\n min[0], min[1]\n ));\n const endOffset = size.indexToOffset(index.getWithNew2D(\n max[0], max[1]\n ));\n\n return rangeRegions(\n dataAccessor, startOffset, endOffset + 1,\n 1, offsetRegions);\n}\n\n/**\n * Get a multiple value iterator. The input array defines the values and\n * their start index.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols}.\n *\n * @param {Array} values An array of {index, value} pairs.\n * @param {number} end The end of the range (excluded).\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function valueRange(values, end) {\n let nextIndex = 0;\n let nextValueIndex = 0;\n // result\n return {\n next: function () {\n if (nextIndex < end) {\n if (nextValueIndex + 1 < values.length &&\n nextIndex >= values[nextValueIndex + 1].index) {\n ++nextValueIndex;\n }\n const result = {\n value: values[nextValueIndex].value,\n done: false,\n index: nextIndex\n };\n ++nextIndex;\n return result;\n }\n return {\n done: true,\n index: end\n };\n }\n };\n}\n","/**\n * Rescale Slope and Intercept.\n */\nexport class RescaleSlopeAndIntercept {\n\n /**\n * The slope.\n *\n * @type {number}\n */\n #slope;\n\n /**\n * The intercept.\n *\n * @type {number}\n */\n #intercept;\n\n /**\n * @param {number} slope The slope of the RSI.\n * @param {number} intercept The intercept of the RSI.\n */\n constructor(slope, intercept) {\n /*// Check the rescale slope.\n if(typeof(slope) === 'undefined') {\n slope = 1;\n }\n // Check the rescale intercept.\n if(typeof(intercept) === 'undefined') {\n intercept = 0;\n }*/\n this.#slope = slope;\n this.#intercept = intercept;\n }\n\n /**\n * Get the slope of the RSI.\n *\n * @returns {number} The slope of the RSI.\n */\n getSlope() {\n return this.#slope;\n }\n\n /**\n * Get the intercept of the RSI.\n *\n * @returns {number} The intercept of the RSI.\n */\n getIntercept() {\n return this.#intercept;\n }\n\n /**\n * Apply the RSI on an input value.\n *\n * @param {number} value The input value.\n * @returns {number} The value to rescale.\n */\n apply(value) {\n return value * this.#slope + this.#intercept;\n }\n\n /**\n * Check for RSI equality.\n *\n * @param {RescaleSlopeAndIntercept} rhs The other RSI to compare to.\n * @returns {boolean} True if both RSI are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n typeof rhs !== 'undefined' &&\n this.getSlope() === rhs.getSlope() &&\n this.getIntercept() === rhs.getIntercept();\n }\n\n /**\n * Is this RSI an ID RSI.\n *\n * @returns {boolean} True if the RSI has a slope of 1 and no intercept.\n */\n isID() {\n return (this.getSlope() === 1 && this.getIntercept() === 0);\n }\n\n} // class RescaleSlopeAndIntercept\n","import {Index} from '../math/index';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Matrix33} from '../math/matrix';\nimport {Scalar2D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Immutable Size class.\n * Warning: the input array is NOT cloned, modifying it will\n * modify the index values.\n */\nexport class Size {\n\n /**\n * The size values.\n *\n * @type {number[]}\n */\n #values;\n\n /**\n * @param {number[]} values The size values.\n */\n constructor(values) {\n if (!values || typeof values === 'undefined') {\n throw new Error('Cannot create size with no values.');\n }\n if (values.length === 0) {\n throw new Error('Cannot create size with empty values.');\n }\n const valueCheck = function (val) {\n return !isNaN(val) && val !== 0;\n };\n if (!values.every(valueCheck)) {\n throw new Error('Cannot create size with non number or zero values.');\n }\n this.#values = values;\n }\n\n /**\n * Get the size value at the given array index.\n *\n * @param {number} i The index to get.\n * @returns {number} The value.\n */\n get(i) {\n return this.#values[i];\n }\n\n /**\n * Get the length of the index.\n *\n * @returns {number} The length.\n */\n length() {\n return this.#values.length;\n }\n\n /**\n * Get a string representation of the size.\n *\n * @returns {string} The Size as a string.\n */\n toString() {\n return '(' + this.#values.toString() + ')';\n }\n\n /**\n * Get the values of this index.\n *\n * @returns {number[]} The array of values.\n */\n getValues() {\n return this.#values.slice();\n }\n\n /**\n * Check if a dimension exists and has more than one element.\n *\n * @param {number} dimension The dimension to check.\n * @returns {boolean} True if the size is more than one.\n */\n moreThanOne(dimension) {\n return this.length() >= dimension + 1 && this.get(dimension) !== 1;\n }\n\n /**\n * Check if the associated data is scrollable in 3D.\n *\n * @param {Matrix33} [viewOrientation] The orientation matrix.\n * @returns {boolean} True if scrollable.\n */\n canScroll3D(viewOrientation) {\n let dimension = 2;\n if (typeof viewOrientation !== 'undefined') {\n dimension = viewOrientation.getThirdColMajorDirection();\n }\n return this.moreThanOne(dimension);\n }\n\n /**\n * Check if the associated data is scrollable: either in 3D or\n * in other directions.\n *\n * @param {Matrix33} viewOrientation The orientation matrix.\n * @returns {boolean} True if scrollable.\n */\n canScroll(viewOrientation) {\n let canScroll = this.canScroll3D(viewOrientation);\n // check possible other dimensions\n for (let i = 3; i < this.length(); ++i) {\n canScroll = canScroll || this.moreThanOne(i);\n }\n return canScroll;\n }\n\n /**\n * Get the size of a given dimension.\n *\n * @param {number} dimension The dimension.\n * @param {number} [start] Optional start dimension to start counting from.\n * @returns {number} The size.\n */\n getDimSize(dimension, start) {\n if (dimension > this.length()) {\n return null;\n }\n if (typeof start === 'undefined') {\n start = 0;\n } else {\n if (start < 0 || start > dimension) {\n throw new Error('Invalid start value for getDimSize');\n }\n }\n let size = 1;\n for (let i = start; i < dimension; ++i) {\n size *= this.get(i);\n }\n return size;\n }\n\n /**\n * Get the total size.\n *\n * @param {number} [start] Optional start dimension to base the offset on.\n * @returns {number} The total size.\n */\n getTotalSize(start) {\n return this.getDimSize(this.length(), start);\n }\n\n /**\n * Check for equality.\n *\n * @param {Size} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n // check input\n if (!rhs) {\n return false;\n }\n // check length\n const length = this.length();\n if (length !== rhs.length()) {\n return false;\n }\n // check values\n for (let i = 0; i < length; ++i) {\n if (this.get(i) !== rhs.get(i)) {\n return false;\n }\n }\n // seems ok!\n return true;\n }\n\n /**\n * Check that an index is within bounds.\n *\n * @param {Index} index The index to check.\n * @param {number[]} dirs Optional list of directions to check.\n * @returns {boolean} True if the given coordinates are within bounds.\n */\n isInBounds(index, dirs) {\n // check input\n if (!index) {\n return false;\n }\n // check length\n const length = this.length();\n if (length !== index.length()) {\n return false;\n }\n // create dirs if not there\n if (typeof dirs === 'undefined') {\n dirs = [];\n for (let j = 0; j < length; ++j) {\n dirs.push(j);\n }\n } else {\n for (let k = 0; k < length; ++k) {\n if (dirs[k] > length - 1) {\n throw new Error('Wrong input dir value: ' + dirs[k]);\n }\n }\n }\n // check values is 0 <= v < size\n const inBound = function (value, size) {\n return value >= 0 && value < size;\n };\n // check\n for (let i = 0; i < dirs.length; ++i) {\n if (!inBound(index.get(dirs[i]), this.get(dirs[i]))) {\n return false;\n }\n }\n // seems ok!\n return true;\n }\n\n /**\n * Convert an index to an offset in memory.\n *\n * @param {Index} index The index to convert.\n * @param {number} [start] Optional start dimension to base the offset on.\n * @returns {number} The offset.\n */\n indexToOffset(index, start) {\n // TODO check for equality\n if (index.length() < this.length()) {\n throw new Error('Incompatible index and size length');\n }\n if (typeof start === 'undefined') {\n start = 0;\n } else {\n if (start < 0 || start > this.length() - 1) {\n throw new Error('Invalid start value for indexToOffset');\n }\n }\n let offset = 0;\n for (let i = start; i < this.length(); ++i) {\n offset += index.get(i) * this.getDimSize(i, start);\n }\n return offset;\n }\n\n /**\n * Convert an offset in memory to an index.\n *\n * @param {number} offset The offset to convert.\n * @returns {Index} The index.\n */\n offsetToIndex(offset) {\n const values = new Array(this.length());\n let off = offset;\n let dimSize = 0;\n for (let i = this.length() - 1; i > 0; --i) {\n dimSize = this.getDimSize(i);\n values[i] = Math.floor(off / dimSize);\n off = off - values[i] * dimSize;\n }\n values[0] = off;\n return new Index(values);\n }\n\n /**\n * Get the 2D base of this size.\n *\n * @returns {Scalar2D} The 2D base [0,1] as {x,y}.\n */\n get2D() {\n return {\n x: this.get(0),\n y: this.get(1)\n };\n }\n\n} // Size class\n","/**\n * Statistics storage class.\n * 'simple' statistics do not include median, p25 nor p75.\n */\nexport class Statistics {\n /**\n * Minimum.\n *\n * @type {number}\n */\n min;\n /**\n * Maximum.\n *\n * @type {number}\n */\n max;\n /**\n * Mean.\n *\n * @type {number}\n */\n mean;\n /**\n * Standard deviation.\n *\n * @type {number}\n */\n stdDev;\n /**\n * Median.\n *\n * @type {number|undefined}\n */\n median;\n /**\n * 25th percentile.\n *\n * @type {number|undefined}\n */\n p25;\n /**\n * 75th percentile.\n *\n * @type {number|undefined}\n */\n p75;\n\n /**\n * @param {number} min The minimum.\n * @param {number} max The maxnimum.\n * @param {number} mean The mean.\n * @param {number} stdDev The standard deviation.\n */\n constructor(min, max, mean, stdDev) {\n this.min = min;\n this.max = max;\n this.mean = mean;\n this.stdDev = stdDev;\n }\n}\n\n/**\n * Get statistics on an input array of number.\n * Note: could use {@link https://github.com/tmcw/simple-statistics}.\n *\n * @param {number[]} values The array of values to extract stats from.\n * @param {string[]} flags A list of stat value names to calculate.\n * @returns {Statistics} A statistics object.\n */\nexport function getStats(values, flags) {\n if (includesFullStatsFlags(flags)) {\n return getFullStats(values);\n } else {\n return getBasicStats(values);\n }\n}\n\n/**\n * Does the input flag list contain a full stat element?\n *\n * @param {string[]} flags A list of stat values to calculate.\n * @returns {boolean} True if one of the flags is a full stat flag.\n */\nfunction includesFullStatsFlags(flags) {\n return typeof flags !== 'undefined' &&\n flags !== null &&\n (flags.includes('median') ||\n flags.includes('p25') ||\n flags.includes('p75'));\n}\n\n/**\n * Get simple stats: minimum, maximum, mean and standard deviation\n * of an array of values.\n *\n * @param {number[]} values The array of values to extract stats from.\n * @returns {Statistics} Simple statistics (no median, p25 nor p75).\n */\nexport function getBasicStats(values) {\n let min = values[0];\n let max = min;\n let sum = 0;\n let sumSqr = 0;\n let val = 0;\n const length = values.length;\n for (let i = 0; i < length; ++i) {\n val = values[i];\n if (val < min) {\n min = val;\n } else if (val > max) {\n max = val;\n }\n sum += val;\n sumSqr += val * val;\n }\n\n const mean = sum / length;\n // see http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance\n let variance = sumSqr / length - mean * mean;\n if (variance < 0) {\n variance = 0;\n }\n const stdDev = Math.sqrt(variance);\n\n return new Statistics(min, max, mean, stdDev);\n}\n\n/**\n * Get full stats: minimum, maximum, mean, standard deviation, median, 25%\n * and 75% percentile of an array of values.\n *\n * @param {number[]} values The array of values to extract stats from.\n * @returns {Statistics} Complete statistics (includes median, p25 and p75).\n */\nfunction getFullStats(values) {\n // get basic stats\n const stats = getBasicStats(values);\n\n // sort array... can get slow...\n values.sort(function (a, b) {\n return a - b;\n });\n\n stats.median = getPercentile(values, 0.5);\n stats.p25 = getPercentile(values, 0.25);\n stats.p75 = getPercentile(values, 0.75);\n\n return stats;\n}\n\n/**\n * Get an arrays' percentile. Uses linear interpolation for percentiles\n * that lie between data points.\n * See: {@link https://en.wikipedia.org/wiki/Percentile} (second variant interpolation).\n *\n * @param {number[]} values The sorted array of values.\n * @param {number} ratio The percentile ratio [0-1].\n * @returns {number} The percentile.\n */\nfunction getPercentile(values, ratio) {\n // check input\n if (values.length === 0) {\n throw new Error('Empty array provided for percentile calculation.');\n }\n if (ratio < 0 || ratio > 1) {\n throw new Error(\n 'Invalid ratio provided for percentile calculation: ' + ratio);\n }\n // return min for ratio=0 amd max for ratio=1\n if (ratio === 0) {\n return values[0];\n } else if (ratio === 1) {\n return values[values.length - 1];\n }\n // general case: interpolate between indices if needed\n const i = (values.length - 1) * ratio;\n const i0 = Math.floor(i);\n const v0 = values[i0];\n const v1 = values[i0 + 1];\n return v0 + (v1 - v0) * (i - i0);\n}\n\n/**\n * Unique ID generator.\n *\n * See {@link http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript}\n * and this {@link http://stackoverflow.com/a/13403498 answer}.\n *\n * @returns {string} A unique ID.\n */\nexport function guid() {\n return Math.random().toString(36).substring(2, 15);\n}\n\n/**\n * Number range.\n */\nexport class NumberRange {\n /**\n * @type {number}\n */\n min;\n /**\n * @type {number}\n */\n max;\n /**\n * @param {number} min The minimum.\n * @param {number} max The maximum.\n */\n constructor(min, max) {\n this.min = min;\n this.max = max;\n }\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Scalar2D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Immutable Spacing class.\n * Warning: the input array is NOT cloned, modifying it will\n * modify the index values.\n */\nexport class Spacing {\n\n /**\n * The spacing values.\n *\n * @type {number[]}\n */\n #values;\n\n /**\n * @param {number[]} values The spacing values.\n */\n constructor(values) {\n if (!values || typeof values === 'undefined') {\n throw new Error('Cannot create spacing with no values.');\n }\n if (values.length === 0) {\n throw new Error('Cannot create spacing with empty values.');\n }\n const valueCheck = function (val) {\n return !isNaN(val) && val !== 0;\n };\n if (!values.every(valueCheck)) {\n throw new Error('Cannot create spacing with non number or zero values.');\n }\n this.#values = values;\n }\n\n /**\n * Get the spacing value at the given array index.\n *\n * @param {number} i The index to get.\n * @returns {number} The value.\n */\n get(i) {\n return this.#values[i];\n }\n\n /**\n * Get the length of the spacing.\n *\n * @returns {number} The length.\n */\n length() {\n return this.#values.length;\n }\n\n /**\n * Get a string representation of the spacing.\n *\n * @returns {string} The spacing as a string.\n */\n toString() {\n return '(' + this.#values.toString() + ')';\n }\n\n /**\n * Get the values of this spacing.\n *\n * @returns {number[]} The array of values.\n */\n getValues() {\n return this.#values.slice();\n }\n\n /**\n * Check for equality.\n *\n * @param {Spacing} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n // check input\n if (!rhs) {\n return false;\n }\n // check length\n const length = this.length();\n if (length !== rhs.length()) {\n return false;\n }\n // check values\n for (let i = 0; i < length; ++i) {\n if (this.get(i) !== rhs.get(i)) {\n return false;\n }\n }\n // seems ok!\n return true;\n }\n\n /**\n * Get the 2D base of this size.\n *\n * @returns {Scalar2D} The 2D base [col,row] as {x,y}.\n */\n get2D() {\n return {\n x: this.get(0),\n y: this.get(1)\n };\n }\n\n} // Spacing class\n","import {\n getIdentityMat33,\n REAL_WORLD_EPSILON\n} from '../math/matrix';\nimport {Point3D, Point} from '../math/point';\nimport {Vector3D} from '../math/vector';\nimport {Index} from '../math/index';\nimport {getBasicStats} from '../math/stats';\nimport {precisionRound} from '../utils/string';\nimport {logger} from '../utils/logger';\nimport {Size} from './size';\nimport {Spacing} from './spacing';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Matrix33} from '../math/matrix';\n/* eslint-enable no-unused-vars */\n\n/**\n * 2D/3D Geometry class.\n */\nexport class Geometry {\n\n /**\n * Array of origins.\n *\n * @type {Point3D[]}\n */\n #origins;\n\n /**\n * Data size.\n *\n * @type {Size}\n */\n #size;\n\n /**\n * Data spacing.\n *\n * @type {Spacing}\n */\n #spacing;\n\n /**\n * Local helper object for time points.\n *\n * @type {Object}\n */\n #timeOrigins = {};\n\n /**\n * Initial time index.\n *\n * @type {number}\n */\n #initialTime;\n\n /**\n * Data orientation.\n *\n * @type {Matrix33}\n */\n #orientation = getIdentityMat33();\n\n /**\n * Flag to know if new origins were added.\n *\n * @type {boolean}\n */\n #newOrigins = false;\n\n /**\n * @param {Point3D} origin The object origin (a 3D point).\n * @param {Size} size The object size.\n * @param {Spacing} spacing The object spacing.\n * @param {Matrix33} [orientation] The object orientation (3*3 matrix,\n * default to 3*3 identity).\n * @param {number} [time] Optional time index.\n */\n constructor(origin, size, spacing, orientation, time) {\n this.#origins = [origin];\n this.#size = size;\n this.#spacing = spacing;\n if (typeof time !== 'undefined') {\n this.#initialTime = time;\n this.#timeOrigins[time] = [origin];\n }\n // check input orientation\n if (typeof orientation !== 'undefined') {\n this.#orientation = orientation;\n }\n }\n\n /**\n * Get the time value that was passed at construction.\n *\n * @returns {number} The time value.\n */\n getInitialTime() {\n return this.#initialTime;\n }\n\n /**\n * Get the total number of slices.\n * Can be different from what is stored in the size object\n * during a volume with time points creation process.\n *\n * @returns {number} The total count.\n */\n getCurrentTotalNumberOfSlices() {\n const keys = Object.keys(this.#timeOrigins);\n if (keys.length === 0) {\n return this.#origins.length;\n }\n let count = 0;\n for (let i = 0; i < keys.length; ++i) {\n count += this.#timeOrigins[keys[i]].length;\n }\n return count;\n }\n\n /**\n * Check if a time point has associated slices.\n *\n * @param {number} time The time point to check.\n * @returns {boolean} True if slices are present.\n */\n hasSlicesAtTime(time) {\n return typeof this.#timeOrigins[time] !== 'undefined';\n }\n\n /**\n * Get the number of slices stored for time points preceding\n * the input one.\n *\n * @param {number} time The time point to check.\n * @returns {number|undefined} The count.\n */\n getCurrentNumberOfSlicesBeforeTime(time) {\n const keys = Object.keys(this.#timeOrigins);\n if (keys.length === 0) {\n return undefined;\n }\n let count = 0;\n for (let i = 0; i < keys.length; ++i) {\n const key = keys[i];\n if (parseInt(key, 10) === time) {\n break;\n }\n count += this.#timeOrigins[key].length;\n }\n return count;\n }\n\n /**\n * Get the object origin.\n * This should be the lowest origin to ease calculations (?).\n *\n * @returns {Point3D} The object origin.\n */\n getOrigin() {\n return this.#origins[0];\n }\n\n /**\n * Get the object origins.\n *\n * @returns {Point3D[]} The object origins.\n */\n getOrigins() {\n return this.#origins;\n }\n\n /**\n * Check if a point is in the origin list.\n *\n * @param {Point3D} point3D The point to check.\n * @param {number} tol The comparison tolerance\n * default to Number.EPSILON.\n * @returns {boolean} True if in list.\n */\n includesOrigin(point3D, tol) {\n for (let i = 0; i < this.#origins.length; ++i) {\n if (this.#origins[i].isSimilar(point3D, tol)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get the object size.\n * Warning: the size comes as stored in DICOM, meaning that it could\n * be oriented.\n *\n * @param {Matrix33} [viewOrientation] The view orientation (optional).\n * @returns {Size} The object size.\n */\n getSize(viewOrientation) {\n let res = this.#size;\n if (viewOrientation && typeof viewOrientation !== 'undefined') {\n let values = getOrientedArray3D(\n [\n this.#size.get(0),\n this.#size.get(1),\n this.#size.get(2)\n ],\n viewOrientation);\n values = values.map(Math.abs);\n res = new Size(values.concat(this.#size.getValues().slice(3)));\n }\n return res;\n }\n\n /**\n * Calculate slice spacing from origins and replace current\n * if needed.\n */\n #updateSliceSpacing() {\n const geoSliceSpacing = getSliceGeometrySpacing(this.#origins);\n // update local if needed\n if (typeof geoSliceSpacing !== 'undefined' &&\n this.#spacing.get(2) !== geoSliceSpacing) {\n logger.trace('Using geometric spacing ' + geoSliceSpacing +\n ' instead of tag spacing ' + this.#spacing.get(2));\n const values = this.#spacing.getValues();\n values[2] = geoSliceSpacing;\n this.#spacing = new Spacing(values);\n }\n }\n\n /**\n * Get the object spacing.\n * Warning: the spacing comes as stored in DICOM, meaning that it could\n * be oriented.\n *\n * @param {Matrix33} [viewOrientation] The view orientation (optional).\n * @returns {Spacing} The object spacing.\n */\n getSpacing(viewOrientation) {\n // update slice spacing after appendSlice\n if (this.#newOrigins) {\n this.#updateSliceSpacing();\n this.#newOrigins = false;\n }\n let res = this.#spacing;\n if (viewOrientation && typeof viewOrientation !== 'undefined') {\n let orientedValues = getOrientedArray3D(\n [\n this.#spacing.get(0),\n this.#spacing.get(1),\n this.#spacing.get(2)\n ],\n viewOrientation);\n orientedValues = orientedValues.map(Math.abs);\n res = new Spacing(orientedValues);\n }\n return res;\n }\n\n /**\n * Get the image spacing in real world.\n *\n * @returns {Spacing} The object spacing.\n */\n getRealSpacing() {\n // asOneAndZeros to not change spacing values...\n return this.getSpacing(\n this.#orientation.getInverse().asOneAndZeros()\n );\n }\n\n /**\n * Get the object orientation.\n *\n * @returns {Matrix33} The object orientation.\n */\n getOrientation() {\n return this.#orientation;\n }\n\n /**\n * Get the slice position of a point in the current slice layout.\n * Slice indices increase with decreasing origins (high index -> low origin),\n * this simplified the handling of reconstruction since it means\n * the displayed data is in the same 'direction' as the extracted data.\n * As seen in the getOrigin method, the main origin is the lowest one.\n * This implies that the index to world and reverse method do some flipping\n * magic...\n *\n * @param {Point3D} point The point to evaluate.\n * @param {number} time Optional time index.\n * @returns {number} The slice index.\n */\n getSliceIndex(point, time) {\n // cannot use this.worldToIndex(point).getK() since\n // we cannot guaranty consecutive slices...\n\n let localOrigins = this.#origins;\n if (typeof time !== 'undefined') {\n localOrigins = this.#timeOrigins[time];\n }\n\n // find the closest origin\n const closestOriginIndex = point.getClosest(localOrigins);\n const closestOrigin = localOrigins[closestOriginIndex];\n\n // direction between the input point and the closest origin\n const pointDir = point.minus(closestOrigin);\n\n // use third orientation matrix column as plane normal vector\n const normal = new Vector3D(\n this.#orientation.get(0, 2),\n this.#orientation.get(1, 2),\n this.#orientation.get(2, 2)\n );\n\n // codirectional vectors: above slice index\n // oposite vectors: below slice index\n const isCodirectional = normal.isCodirectional(pointDir);\n const sliceIndex = isCodirectional\n ? closestOriginIndex + 1 : closestOriginIndex;\n\n return sliceIndex;\n }\n\n /**\n * Append an origin to the geometry.\n *\n * @param {Point3D} origin The origin to append.\n * @param {number} index The index at which to append.\n * @param {number} [time] Optional time index.\n */\n appendOrigin(origin, index, time) {\n // equal callback\n const equalToOrigin = function (element) {\n return element.equals(origin);\n };\n if (typeof time !== 'undefined') {\n // check if not already in list\n const found = this.#timeOrigins[time].find(equalToOrigin);\n if (typeof found !== 'undefined') {\n throw new Error('Cannot append same time origin twice');\n }\n // add in origin array\n this.#timeOrigins[time].splice(index, 0, origin);\n }\n if (typeof time === 'undefined' || time === this.#initialTime) {\n // check if not already in list\n const found = this.#origins.find(equalToOrigin);\n if (typeof found !== 'undefined') {\n throw new Error('Cannot append same origin twice');\n }\n // update flag\n this.#newOrigins = true;\n // add in origin array\n this.#origins.splice(index, 0, origin);\n // increment second dimension\n const values = this.#size.getValues();\n values[2] += 1;\n this.#size = new Size(values);\n }\n }\n\n /**\n * Append a frame to the geometry.\n *\n * @param {Point3D} origin The origin to append.\n * @param {number} time Optional time index.\n */\n appendFrame(origin, time) {\n // add origin to list\n this.#timeOrigins[time] = [origin];\n // increment third dimension\n const sizeValues = this.#size.getValues();\n const spacingValues = this.#spacing.getValues();\n if (sizeValues.length === 4) {\n sizeValues[3] += 1;\n } else {\n sizeValues.push(2);\n spacingValues.push(1);\n }\n this.#size = new Size(sizeValues);\n this.#spacing = new Spacing(spacingValues);\n }\n\n /**\n * Get a string representation of the geometry.\n *\n * @returns {string} The geometry as a string.\n */\n toString() {\n return 'Origin: ' + this.getOrigin() +\n ', Size: ' + this.getSize() +\n ', Spacing: ' + this.getSpacing() +\n ', Orientation: ' + this.getOrientation();\n }\n\n /**\n * Check for equality.\n *\n * @param {Geometry} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.getOrigin().equals(rhs.getOrigin()) &&\n this.getSize().equals(rhs.getSize()) &&\n this.getSpacing().equals(rhs.getSpacing());\n }\n\n /**\n * Check that a point is within bounds.\n *\n * @param {Point} point The point to check.\n * @returns {boolean} True if the given coordinates are within bounds.\n */\n isInBounds(point) {\n return this.isIndexInBounds(this.worldToIndex(point));\n }\n\n /**\n * Check that a index is within bounds.\n *\n * @param {Index} index The index to check.\n * @param {number[]} [dirs] Optional list of directions to check.\n * @returns {boolean} True if the given coordinates are within bounds.\n */\n isIndexInBounds(index, dirs) {\n return this.getSize().isInBounds(index, dirs);\n }\n\n /**\n * Convert an index into world coordinates.\n *\n * @param {Index} index The index to convert.\n * @returns {Point} The corresponding point.\n */\n indexToWorld(index) {\n // apply spacing\n // (spacing is oriented, apply before orientation)\n const spacing = this.getSpacing();\n const orientedPoint3D = new Point3D(\n index.get(0) * spacing.get(0),\n index.get(1) * spacing.get(1),\n index.get(2) * spacing.get(2)\n );\n // de-orient\n const point3D = this.getOrientation().multiplyPoint3D(orientedPoint3D);\n // keep >3d values\n const values = index.getValues();\n const origin = this.getOrigin();\n values[0] = origin.getX() + point3D.getX();\n values[1] = origin.getY() + point3D.getY();\n values[2] = origin.getZ() + point3D.getZ();\n // return point\n return new Point(values);\n }\n\n /**\n * Convert a 3D point into world coordinates.\n *\n * @param {Point3D} point The 3D point to convert.\n * @returns {Point3D} The corresponding world 3D point.\n */\n pointToWorld(point) {\n // apply spacing\n // (spacing is oriented, apply before orientation)\n const spacing = this.getSpacing();\n const orientedPoint3D = new Point3D(\n point.getX() * spacing.get(0),\n point.getY() * spacing.get(1),\n point.getZ() * spacing.get(2)\n );\n // de-orient\n const point3D = this.getOrientation().multiplyPoint3D(orientedPoint3D);\n // return point3D\n const origin = this.getOrigin();\n return new Point3D(\n origin.getX() + point3D.getX(),\n origin.getY() + point3D.getY(),\n origin.getZ() + point3D.getZ()\n );\n }\n\n /**\n * Convert world coordinates into an index.\n *\n * @param {Point} point The point to convert.\n * @returns {Index} The corresponding index.\n */\n worldToIndex(point) {\n // compensate for origin\n // (origin is not oriented, compensate before orientation)\n // TODO: use slice origin...\n const origin = this.getOrigin();\n const point3D = new Point3D(\n point.get(0) - origin.getX(),\n point.get(1) - origin.getY(),\n point.get(2) - origin.getZ()\n );\n // orient\n const orientedPoint3D =\n this.getOrientation().getInverse().multiplyPoint3D(point3D);\n // keep >3d values\n const values = point.getValues();\n // apply spacing and round\n const spacing = this.getSpacing();\n values[0] = Math.round(orientedPoint3D.getX() / spacing.get(0));\n values[1] = Math.round(orientedPoint3D.getY() / spacing.get(1));\n values[2] = Math.round(orientedPoint3D.getZ() / spacing.get(2));\n\n // return index\n return new Index(values);\n }\n\n /**\n * Convert world coordinates into an point.\n *\n * @param {Point} point The world point to convert.\n * @returns {Point3D} The corresponding point.\n */\n worldToPoint(point) {\n // compensate for origin\n // (origin is not oriented, compensate before orientation)\n const origin = this.getOrigin();\n const point3D = new Point3D(\n point.get(0) - origin.getX(),\n point.get(1) - origin.getY(),\n point.get(2) - origin.getZ()\n );\n // orient\n const orientedPoint3D =\n this.getOrientation().getInverse().multiplyPoint3D(point3D);\n // keep >3d values\n const values = point.getValues();\n // apply spacing and round\n const spacing = this.getSpacing();\n values[0] = orientedPoint3D.getX() / spacing.get(0);\n values[1] = orientedPoint3D.getY() / spacing.get(1);\n values[2] = orientedPoint3D.getZ() / spacing.get(2);\n\n // return index\n return new Point3D(values[0], values[1], values[2]);\n }\n\n} // class Geometry\n\n/**\n * Get the oriented values of an input 3D array.\n *\n * @param {number[]} array3D The 3D array.\n * @param {Matrix33} orientation The orientation 3D matrix.\n * @returns {number[]} The values reordered according to the orientation.\n */\nexport function getOrientedArray3D(array3D, orientation) {\n // values = orientation * orientedValues\n // -> inv(orientation) * values = orientedValues\n return orientation.getInverse().multiplyArray3D(array3D);\n}\n\n/**\n * Get the raw values of an oriented input 3D array.\n *\n * @param {number[]} array3D The 3D array.\n * @param {Matrix33} orientation The orientation 3D matrix.\n * @returns {number[]} The values reordered to compensate the orientation.\n */\nexport function getDeOrientedArray3D(array3D, orientation) {\n // values = orientation * orientedValues\n return orientation.multiplyArray3D(array3D);\n}\n\n/**\n * Get the slice spacing from the difference in the Z directions\n * of input origins.\n *\n * @param {Point3D[]} origins An array of Point3D.\n * @returns {number|undefined} The spacing.\n */\nexport function getSliceGeometrySpacing(origins) {\n // check origins\n if (origins.length <= 1) {\n return;\n }\n\n const spacings = [];\n for (let i = 0; i < origins.length - 1; ++i) {\n const origin1 = origins[i];\n const origin2 = origins[i + 1];\n const sliceSpacing = origin1.getDistance(origin2);\n if (sliceSpacing === 0) {\n throw new Error('Zero slice spacing ' +\n origin1.toString() + ' ' + origin2.toString());\n }\n spacings.push(sliceSpacing);\n }\n\n // use rounded mean value as spacing\n const stats = getBasicStats(spacings);\n const spacing = precisionRound(stats.mean, 4);\n\n // warn if non constant\n if (stats.stdDev > REAL_WORLD_EPSILON) {\n logger.warn('Varying slice spacing, value: ' + spacing +\n ' (mean: ' + stats.mean +\n ', min: ' + stats.min +\n ', max: ' + stats.max +\n ', stdDev: ' + stats.stdDev + ')');\n }\n\n return spacing;\n}\n","import {DataElement} from './dataElement';\n\n/**\n * Pad an input string with a '0' to form a 2 digit one.\n *\n * @param {string} str The string to pad.\n * @returns {string} The padded string.\n */\nfunction padZeroTwoDigit(str) {\n return ('0' + str).slice(-2);\n}\n\n/**\n * Get a 'date' object with {year, monthIndex, day} ready for the\n * Date constructor from a DICOM element with vr=DA.\n *\n * @param {DataElement} element The DICOM element with date information.\n * @returns {{year, monthIndex, day}|undefined} The 'date' object.\n */\nexport function getDate(element) {\n if (typeof element === 'undefined') {\n return undefined;\n }\n if (element.value.length !== 1) {\n return undefined;\n }\n const daValue = element.value[0];\n // Two possible formats:\n // - standard 'YYYYMMDD'\n // - non-standard 'YYYY.MM.DD' (previous ACR-NEMA)\n let monthBeginIndex = 4;\n let dayBeginIndex = 6;\n if (daValue.length === 10) {\n monthBeginIndex = 5;\n dayBeginIndex = 8;\n }\n const daYears = parseInt(daValue.substring(0, 4), 10);\n // 0-11 range\n const daMonthIndex = daValue.length >= monthBeginIndex + 2\n ? parseInt(daValue.substring(\n monthBeginIndex, monthBeginIndex + 2), 10) - 1 : 0;\n const daDay = daValue.length === dayBeginIndex + 2\n ? parseInt(daValue.substring(\n dayBeginIndex, dayBeginIndex + 2), 10) : 0;\n return {\n year: daYears,\n monthIndex: daMonthIndex,\n day: daDay\n };\n}\n\n/**\n * Get a time object with {hours, minutes, seconds} ready for the\n * Date constructor from a DICOM element with vr=TM.\n *\n * @param {DataElement} element The DICOM element with date information.\n * @returns {{hours, minutes, seconds, milliseconds}|undefined} The time object.\n */\nexport function getTime(element) {\n if (typeof element === 'undefined') {\n return undefined;\n }\n if (element.value.length !== 1) {\n return undefined;\n }\n // format: HH[MMSS.FFFFFF]\n const tmValue = element.value[0];\n const tmHours = parseInt(tmValue.substring(0, 2), 10);\n const tmMinutes = tmValue.length >= 4\n ? parseInt(tmValue.substring(2, 4), 10) : 0;\n const tmSeconds = tmValue.length >= 6\n ? parseInt(tmValue.substring(4, 6), 10) : 0;\n const tmFracSecondsStr = tmValue.length >= 8\n ? tmValue.substring(7, 10) : 0;\n const tmMilliSeconds = tmFracSecondsStr === 0 ? 0\n : parseInt(tmFracSecondsStr, 10) *\n Math.pow(10, 3 - tmFracSecondsStr.length);\n return {\n hours: tmHours,\n minutes: tmMinutes,\n seconds: tmSeconds,\n milliseconds: tmMilliSeconds\n };\n}\n\n/**\n * Get a 'dateTime' object with {date, time} ready for the\n * Date constructor from a DICOM element with vr=DT.\n *\n * @param {DataElement} element The DICOM element with date-time information.\n * @returns {{date, time}|undefined} The time object.\n */\nexport function getDateTime(element) {\n if (typeof element === 'undefined') {\n return undefined;\n }\n if (element.value.length !== 1) {\n return undefined;\n }\n // format: YYYYMMDDHHMMSS.FFFFFF&ZZXX\n const dtFullValue = element.value[0];\n // remove offset (&ZZXX)\n const dtValue = dtFullValue.split('&')[0];\n const dateDataElement = new DataElement('DA');\n dateDataElement.value = [dtValue.substring(0, 8)];\n const dtDate = getDate(dateDataElement);\n const timeDataElement = new DataElement('TM');\n timeDataElement.value = [dtValue.substring(8)];\n const dtTime = dtValue.length >= 9\n ? getTime(timeDataElement) : undefined;\n return {\n date: dtDate,\n time: dtTime\n };\n}\n\n/**\n * Extract date values from a Date object.\n *\n * @param {Date} date The input date.\n * @returns {{year, monthIndex, day}} A 'date' object.\n */\nexport function dateToDateObj(date) {\n return {\n year: date.getFullYear().toString(),\n monthIndex: padZeroTwoDigit((date.getMonth() + 1).toString()),\n day: padZeroTwoDigit(date.getDate().toString())\n };\n}\n\n/**\n * Extract time values from a Date object.\n *\n * @param {Date} date The input date.\n * @returns {{hours, minutes, seconds}} A 'time' object.\n */\nexport function dateToTimeObj(date) {\n return {\n hours: padZeroTwoDigit(date.getHours().toString()),\n minutes: padZeroTwoDigit(date.getMinutes().toString()),\n seconds: padZeroTwoDigit(date.getSeconds().toString())\n };\n}\n\n/**\n * Get a DICOM formated date string.\n *\n * @param {{year, monthIndex, day}} dateObj The date to format.\n * @returns {string} The formated date.\n */\nexport function getDicomDate(dateObj) {\n // YYYYMMDD\n return (\n dateObj.year +\n dateObj.monthIndex +\n dateObj.day\n );\n}\n\n/**\n * Get a DICOM formated time string.\n *\n * @param {{hours, minutes, seconds}} dateObj The date to format.\n * @returns {string} The formated time.\n */\nexport function getDicomTime(dateObj) {\n // HHMMSS\n return (\n dateObj.hours +\n dateObj.minutes +\n dateObj.seconds\n );\n}\n\n/**\n * Get a DICOM formated datetime string.\n *\n * @param {{date, time}} datetime The datetime to format.\n * @returns {string} The formated datetime.\n */\nexport function getDicomDateTime(datetime) {\n // HHMMSS\n let res = getDicomDate(datetime.date);\n if (typeof datetime.time !== 'undefined') {\n res += getDicomTime(datetime.time);\n }\n return res;\n}\n","import {Vector3D} from './vector';\nimport {\n Matrix33,\n getIdentityMat33\n} from './matrix';\n\n/**\n * Create a 3x3 coronal (xzy) matrix.\n *\n * @returns {Matrix33} The coronal matrix.\n */\nexport function getCoronalMat33() {\n /* eslint-disable @stylistic/js/array-element-newline */\n return new Matrix33([\n 1, 0, 0,\n 0, 0, 1,\n 0, -1, 0\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n}\n\n/**\n * Create a 3x3 sagittal (yzx) matrix.\n *\n * @returns {Matrix33} The sagittal matrix.\n */\nexport function getSagittalMat33() {\n /* eslint-disable @stylistic/js/array-element-newline */\n return new Matrix33([\n 0, 0, -1,\n 1, 0, 0,\n 0, -1, 0\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n}\n\n/**\n * Default anatomical plane orientations.\n */\nexport const Orientation = {\n /**\n * Axial, also known as transverse.\n */\n Axial: 'axial',\n /**\n * Coronal, also known as frontal.\n */\n Coronal: 'coronal',\n /**\n * Sagittal, also known as anteroposterior.\n */\n Sagittal: 'sagittal'\n};\n\n/**\n * Get an orientation matrix from a name.\n *\n * @param {string} name The orientation name.\n * @returns {Matrix33|undefined} The orientation matrix.\n */\nexport function getMatrixFromName(name) {\n let matrix;\n if (name === Orientation.Axial) {\n matrix = getIdentityMat33();\n } else if (name === Orientation.Coronal) {\n matrix = getCoronalMat33();\n } else if (name === Orientation.Sagittal) {\n matrix = getSagittalMat33();\n }\n return matrix;\n}\n\n/**\n * Get the orientation code of an orientation matrix. Each letter defines\n * the towards direction. Letters are: R (right), L (left),\n * A (anterior), P (posterior), I (inferior) and S (superior).\n *\n * @param {Matrix33} matrix The orientation matrix.\n * @returns {string} The orientation code.\n */\nexport function getOrientationStringLPS(matrix) {\n const v0 = new Vector3D(\n matrix.get(0, 0),\n matrix.get(1, 0),\n matrix.get(2, 0)\n );\n const v1 = new Vector3D(\n matrix.get(0, 1),\n matrix.get(1, 1),\n matrix.get(2, 1)\n );\n const v2 = new Vector3D(\n matrix.get(0, 2),\n matrix.get(1, 2),\n matrix.get(2, 2)\n );\n return getVectorStringLPS(v0) +\n getVectorStringLPS(v1) +\n getVectorStringLPS(v2);\n}\n\n/**\n * Get the orientation code of an orientation vector.\n * Credits: David Clunie, {@link https://www.dclunie.com/medical-image-faq/html/part2.html}.\n *\n * @param {Vector3D} vector The orientation vector.\n * @returns {string} The orientation code.\n */\nfunction getVectorStringLPS(vector) {\n let abs = new Vector3D(\n Math.abs(vector.getX()),\n Math.abs(vector.getY()),\n Math.abs(vector.getZ())\n );\n\n let orientation = '';\n const orientationX = vector.getX() < 0 ? 'R' : 'L';\n const orientationY = vector.getY() < 0 ? 'A' : 'P';\n // as defined in DICOM\n //const orientationZ = vector.getZ() < 0 ? 'F' : 'H';\n const orientationZ = vector.getZ() < 0 ? 'I' : 'S';\n\n const threshold = 0.0001;\n\n for (let i = 0; i < 3; i++) {\n if (abs.getX() > threshold &&\n abs.getX() > abs.getY() &&\n abs.getX() > abs.getZ()) {\n orientation += orientationX;\n abs = new Vector3D(0, abs.getY(), abs.getZ());\n } else if (abs.getY() > threshold &&\n abs.getY() > abs.getX() &&\n abs.getY() > abs.getZ()) {\n orientation += orientationY;\n abs = new Vector3D(abs.getX(), 0, abs.getZ());\n } else if (abs.getZ() > threshold &&\n abs.getZ() > abs.getX() &&\n abs.getZ() > abs.getY()) {\n orientation += orientationZ;\n abs = new Vector3D(abs.getX(), abs.getY(), 0);\n } else {\n break;\n }\n }\n\n return orientation;\n}\n\n/**\n * Get the LPS 'group' (axial, coronal or sagittal) from a LPS code.\n *\n * @param {string} code The LPS code string.\n * @returns {string|undefined} The group.\n */\nfunction getLPSGroup(code) {\n let orientStr;\n const axialCodes =\n ['LPS', 'LAI', 'RPI', 'RAS', 'ALS', 'ARI', 'PLI', 'PRS'];\n const coronalCodes =\n ['LSA', 'LIP', 'RSP', 'RIA', 'ILA', 'IRP', 'SLP', 'SRA'];\n const sagittalCodes =\n ['PSL', 'PIR', 'ASR', 'AIL', 'IAR', 'IPL', 'SAL', 'SPR'];\n if (axialCodes.includes(code)) {\n orientStr = Orientation.Axial;\n } else if (coronalCodes.includes(code)) {\n orientStr = Orientation.Coronal;\n } else if (sagittalCodes.includes(code)) {\n orientStr = Orientation.Sagittal;\n }\n return orientStr;\n}\n\n/**\n * Get the name of an image orientation patient.\n *\n * @param {number[]} cosines The image orientation\n * patient cosines (6 values).\n * @returns {string|undefined} The orientation\n * name: axial, coronal or sagittal.\n */\nexport function getOrientationName(cosines) {\n let name;\n const orientMatrix = getOrientationFromCosines(cosines);\n if (typeof orientMatrix !== 'undefined') {\n const lpsStr = getOrientationStringLPS(orientMatrix.asOneAndZeros());\n name = getLPSGroup(lpsStr);\n }\n return name;\n}\n\n/**\n * Get the orientation matrix associated to the direction cosines.\n *\n * @param {number[]} cosines The image orientation\n * patient cosines (6 values).\n * @returns {Matrix33|undefined} The orientation matrix.\n */\nexport function getOrientationFromCosines(cosines) {\n let orientationMatrix;\n if (typeof cosines !== 'undefined' && cosines.length === 6) {\n const rowCosines = new Vector3D(cosines[0], cosines[1], cosines[2]);\n const colCosines = new Vector3D(cosines[3], cosines[4], cosines[5]);\n const normal = rowCosines.crossProduct(colCosines);\n /* eslint-disable @stylistic/js/array-element-newline */\n orientationMatrix = new Matrix33([\n rowCosines.getX(), colCosines.getX(), normal.getX(),\n rowCosines.getY(), colCosines.getY(), normal.getY(),\n rowCosines.getZ(), colCosines.getZ(), normal.getZ()\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n }\n return orientationMatrix;\n}\n\n/**\n * Get the direction cosines from an orientation matrix.\n *\n * @param {Matrix33} matrix The input matrix.\n * @returns {number[]} The image orientation\n * patient cosines (6 values).\n */\nexport function getCosinesFromOrientation(matrix) {\n return [\n matrix.get(0, 0),\n matrix.get(1, 0),\n matrix.get(2, 0),\n matrix.get(0, 1),\n matrix.get(1, 1),\n matrix.get(2, 1)\n ];\n}\n\n/**\n * Get the view orientation according to an image and target orientation.\n * The view orientation is used to go from target to image space.\n *\n * @param {Matrix33} imageOrientation The image geometry.\n * @param {Matrix33} targetOrientation The target orientation.\n * @returns {Matrix33} The view orientation.\n */\nexport function getViewOrientation(imageOrientation, targetOrientation) {\n let viewOrientation = getIdentityMat33();\n if (typeof targetOrientation !== 'undefined') {\n // i: image, v: view, t: target, O: orientation, P: point\n // [Img] -- Oi --> [Real] <-- Ot -- [Target]\n // Pi = (Oi)-1 * Ot * Pt = Ov * Pt\n // -> Ov = (Oi)-1 * Ot\n // TODO: asOneAndZeros simplifies but not nice...\n viewOrientation =\n imageOrientation.asOneAndZeros().getInverse().multiply(targetOrientation);\n }\n // TODO: why abs???\n return viewOrientation.getAbs();\n}\n\n/**\n * Get the target orientation according to an image and view orientation.\n * The target orientation is used to go from target to real space.\n *\n * @param {Matrix33} imageOrientation The image geometry.\n * @param {Matrix33} viewOrientation The view orientation.\n * @returns {Matrix33} The target orientation.\n */\nexport function getTargetOrientation(imageOrientation, viewOrientation) {\n // i: image, v: view, t: target, O: orientation, P: point\n // [Img] -- Oi --> [Real] <-- Ot -- [Target]\n // Pi = (Oi)-1 * Ot * Pt = Ov * Pt\n // -> Ot = Oi * Ov\n // note: asOneAndZeros as in getViewOrientation...\n let targetOrientation =\n imageOrientation.asOneAndZeros().multiply(viewOrientation);\n\n // TODO: why abs???\n const simpleImageOrientation = imageOrientation.asOneAndZeros().getAbs();\n if (simpleImageOrientation.equals(getCoronalMat33().getAbs())) {\n targetOrientation = targetOrientation.getAbs();\n }\n\n return targetOrientation;\n}\n","import {\n DicomParser,\n getTransferSyntaxName,\n isJpeg2000TransferSyntax,\n isJpegBaselineTransferSyntax,\n isJpegLosslessTransferSyntax\n} from './dicomParser';\nimport {\n getDate,\n getTime,\n getDateTime\n} from './dicomDate';\nimport {\n isPixelDataTag,\n isItemDelimitationItemTag,\n isSequenceDelimitationItemTag,\n getItemTag,\n getItemDelimitationItemTag,\n getSequenceDelimitationItemTag,\n getPixelDataTag,\n getTagFromKey\n} from './dicomTag';\nimport {isNativeLittleEndian} from './dataReader';\nimport {getOrientationFromCosines} from '../math/orientation';\nimport {Spacing} from '../image/spacing';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Tag} from './dicomTag';\nimport {DataElement} from './dataElement';\nimport {Matrix33} from '../math/matrix';\n/* eslint-enable no-unused-vars */\n\n/**\n * @typedef {Object} DataElements\n */\n\n/**\n * Dump the DICOM tags to a string in the same way as the\n * DCMTK `dcmdump` command (https://support.dcmtk.org/docs-dcmrt/dcmdump.html).\n *\n * @param {Object} dicomElements The dicom elements.\n * @returns {string} The dumped file.\n */\nexport function dcmdump(dicomElements) {\n const keys = Object.keys(dicomElements);\n let result = '\\n';\n result += '# Dicom-File-Format\\n';\n result += '\\n';\n result += '# Dicom-Meta-Information-Header\\n';\n result += '# Used TransferSyntax: ';\n if (isNativeLittleEndian()) {\n result += 'Little Endian Explicit\\n';\n } else {\n result += 'NOT Little Endian Explicit\\n';\n }\n let dicomElement = null;\n let tag = null;\n let checkHeader = true;\n for (let i = 0, leni = keys.length; i < leni; ++i) {\n dicomElement = dicomElements[keys[i]];\n tag = getTagFromKey(keys[i]);\n if (checkHeader && tag.getGroup() !== '0002') {\n result += '\\n';\n result += '# Dicom-Data-Set\\n';\n result += '# Used TransferSyntax: ';\n const syntax = dicomElements['00020010'].value[0];\n result += getTransferSyntaxName(syntax);\n result += '\\n';\n checkHeader = false;\n }\n result += getElementAsString(tag, dicomElement) + '\\n';\n }\n return result;\n}\n\n/**\n * Get a data element value as a string.\n *\n * @param {Tag} tag The DICOM tag.\n * @param {object} dicomElement The DICOM element.\n * @param {boolean} [pretty] When set to true, returns a 'pretified' content.\n * @returns {string} A string representation of the DICOM element.\n */\nfunction getElementValueAsString(tag, dicomElement, pretty) {\n let str = '';\n const strLenLimit = 65;\n\n // dafault to pretty output\n if (typeof pretty === 'undefined') {\n pretty = true;\n }\n // check dicom element input\n if (typeof dicomElement === 'undefined' || dicomElement === null) {\n return str;\n }\n\n // Polyfill for Number.isInteger.\n const isInteger = Number.isInteger || function (value) {\n return typeof value === 'number' &&\n isFinite(value) &&\n Math.floor(value) === value;\n };\n\n // TODO Support sequences.\n\n if (dicomElement.vr !== 'SQ' &&\n dicomElement.value.length === 1 && dicomElement.value[0] === '') {\n str += '(no value available)';\n } else if (isPixelDataTag(tag) &&\n dicomElement.undefinedLength) {\n str = '(PixelSequence)';\n } else if (dicomElement.vr === 'DA' && pretty) {\n const daObj = getDate(dicomElement);\n const da = new Date(daObj.year, daObj.monthIndex, daObj.day);\n str = da.toLocaleDateString();\n } else if (dicomElement.vr === 'TM' && pretty) {\n const tmObj = getTime(dicomElement);\n str = tmObj.hours + ':' + tmObj.minutes + ':' + tmObj.seconds;\n } else {\n let isOtherVR = false;\n if (dicomElement.vr.length !== 0) {\n isOtherVR = (dicomElement.vr[0].toUpperCase() === 'O');\n }\n const isFloatNumberVR = (dicomElement.vr === 'FL' ||\n dicomElement.vr === 'FD' ||\n dicomElement.vr === 'DS');\n let valueStr = '';\n for (let k = 0, lenk = dicomElement.value.length; k < lenk; ++k) {\n valueStr = '';\n if (k !== 0) {\n valueStr += '\\\\';\n }\n if (isFloatNumberVR) {\n const num = Number(dicomElement.value[k]);\n if (!isInteger(num) && pretty) {\n valueStr += num.toPrecision(4);\n } else {\n valueStr += num.toString();\n }\n } else if (isOtherVR) {\n let tmp = dicomElement.value[k].toString(16);\n if (dicomElement.vr === 'OB') {\n tmp = '00'.substring(0, 2 - tmp.length) + tmp;\n } else {\n tmp = '0000'.substring(0, 4 - tmp.length) + tmp;\n }\n valueStr += tmp;\n } else {\n valueStr += dicomElement.value[k];\n }\n // check length\n if (str.length + valueStr.length <= strLenLimit) {\n str += valueStr;\n } else {\n str += '...';\n break;\n }\n }\n }\n return str;\n}\n\n/**\n * Get a data element as a string.\n *\n * @param {Tag} tag The DICOM tag.\n * @param {object} dicomElement The DICOM element.\n * @param {string} [prefix] A string to prepend this one.\n * @returns {string} The element as a string.\n */\nfunction getElementAsString(tag, dicomElement, prefix) {\n // default prefix\n prefix = prefix || '';\n\n // get tag anme from dictionary\n const tagName = tag.getNameFromDictionary();\n\n let deSize = dicomElement.value.length;\n let isOtherVR = false;\n if (dicomElement.vr.length !== 0) {\n isOtherVR = (dicomElement.vr[0].toUpperCase() === 'O');\n }\n\n // no size for delimitations\n if (isItemDelimitationItemTag(tag) ||\n isSequenceDelimitationItemTag(tag)) {\n deSize = 0;\n } else if (isOtherVR) {\n deSize = 1;\n }\n\n const isPixSequence = (isPixelDataTag(tag) &&\n dicomElement.undefinedLength);\n\n let line = null;\n\n // (group,element)\n line = '(';\n line += tag.getGroup().toLowerCase();\n line += ',';\n line += tag.getElement().toLowerCase();\n line += ') ';\n // value representation\n line += dicomElement.vr;\n // value\n if (dicomElement.vr !== 'SQ' &&\n dicomElement.value.length === 1 &&\n dicomElement.value[0] === '') {\n line += ' (no value available)';\n deSize = 0;\n } else {\n // simple number display\n if (dicomElement.vr === 'na') {\n line += ' ';\n line += dicomElement.value[0];\n } else if (isPixSequence) {\n // pixel sequence\n line += ' (PixelSequence #=' + deSize + ')';\n } else if (dicomElement.vr === 'SQ') {\n line += ' (Sequence with';\n if (dicomElement.undefinedLength) {\n line += ' undefined';\n } else {\n line += ' explicit';\n }\n line += ' length #=';\n line += dicomElement.value.length;\n line += ')';\n } else if (isOtherVR ||\n dicomElement.vr === 'pi' ||\n dicomElement.vr === 'UL' ||\n dicomElement.vr === 'US' ||\n dicomElement.vr === 'SL' ||\n dicomElement.vr === 'SS' ||\n dicomElement.vr === 'FL' ||\n dicomElement.vr === 'FD' ||\n dicomElement.vr === 'AT') {\n // 'O'ther array, limited display length\n line += ' ';\n line += getElementValueAsString(tag, dicomElement, false);\n } else {\n // default\n line += ' [';\n line += getElementValueAsString(tag, dicomElement, false);\n line += ']';\n }\n }\n\n // align #\n const nSpaces = 55 - line.length;\n if (nSpaces > 0) {\n for (let s = 0; s < nSpaces; ++s) {\n line += ' ';\n }\n }\n line += ' # ';\n if (dicomElement.vl < 100) {\n line += ' ';\n }\n if (dicomElement.vl < 10) {\n line += ' ';\n }\n line += dicomElement.vl;\n line += ', ';\n line += deSize; //dictElement[1];\n line += ' ';\n if (tagName !== null) {\n line += tagName;\n } else {\n line += 'Unknown Tag & Data';\n }\n\n let message = null;\n\n // continue for sequence\n if (dicomElement.vr === 'SQ') {\n let item = null;\n for (let l = 0, lenl = dicomElement.value.length; l < lenl; ++l) {\n item = dicomElement.value[l];\n const itemKeys = Object.keys(item);\n if (itemKeys.length === 0) {\n continue;\n }\n\n // get the item element\n const itemTag = getItemTag();\n const itemElement = item['FFFEE000'];\n message = '(Item with';\n if (itemElement.undefinedLength) {\n message += ' undefined';\n } else {\n message += ' explicit';\n }\n message += ' length #=' + (itemKeys.length - 1) + ')';\n itemElement.value = [message];\n itemElement.vr = 'na';\n\n line += '\\n';\n line += getElementAsString(itemTag, itemElement, prefix + ' ');\n\n for (let m = 0, lenm = itemKeys.length; m < lenm; ++m) {\n const itemTag = getTagFromKey(itemKeys[m]);\n if (itemKeys[m] !== 'xFFFEE000') {\n line += '\\n';\n line += getElementAsString(itemTag, item[itemKeys[m]],\n prefix + ' ');\n }\n }\n\n message = '(ItemDelimitationItem';\n if (!itemElement.undefinedLength) {\n message += ' for re-encoding';\n }\n message += ')';\n const itemDelimTag = getItemDelimitationItemTag();\n const itemDelimElement = {\n vr: 'na',\n vl: '0',\n value: [message]\n };\n line += '\\n';\n line += getElementAsString(\n itemDelimTag, itemDelimElement, prefix + ' ');\n\n }\n\n message = '(SequenceDelimitationItem';\n if (!dicomElement.undefinedLength) {\n message += ' for re-encod.';\n }\n message += ')';\n const sqDelimTag = getSequenceDelimitationItemTag();\n const sqDelimElement = {\n vr: 'na',\n vl: '0',\n value: [message]\n };\n line += '\\n';\n line += getElementAsString(sqDelimTag, sqDelimElement, prefix);\n } else if (isPixSequence) {\n // pixel sequence\n let pixItem = null;\n for (let n = 0, lenn = dicomElement.value.length; n < lenn; ++n) {\n pixItem = dicomElement.value[n];\n line += '\\n';\n pixItem.vr = 'pi';\n line += getElementAsString(\n getPixelDataTag(), pixItem, prefix + ' ');\n }\n\n const pixDelimTag = getSequenceDelimitationItemTag();\n const pixDelimElement = {\n vr: 'na',\n vl: '0',\n value: ['(SequenceDelimitationItem)']\n };\n line += '\\n';\n line += getElementAsString(pixDelimTag, pixDelimElement, prefix);\n }\n\n return prefix + line;\n}\n\n/**\n * Extract the 2D size from dicom elements.\n *\n * @param {DataElements} elements The DICOM elements.\n * @returns {number[]} The size.\n */\nexport function getImage2DSize(elements) {\n // rows\n const rows = elements['00280010'];\n if (typeof rows === 'undefined') {\n throw new Error('Missing DICOM image number of rows');\n }\n if (rows.value.length === 0) {\n throw new Error('Empty DICOM image number of rows');\n }\n // columns\n const columns = elements['00280011'];\n if (typeof columns === 'undefined') {\n throw new Error('Missing DICOM image number of columns');\n }\n if (columns.value.length === 0) {\n throw new Error('Empty DICOM image number of columns');\n }\n return [columns.value[0], rows.value[0]];\n}\n\n/**\n * Get the pixel spacing from the different spacing tags.\n *\n * @param {DataElements} elements The DICOM elements.\n * @returns {Spacing} The read spacing or the default [1,1].\n */\nexport function getPixelSpacing(elements) {\n // default\n let rowSpacing = 1;\n let columnSpacing = 1;\n\n // 1. PixelSpacing\n // 2. ImagerPixelSpacing\n // 3. NominalScannedPixelSpacing\n // 4. PixelAspectRatio\n const keys = ['00280030', '00181164', '00182010', '00280034'];\n for (let k = 0; k < keys.length; ++k) {\n const spacing = elements[keys[k]];\n if (spacing && spacing.value.length === 2) {\n // spacing order: [row, column]\n rowSpacing = parseFloat(spacing.value[0]);\n columnSpacing = parseFloat(spacing.value[1]);\n break;\n }\n }\n\n // check\n if (columnSpacing === 0) {\n logger.warn('Zero column spacing.');\n columnSpacing = 1;\n }\n if (rowSpacing === 0) {\n logger.warn('Zero row spacing.');\n rowSpacing = 1;\n }\n\n // return\n // (slice spacing will be calculated using the image position patient)\n return new Spacing([columnSpacing, rowSpacing, 1]);\n}\n\n/**\n * Get the pixel data unit.\n *\n * @param {DataElements} elements The DICOM elements.\n * @returns {string|null} The unit value if available.\n */\nexport function getPixelUnit(elements) {\n let unit;\n // 1. RescaleType\n // 2. Units (for PET)\n const keys = ['00281054', '00541001'];\n for (let i = 0; i < keys.length; ++i) {\n const element = elements[keys[i]];\n if (typeof element !== 'undefined') {\n unit = element.value[0];\n break;\n }\n }\n // default rescale type for CT\n if (typeof unit === 'undefined') {\n const element = elements['00080060'];\n if (typeof element !== 'undefined') {\n const modality = element.value[0];\n if (modality === 'CT') {\n unit = 'HU';\n }\n }\n }\n return unit;\n}\n\n/**\n * Check the dimension organization from a dicom element.\n *\n * @param {DataElements} dataElements The root dicom element.\n * @returns {object} The dimension organizations and indices.\n */\nexport function getDimensionOrganization(dataElements) {\n // Dimension Organization Sequence (required)\n const orgSq = dataElements['00209221'];\n if (typeof orgSq === 'undefined' || orgSq.value.length !== 1) {\n throw new Error('Unsupported dimension organization sequence length');\n }\n // Dimension Organization UID\n const orgUID = orgSq.value[0]['00209164'].value[0];\n\n // Dimension Index Sequence (conditionally required)\n const indices = [];\n const indexSqElem = dataElements['00209222'];\n if (typeof indexSqElem !== 'undefined') {\n const indexSq = indexSqElem.value;\n // expecting 2D index\n if (indexSq.length !== 2) {\n throw new Error('Unsupported dimension index sequence length');\n }\n let indexPointer;\n for (let i = 0; i < indexSq.length; ++i) {\n // Dimension Organization UID (required)\n const indexOrg = indexSq[i]['00209164'].value[0];\n if (indexOrg !== orgUID) {\n throw new Error(\n 'Dimension Index Sequence contains a unknown Dimension Organization');\n }\n // Dimension Index Pointer (required)\n indexPointer = indexSq[i]['00209165'].value[0];\n\n const index = {\n DimensionOrganizationUID: indexOrg,\n DimensionIndexPointer: indexPointer\n };\n // Dimension Description Label (optional)\n if (typeof indexSq[i]['00209421'] !== 'undefined') {\n index.DimensionDescriptionLabel = indexSq[i]['00209421'].value[0];\n }\n // store\n indices.push(index);\n }\n // expecting Image Position at last position\n if (indexPointer !== '(0020,0032)') {\n throw new Error('Unsupported non image position as last index');\n }\n }\n\n return {\n organizations: {\n value: [\n {\n DimensionOrganizationUID: orgUID\n }\n ]\n },\n indices: {\n value: indices\n }\n };\n}\n\n/**\n * Get a spacing object from a dicom measure element.\n *\n * @param {DataElements} dataElements The dicom element.\n * @returns {Spacing} A spacing object.\n */\nexport function getSpacingFromMeasure(dataElements) {\n // Pixel Spacing\n if (typeof dataElements['00280030'] === 'undefined') {\n return null;\n }\n const pixelSpacing = dataElements['00280030'];\n // spacing order: [row, column]\n const spacingValues = [\n parseFloat(pixelSpacing.value[1]),\n parseFloat(pixelSpacing.value[0]),\n ];\n // Spacing Between Slices\n if (typeof dataElements['00180088'] !== 'undefined') {\n spacingValues.push(parseFloat(dataElements['00180088'].value[0]));\n }\n return new Spacing(spacingValues);\n}\n\n/**\n * Get an orientation matrix from a dicom orientation element.\n *\n * @param {DataElements} dataElements The dicom element.\n * @returns {Matrix33|undefined} The orientation matrix.\n */\nexport function getOrientationMatrix(dataElements) {\n const imageOrientationPatient = dataElements['00200037'];\n let orientationMatrix;\n // slice orientation (cosines are matrices' columns)\n // http://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.7.6.2.html#sect_C.7.6.2.1.1\n if (typeof imageOrientationPatient !== 'undefined') {\n orientationMatrix =\n getOrientationFromCosines(\n imageOrientationPatient.value.map((item) => parseFloat(item))\n );\n }\n return orientationMatrix;\n}\n\n/**\n * Get a dicom item from a measure sequence.\n *\n * @param {Spacing} spacing The spacing object.\n * @returns {object} The dicom item.\n */\nexport function getDicomMeasureItem(spacing) {\n return {\n SpacingBetweenSlices: spacing.get(2),\n PixelSpacing: [spacing.get(1), spacing.get(0)]\n };\n}\n\n/**\n * Get a dicom element from a plane orientation sequence.\n *\n * @param {Matrix33} orientation The image orientation.\n * @returns {object} The dicom element.\n */\nexport function getDicomPlaneOrientationItem(orientation) {\n return {\n ImageOrientationPatient: [\n orientation.get(0, 0),\n orientation.get(1, 0),\n orientation.get(2, 0),\n orientation.get(0, 1),\n orientation.get(1, 1),\n orientation.get(2, 1)\n ]\n };\n}\n\n/**\n * Gets the sop class uid from the data elements.\n *\n * @param {object} dataElements The data elements. *.\n * @returns {string | undefined} The sop class uid value.\n */\nexport function getSopClassUid(dataElements) {\n const SOPClassUID = dataElements['00080016'];\n if (typeof SOPClassUID !== 'undefined') {\n return SOPClassUID.value[0];\n }\n return;\n}\n\n/**\n * Check if the received string represents a secondary capture.\n *\n * @param {string} SOPClassUID The sop class uid.\n * @returns {boolean} True if it is secondary capture.\n */\nexport function isSecondatyCapture(SOPClassUID) {\n const pattern = /^1\\.2\\.840\\.10008\\.5\\.1\\.4\\.1\\.1\\.7/;\n return !SOPClassUID && pattern.test(SOPClassUID);\n}\n\n/**\n * Gets the photometric interpretation from the data elements.\n *\n * @param {object} dataElements The data elements.\n * @returns {string | undefined} The photometric interpretation value.\n */\nexport function getPhotometricInterpretation(dataElements) {\n const photometricInterpretation = dataElements['00280004'];\n const syntaxElement = dataElements['00020010'];\n const spp = dataElements['00280002'];\n // samplesPerPixel\n let samplesPerPixel = 1;\n if (typeof spp !== 'undefined') {\n samplesPerPixel = spp.value[0];\n }\n\n if (typeof photometricInterpretation !== 'undefined' &&\n typeof syntaxElement !== 'undefined') {\n let photo = photometricInterpretation.value[0].toUpperCase();\n // TransferSyntaxUID\n const syntax = syntaxElement.value[0];\n const jpeg2000 = isJpeg2000TransferSyntax(syntax);\n const jpegBase = isJpegBaselineTransferSyntax(syntax);\n const jpegLoss = isJpegLosslessTransferSyntax(syntax);\n // jpeg decoders output RGB data\n if ((jpeg2000 || jpegBase || jpegLoss) &&\n (photo !== 'MONOCHROME1' && photo !== 'MONOCHROME2')) {\n photo = 'RGB';\n }\n // check samples per pixels\n if (photo === 'RGB' && samplesPerPixel === 1) {\n photo = 'PALETTE COLOR';\n }\n return photo;\n }\n}\n\n/**\n * Check if the received string is monochrome.\n *\n * @param {string} photometricInterpretation The photometric interpretation.\n * @returns {boolean} True if it is monochrome.\n */\nexport function isMonochrome(photometricInterpretation) {\n return !photometricInterpretation && photometricInterpretation.match(/MONOCHROME/) !== null;\n}\n\n\n/**\n * Check an input tag.\n *\n * @param {object} element The element to check.\n * @param {string} name The element name.\n * @param {Array} [values] The expected values.\n * @returns {string} A warning if the element is not as expected.\n */\nfunction checkTag(element, name, values) {\n let warning = '';\n if (typeof element === 'undefined') {\n warning += ' ' + name + ' is undefined,';\n } else if (element.value.length === 0) {\n warning += ' ' + name + ' is empty,';\n } else {\n if (typeof values !== 'undefined') {\n for (let i = 0; i < values.length; ++i) {\n\n if (!element.value.includes(values[i])) {\n warning += ' ' + name + ' does not contain ' + values[i] +\n ' (value: ' + element.value + '),';\n }\n }\n }\n }\n return warning;\n}\n\n/**\n * Get the decayed dose (Bq).\n *\n * @param {object} elements The DICOM elements to check.\n * @returns {object} The value and a warning if\n * the elements are not as expected.\n */\nfunction getDecayedDose(elements) {\n let warning = '';\n let warn;\n\n // SeriesDate (type1)\n const seriesDateEl = elements['00080021'];\n const seriesDateObj = getDate(seriesDateEl);\n\n let totalDose;\n let halfLife;\n let radioStart;\n\n const radioInfoSqStr = 'RadiopharmaceuticalInformationSequence (00540016)';\n const radioInfoSq = elements['00540016'];\n warning += checkTag(radioInfoSq, radioInfoSqStr);\n if (typeof radioInfoSq !== 'undefined') {\n if (radioInfoSq.value.length !== 1) {\n logger.warn(\n 'Found more than 1 istopes in RadiopharmaceuticalInformation Sequence.'\n );\n }\n\n // RadionuclideTotalDose (type3, Bq)\n const totalDoseStr = 'RadionuclideTotalDose (00181074)';\n const totalDoseEl = radioInfoSq.value[0]['00181074'];\n warn = checkTag(totalDoseEl, totalDoseStr);\n if (warn.length === 0) {\n const dose = parseFloat(totalDoseEl.value[0]);\n if (!isNaN(dose)) {\n totalDose = dose;\n } else {\n warning += ' TotalDose is not a number';\n }\n } else {\n warning += warn;\n }\n\n // RadionuclideHalfLife (type3, seconds)\n const halfLifeStr = 'RadionuclideHalfLife (00181075)';\n const halfLifeEl = radioInfoSq.value[0]['00181075'];\n warn = checkTag(halfLifeEl, halfLifeStr);\n if (warn.length === 0) {\n const hl = parseFloat(halfLifeEl.value[0]);\n if (!isNaN(hl)) {\n halfLife = hl;\n } else {\n warning += ' HalfLife is not a number';\n }\n } else {\n warning += warn;\n }\n\n // RadiopharmaceuticalStartDateTime (type3)\n const radioStartDateTimeEl = radioInfoSq.value[0]['00181078'];\n let radioStartDateObj;\n let radioStartTimeObj;\n if (typeof radioStartDateTimeEl === 'undefined') {\n // use seriesDate as radioStartDate\n radioStartDateObj = seriesDateObj;\n // try RadiopharmaceuticalStartTime (type3)\n const radioStartTimeEl = radioInfoSq.value[0]['00181072'];\n radioStartTimeObj = getTime(radioStartTimeEl);\n } else {\n const radioStartDateTime = getDateTime(radioStartDateTimeEl);\n radioStartDateObj = radioStartDateTime.date;\n radioStartTimeObj = radioStartDateTime.time;\n }\n if (typeof radioStartTimeObj === 'undefined') {\n radioStartTimeObj = {\n hours: 0, minutes: 0, seconds: 0, milliseconds: 0\n };\n }\n radioStart = new Date(\n radioStartDateObj.year,\n radioStartDateObj.monthIndex,\n radioStartDateObj.day,\n radioStartTimeObj.hours,\n radioStartTimeObj.minutes,\n radioStartTimeObj.seconds,\n radioStartTimeObj.milliseconds\n );\n }\n\n // SeriesTime (type1)\n const seriesTimeEl = elements['00080031'];\n const seriesTimeObj = getTime(seriesTimeEl);\n // Series date/time\n let scanStart = new Date(\n seriesDateObj.year,\n seriesDateObj.monthIndex,\n seriesDateObj.day,\n seriesTimeObj.hours,\n seriesTimeObj.minutes,\n seriesTimeObj.seconds,\n seriesTimeObj.milliseconds\n );\n\n // scanStart Date check\n // AcquisitionDate (type3)\n const acqDateEl = elements['00080022'];\n // AcquisitionTime (type3)\n const acqTimeEl = elements['00080032'];\n if (typeof acqDateEl !== 'undefined' &&\n typeof acqTimeEl !== 'undefined') {\n const acqDateObj = getDate(acqDateEl);\n const acqTimeObj = getTime(acqTimeEl);\n const acqDate = new Date(\n acqDateObj.year,\n acqDateObj.monthIndex,\n acqDateObj.day,\n acqTimeObj.hours,\n acqTimeObj.minutes,\n acqTimeObj.seconds,\n acqTimeObj.milliseconds\n );\n\n if (scanStart > acqDate) {\n const diff = scanStart.getTime() - acqDate.getTime();\n const warn = 'Series date/time is after Aquisition date/time (diff=' +\n diff.toString() + 'ms) ';\n logger.debug(warn);\n\n // back compute from center (average count rate) of time window\n // for bed position (frame) in series (reliable in all cases)\n\n let frameRefTime = 0;\n const frameRefTimeElStr = 'FrameReferenceTime (00541300)';\n const frameRefTimeEl = elements['00541300'];\n warning += checkTag(frameRefTimeEl, frameRefTimeElStr);\n if (typeof frameRefTimeEl !== 'undefined') {\n frameRefTime = frameRefTimeEl.value[0];\n }\n let actualFrameDuration = 0;\n const actualFrameDurationElStr = 'ActualFrameDuration (0018,1242)';\n const actualFrameDurationEl = elements['00181242'];\n warning += checkTag(actualFrameDurationEl, actualFrameDurationElStr);\n if (typeof actualFrameDurationEl !== 'undefined') {\n actualFrameDuration = actualFrameDurationEl.value[0];\n }\n if (frameRefTime > 0 && actualFrameDuration > 0) {\n // convert to seconds\n actualFrameDuration = actualFrameDuration / 1000;\n frameRefTime = frameRefTime / 1000;\n const decayConstant = Math.log(2) / halfLife;\n const decayDuringFrame = decayConstant * actualFrameDuration;\n const averageCountRateTimeWithinFrame =\n 1 /\n decayConstant *\n Math.log(decayDuringFrame / (1 - Math.exp(-decayDuringFrame)));\n const offsetSeconds = averageCountRateTimeWithinFrame - frameRefTime;\n scanStart = new Date(\n acqDateObj.year,\n acqDateObj.monthIndex,\n acqDateObj.day,\n acqTimeObj.hours,\n acqTimeObj.minutes,\n acqTimeObj.seconds + offsetSeconds,\n acqTimeObj.milliseconds\n );\n }\n }\n }\n\n // decayed dose (Bq)\n let decayedDose;\n if (typeof scanStart !== 'undefined' &&\n typeof radioStart !== 'undefined' &&\n typeof totalDose !== 'undefined' &&\n typeof halfLife !== 'undefined') {\n // decay time (s) (Date diff is in milliseconds)\n const decayTime = (scanStart.getTime() - radioStart.getTime()) / 1000;\n const decay = Math.pow(2, (-decayTime / halfLife));\n decayedDose = totalDose * decay;\n }\n\n return {\n value: decayedDose,\n warning: warning\n };\n}\n\n/**\n * Get the PET SUV factor.\n *\n * Ref:\n * - {@link https://qibawiki.rsna.org/index.php/Standardized_Uptake_Value_(SUV)#SUV_Calculation},\n * - {@link https://qibawiki.rsna.org/images/6/62/SUV_vendorneutral_pseudocode_happypathonly_20180626_DAC.pdf},\n * - {@link https://qibawiki.rsna.org/images/8/86/SUV_vendorneutral_pseudocode_20180626_DAC.pdf}.\n *\n * @param {object} elements The DICOM elements.\n * @returns {object} The value and a warning if\n * the elements are not as expected.\n */\nexport function getSuvFactor(elements) {\n let warning = '';\n const result = {};\n\n\n // CorrectedImage (type2): must contain ATTN and DECY\n const corrImageTagStr = 'Corrected Image (00280051)';\n const corrImageEl = elements['00280051'];\n warning += checkTag(corrImageEl, corrImageTagStr, ['ATTN', 'DECY']);\n // DecayCorrection (type1): must be START\n const decayCorrTagStr = 'Decay Correction (00541102)';\n const decayCorrEl = elements['00541102'];\n warning += checkTag(decayCorrEl, decayCorrTagStr, ['START']);\n // Units (type1): must be BQML\n const unitTagStr = 'Units (00541001)';\n const unitEl = elements['00541001'];\n warning += checkTag(unitEl, unitTagStr, ['BQML']);\n\n // PatientWeight (type3, kg)\n let patWeight;\n const patientWeightStr = ' PatientWeight (00101030)';\n const patWeightEl = elements['00101030'];\n const warn = checkTag(patWeightEl, patientWeightStr);\n if (warn.length === 0) {\n const weight = parseFloat(patWeightEl.value[0]);\n if (!isNaN(weight)) {\n patWeight = weight;\n } else {\n warning += ' PatientWeight is not a number';\n }\n } else {\n warning += warn;\n }\n\n // Decayed dose (Bq)\n const decayedDose = getDecayedDose(elements);\n warning += decayedDose.warning;\n\n\n if (warning.length !== 0) {\n result.warning = 'Cannot calculate PET SUV:' + warning;\n } else {\n // SUV factor (grams/Bq)\n result.value = (patWeight * 1000) / decayedDose.value;\n }\n\n return result;\n}\n\n\n/**\n * Get the file list from a DICOMDIR.\n *\n * @param {object} data The buffer data of the DICOMDIR.\n * @returns {Array|undefined} The file list as an array ordered by\n * STUDY > SERIES > IMAGES.\n */\nexport function getFileListFromDicomDir(data) {\n // parse file\n const parser = new DicomParser();\n parser.parse(data);\n const elements = parser.getDicomElements();\n\n // Directory Record Sequence\n if (typeof elements['00041220'] === 'undefined' ||\n typeof elements['00041220'].value === 'undefined') {\n logger.warn('No Directory Record Sequence found in DICOMDIR.');\n return undefined;\n }\n const dirSeq = elements['00041220'].value;\n\n if (dirSeq.length === 0) {\n logger.warn('The Directory Record Sequence of the DICOMDIR is empty.');\n return undefined;\n }\n\n const records = [];\n let series = null;\n let study = null;\n for (let i = 0; i < dirSeq.length; ++i) {\n // Directory Record Type\n if (typeof dirSeq[i]['00041430'] === 'undefined' ||\n typeof dirSeq[i]['00041430'].value === 'undefined') {\n continue;\n }\n const recType = dirSeq[i]['00041430'].value[0];\n\n // supposed to come in order...\n if (recType === 'STUDY') {\n study = [];\n records.push(study);\n } else if (recType === 'SERIES') {\n series = [];\n study.push(series);\n } else if (recType === 'IMAGE') {\n // Referenced File ID\n if (typeof dirSeq[i]['00041500'] === 'undefined' ||\n typeof dirSeq[i]['00041500'].value === 'undefined') {\n continue;\n }\n const refFileIds = dirSeq[i]['00041500'].value;\n // join ids\n series.push(refFileIds.join('/'));\n }\n }\n return records;\n}\n\n/**\n * Methods used to extract values from DICOM elements.\n *\n * Implemented as class and method to allow for override via its prototype.\n */\nexport class TagValueExtractor {\n /**\n * Get the time.\n *\n * @param {Object} _elements The DICOM elements.\n * @returns {number|undefined} The time value if available.\n */\n getTime(_elements) {\n // default returns undefined\n return undefined;\n }\n}\n","import {Size} from './size';\nimport {Geometry} from './geometry';\nimport {RescaleSlopeAndIntercept} from './rsi';\nimport {WindowLevel} from './windowLevel';\nimport {Image} from './image';\nimport {ColourMap} from './luts';\nimport {\n isJpeg2000TransferSyntax,\n isJpegBaselineTransferSyntax,\n isJpegLosslessTransferSyntax\n} from '../dicom/dicomParser';\nimport {\n getImage2DSize,\n getPixelSpacing,\n getPixelUnit,\n TagValueExtractor,\n getSuvFactor,\n getOrientationMatrix,\n isSecondatyCapture,\n getPhotometricInterpretation,\n getSopClassUid,\n isMonochrome\n} from '../dicom/dicomElementsWrapper';\nimport {Point3D} from '../math/point';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * @typedef {Object} DataElements\n */\n\n/**\n * {@link Image} factory.\n */\nexport class ImageFactory {\n\n /**\n * Possible warning created by checkElements.\n *\n * @type {string|undefined}\n */\n #warning;\n\n /**\n * The PET SUV factor.\n *\n * @type {number|undefined}\n */\n #suvFactor;\n\n /**\n * Get a warning string if elements are not as expected.\n * Created by checkElements.\n *\n * @returns {string|undefined} The warning.\n */\n getWarning() {\n return this.#warning;\n }\n\n /**\n * Check dicom elements. Throws an error if not suitable.\n *\n * @param {DataElements} dataElements The DICOM data elements.\n * @returns {string|undefined} A possible warning.\n */\n checkElements(dataElements) {\n // reset\n this.#warning = undefined;\n // will throw if columns or rows is not defined\n getImage2DSize(dataElements);\n // check PET SUV\n let modality;\n const element = dataElements['00080060'];\n if (typeof element !== 'undefined') {\n modality = element.value[0];\n\n if (modality === 'PT') {\n const photometricInterpretation =\n getPhotometricInterpretation(dataElements);\n const SOPClassUID = getSopClassUid(dataElements);\n if (isSecondatyCapture(SOPClassUID) ||\n !isMonochrome(photometricInterpretation)) {\n return this.#warning;\n }\n const suvFactor = getSuvFactor(dataElements);\n this.#suvFactor = suvFactor.value;\n this.#warning = suvFactor.warning;\n }\n }\n\n return this.#warning;\n }\n\n /**\n * Get an {@link Image} object from the read DICOM file.\n *\n * @param {DataElements} dataElements The DICOM tags.\n * @param {Uint8Array | Int8Array |\n * Uint16Array | Int16Array |\n * Uint32Array | Int32Array} pixelBuffer The pixel buffer.\n * @param {number} numberOfFiles The input number of files.\n * @returns {Image} A new Image.\n */\n create(dataElements, pixelBuffer, numberOfFiles) {\n const size2D = getImage2DSize(dataElements);\n const sizeValues = [size2D[0], size2D[1], 1];\n\n // NumberOfFrames\n const numberOfFramesEl = dataElements['00280008'];\n if (typeof numberOfFramesEl !== 'undefined') {\n const number = parseInt(numberOfFramesEl.value[0], 10);\n if (number > 1) {\n sizeValues.push(number);\n }\n }\n\n // image size\n const size = new Size(sizeValues);\n\n // image spacing\n const spacing = getPixelSpacing(dataElements);\n\n // TransferSyntaxUID\n const syntax = dataElements['00020010'].value[0];\n const jpeg2000 = isJpeg2000TransferSyntax(syntax);\n const jpegBase = isJpegBaselineTransferSyntax(syntax);\n const jpegLoss = isJpegLosslessTransferSyntax(syntax);\n\n // ImagePositionPatient\n const imagePositionPatient = dataElements['00200032'];\n // slice position\n let slicePosition = new Array(0, 0, 0);\n if (typeof imagePositionPatient !== 'undefined') {\n slicePosition = [\n parseFloat(imagePositionPatient.value[0]),\n parseFloat(imagePositionPatient.value[1]),\n parseFloat(imagePositionPatient.value[2])\n ];\n }\n\n // Image orientation patient\n const orientationMatrix = getOrientationMatrix(dataElements);\n\n // geometry\n const origin = new Point3D(\n slicePosition[0], slicePosition[1], slicePosition[2]);\n const extractor = new TagValueExtractor();\n const time = extractor.getTime(dataElements);\n const geometry = new Geometry(\n origin, size, spacing, orientationMatrix, time);\n\n // SOP Instance UID\n let sopInstanceUid;\n const siu = dataElements['00080018'];\n if (typeof siu !== 'undefined') {\n sopInstanceUid = siu.value[0];\n }\n\n // Sample per pixels\n let samplesPerPixel = 1;\n const spp = dataElements['00280002'];\n if (typeof spp !== 'undefined') {\n samplesPerPixel = spp.value[0];\n }\n\n // check buffer size\n const bufferSize = size.getTotalSize() * samplesPerPixel;\n if (bufferSize !== pixelBuffer.length) {\n logger.warn('Badly sized pixel buffer: ' +\n pixelBuffer.length + ' != ' + bufferSize);\n if (bufferSize < pixelBuffer.length) {\n pixelBuffer = pixelBuffer.slice(0, size.getTotalSize());\n } else {\n throw new Error('Underestimated buffer size, can\\'t fix it...');\n }\n }\n\n // image\n const image = new Image(geometry, pixelBuffer, [sopInstanceUid]);\n // PhotometricInterpretation\n const photometricInterpretation = dataElements['00280004'];\n if (typeof photometricInterpretation !== 'undefined') {\n let photo = photometricInterpretation.value[0].toUpperCase();\n // jpeg decoders output RGB data\n if ((jpeg2000 || jpegBase || jpegLoss) &&\n (photo !== 'MONOCHROME1' && photo !== 'MONOCHROME2')) {\n photo = 'RGB';\n }\n // check samples per pixels\n if (photo === 'RGB' && samplesPerPixel === 1) {\n photo = 'PALETTE COLOR';\n }\n image.setPhotometricInterpretation(photo);\n }\n // PlanarConfiguration\n const planarConfiguration = dataElements['00280006'];\n if (typeof planarConfiguration !== 'undefined') {\n image.setPlanarConfiguration(planarConfiguration.value[0]);\n }\n\n // rescale slope and intercept\n let slope = 1;\n // RescaleSlope\n const rescaleSlope = dataElements['00281053'];\n if (typeof rescaleSlope !== 'undefined') {\n const value = parseFloat(rescaleSlope.value[0]);\n if (!isNaN(value)) {\n slope = value;\n }\n }\n let intercept = 0;\n // RescaleIntercept\n const rescaleIntercept = dataElements['00281052'];\n if (typeof rescaleIntercept !== 'undefined') {\n const value = parseFloat(rescaleIntercept.value[0]);\n if (!isNaN(value)) {\n intercept = value;\n }\n }\n\n // meta information\n const meta = {\n numberOfFiles: numberOfFiles\n };\n\n // Modality\n const modality = dataElements['00080060'];\n if (typeof modality !== 'undefined') {\n meta.Modality = modality.value[0];\n }\n\n // PET SUV\n let isPetWithSuv = false;\n let intensityFactor = 1;\n if (typeof this.#suvFactor !== 'undefined') {\n isPetWithSuv = true;\n intensityFactor = this.#suvFactor;\n logger.info('Applying PET SUV calibration: ' + intensityFactor);\n slope *= intensityFactor;\n intercept *= intensityFactor;\n }\n const rsi = new RescaleSlopeAndIntercept(slope, intercept);\n image.setRescaleSlopeAndIntercept(rsi);\n\n const safeGet = function (key) {\n let res;\n const element = dataElements[key];\n if (typeof element !== 'undefined') {\n res = element.value[0];\n }\n return res;\n };\n\n // defaults\n meta.TransferSyntaxUID = safeGet('00020010');\n meta.MediaStorageSOPClassUID = safeGet('00020002');\n meta.SOPClassUID = safeGet('00080016');\n meta.Modality = safeGet('00080060');\n meta.ImageType = safeGet('00080008');\n meta.SamplesPerPixel = safeGet('00280002');\n meta.PhotometricInterpretation = safeGet('00280004');\n meta.PixelRepresentation = safeGet('00280103');\n meta.BitsAllocated = safeGet('00280100');\n meta.BitsStored = safeGet('00280101');\n meta.HighBit = safeGet('00280102');\n\n // Study\n meta.StudyDate = safeGet('00080020');\n meta.StudyTime = safeGet('00080030');\n meta.StudyInstanceUID = safeGet('0020000D');\n meta.StudyID = safeGet('00200010');\n // Series\n meta.SeriesInstanceUID = safeGet('0020000E');\n meta.SeriesNumber = safeGet('00200011');\n // ReferringPhysicianName\n meta.ReferringPhysicianName = safeGet('00080090');\n // patient info\n meta.PatientName = safeGet('00100010');\n meta.PatientID = safeGet('00100020');\n meta.PatientBirthDate = safeGet('00100030');\n meta.PatientSex = safeGet('00100040');\n // General Equipment Module\n meta.Manufacturer = safeGet('00080070');\n meta.ManufacturerModelName = safeGet('00081090');\n meta.DeviceSerialNumber = safeGet('00181000');\n meta.SoftwareVersions = safeGet('00181020');\n\n meta.ImageOrientationPatient = safeGet('00200037');\n meta.FrameOfReferenceUID = safeGet('00200052');\n\n // PixelRepresentation -> is signed\n meta.IsSigned = meta.PixelRepresentation === 1;\n // local pixel unit\n if (isPetWithSuv) {\n meta.pixelUnit = 'SUV';\n } else {\n const pixelUnit = getPixelUnit(dataElements);\n if (typeof pixelUnit !== 'undefined') {\n meta.pixelUnit = pixelUnit;\n }\n }\n // window level presets\n const windowPresets = {};\n const windowCenter = dataElements['00281050'];\n const windowWidth = dataElements['00281051'];\n const windowCWExplanation = dataElements['00281055'];\n if (typeof windowCenter !== 'undefined' &&\n typeof windowWidth !== 'undefined') {\n let name;\n for (let j = 0; j < windowCenter.value.length; ++j) {\n const center = parseFloat(windowCenter.value[j]);\n let width = parseFloat(windowWidth.value[j]);\n if (center && width && width !== 0) {\n name = '';\n if (typeof windowCWExplanation !== 'undefined') {\n name = windowCWExplanation.value[j];\n }\n if (name === '') {\n name = 'Default' + j;\n }\n width *= intensityFactor;\n if (width < 1) {\n width = 1;\n }\n windowPresets[name] = {\n wl: [new WindowLevel(\n center * intensityFactor,\n width\n )],\n name: name\n };\n }\n if (width === 0) {\n logger.warn('Zero window width found in DICOM.');\n }\n }\n }\n meta.windowPresets = windowPresets;\n\n // PALETTE COLOR luts\n if (image.getPhotometricInterpretation() === 'PALETTE COLOR') {\n // Red Palette Color Lookup Table Data\n const redLutElement = dataElements['00281201'];\n // Green Palette Color Lookup Table Data\n const greenLutElement = dataElements['00281202'];\n // Blue Palette Color Lookup Table Data\n const blueLutElement = dataElements['00281203'];\n let redLut;\n let greenLut;\n let blueLut;\n // check red palette descriptor (should all be equal)\n // Red Palette Color Lookup Table Descriptor\n // 0: number of entries in the lookup table\n // 1: first input value mapped\n // 2: number of bits for each entry in the Lookup Table Data (8 or 16)\n const descriptor = dataElements['00281101'];\n if (typeof descriptor !== 'undefined' &&\n descriptor.value.length === 3) {\n if (descriptor.value[2] === 16) {\n let doScale = false;\n // (C.7.6.3.1.5 Palette Color Lookup Table Descriptor)\n // Some implementations have encoded 8 bit entries with 16 bits\n // allocated, padding the high bits;\n let descSize = descriptor.value[0];\n // (C.7.6.3.1.5 Palette Color Lookup Table Descriptor)\n // The first Palette Color Lookup Table Descriptor value is the\n // number of entries in the lookup table. When the number of table\n // entries is equal to 216 then this value shall be 0.\n if (descSize === 0) {\n descSize = 65536;\n }\n // red palette VL\n // TODO vl is undefined, find info elsewhere...\n const vlSize = redLutElement.vl;\n // check double size\n if (vlSize !== 2 * descSize) {\n doScale = true;\n logger.info('16bits lut but size is not double. desc: ' +\n descSize + ' vl: ' + vlSize);\n }\n // (C.7.6.3.1.6 Palette Color Lookup Table Data)\n // Palette color values must always be scaled across the full\n // range of available intensities\n const bitsAllocated = parseInt(\n dataElements['00280100'].value[0], 10);\n if (bitsAllocated === 8) {\n doScale = true;\n logger.info(\n 'Scaling 16bits color lut since bits allocated is 8.');\n }\n\n if (doScale) {\n const scaleTo8 = function (value) {\n return value >> 8;\n };\n\n redLut = redLutElement.value.map(scaleTo8);\n greenLut = greenLutElement.value.map(scaleTo8);\n blueLut = blueLutElement.value.map(scaleTo8);\n }\n } else if (descriptor.value[2] === 8) {\n // lut with vr=OW was read as Uint16, convert it to Uint8\n logger.info(\n 'Scaling 16bits color lut since the lut descriptor is 8.');\n let clone = redLutElement.value.slice(0);\n // @ts-expect-error\n redLut = Array.from(new Uint8Array(clone.buffer));\n clone = greenLutElement.value.slice(0);\n // @ts-expect-error\n greenLut = Array.from(new Uint8Array(clone.buffer));\n clone = blueLutElement.value.slice(0);\n // @ts-expect-error\n blueLut = Array.from(new Uint8Array(clone.buffer));\n }\n }\n // set the palette\n image.setPaletteColourMap(new ColourMap(redLut, greenLut, blueLut));\n }\n\n // RecommendedDisplayFrameRate\n const recommendedDisplayFrameRate = dataElements['00082144'];\n if (typeof recommendedDisplayFrameRate !== 'undefined') {\n meta.RecommendedDisplayFrameRate = parseInt(\n recommendedDisplayFrameRate.value[0], 10);\n }\n\n // store the meta data\n image.setMeta(meta);\n\n return image;\n }\n\n}","/**\n * Data writer.\n */\nexport class DataWriter {\n\n /**\n * Is the endianness Little Endian.\n *\n * @type {boolean}\n */\n #isLittleEndian = true;\n\n /**\n * The main data view.\n *\n * @type {DataView}\n */\n #view;\n\n /**\n * @param {ArrayBuffer} buffer The input array buffer.\n * @param {boolean} [isLittleEndian] Flag to tell if the data is\n * little or big endian.\n */\n constructor(buffer, isLittleEndian) {\n // Set endian flag if not defined.\n if (typeof isLittleEndian !== 'undefined') {\n this.#isLittleEndian = isLittleEndian;\n }\n this.#view = new DataView(buffer);\n }\n\n /**\n * Write Uint8 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeUint8(byteOffset, value) {\n this.#view.setUint8(byteOffset, value);\n return byteOffset + Uint8Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Int8 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeInt8(byteOffset, value) {\n this.#view.setInt8(byteOffset, value);\n return byteOffset + Int8Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Uint16 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeUint16(byteOffset, value) {\n this.#view.setUint16(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Uint16Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Int16 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeInt16(byteOffset, value) {\n this.#view.setInt16(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Int16Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Uint32 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeUint32(byteOffset, value) {\n this.#view.setUint32(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Uint32Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Uint64 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {bigint} value The data to write.\n * @returns {number} The new offset position.\n */\n writeUint64(byteOffset, value) {\n this.#view.setBigUint64(byteOffset, value, this.#isLittleEndian);\n return byteOffset + BigUint64Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Int32 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeInt32(byteOffset, value) {\n this.#view.setInt32(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Int32Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Int64 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {bigint} value The data to write.\n * @returns {number} The new offset position.\n */\n writeInt64(byteOffset, value) {\n this.#view.setBigInt64(byteOffset, value, this.#isLittleEndian);\n return byteOffset + BigInt64Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Float32 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeFloat32(byteOffset, value) {\n this.#view.setFloat32(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Float32Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Float64 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeFloat64(byteOffset, value) {\n this.#view.setFloat64(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Float64Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write string data of length 4 as hexadecimal (no '0x' prefix).\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {string} str The hexadecimal string to write ('####').\n * @returns {number} The new offset position.\n */\n writeHex(byteOffset, str) {\n // remove first two chars and parse\n const value = parseInt(str, 16);\n this.#view.setUint16(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Uint16Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write a boolean array as binary.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeBinaryArray(byteOffset, array) {\n if (array.length % 8 !== 0) {\n throw new Error('Cannot write boolean array as binary.');\n }\n let byte = null;\n let val = null;\n for (let i = 0, len = array.length; i < len; i += 8) {\n byte = 0;\n for (let j = 0; j < 8; ++j) {\n val = array[i + j] === 0 ? 0 : 1;\n byte += val << j;\n }\n byteOffset = this.writeUint8(byteOffset, byte);\n }\n return byteOffset;\n }\n\n /**\n * Write Uint8 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array|Uint8Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeUint8Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeUint8(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Int8 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeInt8Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeInt8(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Uint16 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeUint16Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeUint16(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Int16 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeInt16Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeInt16(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Uint32 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeUint32Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeUint32(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Uint64 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeUint64Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeUint64(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Int32 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeInt32Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeInt32(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Int64 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeInt64Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeInt64(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Float32 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeFloat32Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeFloat32(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Float64 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeFloat64Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeFloat64(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n} // class DataWriter\n","import {\n is32bitVLVR,\n isCharSetStringVR,\n vrTypes\n} from './dictionary';\nimport {\n Tag,\n getTagFromDictionary,\n getTagFromKey,\n getItemTag,\n getItemDelimitationItemTag,\n getSequenceDelimitationItemTag,\n getFileMetaInformationGroupLengthTag,\n isPixelDataTag,\n isItemTag,\n isItemDelimitationItemTag,\n tagCompareFunction\n} from './dicomTag';\nimport {\n getDwvVersion,\n isImplicitTransferSyntax,\n isBigEndianTransferSyntax,\n getDataElementPrefixByteSize\n} from './dicomParser';\nimport {DataElement} from './dataElement';\nimport {DataWriter} from './dataWriter';\nimport {DataReader} from './dataReader';\nimport {logger} from '../utils/logger';\n\n/**\n * Get the dwv UID prefix.\n * Issued by Medical Connections Ltd (www.medicalconnections.co.uk)\n * on 25/10/2017.\n *\n * @returns {string} The dwv UID prefix.\n */\nfunction getDwvUIDPrefix() {\n return '1.2.826.0.1.3680043.9.7278.1';\n}\n\n// local generated uid counter\nlet _uidCount = 0;\n\n/**\n * Writer rule.\n */\nexport class WriterRule {\n /**\n * Rule action: `copy`, `remove`, `clear` or `replace`.\n *\n * @type {string}\n */\n action;\n /**\n * Optional value to use for replace action.\n *\n * @type {any|undefined}\n */\n value;\n\n /**\n * @param {string} action The rule action.\n */\n constructor(action) {\n this.action = action;\n }\n}\n\n/**\n * Possible writer actions.\n *\n * @type {Object}\n */\nconst writerActions = {\n copy: function (item) {\n return item;\n },\n remove: function () {\n return null;\n },\n clear: function (item) {\n item.value = [];\n return item;\n },\n replace: function (item, value) {\n item.value = [value];\n return item;\n }\n};\n\n/**\n * Get simple (non official) DICOM anonymisation rules.\n *\n * @returns {Object} The rules.\n */\nexport function getDefaultAnonymisationRules() {\n return {\n default: {action: 'copy', value: null},\n PatientName: {action: 'replace', value: 'Anonymized'}, // tag\n 'Meta Element': {action: 'copy', value: null}, // group '0002'\n Acquisition: {action: 'copy', value: null}, // group '0018'\n 'Image Presentation': {action: 'copy', value: null}, // group '0028'\n Procedure: {action: 'copy', value: null}, // group '0040'\n 'Pixel Data': {action: 'copy', value: null} // group '7fe0'\n };\n}\n\n/**\n * Get a UID for a DICOM tag.\n *\n * Note: Use {@link https://github.com/uuidjs/uuid}?\n *\n * Ref:\n * - {@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/chapter_9.html},\n * - {@link http://dicomiseasy.blogspot.com/2011/12/chapter-4-dicom-objects-in-chapter-3.html},\n * - {@link https://stackoverflow.com/questions/46304306/how-to-generate-unique-dicom-uid}.\n *\n * @param {string} tagName The input tag.\n * @returns {string} The corresponding UID.\n */\nexport function getUID(tagName) {\n const prefix = getDwvUIDPrefix() + '.';\n let uid = '';\n if (tagName === 'ImplementationClassUID') {\n uid = prefix + getDwvVersion();\n } else {\n // date (only numbers), do not keep milliseconds\n const date = (new Date()).toISOString().replace(/\\D/g, '');\n const datePart = '.' + date.substring(0, 14);\n // count\n _uidCount += 1;\n const countPart = '.' + _uidCount;\n\n // uid = prefix . tag . date . count\n uid = prefix;\n\n // limit tag part to not exceed 64 length\n const nonTagLength = prefix.length + countPart.length + datePart.length;\n const leni = Math.min(tagName.length, 64 - nonTagLength);\n if (leni > 1) {\n let tagNumber = '';\n for (let i = 0; i < leni; ++i) {\n tagNumber += tagName.charCodeAt(i);\n }\n uid += tagNumber.substring(0, leni);\n }\n\n // finish\n uid += datePart + countPart;\n }\n return uid;\n}\n\n/**\n * Return true if the input number is even.\n *\n * @param {number} number The number to check.\n * @returns {boolean} True is the number is even.\n */\nfunction isEven(number) {\n return number % 2 === 0;\n}\n\n/**\n * Is the input VR a VR that stores data in a typed array.\n * TODO: include ox and xs?\n *\n * @param {string} vr The element VR.\n * @returns {boolean} True if the VR is a typed array one.\n */\nfunction isTypedArrayVr(vr) {\n const vrType = vrTypes[vr];\n return typeof vrType !== 'undefined' &&\n vrType !== 'string';\n}\n\n/**\n * Is the input VR a string VR.\n *\n * @param {string} vr The element VR.\n * @returns {boolean} True if the VR is a string one.\n */\nfunction isStringVr(vr) {\n const vrType = vrTypes[vr];\n return typeof vrType !== 'undefined' &&\n vrType === 'string';\n}\n\n/**\n * Is the input VR a VR that could need padding.\n *\n * See {@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_6.2.html}.\n *\n * @param {string} vr The element VR.\n * @returns {boolean} True if the VR needs padding.\n */\nfunction isVrToPad(vr) {\n return isStringVr(vr) || vr === 'OB';\n}\n\n/**\n * Get the VR specific padding value.\n *\n * @param {string} vr The element VR.\n * @returns {string} The value used to pad.\n */\nfunction getVrPad(vr) {\n let pad = '';\n if (isStringVr(vr)) {\n if (vr === 'UI') {\n pad = '\\0';\n } else {\n pad = ' ';\n }\n }\n return pad;\n}\n\n/**\n * Push a value at the end of an input Uint8Array.\n *\n * @param {Array|Uint8Array} arr The input array.\n * @param {Array|Uint8Array} value The value to push.\n * @returns {Uint8Array} The new array.\n */\nfunction uint8ArrayPush(arr, value) {\n const newArr = new Uint8Array(arr.length + 1);\n newArr.set(arr);\n newArr.set(value, arr.length);\n return newArr;\n}\n\n/**\n * Pad an input OB value.\n *\n * @param {Array|Uint8Array} value The input value.\n * @returns {Array|Uint8Array} The padded input.\n */\nfunction padOBValue(value) {\n if (value !== null &&\n typeof value !== 'undefined' &&\n typeof value.length !== 'undefined') {\n // calculate size and pad if needed\n if (value.length !== 0 &&\n typeof value[0].length !== 'undefined') {\n // handle array of array\n let size = 0;\n for (let i = 0; i < value.length; ++i) {\n size += value[i].length;\n }\n if (!isEven(size)) {\n value[value.length - 1] = uint8ArrayPush(\n value[value.length - 1], [0]);\n }\n } else {\n if (!isEven(value.length)) {\n value = uint8ArrayPush(value, [0]);\n }\n }\n } else {\n throw new Error('Cannot pad undefined or null OB value.');\n }\n // uint8ArrayPush may create a new array so we\n // need to return it\n return value;\n}\n\n/**\n * Helper method to flatten an array of typed arrays to 2D typed array.\n *\n * @param {Array} initialArray Array of typed arrays.\n * @returns {object} A typed array containing all values.\n */\nfunction flattenArrayOfTypedArrays(initialArray) {\n const initialArrayLength = initialArray.length;\n const arrayLength = initialArray[0].length;\n // If this is not a array of arrays, just return the initial one:\n if (typeof arrayLength === 'undefined') {\n return initialArray;\n }\n\n const flattenendArrayLength = initialArrayLength * arrayLength;\n\n const flattenedArray = new initialArray[0].constructor(flattenendArrayLength);\n\n for (let i = 0; i < initialArrayLength; i++) {\n const indexFlattenedArray = i * arrayLength;\n flattenedArray.set(initialArray[i], indexFlattenedArray);\n }\n return flattenedArray;\n}\n\n/**\n * Default text encoder.\n */\nclass DefaultTextEncoder {\n /**\n * Encode an input string.\n *\n * @param {string} str The string to encode.\n * @returns {Uint8Array} The encoded string.\n */\n encode(str) {\n const result = new Uint8Array(str.length);\n for (let i = 0, leni = str.length; i < leni; ++i) {\n result[i] = str.charCodeAt(i);\n }\n return result;\n }\n}\n\n/**\n * Small list of used tag keys.\n */\nconst TagKeys = {\n TransferSyntax: '00020010',\n SpecificCharacterSet: '00080005',\n BitsAllocated: '00280100',\n};\n\n/**\n * DICOM writer.\n *\n * @example\n * // add link to html\n * const link = document.createElement(\"a\");\n * link.appendChild(document.createTextNode(\"download\"));\n * const div = document.getElementById(\"dwv\");\n * div.appendChild(link);\n * // XMLHttpRequest onload callback\n * const onload = function (event) {\n * const parser = new dwv.DicomParser();\n * parser.parse(event.target.response);\n * // create writer\n * const writer = new dwv.DicomWriter();\n * // get buffer using default rules\n * const dicomBuffer = writer.getBuffer(parser.getDicomElements());\n * // create blob\n * const blob = new Blob([dicomBuffer], {type: 'application/dicom'});\n * // add blob to download link\n * link.href = URL.createObjectURL(blob);\n * link.download = \"anonym.dcm\";\n * };\n * // DICOM file request\n * const request = new XMLHttpRequest();\n * const url = 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm';\n * request.open('GET', url);\n * request.responseType = 'arraybuffer';\n * request.onload = onload;\n * request.send();\n */\nexport class DicomWriter {\n\n /**\n * Flag to use VR=UN for private sequences, default to false\n * (mainly used in tests).\n *\n * @type {boolean}\n */\n #useUnVrForPrivateSq = false;\n\n /**\n * Flag to activate or not the vr=UN tag check and fix\n * if present in the dictionary. Default to true.\n *\n * @type {boolean}\n */\n #fixUnknownVR = true;\n\n /**\n * Default rules: just copy.\n *\n * @type {Object}\n */\n #defaultRules = {\n default: {action: 'copy', value: null}\n };\n\n /**\n * Writing rules.\n *\n * @type {Object}\n */\n #rules = this.#defaultRules;\n\n /**\n * List of compulsory tags keys.\n *\n * @type {string[]}\n */\n #compulsoryTags = [];\n\n /**\n * Default text encoder.\n *\n * @type {DefaultTextEncoder}\n */\n #defaultTextEncoder = new DefaultTextEncoder();\n\n /**\n * Special text encoder.\n *\n * @type {DefaultTextEncoder|TextEncoder}\n */\n #textEncoder = this.#defaultTextEncoder;\n\n /**\n * Set the use UN VR for private sequence flag.\n *\n * @param {boolean} flag True to use UN VR.\n */\n setUseUnVrForPrivateSq(flag) {\n this.#useUnVrForPrivateSq = flag;\n }\n\n /**\n * Set the vr=UN check and fix flag.\n *\n * @param {boolean} flag True to activate the check and fix.\n */\n setFixUnknownVR(flag) {\n this.#fixUnknownVR = flag;\n }\n\n /**\n * Set the writing rules.\n * List of writer rules indexed by either `default`,\n * tagKey, tagName or groupName.\n * Each DICOM element will be checked to see if a rule is applicable.\n * First checked by tagKey, tagName and then by groupName,\n * if nothing is found the default rule is applied.\n *\n * @param {Object} rules The input rules.\n * @param {boolean} [addMissingTags] If true, explicit tags that\n * have replace rule and a value will be\n * added if missing. Defaults to false.\n */\n setRules(rules, addMissingTags) {\n this.#rules = rules;\n\n // default compulsory list is empty\n this.#compulsoryTags = [];\n\n // use replace rule tags as compulsory tags\n if (addMissingTags) {\n const keys = Object.keys(rules);\n for (const key of keys) {\n const rule = rules[key];\n if (rule.action === 'replace' &&\n typeof rule.value !== 'undefined' &&\n rule.value !== null) {\n // check if key really exists\n let isKey = false;\n if (key.length === 8) {\n const tag = getTagFromKey(key);\n isKey = typeof tag.getNameFromDictionary() !== 'undefined';\n }\n // get tag key, rules can use key or tag name\n let tagKey;\n if (isKey) {\n tagKey = key;\n } else {\n // try tag name\n const tag = getTagFromDictionary(key);\n if (typeof tag !== 'undefined') {\n tagKey = tag.getKey();\n }\n }\n // add to list\n if (typeof tagKey !== 'undefined') {\n this.#compulsoryTags.push(tagKey);\n }\n }\n }\n }\n }\n\n /**\n * Encode string data.\n *\n * @param {string} str The string to encode.\n * @returns {Uint8Array} The encoded string.\n */\n #encodeString(str) {\n return this.#defaultTextEncoder.encode(str);\n }\n\n /**\n * Encode data as a UTF-8.\n *\n * @param {string} str The string to write.\n * @returns {Uint8Array} The encoded string.\n */\n #encodeSpecialString(str) {\n return this.#textEncoder.encode(str);\n }\n\n /**\n * Use a TextEncoder instead of the default text decoder.\n */\n useSpecialTextEncoder() {\n /**\n * The text encoder.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder}.\n *\n * @external TextEncoder\n */\n this.#textEncoder = new TextEncoder();\n }\n\n /**\n * Get the element to write according to the class rules.\n * Priority order: tagName, groupName, default.\n *\n * @param {DataElement} element The element to check.\n * @returns {DataElement|null} The element to write, can be null.\n */\n getElementToWrite(element) {\n // get group and tag string name\n const groupName = element.tag.getGroupName();\n const tagName = element.tag.getNameFromDictionary();\n\n // apply rules:\n let rule;\n if (typeof this.#rules[element.tag.getKey()] !== 'undefined') {\n // 1. tag itself\n rule = this.#rules[element.tag.getKey()];\n } else if (typeof tagName !== 'undefined' &&\n typeof this.#rules[tagName] !== 'undefined') {\n // 2. tag name\n rule = this.#rules[tagName];\n } else if (typeof this.#rules[groupName] !== 'undefined') {\n // 3. group name\n rule = this.#rules[groupName];\n } else {\n // 4. default\n rule = this.#rules['default'];\n }\n // apply action on element and return\n return writerActions[rule.action](element, rule.value);\n }\n\n /**\n * Write a list of items.\n *\n * @param {DataWriter} writer The raw data writer.\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} items The list of items to write.\n * @param {boolean} isImplicit Is the DICOM VR implicit?\n * @returns {number} The new offset position.\n */\n #writeDataElementItems(\n writer, byteOffset, items, isImplicit) {\n let item;\n for (let i = 0; i < items.length; ++i) {\n item = items[i];\n if (item.length === 0) {\n continue;\n }\n // item element (create new to not modify original)\n let undefinedLength = false;\n const itemTag = item.find((subItem) => isItemTag(subItem.tag));\n if (typeof itemTag !== 'undefined' &&\n typeof itemTag.undefinedLength !== 'undefined') {\n undefinedLength = itemTag.undefinedLength;\n }\n const itemElement = new DataElement('NONE');\n itemElement.vl = undefinedLength ? 0xffffffff : itemTag.vl,\n itemElement.tag = getItemTag();\n itemElement.value = [];\n byteOffset = this.#writeDataElement(\n writer, itemElement, byteOffset, isImplicit);\n // write rest\n for (const subItem of item) {\n if (!isItemTag(subItem.tag) &&\n !isItemDelimitationItemTag(subItem.tag)) {\n byteOffset = this.#writeDataElement(\n writer, subItem, byteOffset, isImplicit);\n }\n }\n // item delimitation\n if (undefinedLength) {\n const itemDelimElement = new DataElement('NONE');\n itemDelimElement.vl = 0;\n itemDelimElement.tag = getItemDelimitationItemTag();\n itemDelimElement.value = [];\n byteOffset = this.#writeDataElement(\n writer, itemDelimElement, byteOffset, isImplicit);\n }\n }\n\n // return new offset\n return byteOffset;\n }\n\n /**\n * Write data with a specific Value Representation (VR).\n *\n * @param {DataWriter} writer The raw data writer.\n * @param {DataElement} element The element to write.\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} value The array to write.\n * @param {boolean} isImplicit Is the DICOM VR implicit?\n * @returns {number} The new offset position.\n */\n #writeDataElementValue(\n writer, element, byteOffset, value, isImplicit) {\n\n const startOffset = byteOffset;\n\n if (element.vr === 'NONE') {\n // nothing to do!\n } else if (value instanceof Uint8Array) {\n // binary data has been expanded 8 times at read\n if (value.length === 8 * element.vl) {\n byteOffset = writer.writeBinaryArray(byteOffset, value);\n } else {\n byteOffset = writer.writeUint8Array(byteOffset, value);\n }\n } else if (value instanceof Int8Array) {\n byteOffset = writer.writeInt8Array(byteOffset, value);\n } else if (value instanceof Uint16Array) {\n byteOffset = writer.writeUint16Array(byteOffset, value);\n } else if (value instanceof Int16Array) {\n byteOffset = writer.writeInt16Array(byteOffset, value);\n } else if (value instanceof Uint32Array) {\n byteOffset = writer.writeUint32Array(byteOffset, value);\n } else if (value instanceof Int32Array) {\n byteOffset = writer.writeInt32Array(byteOffset, value);\n } else if (value instanceof BigUint64Array) {\n byteOffset = writer.writeUint64Array(byteOffset, value);\n } else if (value instanceof BigInt64Array) {\n byteOffset = writer.writeInt64Array(byteOffset, value);\n } else {\n // switch according to VR if input type is undefined\n const vrType = vrTypes[element.vr];\n if (typeof vrType !== 'undefined') {\n if (vrType === 'Uint8') {\n byteOffset = writer.writeUint8Array(byteOffset, value);\n } else if (vrType === 'Uint16') {\n byteOffset = writer.writeUint16Array(byteOffset, value);\n } else if (vrType === 'Int16') {\n byteOffset = writer.writeInt16Array(byteOffset, value);\n } else if (vrType === 'Uint32') {\n byteOffset = writer.writeUint32Array(byteOffset, value);\n } else if (vrType === 'Int32') {\n byteOffset = writer.writeInt32Array(byteOffset, value);\n } else if (vrType === 'Uint64') {\n byteOffset = writer.writeUint64Array(byteOffset, value);\n } else if (vrType === 'Int64') {\n byteOffset = writer.writeInt64Array(byteOffset, value);\n } else if (vrType === 'Float32') {\n byteOffset = writer.writeFloat32Array(byteOffset, value);\n } else if (vrType === 'Float64') {\n byteOffset = writer.writeFloat64Array(byteOffset, value);\n } else if (vrType === 'string') {\n byteOffset = writer.writeUint8Array(byteOffset, value);\n } else {\n throw new Error('Unknown VR type: ' + vrType);\n }\n } else if (element.vr === 'SQ') {\n byteOffset = this.#writeDataElementItems(\n writer, byteOffset, value, isImplicit);\n } else if (element.vr === 'AT') {\n for (let i = 0; i < value.length; ++i) {\n const hexString = value[i] + '';\n const hexString1 = hexString.substring(1, 5);\n const hexString2 = hexString.substring(6, 10);\n const dec1 = parseInt(hexString1, 16);\n const dec2 = parseInt(hexString2, 16);\n const atValue = [dec1, dec2];\n byteOffset = writer.writeUint16Array(byteOffset, atValue);\n }\n } else if (element.vr === 'xs') {\n // TODO would be better to use pixelRepresentation in if\n if (value instanceof Int16Array) {\n byteOffset = writer.writeInt16Array(byteOffset, value);\n } else {\n byteOffset = writer.writeUint16Array(byteOffset, value);\n }\n } else {\n logger.warn('Unknown VR: ' + element.vr);\n }\n }\n\n if (element.vr !== 'SQ' && element.vr !== 'NONE') {\n const diff = byteOffset - startOffset;\n if (diff !== element.vl) {\n let message = 'Offset difference and VL are not equal: ' +\n diff + ' != ' + element.vl;\n message += ' (';\n if (typeof element.tag !== 'undefined') {\n message += element.tag + ', ';\n }\n message += 'vr:' + element.vr + ')';\n logger.warn(message);\n }\n }\n\n // return new offset\n return byteOffset;\n }\n\n /**\n * Write a pixel data element.\n *\n * @param {DataWriter} writer The raw data writer.\n * @param {DataElement} element The element to write.\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} value The array to write.\n * @param {boolean} isImplicit Is the DICOM VR implicit?\n * @returns {number} The new offset position.\n */\n #writePixelDataElementValue(\n writer, element, byteOffset, value, isImplicit) {\n // undefined length flag\n let undefinedLength = false;\n if (typeof element.undefinedLength !== 'undefined') {\n undefinedLength = element.undefinedLength;\n }\n // explicit length\n if (!undefinedLength) {\n let finalValue = value[0];\n // flatten multi frame\n if (value.length > 1) {\n finalValue = flattenArrayOfTypedArrays(value);\n }\n // write\n byteOffset = this.#writeDataElementValue(\n writer, element, byteOffset, finalValue, isImplicit);\n } else {\n // pixel data as sequence\n const item = {};\n // first item: basic offset table\n item['FFFEE000'] = {\n tag: getItemTag(),\n vr: 'NONE',\n vl: 0,\n value: []\n };\n // data\n for (let i = 0; i < value.length; ++i) {\n item[i] = {\n tag: getItemTag(),\n vr: element.vr,\n vl: value[i].length,\n value: value[i]\n };\n }\n // write\n byteOffset = this.#writeDataElementItems(\n writer, byteOffset, [item], isImplicit);\n }\n\n // return new offset\n return byteOffset;\n }\n\n /**\n * Write a data element.\n *\n * @param {DataWriter} writer The raw data writer.\n * @param {DataElement} element The DICOM data element to write.\n * @param {number} byteOffset The offset to start writing from.\n * @param {boolean} isImplicit Is the DICOM VR implicit?\n * @returns {number} The new offset position.\n */\n #writeDataElement(\n writer, element, byteOffset, isImplicit) {\n const isTagWithVR = element.tag.isWithVR();\n const is32bitVL = (isImplicit || !isTagWithVR)\n ? true : is32bitVLVR(element.vr);\n // group\n byteOffset = writer.writeHex(byteOffset, element.tag.getGroup());\n // element\n byteOffset = writer.writeHex(byteOffset, element.tag.getElement());\n // VR\n let vr = element.vr;\n // use VR=UN for private sequence\n if (this.#useUnVrForPrivateSq &&\n element.tag.isPrivate() &&\n vr === 'SQ') {\n logger.warn('Write element using VR=UN for private sequence.');\n vr = 'UN';\n }\n if (isTagWithVR && !isImplicit) {\n byteOffset = writer.writeUint8Array(byteOffset, this.#encodeString(vr));\n // reserved 2 bytes for 32bit VL\n if (is32bitVL) {\n byteOffset += 2;\n }\n }\n\n let undefinedLengthSequence = false;\n if (element.vr === 'SQ' ||\n isPixelDataTag(element.tag)) {\n if (typeof element.undefinedLength !== 'undefined') {\n undefinedLengthSequence = element.undefinedLength;\n }\n }\n let undefinedLengthItem = false;\n if (isItemTag(element.tag)) {\n if (typeof element.undefinedLength !== 'undefined') {\n undefinedLengthItem = element.undefinedLength;\n }\n }\n\n // update vl for sequence or item with undefined length\n let vl = element.vl;\n if (undefinedLengthSequence || undefinedLengthItem) {\n vl = 0xffffffff;\n }\n // VL\n if (is32bitVL) {\n byteOffset = writer.writeUint32(byteOffset, vl);\n } else {\n byteOffset = writer.writeUint16(byteOffset, vl);\n }\n\n // value\n let value = element.value;\n // check value\n if (typeof value === 'undefined') {\n value = [];\n }\n // write\n if (isPixelDataTag(element.tag)) {\n byteOffset = this.#writePixelDataElementValue(\n writer, element, byteOffset, value, isImplicit);\n } else {\n byteOffset = this.#writeDataElementValue(\n writer, element, byteOffset, value, isImplicit);\n }\n\n // sequence delimitation item for sequence with undefined length\n if (undefinedLengthSequence) {\n const seqDelimElement = new DataElement('NONE');\n seqDelimElement.vl = 0;\n seqDelimElement.tag = getSequenceDelimitationItemTag();\n seqDelimElement.value = [];\n byteOffset = this.#writeDataElement(\n writer, seqDelimElement, byteOffset, isImplicit);\n }\n\n // return new offset\n return byteOffset;\n }\n\n /**\n * Get the ArrayBuffer corresponding to input DICOM elements.\n *\n * @param {Object} dataElements The elements to write.\n * @returns {ArrayBuffer} The elements as a buffer.\n */\n getBuffer(dataElements) {\n // Transfer Syntax\n const syntax = dataElements[TagKeys.TransferSyntax].value[0];\n const isImplicit = isImplicitTransferSyntax(syntax);\n const isBigEndian = isBigEndianTransferSyntax(syntax);\n // Specific CharacterSet\n if (typeof dataElements[TagKeys.SpecificCharacterSet] !== 'undefined') {\n const oldscs = dataElements[TagKeys.SpecificCharacterSet].value[0];\n // force UTF-8 if not default character set\n if (typeof oldscs !== 'undefined' && oldscs !== 'ISO-IR 6') {\n logger.debug('Change charset to UTF, was: ' + oldscs);\n this.useSpecialTextEncoder();\n dataElements[TagKeys.SpecificCharacterSet].value = ['ISO_IR 192'];\n }\n }\n // Bits Allocated (for image data)\n let bitsAllocated;\n if (typeof dataElements[TagKeys.BitsAllocated] !== 'undefined') {\n bitsAllocated = dataElements[TagKeys.BitsAllocated].value[0];\n }\n\n // calculate buffer size and split elements (meta and non meta)\n let totalSize = 128 + 4; // DICM\n let localSize = 0;\n const metaElements = [];\n const rawElements = [];\n let element;\n let groupName;\n let metaLength = 0;\n // FileMetaInformationGroupLength\n const fmiglTag = getFileMetaInformationGroupLengthTag();\n // FileMetaInformationVersion\n const fmivTag = new Tag('0002', '0001');\n // ImplementationClassUID\n const icUIDTag = new Tag('0002', '0012');\n // ImplementationVersionName\n const ivnTag = new Tag('0002', '0013');\n\n // missing tag list: start as a copy of compulsory\n const missingTags = this.#compulsoryTags.slice();\n\n // loop through elements to get the buffer size\n const keys = Object.keys(dataElements);\n for (let i = 0, leni = keys.length; i < leni; ++i) {\n const originalElement = dataElements[keys[i]];\n originalElement.tag = getTagFromKey(keys[i]);\n element = this.getElementToWrite(originalElement);\n if (element !== null &&\n !fmiglTag.equals(element.tag) &&\n !fmivTag.equals(element.tag) &&\n !icUIDTag.equals(element.tag) &&\n !ivnTag.equals(element.tag)) {\n localSize = 0;\n\n // check if compulsory tag, if present remove from missing list\n const index = missingTags.indexOf(element.tag.getKey());\n if (index !== -1) {\n missingTags.splice(index, 1);\n }\n\n // XB7 2020-04-17\n // Check if UN can be converted to correct VR.\n // This check must be done BEFORE calculating totalSize,\n // otherwise there may be extra null bytes at the end of the file\n // (dcmdump may crash because of these bytes)\n if (this.#fixUnknownVR) {\n checkAndFixUnknownVR(element, !isBigEndian);\n }\n\n // update value and vl\n this.#setElementValue(\n element, element.value, isImplicit, bitsAllocated);\n\n // tag group name\n groupName = element.tag.getGroupName();\n\n // prefix\n if (groupName === 'Meta Element') {\n localSize += getDataElementPrefixByteSize(element.vr, false);\n } else {\n localSize += getDataElementPrefixByteSize(\n element.vr, isImplicit);\n }\n\n // value\n localSize += element.vl;\n\n // sort elements\n if (groupName === 'Meta Element') {\n metaElements.push(element);\n metaLength += localSize;\n } else {\n rawElements.push(element);\n }\n\n // add to total size\n totalSize += localSize;\n }\n }\n\n // add compulsory tags to output data if not present\n for (const key of missingTags) {\n const tag = getTagFromKey(key);\n const dataElement = new DataElement(tag.getVrFromDictionary());\n dataElement.tag = tag;\n // rules are indexed by key or tag name\n let value;\n if (typeof this.#rules[key] !== 'undefined') {\n value = this.#rules[key].value;\n } else {\n const name = tag.getNameFromDictionary();\n value = this.#rules[name].value;\n }\n // add element\n let size = getDataElementPrefixByteSize(dataElement.vr, isImplicit);\n size += this.#setElementValue(dataElement, [value], isImplicit);\n rawElements.push(dataElement);\n totalSize += size;\n }\n\n // FileMetaInformationVersion\n const fmiv = getDataElement('FileMetaInformationVersion');\n let fmivSize = getDataElementPrefixByteSize(fmiv.vr, false);\n fmivSize += this.#setElementValue(fmiv, [0, 1], false);\n metaElements.push(fmiv);\n metaLength += fmivSize;\n totalSize += fmivSize;\n // ImplementationClassUID\n const icUID = getDataElement('ImplementationClassUID');\n let icUIDSize = getDataElementPrefixByteSize(icUID.vr, false);\n const icUIDValue =\n getUID('ImplementationClassUID').replace('-beta', '.99');\n icUIDSize += this.#setElementValue(icUID, [icUIDValue], false);\n metaElements.push(icUID);\n metaLength += icUIDSize;\n totalSize += icUIDSize;\n // ImplementationVersionName\n const ivn = getDataElement('ImplementationVersionName');\n let ivnSize = getDataElementPrefixByteSize(ivn.vr, false);\n const dwvVersion = getDwvVersion().replace('-beta', '.99');\n const ivnValue = 'DWV_' + dwvVersion;\n ivnSize += this.#setElementValue(ivn, [ivnValue], false);\n metaElements.push(ivn);\n metaLength += ivnSize;\n totalSize += ivnSize;\n\n // sort elements\n const elemSortFunc = function (a, b) {\n return tagCompareFunction(a.tag, b.tag);\n };\n metaElements.sort(elemSortFunc);\n rawElements.sort(elemSortFunc);\n\n // create the FileMetaInformationGroupLength element\n const fmigl = getDataElement('FileMetaInformationGroupLength');\n let fmiglSize = getDataElementPrefixByteSize(fmigl.vr, false);\n fmiglSize += this.#setElementValue(\n fmigl, new Uint32Array([metaLength]), false);\n totalSize += fmiglSize;\n\n // create buffer\n const buffer = new ArrayBuffer(totalSize);\n const metaWriter = new DataWriter(buffer);\n const dataWriter = new DataWriter(buffer, !isBigEndian);\n\n let offset = 128;\n // DICM\n offset = metaWriter.writeUint8Array(offset, this.#encodeString('DICM'));\n // FileMetaInformationGroupLength\n offset = this.#writeDataElement(metaWriter, fmigl, offset, false);\n // write meta\n for (let j = 0, lenj = metaElements.length; j < lenj; ++j) {\n offset = this.#writeDataElement(\n metaWriter, metaElements[j], offset, false);\n }\n\n // check meta position\n const preambleSize = 128 + 4;\n const metaOffset = preambleSize + fmiglSize + metaLength;\n if (offset !== metaOffset) {\n logger.warn('Bad size calculation... meta offset: ' + offset +\n ', calculated size:' + metaOffset +\n ' (diff:' + (offset - metaOffset) + ')');\n }\n\n // write non meta\n for (let k = 0, lenk = rawElements.length; k < lenk; ++k) {\n offset = this.#writeDataElement(\n dataWriter, rawElements[k], offset, isImplicit);\n }\n\n // check final position\n if (offset !== totalSize) {\n logger.warn('Bad size calculation... final offset: ' + offset +\n ', calculated size:' + totalSize +\n ' (diff:' + (offset - totalSize) + ')');\n }\n // return\n return buffer;\n }\n\n /**\n * Set a DICOM element value according to its VR (Value Representation).\n *\n * @param {DataElement} element The DICOM element to set the value.\n * @param {object} value The value to set.\n * @param {boolean} isImplicit Does the data use implicit VR?\n * @param {number} [bitsAllocated] Bits allocated used for pixel data.\n * @returns {number} The total element size.\n */\n #setElementValue(\n element, value, isImplicit, bitsAllocated) {\n // byte size of the element\n let size = 0;\n // special sequence case\n if (element.vr === 'SQ') {\n\n if (value !== null && value !== 0) {\n const newItems = [];\n\n // explicit or undefined length sequence\n let undefinedLength = false;\n if (typeof element.undefinedLength !== 'undefined') {\n undefinedLength = element.undefinedLength;\n delete element.undefinedLength;\n }\n\n // items\n for (let i = 0; i < value.length; ++i) {\n const oldItemElements = value[i];\n const newItemElements = [];\n let subSize = 0;\n\n // check data\n if (oldItemElements === null || oldItemElements === 0) {\n continue;\n }\n\n // possible local bitsAllocated\n let sqBitsAllocated = bitsAllocated;\n const dataElement = oldItemElements[TagKeys.BitsAllocated];\n if (typeof dataElement !== 'undefined' &&\n typeof dataElement.value !== 'undefined') {\n sqBitsAllocated = dataElement.value[0];\n }\n\n // elements\n const itemKeys = Object.keys(oldItemElements);\n for (let j = 0, lenj = itemKeys.length; j < lenj; ++j) {\n const itemKey = itemKeys[j];\n const subElement = oldItemElements[itemKey];\n subElement.tag = getTagFromKey(itemKey);\n\n if (isItemTag(subElement.tag)) {\n continue;\n }\n // set item value\n subSize += this.#setElementValue(\n subElement, subElement.value, isImplicit, sqBitsAllocated);\n newItemElements.push(subElement);\n // add prefix size\n subSize += getDataElementPrefixByteSize(\n subElement.vr, isImplicit);\n }\n\n // add item element (used to store its size)\n const itemElement = {\n tag: getItemTag(),\n vr: 'NONE',\n vl: subSize,\n value: []\n };\n if (undefinedLength) {\n itemElement.undefinedLength = undefinedLength;\n }\n newItemElements.push(itemElement);\n subSize += getDataElementPrefixByteSize(\n itemElement.vr, isImplicit);\n\n // add item delimitation size\n if (undefinedLength) {\n subSize += getDataElementPrefixByteSize(\n 'NONE', isImplicit);\n }\n\n // sort\n const elemSortFunc = function (a, b) {\n return tagCompareFunction(a.tag, b.tag);\n };\n newItemElements.sort(elemSortFunc);\n\n size += subSize;\n newItems.push(newItemElements);\n }\n\n // add sequence delimitation size\n if (undefinedLength) {\n size += getDataElementPrefixByteSize('NONE', isImplicit);\n }\n\n // update sequence element\n element.value = newItems;\n element.vl = size;\n if (undefinedLength) {\n element.undefinedLength = undefinedLength;\n }\n }\n } else {\n // pad if necessary\n if (isVrToPad(element.vr)) {\n const padStr = getVrPad(element.vr);\n // encode string\n // TODO: not sure for UN...\n if (isStringVr(element.vr)) {\n let pad;\n if (isCharSetStringVR(element.vr)) {\n value = this.#encodeSpecialString(value.join('\\\\'));\n pad = this.#encodeSpecialString(padStr);\n } else {\n value = this.#encodeString(value.join('\\\\'));\n pad = this.#encodeString(padStr);\n }\n if (!isEven(value.length)) {\n value = uint8ArrayPush(value, pad);\n }\n } else if (element.vr === 'OB') {\n value = padOBValue(value);\n }\n }\n\n // calculate byte size\n size = 0;\n if (element.vr === 'AT') {\n size = 4 * value.length;\n } else if (element.vr === 'xs') {\n size = value.length * Uint16Array.BYTES_PER_ELEMENT;\n } else if (isTypedArrayVr(element.vr) || element.vr === 'ox') {\n if (isPixelDataTag(element.tag) &&\n Array.isArray(value)) {\n size = 0;\n for (let b = 0; b < value.length; ++b) {\n size += value[b].length;\n }\n } else {\n size = value.length;\n }\n\n // convert size to bytes\n const vrType = vrTypes[element.vr];\n if (isPixelDataTag(element.tag) || element.vr === 'ox') {\n if (element.undefinedLength) {\n const itemPrefixSize =\n getDataElementPrefixByteSize('NONE', isImplicit);\n // offset table\n size += itemPrefixSize;\n // pixel items\n size += itemPrefixSize * value.length;\n // add sequence delimitation size\n size += itemPrefixSize;\n } else {\n // use bitsAllocated for pixel data\n // no need to multiply for 8 bits\n if (typeof bitsAllocated !== 'undefined') {\n if (bitsAllocated === 1) {\n // binary data\n size /= 8;\n } else if (bitsAllocated === 16) {\n size *= Uint16Array.BYTES_PER_ELEMENT;\n }\n }\n }\n } else if (typeof vrType !== 'undefined') {\n const bpe = getBpeForVrType(vrType);\n if (typeof bpe !== 'undefined') {\n size *= bpe;\n } else {\n throw new Error('Unknown bytes per element for VR type: ' + vrType);\n }\n } else {\n throw new Error('Unsupported element: ' + element.vr);\n }\n } else {\n size = value.length;\n }\n\n element.value = value;\n element.vl = size;\n }\n\n // return the size of that data\n return size;\n }\n\n} // class DicomWriter\n\n/**\n * Fix for broken DICOM elements: replace \"UN\" with correct VR if the\n * element exists in dictionary.\n *\n * @param {DataElement} element The DICOM element.\n * @param {boolean} [isLittleEndian] Flag to tell if the data is little\n * or big endian (default: true).\n */\nfunction checkAndFixUnknownVR(element, isLittleEndian) {\n if (element.vr === 'UN') {\n const dictVr = element.tag.getVrFromDictionary();\n if (typeof dictVr !== 'undefined' && element.vr !== dictVr) {\n element.vr = dictVr;\n // cast typed array value from Uint8 to vr type\n const vrType = vrTypes[element.vr];\n if (typeof vrType !== 'undefined' &&\n vrType !== 'Uint8' &&\n vrType !== 'string') {\n const data = getUint8ToVrValue(\n element.value, element.vr, isLittleEndian);\n if (typeof data !== 'undefined') {\n element.value = data;\n }\n }\n logger.info('Element ' + element.tag.getGroup() +\n ' ' + element.tag.getElement() +\n ' VR changed from UN to ' + element.vr);\n }\n }\n}\n\n/**\n * Get the casted typed array value from Uint8 to vr type.\n *\n * @param {object} value The value to cast.\n * @param {string} vr The DICOM element VR.\n * @param {boolean} [isLittleEndian] Flag to tell if the data is little\n * or big endian (default: true).\n * @returns {object} The element value casted to the vr type.\n */\nfunction getUint8ToVrValue(value, vr, isLittleEndian) {\n let data;\n if (typeof value.buffer === 'undefined') {\n return data;\n }\n const reader = new DataReader(value.buffer, isLittleEndian);\n const offset = value.byteOffset;\n const vl = value.length; // size before cast\n const vrType = vrTypes[vr];\n if (vrType === 'Uint16') {\n data = reader.readUint16Array(offset, vl);\n } else if (vrType === 'Uint32') {\n data = reader.readUint32Array(offset, vl);\n } else if (vrType === 'Uint64') {\n data = reader.readUint64Array(offset, vl);\n } else if (vrType === 'Int16') {\n data = Array.from(reader.readInt16Array(offset, vl));\n } else if (vrType === 'Int32') {\n data = Array.from(reader.readInt32Array(offset, vl));\n } else if (vrType === 'Int64') {\n data = reader.readInt64Array(offset, vl);\n } else if (vrType === 'Float32') {\n data = Array.from(reader.readFloat32Array(offset, vl));\n } else if (vrType === 'Float64') {\n data = Array.from(reader.readFloat64Array(offset, vl));\n }\n return data;\n}\n\n/**\n * Get a DICOM element from its tag name (value set separatly).\n *\n * @param {string} tagName The string tag name.\n * @returns {DataElement} The DICOM element.\n */\nfunction getDataElement(tagName) {\n const tag = getTagFromDictionary(tagName);\n const element = new DataElement(tag.getVrFromDictionary());\n element.tag = tag;\n return element;\n}\n\n/**\n * Get the number of bytes per element for a given VR type.\n *\n * @param {string} vrType The VR type as defined in the dictionary.\n * @returns {number} The bytes per element.\n */\nfunction getBpeForVrType(vrType) {\n let bpe;\n if (vrType === 'Uint8') {\n bpe = Uint8Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Uint16') {\n bpe = Uint16Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Int16') {\n bpe = Int16Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Uint32') {\n bpe = Uint32Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Int32') {\n bpe = Int32Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Float32') {\n bpe = Float32Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Float64') {\n bpe = Float64Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Uint64') {\n bpe = BigUint64Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Int64') {\n bpe = BigInt64Array.BYTES_PER_ELEMENT;\n }\n return bpe;\n}\n\n/**\n * Get the DICOM elements from a 'simple' DICOM tags object.\n * The input object is a simplified version of the oficial DICOM json with\n * tag names instead of keys and direct values (no value property) for\n * simple tags. See synthetic test data (in tests/dicom) for examples.\n *\n * @param {Object} simpleTags The 'simple' DICOM\n * tags object.\n * @returns {Object} The DICOM elements.\n */\nexport function getElementsFromJSONTags(simpleTags) {\n const keys = Object.keys(simpleTags);\n const dataElements = {};\n for (let k = 0, len = keys.length; k < len; ++k) {\n // get the DICOM element definition from its name\n const tag = getTagFromDictionary(keys[k]);\n if (typeof tag === 'undefined') {\n continue;\n }\n const vr = tag.getVrFromDictionary();\n // tag value\n let value;\n let undefinedLength = false;\n const simpleTag = simpleTags[keys[k]];\n if (vr === 'SQ') {\n const items = [];\n if (typeof simpleTag.undefinedLength !== 'undefined') {\n undefinedLength = simpleTag.undefinedLength;\n }\n if (typeof simpleTag.value !== 'undefined' &&\n simpleTag.value !== null) {\n for (let i = 0; i < simpleTag.value.length; ++i) {\n items.push(getElementsFromJSONTags(simpleTag.value[i]));\n }\n } else {\n logger.trace('Undefined or null simpleTag SQ value.');\n }\n value = items;\n } else {\n if (Array.isArray(simpleTag)) {\n value = simpleTag;\n } else {\n value = [simpleTag];\n }\n }\n // create element\n const dataElement = new DataElement(vr);\n dataElement.tag = tag;\n dataElement.value = value;\n if (undefinedLength) {\n dataElement.undefinedLength = undefinedLength;\n }\n // store\n dataElements[tag.getKey()] = dataElement;\n }\n // return\n // @ts-expect-error\n return dataElements;\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * DICOM code tag keys.\n */\nconst TagKeys = {\n CodeValue: '00080100',\n CodingSchemeDesignator: '00080102',\n CodeMeaning: '00080104',\n LongCodeValue: '00080119',\n URNCodeValue: '00080120'\n};\n\n/**\n * DICOM code: item of a basic code sequence.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_8.8.html}.\n */\nexport class DicomCode {\n /**\n * Code meaning.\n *\n * @type {string}\n */\n meaning;\n /**\n * Code value.\n *\n * @type {string|undefined}\n */\n value;\n /**\n * Long code value.\n *\n * @type {string|undefined}\n */\n longValue;\n /**\n * URN code value.\n *\n * @type {string|undefined}\n */\n urnValue;\n /**\n * Coding scheme designator.\n *\n * @type {string|undefined}\n */\n schemeDesignator;\n\n /**\n * @param {string} meaning The code meaning.\n */\n constructor(meaning) {\n this.meaning = meaning;\n }\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The code as string.\n */\n toString() {\n return '(' + this.value + ', ' +\n this.schemeDesignator + ', \\'' +\n this.meaning + '\\')';\n }\n}\n\n/**\n * Check if two code objects are equal.\n *\n * @param {DicomCode} code1 The first code.\n * @param {DicomCode} code2 The second code.\n * @returns {boolean} True if both codes are equal.\n */\nexport function isEqualCode(code1, code2) {\n return Object.keys(code1).length === Object.keys(code2).length &&\n Object.keys(code1).every(key =>\n Object.prototype.hasOwnProperty.call(code2, key) &&\n code1[key] === code2[key]\n );\n}\n\n/**\n * Get a code object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {DicomCode} A code object.\n */\nexport function getCode(dataElements) {\n // meaning -> CodeMeaning (type1)\n const code = new DicomCode(dataElements[TagKeys.CodeMeaning].value[0]);\n // value -> CodeValue (type1C)\n // longValue -> LongCodeValue (type1C)\n // urnValue -> URNCodeValue (type1C)\n if (typeof dataElements[TagKeys.CodeValue] !== 'undefined') {\n code.value = dataElements[TagKeys.CodeValue].value[0];\n } else if (typeof dataElements[TagKeys.LongCodeValue] !== 'undefined') {\n code.longValue = dataElements[TagKeys.LongCodeValue].value[0];\n } else if (typeof dataElements[TagKeys.URNCodeValue] !== 'undefined') {\n code.urnValue = dataElements[TagKeys.URNCodeValue].value[0];\n } else {\n throw new Error(\n 'Invalid code with no value, no long value and no urn value.');\n }\n // schemeDesignator -> CodingSchemeDesignator (type1C)\n if (typeof code.value !== 'undefined' ||\n typeof code.longValue !== 'undefined') {\n if (typeof dataElements[TagKeys.CodingSchemeDesignator] !== 'undefined') {\n code.schemeDesignator =\n dataElements[TagKeys.CodingSchemeDesignator].value[0];\n } else {\n throw new Error(\n 'No coding sheme designator when code value or long value is present');\n }\n }\n return code;\n}\n\n/**\n * Get a simple dicom element item from a code object.\n *\n * @param {DicomCode} code The code object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomCodeItem(code) {\n // dicom item (tags are in group/element order)\n const item = {};\n // value\n if (typeof code.value !== 'undefined') {\n item.CodeValue = code.value;\n } else if (typeof code.longValue !== 'undefined') {\n item.LongCodeValue = code.longValue;\n } else if (typeof code.urnValue !== 'undefined') {\n item.URNCodeValue = code.urnValue;\n }\n // CodingSchemeDesignator\n if (typeof code.schemeDesignator !== 'undefined') {\n item.CodingSchemeDesignator = code.schemeDesignator;\n }\n // CodeMeaning\n item.CodeMeaning = code.meaning;\n // return\n return item;\n}\n\n/**\n * DICOM codes.\n * List: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part16/chapter_d.html}.\n */\nconst DcmCodes = {\n 111030: 'Image Region',\n 112039: 'Tracking Identifier',\n 112040: 'Tracking Unique Identifier',\n 113048: 'Pixel by pixel Maximum',\n 113049: 'Pixel by pixel mean',\n 113051: 'Pixel by pixel Minimum',\n 113061: 'Standard Deviation',\n 113076: 'Segmentation',\n 121055: 'Path',\n 121207: 'Height',\n 121322: 'Source image for image processing operation',\n 121324: 'Source Image',\n 122438: 'Reference Points',\n 125007: 'Measurement Group',\n 125309: 'Short label',\n 128773: 'Reference Geometry'\n};\n\n/**\n * SNOMED-CT codes.\n * List: {@link https://browser.ihtsdotools.org}.\n */\nconst SctCodes = {\n 1483009: 'Angle',\n 42798000: 'Area',\n 103355008: 'Width',\n 103339001: 'Long axis',\n 103340004: 'Short axis',\n 131190003: 'Radius',\n 261665006: 'Unknown',\n 410668003: 'Length',\n 718499004: 'Color'\n};\n\n/**\n * UCUM codes.\n * Definition: {@link https://unitsofmeasure.org/ucum}.\n * List: {@link https://ucum.nlm.nih.gov/ucum-lhc/demo.html}.\n */\nconst UcumCodes = {\n 1: 'No units',\n mm: 'Millimeter',\n deg: 'Degree - plane angle',\n cm2: 'Square centimeter',\n 'cm2/ml': 'Square centimeter per milliliter',\n '/cm': 'Per centimeter',\n 'g/ml': 'Gram per milliliter',\n 'g/ml{SUVbw}': 'Standardized Uptake Value body weight',\n 'mg/ml': 'Milligram per milliliter',\n 'umol/ml': 'Micromole per milliliter',\n 'Bq/ml': 'Becquerels per milliliter',\n 'mg/min/ml': 'Milligrams per minute per milliliter',\n 'umol/min/ml': 'Micromole per minute per milliliter',\n 'ml/min/g': 'Milliliter per minute per gram',\n 'ml/g': 'Milliliter per gram',\n 'ml/min/ml': 'Milliliter per minute per milliliter',\n 'ml/ml': 'Milliliter per milliliter',\n '%': 'Percentage',\n '[hnsf\\'U]': 'Hounsfield unit',\n '10*23/ml': 'Electron density',\n '{counts}': 'Counts',\n '{counts}/s': 'Counts per second',\n '{propcounts}': 'Proportional to counts',\n '{propcounts}/s': 'Proportional to counts per second',\n};\n\n/**\n * Get a DICOM code from a value (~id).\n *\n * @param {string} value The code value.\n * @param {string} scheme The scheme designator.\n * @returns {DicomCode|undefined} The DICOM code.\n */\nfunction getDicomCode(value, scheme) {\n let meaning;\n if (scheme === 'DCM') {\n meaning = DcmCodes[value];\n } else if (scheme === 'SCT') {\n meaning = SctCodes[value];\n } else if (scheme === 'UCUM') {\n meaning = UcumCodes[value];\n }\n let code;\n if (typeof meaning !== 'undefined') {\n code = new DicomCode(meaning);\n code.schemeDesignator = scheme;\n code.value = value;\n }\n return code;\n}\n\n/**\n * Get a measurement group DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getMeasurementGroupCode() {\n return getDicomCode('125007', 'DCM');\n}\n\n/**\n * Get an image region DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getImageRegionCode() {\n return getDicomCode('111030', 'DCM');\n}\n\n/**\n * Get a reference geometry DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getReferenceGeometryCode() {\n return getDicomCode('128773', 'DCM');\n}\n\n/**\n * Get a path DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getPathCode() {\n return getDicomCode('121055', 'DCM');\n}\n\n/**\n * Get a source image DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getSourceImageCode() {\n return getDicomCode('121324', 'DCM');\n}\n\n/**\n * Get a tracking identifier DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getTrackingIdentifierCode() {\n return getDicomCode('112039', 'DCM');\n}\n\n/**\n * Get a segmentation DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getSegmentationCode() {\n return getDicomCode('113076', 'DCM');\n}\n\n/**\n * Get a source image for processing DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getSourceImageForProcessingCode() {\n return getDicomCode('121322', 'DCM');\n}\n\n/**\n * Get a short label DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getShortLabelCode() {\n return getDicomCode('125309', 'DCM');\n}\n\n/**\n * Get a reference points DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getReferencePointsCode() {\n return getDicomCode('122438', 'DCM');\n}\n\n/**\n * Get a colour DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getColourCode() {\n return getDicomCode('718499004', 'SCT');\n}\n\n/**\n * Quantification name to dictionary item.\n */\nconst QuantificationName2DictItem = {\n angle: {key: '1483009', scheme: 'SCT'},\n length: {key: '410668003', scheme: 'SCT'},\n surface: {key: '42798000', scheme: 'SCT'},\n height: {key: '121207', scheme: 'DCM'},\n width: {key: '103355008', scheme: 'SCT'},\n radius: {key: '131190003', scheme: 'SCT'},\n a: {key: '103339001', scheme: 'SCT'},\n b: {key: '103340004', scheme: 'SCT'},\n min: {key: '113051', scheme: 'DCM'},\n max: {key: '113048', scheme: 'DCM'},\n mean: {key: '113049', scheme: 'DCM'},\n stddev: {key: '113061', scheme: 'DCM'},\n // median\n // 25th percentile\n // 75th percentile\n};\n\n/**\n * Get a concept name DICOM code.\n *\n * @param {string} name The measurment name as defined\n * in a quantification object.\n * @returns {DicomCode|undefined} The code.\n */\nexport function getConceptNameCode(name) {\n const item = QuantificationName2DictItem[name];\n let code;\n if (typeof item !== 'undefined') {\n code = getDicomCode(item.key, item.scheme);\n }\n return code;\n}\n\n/**\n * Get the DICOM code for a quantification name.\n *\n * @param {DicomCode} code The Dicom code.\n * @returns {string|undefined} The quantification name.\n */\nexport function getQuantificationName(code) {\n let name;\n for (const propKey in QuantificationName2DictItem) {\n const item = QuantificationName2DictItem[propKey];\n if (item.scheme === code.schemeDesignator &&\n item.key === code.value) {\n name = propKey;\n break;\n }\n }\n return name;\n}\n\n/**\n * Quantification unit to UCUM key. Associated tags:\n * - Rescale type {@link https://dicom.innolitics.com/ciods/computed-radiography-image/modality-lut/00281054},\n * - Units {@link https://dicom.innolitics.com/ciods/positron-emission-tomography-image/pet-series/00541001}.\n * - SUV {@link https://dicom.nema.org/medical/dicom/current/output/chtml/part16/sect_CID_85.html}.\n */\nconst QuantificationUnit2UcumKey = {\n 'unit.mm': 'mm',\n 'unit.cm2': 'cm2',\n 'unit.degree': 'deg',\n // OD optical density\n HU: '[hnsf\\'U]',\n // US: '1', // duplicates 'NONE'\n MGML: 'mg/ml',\n // Z_EFF Effective Atomic Number (i.e., Effective-Z)\n ED: '10*23/ml',\n // EDW Electron density normalized\n // HU_MOD Modified Hounsfield Unit\n PCT: '%',\n CNTS: '{counts}',\n NONE: '1',\n CM2: 'cm2',\n CM2ML: 'cm2/ml',\n PCNT: '%',\n CPS: '{counts}/s',\n BQML: 'Bq/ml',\n MGMINML: 'mg/min/ml',\n UMOLMINML: 'umol/min/ml',\n MLMING: 'ml/min/g',\n MLG: 'ml/g',\n '1CM': '/cm',\n UMOLML: 'umol/ml',\n PROPCNTS: '{propcounts}',\n PROPCPS: '{propcounts}/s',\n MLMINML: 'ml/min/ml',\n MLML: 'ml/ml',\n GML: 'g/ml',\n //STDDEV\n SUV: 'g/ml{SUVbw}',\n};\n\n/**\n * Get a measurement units DICOM code.\n *\n * @param {string} name The unit name as defined in a quantification object.\n * @returns {DicomCode|undefined} The code.\n */\nexport function getMeasurementUnitsCode(name) {\n const key = QuantificationUnit2UcumKey[name];\n let code;\n if (typeof key !== 'undefined') {\n code = getDicomCode(key, 'UCUM');\n } else if (typeof key === 'undefined') {\n // no unit\n code = getDicomCode('1', 'UCUM');\n }\n return code;\n}\n\n/**\n * Get a quantification unit name.\n *\n * @param {DicomCode} code The code to get the unit from.\n * @returns {string} The quantification unit.\n */\nexport function getQuantificationUnit(code) {\n let unit;\n for (const propKey in QuantificationUnit2UcumKey) {\n const ucumKey = QuantificationUnit2UcumKey[propKey];\n if (code.schemeDesignator === 'UCUM' &&\n ucumKey === code.value) {\n unit = propKey;\n break;\n }\n }\n return unit;\n}\n","import {\n isEqualRgb,\n cielabToSrgb,\n uintLabToLab,\n labToUintLab,\n srgbToCielab\n} from '../utils/colour';\nimport {\n getCode,\n getDicomCodeItem\n} from './dicomCode';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {RGB} from '../utils/colour';\nimport {DataElement} from './dataElement';\nimport {DicomCode} from './dicomCode';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n SegmentNumber: '00620004',\n SegmentLabel: '00620005',\n SegmentAlgorithmType: '00620008',\n SegmentAlgorithmName: '00620009',\n RecommendedDisplayGrayscaleValue: '0062000C',\n RecommendedDisplayCIELabValue: '0062000D',\n SegmentedPropertyCategoryCodeSequence: '00620003',\n SegmentedPropertyTypeCodeSequence: '0062000F',\n TrackingID: '00620020',\n TrackingUID: '00620021'\n};\n\n/**\n * DICOM (mask) segment: item of a SegmentSequence (0062,0002).\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.8.20.4.html}.\n */\nexport class MaskSegment {\n /**\n * Segment number (0062,0004).\n *\n * @type {number}\n */\n number;\n /**\n * Segment label (0062,0005).\n *\n * @type {string}\n */\n label;\n /**\n * Segment algorithm type (0062,0008).\n *\n * @type {string}\n */\n algorithmType;\n /**\n * Segment algorithm name (0062,0009).\n *\n * @type {string|undefined}\n */\n algorithmName;\n /**\n * Segment display value as simple value.\n *\n * @type {number|undefined}\n */\n displayValue;\n /**\n * Segment display value as RGB colour ({r,g,b}).\n *\n * @type {RGB|undefined}\n */\n displayRGBValue;\n /**\n * Segment property code: specific property\n * the segment represents (0062,000F).\n *\n * @type {DicomCode|undefined}\n */\n propertyTypeCode;\n /**\n * Segment property category code: general category\n * of the property the segment represents (0062,0003).\n *\n * @type {DicomCode|undefined}\n */\n propertyCategoryCode;\n /**\n * Segment tracking UID (0062,0021).\n *\n * @type {string|undefined}\n */\n trackingUid;\n /**\n * Segment tracking id: text label for the UID (0062,0020).\n *\n * @type {string|undefined}\n */\n trackingId;\n\n /**\n * @param {number} number The segment number.\n * @param {string} label The segment label.\n * @param {string} algorithmType The segment number.\n */\n constructor(number, label, algorithmType) {\n this.number = number;\n this.label = label;\n this.algorithmType = algorithmType;\n }\n}\n\n/**\n * Get a segment object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {MaskSegment} A segment object.\n */\nexport function getSegment(dataElements) {\n // number -> SegmentNumber (type1)\n // label -> SegmentLabel (type1)\n // algorithmType -> SegmentAlgorithmType (type1)\n const segment = new MaskSegment(\n dataElements[TagKeys.SegmentNumber].value[0],\n dataElements[TagKeys.SegmentLabel]\n ? dataElements[TagKeys.SegmentLabel].value[0] : 'n/a',\n dataElements[TagKeys.SegmentAlgorithmType].value[0]\n );\n // algorithmName -> SegmentAlgorithmName (type1C)\n if (typeof dataElements[TagKeys.SegmentAlgorithmName] !== 'undefined') {\n segment.algorithmName = dataElements[TagKeys.SegmentAlgorithmName].value[0];\n }\n // // required if type is not MANUAL\n // if (segment.algorithmType !== 'MANUAL' &&\n // (typeof segment.algorithmName === 'undefined' ||\n // segment.algorithmName.length === 0)) {\n // throw new Error('Empty algorithm name for non MANUAL algorithm type.');\n // }\n // displayValue ->\n // - RecommendedDisplayGrayscaleValue\n // - RecommendedDisplayCIELabValue converted to RGB\n if (typeof dataElements[TagKeys.RecommendedDisplayGrayscaleValue] !==\n 'undefined') {\n segment.displayValue =\n dataElements[TagKeys.RecommendedDisplayGrayscaleValue].value[0];\n } else if (typeof dataElements[TagKeys.RecommendedDisplayCIELabValue] !==\n 'undefined') {\n const cielabElement =\n dataElements[TagKeys.RecommendedDisplayCIELabValue].value;\n const rgb = cielabToSrgb(uintLabToLab({\n l: cielabElement[0],\n a: cielabElement[1],\n b: cielabElement[2]\n }));\n segment.displayRGBValue = rgb;\n }\n // Segmented Property Category Code Sequence (type1, only one)\n if (typeof dataElements[TagKeys.SegmentedPropertyCategoryCodeSequence] !==\n 'undefined') {\n segment.propertyCategoryCode =\n getCode(\n dataElements[TagKeys.SegmentedPropertyCategoryCodeSequence].value[0]\n );\n } else {\n throw new Error('Missing Segmented Property Category Code Sequence.');\n }\n // Segmented Property Type Code Sequence (type1)\n if (typeof dataElements[TagKeys.SegmentedPropertyTypeCodeSequence] !==\n 'undefined') {\n segment.propertyTypeCode =\n getCode(dataElements[TagKeys.SegmentedPropertyTypeCodeSequence].value[0]);\n } else {\n throw new Error('Missing Segmented Property Type Code Sequence.');\n }\n // tracking Id and UID (type1C)\n if (typeof dataElements[TagKeys.TrackingID] !== 'undefined') {\n segment.trackingId = dataElements[TagKeys.TrackingID].value[0];\n segment.trackingUid = dataElements[TagKeys.TrackingUID].value[0];\n }\n\n return segment;\n}\n\n/**\n * Check if two segment objects are equal.\n *\n * @param {MaskSegment} seg1 The first segment.\n * @param {MaskSegment} seg2 The second segment.\n * @returns {boolean} True if both segment are equal.\n */\nexport function isEqualSegment(seg1, seg2) {\n // basics\n if (typeof seg1 === 'undefined' ||\n typeof seg2 === 'undefined' ||\n seg1 === null ||\n seg2 === null) {\n return false;\n }\n let isEqual = seg1.number === seg2.number &&\n seg1.label === seg2.label &&\n seg1.algorithmType === seg2.algorithmType;\n // display value\n if (typeof seg1.displayRGBValue !== 'undefined' &&\n typeof seg2.displayRGBValue !== 'undefined') {\n isEqual = isEqual &&\n isEqualRgb(seg1.displayRGBValue, seg2.displayRGBValue);\n } else if (typeof seg1.displayValue !== 'undefined' &&\n typeof seg2.displayValue !== 'undefined') {\n isEqual = isEqual &&\n seg1.displayValue === seg2.displayValue;\n } else {\n isEqual = false;\n }\n // algorithmName\n if (typeof seg1.algorithmName !== 'undefined') {\n if (typeof seg2.algorithmName === 'undefined') {\n isEqual = false;\n } else {\n isEqual = isEqual &&\n seg1.algorithmName === seg2.algorithmName;\n }\n }\n\n return isEqual;\n}\n\n/**\n * Check if two segment objects are similar: either the\n * number or the displayValue are equal.\n *\n * @param {MaskSegment} seg1 The first segment.\n * @param {MaskSegment} seg2 The second segment.\n * @returns {boolean} True if both segment are similar.\n */\nexport function isSimilarSegment(seg1, seg2) {\n // basics\n if (typeof seg1 === 'undefined' ||\n typeof seg2 === 'undefined' ||\n seg1 === null ||\n seg2 === null) {\n return false;\n }\n let isSimilar = seg1.number === seg2.number;\n // display value\n if (typeof seg1.displayRGBValue !== 'undefined' &&\n typeof seg2.displayRGBValue !== 'undefined') {\n isSimilar = isSimilar ||\n isEqualRgb(seg1.displayRGBValue, seg2.displayRGBValue);\n } else if (typeof seg1.displayValue !== 'undefined' &&\n typeof seg2.displayValue !== 'undefined') {\n isSimilar = isSimilar ||\n seg1.displayValue === seg2.displayValue;\n } else {\n isSimilar = false;\n }\n\n return isSimilar;\n}\n\n/**\n * Get a dicom simple tag from a segment object.\n *\n * @param {MaskSegment} segment The segment object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomSegmentItem(segment) {\n let algoType = segment.algorithmType;\n if (algoType === undefined) {\n algoType = 'MANUAL';\n }\n // dicom item (tags are in group/element order)\n const segmentItem = {\n SegmentNumber: segment.number,\n SegmentLabel: segment.label,\n SegmentAlgorithmType: algoType\n };\n // SegmentAlgorithmName\n if (algoType !== 'MANUAL' && segment.algorithmName !== undefined) {\n segmentItem.SegmentAlgorithmName = segment.algorithmName;\n }\n // RecommendedDisplay value\n if (segment.displayRGBValue) {\n const cieLab = labToUintLab(srgbToCielab(segment.displayRGBValue));\n segmentItem.RecommendedDisplayCIELabValue = [\n Math.round(cieLab.l),\n Math.round(cieLab.a),\n Math.round(cieLab.b)\n ];\n } else {\n segmentItem.RecommendedDisplayGrayscaleValue = segment.displayValue;\n }\n // SegmentedPropertyCategoryCodeSequence\n if (segment.propertyCategoryCode) {\n segmentItem.SegmentedPropertyCategoryCodeSequence = {\n value: [getDicomCodeItem(segment.propertyCategoryCode)]\n };\n }\n // SegmentedPropertyTypeCodeSequence\n if (segment.propertyTypeCode) {\n segmentItem.SegmentedPropertyTypeCodeSequence = {\n value: [getDicomCodeItem(segment.propertyTypeCode)]\n };\n }\n // tracking\n if (segment.trackingId) {\n segmentItem.TrackingID = segment.trackingId;\n segmentItem.TrackingUID = segment.trackingUid;\n }\n // return\n return segmentItem;\n}\n","import {getSpacingFromMeasure} from './dicomElementsWrapper';\nimport {logger} from '../utils/logger';\nimport {arrayEquals} from '../utils/array';\nimport {\n getDicomCodeItem,\n getSegmentationCode,\n getSourceImageForProcessingCode\n} from './dicomCode';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\nimport {Spacing} from '../image/spacing';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n DerivationImageSequence: '00089124',\n SourceImageSequence: '00082112',\n ReferencedSOPClassUID: '00081150',\n ReferencedSOPInstanceUID: '00081155',\n FrameContentSequence: '00209111',\n DimensionIndexValue: '00209157',\n SegmentIdentificationSequence: '0062000A',\n ReferencedSegmentNumber: '0062000B',\n PlanePositionSequence: '00209113',\n ImagePosition: '00200032',\n PlaneOrientationSequence: '00209116',\n ImageOrientation: '00200037',\n PixelMeasuresSequence: '00289110'\n};\n\n/**\n * DICOM segment frame info: item of a\n * PerframeFunctionalGroupsSequence (5200,9230).\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.7.6.16.html}.\n */\nexport class DicomSegmentFrameInfo {\n /**\n * The dimension index.\n *\n * @type {number[]}\n */\n dimIndex;\n /**\n * The frame image position patient.\n *\n * @type {number[]}\n */\n imagePosPat;\n /**\n * List of derivation images.\n *\n * @type {Array}\n */\n derivationImages;\n /**\n * The reference segment number.\n *\n * @type {number}\n */\n refSegmentNumber;\n\n /**\n * The frame image orientation.\n *\n * @type {number[]|undefined}\n */\n imageOrientationPatient;\n /**\n * The frame spacing.\n *\n * @type {Spacing|undefined}\n */\n spacing;\n\n /**\n * @param {number[]} dimIndex The dimension index.\n * @param {number[]} imagePosPat The frame image position patient.\n * @param {Array} derivationImages List of derivation images.\n * @param {number} refSegmentNumber The reference segment number.\n */\n constructor(dimIndex, imagePosPat, derivationImages, refSegmentNumber) {\n this.dimIndex = dimIndex;\n this.imagePosPat = imagePosPat;\n this.derivationImages = derivationImages;\n this.refSegmentNumber = refSegmentNumber;\n }\n}\n\n/**\n * Get a frame information object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {DicomSegmentFrameInfo} A frame information object.\n */\nexport function getSegmentFrameInfo(dataElements) {\n // Derivation Image Sequence\n const derivationImages = [];\n if (typeof dataElements[TagKeys.DerivationImageSequence] !== 'undefined') {\n const derivationImageSq =\n dataElements[TagKeys.DerivationImageSequence].value;\n // Source Image Sequence\n for (let i = 0; i < derivationImageSq.length; ++i) {\n const sourceImages = [];\n if (typeof derivationImageSq[i][TagKeys.SourceImageSequence] !==\n 'undefined') {\n const sourceImageSq =\n derivationImageSq[i][TagKeys.SourceImageSequence].value;\n for (let j = 0; j < sourceImageSq.length; ++j) {\n const sourceImage = {};\n // Referenced SOP Class UID\n if (typeof sourceImageSq[j][TagKeys.ReferencedSOPClassUID] !==\n 'undefined') {\n sourceImage.referencedSOPClassUID =\n sourceImageSq[j][TagKeys.ReferencedSOPClassUID].value[0];\n }\n // Referenced SOP Instance UID\n if (typeof sourceImageSq[j][TagKeys.ReferencedSOPInstanceUID] !==\n 'undefined') {\n sourceImage.referencedSOPInstanceUID =\n sourceImageSq[j][TagKeys.ReferencedSOPInstanceUID].value[0];\n }\n sourceImages.push(sourceImage);\n }\n }\n derivationImages.push({\n sourceImages: sourceImages\n });\n }\n }\n // Frame Content Sequence (required, only one)\n const frameContentSq = dataElements[TagKeys.FrameContentSequence].value;\n // Dimension Index Value\n const dimIndex = frameContentSq[0][TagKeys.DimensionIndexValue].value;\n // Segment Identification Sequence (required, only one)\n const segmentIdSq = dataElements[TagKeys.SegmentIdentificationSequence].value;\n // Referenced Segment Number\n const refSegmentNumber =\n parseInt(segmentIdSq[0][TagKeys.ReferencedSegmentNumber].value[0], 0);\n // Plane Position Sequence (required, only one)\n const planePosSq = dataElements[TagKeys.PlanePositionSequence].value;\n // Image Position (Patient) (conditionally required)\n const imagePosPat = planePosSq[0][TagKeys.ImagePosition].value;\n for (let p = 0; p < imagePosPat.length; ++p) {\n imagePosPat[p] = parseFloat(imagePosPat[p]);\n }\n const frameInfo = new DicomSegmentFrameInfo(\n dimIndex,\n imagePosPat,\n derivationImages,\n refSegmentNumber\n );\n // Plane Orientation Sequence\n if (typeof dataElements[TagKeys.PlaneOrientationSequence] !== 'undefined') {\n const framePlaneOrientationSeq =\n dataElements[TagKeys.PlaneOrientationSequence];\n if (framePlaneOrientationSeq.value.length !== 0) {\n // should only be one Image Orientation (Patient)\n const frameImageOrientation =\n framePlaneOrientationSeq.value[0][TagKeys.ImageOrientation].value;\n if (typeof frameImageOrientation !== 'undefined') {\n frameInfo.imageOrientationPatient = frameImageOrientation;\n }\n }\n }\n // Pixel Measures Sequence\n if (typeof dataElements[TagKeys.PixelMeasuresSequence] !== 'undefined') {\n const framePixelMeasuresSeq = dataElements[TagKeys.PixelMeasuresSequence];\n if (framePixelMeasuresSeq.value.length !== 0) {\n // should only be one\n const frameSpacing =\n getSpacingFromMeasure(framePixelMeasuresSeq.value[0]);\n if (typeof frameSpacing !== 'undefined') {\n frameInfo.spacing = frameSpacing;\n }\n } else {\n logger.warn(\n 'No shared functional group pixel measure sequence items.');\n }\n }\n\n return frameInfo;\n}\n\n/**\n * Check if two frame info objects are equal.\n *\n * @param {DicomSegmentFrameInfo} dsfi1 The first frame info.\n * @param {DicomSegmentFrameInfo} dsfi2 The second frame info.\n * @returns {boolean} True if both frame info are equal.\n */\nexport function isEqualSegmentFrameInfo(dsfi1, dsfi2) {\n // basics\n if (typeof dsfi1 === 'undefined' ||\n typeof dsfi2 === 'undefined' ||\n dsfi1 === null ||\n dsfi2 === null) {\n return false;\n }\n let isEqual =\n arrayEquals(dsfi1.dimIndex, dsfi2.dimIndex) &&\n arrayEquals(dsfi1.imagePosPat, dsfi2.imagePosPat) &&\n dsfi1.refSegmentNumber === dsfi2.refSegmentNumber;\n\n isEqual = isEqual &&\n dsfi1.derivationImages.length === dsfi2.derivationImages.length;\n for (let i = 0; i < dsfi1.derivationImages.length; ++i) {\n const derivationImage1 = dsfi1.derivationImages[i];\n const derivationImage2 = dsfi2.derivationImages[i];\n isEqual = isEqual &&\n derivationImage1.sourceImages.length ===\n derivationImage2.sourceImages.length;\n for (let j = 0; j < derivationImage1.length; ++j) {\n const sourceImage1 = derivationImage1.sourceImages[j];\n const sourceImage2 = derivationImage2.sourceImages[j];\n isEqual = isEqual &&\n sourceImage1.referencedSOPClassUID ===\n sourceImage2.referencedSOPClassUID &&\n sourceImage1.referencedSOPInstanceUID ===\n sourceImage2.referencedSOPInstanceUID;\n }\n }\n\n return isEqual;\n}\n\n/**\n * Get a dicom item from a frame information object.\n *\n * @param {object} frameInfo The frame information object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomSegmentFrameInfoItem(frameInfo) {\n const item = {\n FrameContentSequence: {\n value: [\n {\n DimensionIndexValues: frameInfo.dimIndex\n }\n ]\n },\n PlanePositionSequence: {\n value: [\n {\n ImagePositionPatient: frameInfo.imagePosPat\n }\n ]\n },\n SegmentIdentificationSequence: {\n value: [\n {\n ReferencedSegmentNumber: frameInfo.refSegmentNumber\n }\n ]\n }\n };\n // optional DerivationImageSequence\n if (frameInfo.derivationImages !== undefined) {\n const sourceImgPurposeOfReferenceCode =\n getDicomCodeItem(getSourceImageForProcessingCode());\n const segDerivationCode =\n getDicomCodeItem(getSegmentationCode());\n\n const derivationImageItems = [];\n for (const derivationImage of frameInfo.derivationImages) {\n const sourceImages = [];\n for (const sourceImage of derivationImage.sourceImages) {\n sourceImages.push({\n PurposeOfReferenceCodeSequence: {\n value: [sourceImgPurposeOfReferenceCode]\n },\n ReferencedSOPClassUID: sourceImage.referencedSOPClassUID,\n ReferencedSOPInstanceUID: sourceImage.referencedSOPInstanceUID\n });\n }\n\n derivationImageItems.push({\n DerivationCodeSequence: {\n value: [segDerivationCode]\n },\n SourceImageSequence: {\n value: sourceImages\n }\n });\n }\n\n item.DerivationImageSequence = {\n value: derivationImageItems\n };\n }\n\n return item;\n}\n","import {\n dateToDateObj,\n getDicomDate,\n dateToTimeObj,\n getDicomTime,\n} from '../dicom/dicomDate';\nimport {\n getImage2DSize,\n getSpacingFromMeasure,\n getDimensionOrganization,\n getDicomMeasureItem,\n getDicomPlaneOrientationItem\n} from '../dicom/dicomElementsWrapper';\nimport {Tag} from '../dicom/dicomTag';\nimport {getElementsFromJSONTags} from '../dicom/dicomWriter';\nimport {\n getSegment,\n getDicomSegmentItem,\n} from '../dicom/dicomSegment';\nimport {\n getSegmentFrameInfo,\n getDicomSegmentFrameInfoItem\n} from '../dicom/dicomSegmentFrameInfo';\nimport {transferSyntaxKeywords} from '../dicom/dictionary';\nimport {Image} from '../image/image';\nimport {Geometry} from '../image/geometry';\nimport {Point, Point3D} from '../math/point';\nimport {Vector3D} from '../math/vector';\nimport {Index} from '../math/index';\nimport {Matrix33, REAL_WORLD_EPSILON} from '../math/matrix';\nimport {logger} from '../utils/logger';\nimport {arraySortEquals} from '../utils/array';\nimport {Size} from './size';\nimport {ColourMap} from './luts';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from '../dicom/dataElement';\nimport {MaskSegment} from '../dicom/dicomSegment';\n/* eslint-enable no-unused-vars */\n\n/**\n * @typedef {Object} DataElements\n */\n\n/**\n * Check two position patients for equality.\n *\n * @param {*} pos1 The first position patient.\n * @param {*} pos2 The second position patient.\n * @returns {boolean} True is equal.\n */\nfunction equalPosPat(pos1, pos2) {\n return JSON.stringify(pos1) === JSON.stringify(pos2);\n}\n\n/**\n * @callback compareFn\n * @param {object} a The first object.\n * @param {object} b The first object.\n * @returns {number} >0 to sort a after b, <0 to sort a before b,\n * 0 to not change order.\n */\n\n/**\n * Get a position patient compare function accroding to an\n * input orientation.\n *\n * @param {Matrix33} orientation The orientation matrix.\n * @returns {compareFn} The position compare function.\n */\nfunction getComparePosPat(orientation) {\n const invOrientation = orientation.getInverse();\n return function (pos1, pos2) {\n const p1 = invOrientation.multiplyArray3D(pos1);\n const p2 = invOrientation.multiplyArray3D(pos2);\n return p1[2] - p2[2];\n };\n}\n\n/**\n * Merge two tag lists.\n *\n * @param {object} tags1 Base list, will be modified.\n * @param {object} tags2 List to merge.\n */\nfunction mergeTags(tags1, tags2) {\n const keys2 = Object.keys(tags2);\n for (const tagName2 of keys2) {\n if (tags1[tagName2] !== undefined) {\n logger.trace('Overwritting tag: ' + tagName2);\n }\n tags1[tagName2] = tags2[tagName2];\n }\n}\n\n/**\n * Check that a DICOM tag definition is present in a parsed element.\n *\n * @param {DataElements} dataElements The root dicom element.\n * @param {object} tagDefinition The tag definition as {name, tag, type, enum}.\n */\nfunction checkTag(dataElements, tagDefinition) {\n const element = dataElements[tagDefinition.tag];\n // check null and undefined\n if (tagDefinition.type === 1 || tagDefinition.type === 2) {\n if (typeof element === 'undefined') {\n throw new Error('Missing or empty ' + tagDefinition.name);\n }\n } else {\n if (typeof element === 'undefined') {\n // non mandatory value, exit\n return;\n }\n }\n let includes = false;\n let tagValue;\n if (element.value.length === 1) {\n tagValue = element.value[0];\n } else {\n tagValue = element.value;\n }\n if (Array.isArray(tagValue)) {\n for (let i = 0; i < tagDefinition.enum.length; ++i) {\n if (!Array.isArray(tagDefinition.enum[i])) {\n throw new Error('Cannot compare array and non array tag value.');\n }\n if (arraySortEquals(tagDefinition.enum[i], tagValue)) {\n includes = true;\n break;\n }\n }\n } else {\n includes = tagDefinition.enum.includes(tagValue);\n }\n if (!includes) {\n throw new Error(\n 'Unsupported ' + tagDefinition.name + ' value: ' + tagValue);\n }\n}\n\n/**\n * Create ROI slice buffers.\n *\n * @param {Image} image The mask image.\n * @param {MaskSegment[]} segments The mask segments.\n * @param {number} sliceOffset The slice offset.\n * @returns {object} The ROI slice image buffers.\n */\nfunction createRoiSliceBuffers(\n image,\n segments,\n sliceOffset\n) {\n // create binary mask buffers\n const geometry = image.getGeometry();\n const size = geometry.getSize();\n const sliceSize = size.getDimSize(2);\n const buffers = {};\n for (let o = 0; o < sliceSize; ++o) {\n const inputOffset = sliceOffset + o;\n const pixelValue = image.getValueAtOffset(inputOffset);\n for (const segment of segments) {\n const segmentIndex = segment.number - 1;\n if (pixelValue === segment.number) {\n if (buffers[segmentIndex] === undefined) {\n buffers[segmentIndex] = new Uint8Array(sliceSize);\n }\n buffers[segmentIndex][o] = 1;\n }\n }\n }\n return buffers;\n}\n\n/**\n * Create ROI buffers.\n *\n * @param {Image} image The mask image.\n * @param {MaskSegment[]} segments The mask segments.\n * @returns {object} The ROI buffers.\n */\nfunction createRoiBuffers(image, segments) {\n const geometry = image.getGeometry();\n const size = geometry.getSize();\n\n // image buffer to multi frame\n const sliceSize = size.getDimSize(2);\n const roiBuffers = {};\n for (let k = 0; k < size.get(2); ++k) {\n const sliceOffset = k * sliceSize;\n // create slice buffers\n const buffers = createRoiSliceBuffers(image, segments, sliceOffset);\n // store slice buffers\n const keys0 = Object.keys(buffers);\n for (const key0 of keys0) {\n if (roiBuffers[key0] === undefined) {\n roiBuffers[key0] = {};\n }\n // ordering by slice index (follows posPat)\n roiBuffers[key0][k] = buffers[key0];\n }\n }\n return roiBuffers;\n}\n\n/**\n * List of DICOM Seg required tags.\n */\nconst RequiredDicomSegTags = [\n {\n name: 'TransferSyntaxUID',\n tag: '00020010',\n type: '1',\n enum: [\n transferSyntaxKeywords.ImplicitVRLittleEndian,\n transferSyntaxKeywords.ExplicitVRLittleEndian,\n transferSyntaxKeywords.ExplicitVRBigEndian\n ]\n },\n {\n name: 'MediaStorageSOPClassUID',\n tag: '00020002',\n type: '1',\n enum: ['1.2.840.10008.5.1.4.1.1.66.4']\n },\n {\n name: 'SOPClassUID',\n tag: '00020002',\n type: '1',\n enum: ['1.2.840.10008.5.1.4.1.1.66.4']\n },\n {\n name: 'Modality',\n tag: '00080060',\n type: '1',\n enum: ['SEG']\n },\n {\n name: 'SegmentationType',\n tag: '00620001',\n type: '1',\n enum: ['BINARY']\n },\n {\n name: 'DimensionOrganizationType',\n tag: '00209311',\n type: '3',\n enum: ['3D']\n },\n {\n name: 'ImageType',\n tag: '00080008',\n type: '1',\n enum: [['DERIVED', 'PRIMARY']]\n },\n {\n name: 'SamplesPerPixel',\n tag: '00280002',\n type: '1',\n enum: [1]\n },\n {\n name: 'PhotometricInterpretation',\n tag: '00280004',\n type: '1',\n enum: ['MONOCHROME2']\n },\n {\n name: 'PixelRepresentation',\n tag: '00280103',\n type: '1',\n enum: [0]\n },\n {\n name: 'BitsAllocated',\n tag: '00280100',\n type: '1',\n enum: [1]\n },\n {\n name: 'BitsStored',\n tag: '00280101',\n type: '1',\n enum: [1]\n },\n {\n name: 'HighBit',\n tag: '00280102',\n type: '1',\n enum: [0]\n },\n];\n\n/**\n * Get the default DICOM seg tags as an object.\n *\n * @returns {object} The default tags.\n */\nexport function getDefaultDicomSegJson() {\n const tags = {};\n for (let i = 0; i < RequiredDicomSegTags.length; ++i) {\n const reqTag = RequiredDicomSegTags[i];\n tags[reqTag.name] = reqTag.enum[0];\n }\n return tags;\n}\n\n/**\n * Mask {@link Image} factory.\n */\nexport class MaskFactory {\n\n /**\n * Possible warning created by checkElements.\n *\n * @type {string|undefined}\n */\n #warning;\n\n /**\n * Get a warning string if elements are not as expected.\n * Created by checkElements.\n *\n * @returns {string|undefined} The warning.\n */\n getWarning() {\n return this.#warning;\n }\n\n /**\n * Check dicom elements. Throws an error if not suitable.\n *\n * @param {Object} _dicomElements The DICOM tags.\n * @returns {string|undefined} A possible warning.\n */\n checkElements(_dicomElements) {\n // does nothing\n return;\n }\n\n /**\n * Get an {@link Image} object from the read DICOM file.\n *\n * @param {Object} dataElements The DICOM tags.\n * @param {Uint8Array | Int8Array |\n * Uint16Array | Int16Array |\n * Uint32Array | Int32Array} pixelBuffer The pixel buffer.\n * @returns {Image} A new Image.\n */\n create(dataElements, pixelBuffer) {\n // check required and supported tags\n for (let d = 0; d < RequiredDicomSegTags.length; ++d) {\n checkTag(dataElements, RequiredDicomSegTags[d]);\n }\n\n // image size\n const size2D = getImage2DSize(dataElements);\n const size = new Size([size2D[0], size2D[1], 1]);\n\n const sliceSize = size.getTotalSize();\n\n // frames\n let frames = 1;\n const framesElem = dataElements['00280008'];\n if (typeof framesElem !== 'undefined') {\n frames = parseInt(framesElem.value[0], 10);\n }\n\n if (frames !== pixelBuffer.length / sliceSize) {\n throw new Error(\n 'Buffer and numberOfFrames meta are not equal.' +\n frames + ' ' + pixelBuffer.length / sliceSize);\n }\n\n // Dimension Organization and Index\n const dimension = getDimensionOrganization(dataElements);\n\n // Segment Sequence\n const segSequence = dataElements['00620002'];\n if (typeof segSequence === 'undefined') {\n throw new Error('Missing or empty segmentation sequence');\n }\n const segments = [];\n // segment number is unique and starts at 1, use 0 as background\n const redLut = [0];\n const greenLut = [0];\n const blueLut = [0];\n for (let i = 0; i < segSequence.value.length; ++i) {\n const segment = getSegment(segSequence.value[i]);\n if (typeof segment.displayRGBValue !== 'undefined') {\n // add palette colour\n redLut[segment.number] = segment.displayRGBValue.r;\n greenLut[segment.number] = segment.displayRGBValue.g;\n blueLut[segment.number] = segment.displayRGBValue.b;\n }\n // store\n segments.push(segment);\n }\n\n let hasDisplayRGBValue = false;\n let paletteColourMap;\n if (redLut.length > 1) {\n hasDisplayRGBValue = true;\n paletteColourMap = new ColourMap(redLut, greenLut, blueLut);\n }\n\n // Shared Functional Groups Sequence\n let spacing;\n let imageOrientationPatient;\n const sharedFunctionalGroupsSeq = dataElements['52009229'];\n if (typeof sharedFunctionalGroupsSeq !== 'undefined') {\n // should be only one\n const funcGroup0 = sharedFunctionalGroupsSeq.value[0];\n // Plane Orientation Sequence\n if (typeof funcGroup0['00209116'] !== 'undefined') {\n const planeOrientationSeq = funcGroup0['00209116'];\n if (planeOrientationSeq.value.length !== 0) {\n // should be only one\n imageOrientationPatient =\n planeOrientationSeq.value[0]['00200037'].value;\n } else {\n logger.warn(\n 'No shared functional group plane orientation sequence items.');\n }\n }\n // Pixel Measures Sequence\n if (typeof funcGroup0['00289110'] !== 'undefined') {\n const pixelMeasuresSeq = funcGroup0['00289110'];\n if (pixelMeasuresSeq.value.length !== 0) {\n // should be only one\n spacing = getSpacingFromMeasure(pixelMeasuresSeq.value[0]);\n } else {\n logger.warn(\n 'No shared functional group pixel measure sequence items.');\n }\n }\n }\n\n const includesPosPat = function (arr, val) {\n return arr.some(function (arrVal) {\n return equalPosPat(val, arrVal);\n });\n };\n\n const findIndexPosPat = function (arr, val) {\n return arr.findIndex(function (arrVal) {\n return equalPosPat(val, arrVal);\n });\n };\n\n // Per-frame Functional Groups Sequence\n const perFrameFuncGroupSequence = dataElements['52009230'];\n if (typeof perFrameFuncGroupSequence === 'undefined') {\n throw new Error('Missing or empty per frame functional sequence');\n }\n if (frames !== perFrameFuncGroupSequence.value.length) {\n throw new Error(\n 'perFrameFuncGroupSequence meta and numberOfFrames are not equal.');\n }\n // create frame info object from per frame func\n const frameInfos = [];\n for (let j = 0; j < perFrameFuncGroupSequence.value.length; ++j) {\n frameInfos.push(\n getSegmentFrameInfo(perFrameFuncGroupSequence.value[j]));\n }\n\n // check frame infos\n const framePosPats = [];\n for (let ii = 0; ii < frameInfos.length; ++ii) {\n if (!includesPosPat(framePosPats, frameInfos[ii].imagePosPat)) {\n framePosPats.push(frameInfos[ii].imagePosPat);\n }\n // store orientation if needed, avoid multi\n if (typeof frameInfos[ii].imageOrientationPatient !== 'undefined') {\n if (typeof imageOrientationPatient === 'undefined') {\n imageOrientationPatient = frameInfos[ii].imageOrientationPatient;\n } else {\n if (!arraySortEquals(\n imageOrientationPatient, frameInfos[ii].imageOrientationPatient)) {\n throw new Error('Unsupported multi orientation dicom seg.');\n }\n }\n }\n // store spacing if needed, avoid multi\n if (typeof frameInfos[ii].spacing !== 'undefined') {\n if (typeof spacing === 'undefined') {\n spacing = frameInfos[ii].spacing;\n } else {\n if (!spacing.equals(frameInfos[ii].spacing)) {\n throw new Error('Unsupported multi resolution dicom seg.');\n }\n }\n }\n }\n\n // check spacing and orientation\n if (typeof spacing === 'undefined') {\n throw new Error('No spacing found for DICOM SEG');\n }\n if (spacing.length() !== 3) {\n throw new Error('Incomplete spacing found for DICOM SEG');\n }\n if (typeof imageOrientationPatient === 'undefined') {\n throw new Error('No imageOrientationPatient found for DICOM SEG');\n }\n if (imageOrientationPatient.length !== 6) {\n throw new Error('Incomplete imageOrientationPatient found for DICOM SEG');\n }\n\n // orientation\n const rowCosines = new Vector3D(\n parseFloat(imageOrientationPatient[0]),\n parseFloat(imageOrientationPatient[1]),\n parseFloat(imageOrientationPatient[2]));\n const colCosines = new Vector3D(\n parseFloat(imageOrientationPatient[3]),\n parseFloat(imageOrientationPatient[4]),\n parseFloat(imageOrientationPatient[5]));\n const normal = rowCosines.crossProduct(colCosines);\n /* eslint-disable @stylistic/js/array-element-newline */\n const orientationMatrix = new Matrix33([\n rowCosines.getX(), colCosines.getX(), normal.getX(),\n rowCosines.getY(), colCosines.getY(), normal.getY(),\n rowCosines.getZ(), colCosines.getZ(), normal.getZ()\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n\n // sort positions patient\n framePosPats.sort(getComparePosPat(orientationMatrix));\n\n const point3DFromArray = function (arr) {\n return new Point3D(arr[0], arr[1], arr[2]);\n };\n\n // frame origins\n const frameOrigins = [];\n for (let n = 0; n < framePosPats.length; ++n) {\n frameOrigins.push(point3DFromArray(framePosPats[n]));\n }\n\n // tmp geometry with correct spacing but only one slice\n const tmpGeometry = new Geometry(\n frameOrigins[0], size, spacing, orientationMatrix);\n\n // origin distance test\n // TODO: maybe use sliceSpacing / 10\n const isAboveEpsilon = function (value) {\n let res = value > REAL_WORLD_EPSILON;\n if (res) {\n // try larger epsilon\n res = value > REAL_WORLD_EPSILON * 10;\n if (!res) {\n // warn if epsilon < value < epsilon * 10\n logger.warn(\n 'Using larger real world epsilon in SEG pos pat adding'\n );\n } else {\n res = value > REAL_WORLD_EPSILON * 100;\n if (!res) {\n // warn if epsilon < value < epsilon * 100\n logger.warn(\n 'Using larger+ real world epsilon in SEG pos pat adding'\n );\n }\n }\n }\n return res;\n };\n\n // add possibly missing posPats\n const posPats = [];\n posPats.push(framePosPats[0]);\n let sliceIndex = 0;\n for (let g = 1; g < framePosPats.length; ++g) {\n ++sliceIndex;\n let index = new Index([0, 0, sliceIndex]);\n let point = tmpGeometry.indexToWorld(index).get3D();\n const frameOrigin = frameOrigins[g];\n // check if more pos pats are needed\n let dist = frameOrigin.getDistance(point);\n const distPrevious = dist;\n // TODO: good threshold?\n while (isAboveEpsilon(dist)) {\n logger.debug('Adding intermediate pos pats for DICOM seg at ' +\n point.toString());\n posPats.push([point.getX(), point.getY(), point.getZ()]);\n ++sliceIndex;\n index = new Index([0, 0, sliceIndex]);\n point = tmpGeometry.indexToWorld(index).get3D();\n dist = frameOrigin.getDistance(point);\n if (dist > distPrevious) {\n throw new Error(\n 'Test distance is increasing when adding intermediate pos pats');\n }\n }\n // add frame pos pat\n posPats.push(framePosPats[g]);\n }\n\n // as many slices as posPats\n const numberOfSlices = posPats.length;\n\n // final geometry\n const geometry = new Geometry(\n frameOrigins[0], size, spacing, orientationMatrix);\n const uids = ['0'];\n for (let m = 1; m < numberOfSlices; ++m) {\n geometry.appendOrigin(point3DFromArray(posPats[m]), m);\n uids.push(m.toString());\n }\n\n const getFindSegmentFunc = function (number) {\n return function (item) {\n return item.number === number;\n };\n };\n\n // create output buffer\n const buffer =\n // @ts-ignore\n new pixelBuffer.constructor(sliceSize * numberOfSlices);\n buffer.fill(0);\n // merge frame buffers\n let sliceOffset = null;\n let frameOffset = null;\n for (let f = 0; f < frameInfos.length; ++f) {\n // get the slice index from the position in the posPat array\n sliceIndex = findIndexPosPat(posPats, frameInfos[f].imagePosPat);\n frameOffset = sliceSize * f;\n sliceOffset = sliceSize * sliceIndex;\n // get the frame display value\n const frameSegment = segments.find(\n getFindSegmentFunc(frameInfos[f].refSegmentNumber)\n );\n for (let l = 0; l < sliceSize; ++l) {\n if (pixelBuffer[frameOffset + l] !== 0) {\n const offset = sliceOffset + l;\n if (hasDisplayRGBValue) {\n buffer[offset] = frameSegment.number;\n } else {\n buffer[offset] = frameSegment.displayValue;\n }\n }\n }\n }\n\n // create image\n const image = new Image(geometry, buffer, uids);\n if (hasDisplayRGBValue) {\n image.setPhotometricInterpretation('PALETTE COLOR');\n image.setPaletteColourMap(paletteColourMap);\n }\n // meta information\n const meta = getDefaultDicomSegJson();\n const safeGet = function (key) {\n let res;\n const element = dataElements[key];\n if (typeof element !== 'undefined') {\n res = element.value[0];\n }\n return res;\n };\n // Study\n meta.StudyDate = safeGet('00080020');\n meta.StudyTime = safeGet('00080030');\n meta.StudyInstanceUID = safeGet('0020000D');\n meta.StudyID = safeGet('00200010');\n // Series\n meta.SeriesDate = safeGet('00080021');\n meta.SeriesTime = safeGet('00080031');\n meta.SeriesInstanceUID = safeGet('0020000E');\n meta.SeriesNumber = safeGet('00200011');\n // ReferringPhysicianName\n meta.ReferringPhysicianName = safeGet('00080090');\n // patient info\n meta.PatientName = safeGet('00100010');\n meta.PatientID = safeGet('00100020');\n meta.PatientBirthDate = safeGet('00100030');\n meta.PatientSex = safeGet('00100040');\n // Enhanced General Equipment Module\n meta.Manufacturer = safeGet('00080070');\n meta.ManufacturerModelName = safeGet('00081090');\n meta.DeviceSerialNumber = safeGet('00181000');\n meta.SoftwareVersions = safeGet('00181020');\n // dicom seg dimension\n meta.DimensionOrganizationSequence = dimension.organizations;\n meta.DimensionIndexSequence = dimension.indices;\n // custom\n meta.custom = {\n segments: segments,\n frameInfos: frameInfos,\n SOPInstanceUID: dataElements['00080018'].value[0]\n };\n\n // number of files: in this case equal to number slices,\n // used to calculate buffer size\n meta.numberOfFiles = numberOfSlices;\n // FrameOfReferenceUID (optional)\n const frameOfReferenceUID = dataElements['00200052'];\n if (frameOfReferenceUID) {\n meta.FrameOfReferenceUID = frameOfReferenceUID.value[0];\n }\n // LossyImageCompression (optional)\n const lossyImageCompression = dataElements['00282110'];\n if (lossyImageCompression) {\n meta.LossyImageCompression = lossyImageCompression.value[0];\n }\n\n image.setMeta(meta);\n\n return image;\n }\n\n /**\n * Convert a mask image into a DICOM segmentation object.\n *\n * @param {Image} image The mask image.\n * @param {MaskSegment[]} segments The mask segments.\n * @param {Image} sourceImage The source image.\n * @param {Object} [extraTags] Optional list of extra tags.\n * @returns {Object} A list of dicom elements.\n */\n toDicom(\n image,\n segments,\n sourceImage,\n extraTags\n ) {\n // original image tags\n const tags = image.getMeta();\n\n // use image segments if not provided as input\n if (segments === undefined) {\n segments = tags.segments;\n }\n\n const geometry = image.getGeometry();\n const size = geometry.getSize();\n\n // (not in meta)\n tags.Rows = size.get(1);\n tags.Columns = size.get(0);\n // update content tags\n const now = new Date();\n tags.ContentDate = getDicomDate(dateToDateObj(now));\n tags.ContentTime = getDicomTime(dateToTimeObj(now));\n\n // keep source image StudyInstanceUID\n if (sourceImage !== undefined) {\n tags.StudyInstanceUID = (sourceImage.getMeta()).StudyInstanceUID;\n }\n\n // segments\n const segmentItems = [];\n for (const segment of segments) {\n segmentItems.push(getDicomSegmentItem(segment));\n }\n tags.SegmentSequence = {\n value: segmentItems\n };\n\n // Shared Functional Groups Sequence\n tags.SharedFunctionalGroupsSequence = {\n value: [\n {\n PlaneOrientationSequence: {\n value: [getDicomPlaneOrientationItem(geometry.getOrientation())]\n },\n PixelMeasuresSequence: {\n value: [getDicomMeasureItem(geometry.getSpacing())]\n }\n }\n ]\n };\n\n // image buffer to multi frame\n const roiBuffers = createRoiBuffers(image, segments);\n\n const frameInfos = [];\n\n // flatten buffer array\n const finalBuffers = [];\n const referencedSOPs = [];\n for (const segment of segments) {\n const number40 = segment.number;\n const number4 = number40 - 1;\n // check if buffer has values\n if (roiBuffers[number4] === undefined) {\n continue;\n }\n const keys1 = Object.keys(roiBuffers[number4]);\n // revert slice order\n for (let k1 = keys1.length - 1; k1 >= 0; --k1) {\n const key1 = Number.parseInt(keys1[k1], 10);\n finalBuffers.push(roiBuffers[number4][key1]);\n // frame info\n const posPat = image.getGeometry().getOrigins()[key1];\n const posPatArray = [posPat.getX(), posPat.getY(), posPat.getZ()];\n const frameInfo = {\n dimIndex: [number40, keys1.length - k1],\n imagePosPat: posPatArray,\n refSegmentNumber: number40\n };\n // derivation image info\n if (sourceImage !== undefined) {\n const sourceGeometry = sourceImage.getGeometry();\n const sourceIndex = sourceGeometry.worldToIndex(\n new Point([posPat.getX(), posPat.getY(), posPat.getZ()])\n );\n frameInfo.derivationImages = [\n {\n sourceImages: [\n {\n referencedSOPInstanceUID:\n sourceImage.getImageUid(sourceIndex),\n referencedSOPClassUID:\n (sourceImage.getMeta()).SOPClassUID\n }\n ]\n }\n ];\n // store as tag\n referencedSOPs.push({\n ReferencedSOPInstanceUID:\n sourceImage.getImageUid(sourceIndex),\n ReferencedSOPClassUID:\n (sourceImage.getMeta()).SOPClassUID\n });\n }\n frameInfos.push(frameInfo);\n }\n }\n\n tags.NumberOfFrames = finalBuffers.length.toString();\n\n // frame infos\n const frameInfosTag = [];\n for (const frameInfo of frameInfos) {\n frameInfosTag.push(getDicomSegmentFrameInfoItem(frameInfo));\n }\n tags.PerFrameFunctionalGroupsSequence = {\n value: frameInfosTag\n };\n\n // also store referenced SOPs in ReferencedSeriesSequence\n if (sourceImage !== undefined) {\n const refSeriesTag = [];\n refSeriesTag.push({\n ReferencedInstanceSequence: {\n value: referencedSOPs\n },\n SeriesInstanceUID: (sourceImage.getMeta()).SeriesInstanceUID\n });\n tags.ReferencedSeriesSequence = {\n value: refSeriesTag\n };\n }\n\n // merge extra tags if provided\n if (extraTags !== undefined) {\n mergeTags(tags, extraTags);\n }\n\n // convert JSON to DICOM element object\n const dicomElements = getElementsFromJSONTags(tags);\n\n // pixel value length: divide by 8 to trigger binary write\n const sliceSize = size.getDimSize(2);\n const pixVl = (finalBuffers.length * sliceSize) / 8;\n const de = new DataElement('OB');\n de.tag = new Tag('7FE0', '0010');\n de.vl = pixVl;\n de.value = finalBuffers;\n dicomElements['7FE00010'] = de;\n\n return dicomElements;\n }\n\n} // class MaskFactory\n","import {Index} from '../math/index';\nimport {Point3D} from '../math/point';\nimport {logger} from '../utils/logger';\nimport {arrayContains} from '../utils/array';\nimport {getTypedArray} from '../dicom/dicomParser';\nimport {ListenerHandler} from '../utils/listen';\nimport {valueRange} from './iterator';\nimport {RescaleSlopeAndIntercept} from './rsi';\nimport {ImageFactory} from './imageFactory';\nimport {MaskFactory} from './maskFactory';\nimport {isMonochrome} from '../dicom/dicomElementsWrapper';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Geometry} from './geometry';\nimport {Matrix33} from '../math/matrix';\nimport {NumberRange} from '../math/stats';\nimport {DataElement} from '../dicom/dataElement';\nimport {RGB} from '../utils/colour';\nimport {ColourMap} from './luts';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get the slice index of an input slice into a volume geometry.\n *\n * @param {Geometry} volumeGeometry The volume geometry.\n * @param {Geometry} sliceGeometry The slice geometry.\n * @returns {Index} The index of the slice in the volume geomtry.\n */\nfunction getSliceIndex(volumeGeometry, sliceGeometry) {\n // possible time\n const timeId = sliceGeometry.getInitialTime();\n // index values\n const values = [];\n // x, y\n values.push(0);\n values.push(0);\n // z\n values.push(volumeGeometry.getSliceIndex(sliceGeometry.getOrigin(), timeId));\n // time\n if (typeof timeId !== 'undefined') {\n values.push(timeId);\n }\n // return index\n return new Index(values);\n}\n\n/**\n * Create an Image from DICOM elements.\n *\n * @param {Object} elements The DICOM elements.\n * @returns {Image} The Image object.\n */\nexport function createImage(elements) {\n const factory = new ImageFactory();\n return factory.create(\n elements,\n elements['7FE00010'].value[0],\n 1\n );\n}\n\n/**\n * Create a mask Image from DICOM elements.\n *\n * @param {Object} elements The DICOM elements.\n * @returns {Image} The mask Image object.\n */\nexport function createMaskImage(elements) {\n const factory = new MaskFactory();\n return factory.create(\n elements,\n elements['7FE00010'].value[0]\n );\n}\n\n/**\n * Image class.\n * Usable once created, optional are:\n * - rescale slope and intercept (default 1:0),\n * - photometric interpretation (default MONOCHROME2),\n * - planar configuration (default RGBRGB...).\n *\n * @example\n * // XMLHttpRequest onload callback\n * const onload = function (event) {\n * // parse the dicom buffer\n * const dicomParser = new dwv.DicomParser();\n * dicomParser.parse(event.target.response);\n * // create the image object\n * const image = dwv.createImage(dicomParser.getDicomElements());\n * // result div\n * const div = document.getElementById('dwv');\n * // display the image size\n * const size = image.getGeometry().getSize();\n * div.appendChild(document.createTextNode(\n * 'Size: ' + size.toString() +\n * ' (should be 256,256,1)'));\n * // break line\n * div.appendChild(document.createElement('br'));\n * // display a pixel value\n * div.appendChild(document.createTextNode(\n * 'Pixel @ [128,40,0]: ' +\n * image.getRescaledValue(128,40,0) +\n * ' (should be 101)'));\n * };\n * // DICOM file request\n * const request = new XMLHttpRequest();\n * const url = 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm';\n * request.open('GET', url);\n * request.responseType = 'arraybuffer';\n * request.onload = onload;\n * request.send();\n */\nexport class Image {\n\n /**\n * Data geometry.\n *\n * @type {Geometry}\n */\n #geometry;\n\n /**\n * List of compatible typed arrays.\n *\n * @typedef {(\n * Uint8Array | Int8Array |\n * Uint16Array | Int16Array |\n * Uint32Array | Int32Array\n * )} TypedArray\n */\n\n /**\n * Data buffer.\n *\n * @type {TypedArray}\n */\n #buffer;\n\n /**\n * Image UIDs.\n *\n * @type {string[]}\n */\n #imageUids;\n\n /**\n * Constant rescale slope and intercept (default).\n *\n * @type {RescaleSlopeAndIntercept}\n */\n #rsi = new RescaleSlopeAndIntercept(1, 0);\n\n /**\n * Varying rescale slope and intercept.\n *\n * @type {RescaleSlopeAndIntercept[]}\n */\n #rsis = null;\n\n /**\n * Flag to know if the RSIs are all identity (1,0).\n *\n * @type {boolean}\n */\n #isIdentityRSI = true;\n\n /**\n * Flag to know if the RSIs are all equals.\n *\n * @type {boolean}\n */\n #isConstantRSI = true;\n\n /**\n * Photometric interpretation (MONOCHROME, RGB...).\n *\n * @type {string}\n */\n #photometricInterpretation = 'MONOCHROME2';\n\n /**\n * Palette colour map.\n *\n * @type {ColourMap}\n */\n #paletteColourMap;\n\n /**\n * Planar configuration for RGB data (`0:RGBRGBRGBRGB...` or\n * `1:RRR...GGG...BBB...`).\n *\n * @type {number}\n */\n #planarConfiguration = 0;\n\n /**\n * Number of components.\n *\n * @type {number}\n */\n #numberOfComponents;\n\n /**\n * Meta information.\n *\n * @type {Object}\n */\n #meta = {};\n\n /**\n * Data range.\n *\n * @type {NumberRange}\n */\n #dataRange = null;\n\n /**\n * Rescaled data range.\n *\n * @type {NumberRange}\n */\n #rescaledDataRange = null;\n\n /**\n * Histogram.\n *\n * @type {Array}\n */\n #histogram = null;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * @param {Geometry} geometry The geometry of the image.\n * @param {TypedArray} buffer The image data as a one dimensional buffer.\n * @param {string[]} [imageUids] An array of Uids indexed to slice number.\n */\n constructor(geometry, buffer, imageUids) {\n this.#geometry = geometry;\n this.#buffer = buffer;\n this.#imageUids = imageUids;\n\n this.#numberOfComponents = this.#buffer.length / (\n this.#geometry.getSize().getTotalSize());\n }\n\n /**\n * Get the image UID at a given index.\n *\n * @param {Index} [index] The index at which to get the id.\n * @returns {string} The UID.\n */\n getImageUid(index) {\n let uid = this.#imageUids[0];\n if (this.#imageUids.length !== 1 && typeof index !== 'undefined') {\n uid = this.#imageUids[this.getSecondaryOffset(index)];\n }\n return uid;\n }\n\n /**\n * Get the image origin for a image UID.\n *\n * @param {string} uid The UID.\n * @returns {Point3D|undefined} The origin.\n */\n getOriginForImageUid(uid) {\n let origin;\n const uidIndex = this.#imageUids.indexOf(uid);\n if (uidIndex !== -1) {\n const origins = this.getGeometry().getOrigins();\n origin = origins[uidIndex];\n }\n return origin;\n }\n\n /**\n * Check if the image includes an UID.\n *\n * @param {string} uid The UID.\n * @returns {boolean} True if present.\n */\n includesImageUid(uid) {\n return this.#imageUids.includes(uid);\n }\n\n /**\n * Check if this image includes the input uids.\n *\n * @param {string[]} uids UIDs to test for presence.\n * @returns {boolean} True if all uids are in this image uids.\n */\n containsImageUids(uids) {\n return arrayContains(this.#imageUids, uids);\n }\n\n /**\n * Get the geometry of the image.\n *\n * @returns {Geometry} The geometry.\n */\n getGeometry() {\n return this.#geometry;\n }\n\n /**\n * Get the data buffer of the image.\n *\n * @todo Dangerous...\n * @returns {TypedArray} The data buffer of the image.\n */\n getBuffer() {\n return this.#buffer;\n }\n\n /**\n * Can the image values be quantified?\n *\n * @returns {boolean} True if only one component.\n */\n canQuantify() {\n return this.getNumberOfComponents() === 1;\n }\n\n /**\n * Can window and level be applied to the data?\n *\n * @returns {boolean} True if the data is monochrome.\n * @deprecated Since v0.33, please use isMonochrome instead.\n */\n canWindowLevel() {\n return this.isMonochrome();\n }\n\n /**\n * Is the data monochrome.\n *\n * @returns {boolean} True if the data is monochrome.\n */\n isMonochrome() {\n return isMonochrome(this.getPhotometricInterpretation());\n }\n\n /**\n * Can the data be scrolled?\n *\n * @param {Matrix33} viewOrientation The view orientation.\n * @returns {boolean} True if the data has a third dimension greater than one\n * after applying the view orientation.\n */\n canScroll(viewOrientation) {\n const size = this.getGeometry().getSize();\n // also check the numberOfFiles in case we are in the middle of a load\n let nFiles = 1;\n if (typeof this.#meta.numberOfFiles !== 'undefined') {\n nFiles = this.#meta.numberOfFiles;\n }\n return size.canScroll(viewOrientation) || nFiles !== 1;\n }\n\n /**\n * Get the secondary offset max.\n *\n * @returns {number} The maximum offset.\n */\n #getSecondaryOffsetMax() {\n return this.#geometry.getSize().getTotalSize(2);\n }\n\n /**\n * Get the secondary offset: an offset that takes into account\n * the slice and above dimension numbers.\n *\n * @param {Index} index The index.\n * @returns {number} The offset.\n */\n getSecondaryOffset(index) {\n return this.#geometry.getSize().indexToOffset(index, 2);\n }\n\n /**\n * Get the rescale slope and intercept.\n *\n * @param {Index} [index] The index (only needed for non constant rsi).\n * @returns {RescaleSlopeAndIntercept} The rescale slope and intercept.\n */\n getRescaleSlopeAndIntercept(index) {\n let res = this.#rsi;\n if (!this.isConstantRSI()) {\n if (typeof index === 'undefined') {\n throw new Error('Cannot get non constant RSI with empty slice index.');\n }\n const offset = this.getSecondaryOffset(index);\n if (typeof this.#rsis[offset] !== 'undefined') {\n res = this.#rsis[offset];\n } else {\n logger.warn('undefined non constant rsi at ' + offset);\n }\n }\n return res;\n }\n\n /**\n * Get the rsi at a specified (secondary) offset.\n *\n * @param {number} offset The desired (secondary) offset.\n * @returns {RescaleSlopeAndIntercept} The coresponding rsi.\n */\n #getRescaleSlopeAndInterceptAtOffset(offset) {\n return this.#rsis[offset];\n }\n\n /**\n * Set the rescale slope and intercept.\n *\n * @param {RescaleSlopeAndIntercept} inRsi The input rescale\n * slope and intercept.\n * @param {number} [offset] The rsi offset (only needed for non constant rsi).\n */\n setRescaleSlopeAndIntercept(inRsi, offset) {\n // update identity flag\n this.#isIdentityRSI = this.#isIdentityRSI && inRsi.isID();\n // update constant flag\n if (!this.#isConstantRSI) {\n if (typeof offset === 'undefined') {\n throw new Error(\n 'Cannot store non constant RSI with empty slice index.');\n }\n this.#rsis.splice(offset, 0, inRsi);\n } else {\n if (!this.#rsi.equals(inRsi)) {\n if (typeof offset === 'undefined') {\n // no slice index, replace existing\n this.#rsi = inRsi;\n } else {\n // first non constant rsi\n this.#isConstantRSI = false;\n // switch to non constant mode\n this.#rsis = [];\n // initialise RSIs\n for (let i = 0, leni = this.#getSecondaryOffsetMax(); i < leni; ++i) {\n this.#rsis.push(this.#rsi);\n }\n // store\n this.#rsi = null;\n this.#rsis.splice(offset, 0, inRsi);\n }\n }\n }\n }\n\n /**\n * Are all the RSIs identity (1,0).\n *\n * @returns {boolean} True if they are.\n */\n isIdentityRSI() {\n return this.#isIdentityRSI;\n }\n\n /**\n * Are all the RSIs equal.\n *\n * @returns {boolean} True if they are.\n */\n isConstantRSI() {\n return this.#isConstantRSI;\n }\n\n /**\n * Get the photometricInterpretation of the image.\n *\n * @returns {string} The photometricInterpretation of the image.\n */\n getPhotometricInterpretation() {\n return this.#photometricInterpretation;\n }\n\n /**\n * Set the photometricInterpretation of the image.\n *\n * @param {string} interp The photometricInterpretation of the image.\n */\n setPhotometricInterpretation(interp) {\n this.#photometricInterpretation = interp;\n }\n\n /**\n * Set the palette colour map.\n *\n * @param {ColourMap} map The colour map.\n */\n setPaletteColourMap(map) {\n this.#paletteColourMap = map;\n // fire imagecontentchange\n this.#fireEvent({type: 'imagecontentchange'});\n }\n\n /**\n * Get the palette colour map.\n *\n * @returns {ColourMap} The colour map.\n */\n getPaletteColourMap() {\n return this.#paletteColourMap;\n }\n\n /**\n * Update the palette colour map.\n *\n * @param {number} index The index to change the colour of.\n * @param {RGB} colour The colour to use at index.\n */\n updatePaletteColourMap(index, colour) {\n this.#paletteColourMap.red[index] = colour.r;\n this.#paletteColourMap.green[index] = colour.g;\n this.#paletteColourMap.blue[index] = colour.b;\n // fire imagecontentchange\n this.#fireEvent({type: 'imagecontentchange'});\n }\n\n /**\n * Get the planarConfiguration of the image.\n *\n * @returns {number} The planarConfiguration of the image.\n */\n getPlanarConfiguration() {\n return this.#planarConfiguration;\n }\n\n /**\n * Set the planarConfiguration of the image.\n *\n * @param {number} config The planarConfiguration of the image.\n */\n setPlanarConfiguration(config) {\n this.#planarConfiguration = config;\n }\n\n /**\n * Get the numberOfComponents of the image.\n *\n * @returns {number} The numberOfComponents of the image.\n */\n getNumberOfComponents() {\n return this.#numberOfComponents;\n }\n\n /**\n * Get the meta information of the image.\n *\n * @returns {Object} The meta information of the image.\n */\n getMeta() {\n return this.#meta;\n }\n\n /**\n * Set the meta information of the image.\n *\n * @param {Object} rhs The meta information of the image.\n */\n setMeta(rhs) {\n this.#meta = rhs;\n }\n\n /**\n * Get value at offset. Warning: No size check...\n *\n * @param {number} offset The desired offset.\n * @returns {number} The value at offset.\n */\n getValueAtOffset(offset) {\n return this.#buffer[offset];\n }\n\n /**\n * Get the offsets where the buffer equals the input value.\n * Loops through the whole volume, can get long for big data...\n *\n * @param {number|RGB} value The value to check.\n * @returns {number[]} The list of offsets.\n */\n getOffsets(value) {\n // value to array\n let bufferValue;\n if (typeof value === 'number') {\n if (this.#numberOfComponents !== 1) {\n throw new Error(\n 'Number of components is not 1 for getting single value.');\n }\n bufferValue = [value];\n } else if (typeof value.r !== 'undefined' &&\n typeof value.g !== 'undefined' &&\n typeof value.b !== 'undefined') {\n if (this.#numberOfComponents !== 3) {\n throw new Error(\n 'Number of components is not 3 for getting RGB value.');\n }\n bufferValue = [value.r, value.g, value.b];\n }\n\n // main loop\n const offsets = [];\n let equal;\n for (let i = 0; i < this.#buffer.length; i = i + this.#numberOfComponents) {\n equal = true;\n for (let j = 0; j < this.#numberOfComponents; ++j) {\n if (this.#buffer[i + j] !== bufferValue[j]) {\n equal = false;\n break;\n }\n }\n if (equal) {\n offsets.push(i);\n }\n }\n return offsets;\n }\n\n /**\n * Check if the input values are in the buffer.\n * Could loop through the whole volume, can get long for big data...\n *\n * @param {Array} values The values to check.\n * @returns {boolean[]} A list of booleans for each input value,\n * set to true if the value is present in the buffer.\n */\n hasValues(values) {\n // check input\n if (typeof values === 'undefined' ||\n values.length === 0) {\n return [];\n }\n // final array value\n const finalValues = [];\n for (let v1 = 0; v1 < values.length; ++v1) {\n if (this.#numberOfComponents === 1) {\n finalValues.push([values[v1]]);\n } else if (this.#numberOfComponents === 3) {\n finalValues.push([\n values[v1].r,\n values[v1].g,\n values[v1].b\n ]);\n }\n }\n // find callback\n let equalFunc;\n if (this.#numberOfComponents === 1) {\n equalFunc = function (a, b) {\n return a[0] === b[0];\n };\n } else if (this.#numberOfComponents === 3) {\n equalFunc = function (a, b) {\n return a[0] === b[0] &&\n a[1] === b[1] &&\n a[2] === b[2];\n };\n }\n const getEqualCallback = function (value) {\n return function (item) {\n return equalFunc(item, value);\n };\n };\n // main loop\n const res = new Array(values.length);\n res.fill(false);\n const valuesToFind = finalValues.slice();\n let equal;\n let indicesToRemove;\n for (let i = 0, leni = this.#buffer.length;\n i < leni; i = i + this.#numberOfComponents) {\n indicesToRemove = [];\n for (let v = 0; v < valuesToFind.length; ++v) {\n equal = true;\n // check value(s)\n for (let j = 0; j < this.#numberOfComponents; ++j) {\n if (this.#buffer[i + j] !== valuesToFind[v][j]) {\n equal = false;\n break;\n }\n }\n // if found, store answer and add to indices to remove\n if (equal) {\n const valIndex = finalValues.findIndex(\n getEqualCallback(valuesToFind[v]));\n res[valIndex] = true;\n indicesToRemove.push(v);\n }\n }\n // remove found values\n for (let r = 0; r < indicesToRemove.length; ++r) {\n valuesToFind.splice(indicesToRemove[r], 1);\n }\n // exit if no values to find\n if (valuesToFind.length === 0) {\n break;\n }\n }\n // return\n return res;\n }\n\n /**\n * Clone the image.\n *\n * @returns {Image} A clone of this image.\n */\n clone() {\n // clone the image buffer\n const clonedBuffer = this.#buffer.slice(0);\n // create the image copy\n const copy = new Image(this.getGeometry(), clonedBuffer, this.#imageUids);\n // copy the RSI(s)\n if (this.isConstantRSI()) {\n copy.setRescaleSlopeAndIntercept(this.getRescaleSlopeAndIntercept());\n } else {\n for (let i = 0; i < this.#getSecondaryOffsetMax(); ++i) {\n copy.setRescaleSlopeAndIntercept(\n this.#getRescaleSlopeAndInterceptAtOffset(i), i);\n }\n }\n // copy extras\n copy.setPhotometricInterpretation(this.getPhotometricInterpretation());\n copy.setPlanarConfiguration(this.getPlanarConfiguration());\n copy.setMeta(this.getMeta());\n // return\n return copy;\n }\n\n /**\n * Re-allocate buffer memory to an input size.\n *\n * @param {number} size The new size.\n */\n #realloc(size) {\n // save buffer\n let tmpBuffer = this.#buffer;\n // create new\n this.#buffer = getTypedArray(\n this.#buffer.BYTES_PER_ELEMENT * 8,\n this.#meta.IsSigned ? 1 : 0,\n size);\n if (this.#buffer === null) {\n throw new Error('Cannot reallocate data for image.');\n }\n // put old in new\n this.#buffer.set(tmpBuffer);\n // clean\n tmpBuffer = null;\n }\n\n /**\n * Append a slice to the image.\n *\n * @param {Image} rhs The slice to append.\n * @fires Image#imagegeometrychange\n */\n appendSlice(rhs) {\n // check input\n if (rhs === null) {\n throw new Error('Cannot append null slice');\n }\n const rhsSize = rhs.getGeometry().getSize();\n let size = this.#geometry.getSize();\n if (rhsSize.get(2) !== 1) {\n throw new Error('Cannot append more than one slice');\n }\n if (size.get(0) !== rhsSize.get(0)) {\n throw new Error('Cannot append a slice with different number of columns');\n }\n if (size.get(1) !== rhsSize.get(1)) {\n throw new Error('Cannot append a slice with different number of rows');\n }\n if (!this.#geometry.getOrientation().equals(\n rhs.getGeometry().getOrientation(), 0.0001)) {\n throw new Error('Cannot append a slice with different orientation');\n }\n if (this.#photometricInterpretation !==\n rhs.getPhotometricInterpretation()) {\n throw new Error(\n 'Cannot append a slice with different photometric interpretation');\n }\n // all meta should be equal\n for (const key in this.#meta) {\n if (key === 'windowPresets' || key === 'numberOfFiles' ||\n key === 'custom') {\n continue;\n }\n if (this.#meta[key] !== rhs.getMeta()[key]) {\n throw new Error('Cannot append a slice with different ' + key +\n ': ' + this.#meta[key] + ' != ' + rhs.getMeta()[key]);\n }\n }\n\n // update ranges\n const rhsRange = rhs.getDataRange();\n const range = this.getDataRange();\n this.#dataRange = {\n min: Math.min(rhsRange.min, range.min),\n max: Math.max(rhsRange.max, range.max),\n };\n const rhsResRange = rhs.getRescaledDataRange();\n const resRange = this.getRescaledDataRange();\n this.#rescaledDataRange = {\n min: Math.min(rhsResRange.min, resRange.min),\n max: Math.max(rhsResRange.max, resRange.max),\n };\n\n // possible time\n const timeId = rhs.getGeometry().getInitialTime();\n\n // append frame if needed\n let isNewFrame = false;\n if (typeof timeId !== 'undefined' &&\n !this.#geometry.hasSlicesAtTime(timeId)) {\n // update grometry\n this.appendFrame(timeId, rhs.getGeometry().getOrigin());\n // update size\n size = this.#geometry.getSize();\n // update flag\n isNewFrame = true;\n }\n\n // get slice index\n const index = getSliceIndex(this.#geometry, rhs.getGeometry());\n\n // calculate slice size\n const sliceSize = this.#numberOfComponents * size.getDimSize(2);\n\n // create full buffer if not done yet\n if (typeof this.#meta.numberOfFiles === 'undefined') {\n throw new Error('Missing number of files for buffer manipulation.');\n }\n const fullBufferSize = sliceSize * this.#meta.numberOfFiles;\n if (this.#buffer.length !== fullBufferSize) {\n this.#realloc(fullBufferSize);\n }\n\n // slice index\n const sliceIndex = index.get(2);\n\n // slice index including possible 4D\n let fullSliceIndex = sliceIndex;\n if (typeof timeId !== 'undefined') {\n fullSliceIndex +=\n this.#geometry.getCurrentNumberOfSlicesBeforeTime(timeId);\n }\n // offset of the input slice\n const indexOffset = fullSliceIndex * sliceSize;\n const maxOffset =\n this.#geometry.getCurrentTotalNumberOfSlices() * sliceSize;\n // move content if needed\n if (indexOffset < maxOffset) {\n this.#buffer.set(\n this.#buffer.subarray(indexOffset, maxOffset),\n indexOffset + sliceSize\n );\n }\n // add new slice content\n this.#buffer.set(rhs.getBuffer(), indexOffset);\n\n // update geometry\n if (!isNewFrame) {\n this.#geometry.appendOrigin(\n rhs.getGeometry().getOrigin(), sliceIndex, timeId);\n }\n // update rsi\n // (rhs should just have one rsi)\n this.setRescaleSlopeAndIntercept(\n rhs.getRescaleSlopeAndIntercept(), fullSliceIndex);\n\n // current number of images\n const numberOfImages = this.#imageUids.length;\n\n // insert sop instance UIDs\n this.#imageUids.splice(fullSliceIndex, 0, rhs.getImageUid());\n\n // update window presets\n if (typeof this.#meta.windowPresets !== 'undefined') {\n const windowPresets = this.#meta.windowPresets;\n const rhsPresets = rhs.getMeta().windowPresets;\n const keys = Object.keys(rhsPresets);\n let pkey = null;\n for (let i = 0; i < keys.length; ++i) {\n pkey = keys[i];\n const rhsPreset = rhsPresets[pkey];\n const windowPreset = windowPresets[pkey];\n if (typeof windowPreset !== 'undefined') {\n // if not set or false, check perslice\n if (typeof windowPreset.perslice === 'undefined' ||\n windowPreset.perslice === false) {\n // if different preset.wl, mark it as perslice\n if (!windowPreset.wl[0].equals(rhsPreset.wl[0])) {\n windowPreset.perslice = true;\n // fill wl array with copy of wl[0]\n // (loop on number of images minus the existing one)\n for (let j = 0; j < numberOfImages - 1; ++j) {\n windowPreset.wl.push(windowPreset.wl[0]);\n }\n }\n }\n // store (first) rhs preset.wl if needed\n if (typeof windowPreset.perslice !== 'undefined' &&\n windowPreset.perslice === true) {\n windowPresets[pkey].wl.splice(\n fullSliceIndex, 0, rhsPreset.wl[0]);\n }\n } else {\n // if not defined (it should be), store all\n windowPresets[pkey] = rhsPresets[pkey];\n }\n }\n }\n /**\n * Image geometry change event.\n *\n * @event Image#imagegeometrychange\n * @type {object}\n * @property {string} type The event type.\n */\n this.#fireEvent({\n type: 'imagegeometrychange'\n });\n }\n\n /**\n * Append a frame buffer to the image.\n *\n * @param {object} frameBuffer The frame buffer to append.\n * @param {number} frameIndex The frame index.\n */\n appendFrameBuffer(frameBuffer, frameIndex) {\n // create full buffer if not done yet\n const size = this.#geometry.getSize();\n const frameSize = this.#numberOfComponents * size.getDimSize(2);\n if (typeof this.#meta.numberOfFiles === 'undefined') {\n throw new Error('Missing number of files for frame buffer manipulation.');\n }\n const fullBufferSize = frameSize * this.#meta.numberOfFiles;\n if (this.#buffer.length !== fullBufferSize) {\n this.#realloc(fullBufferSize);\n }\n // check index\n if (frameIndex >= this.#meta.numberOfFiles) {\n logger.warn('Ignoring frame at index ' + frameIndex +\n ' (size: ' + this.#meta.numberOfFiles + ')');\n return;\n }\n // append\n this.#buffer.set(frameBuffer, frameSize * frameIndex);\n // update geometry\n this.appendFrame(frameIndex, new Point3D(0, 0, 0));\n }\n\n /**\n * Append a frame to the image.\n *\n * @param {number} time The frame time value.\n * @param {Point3D} origin The origin of the frame.\n */\n appendFrame(time, origin) {\n this.#geometry.appendFrame(origin, time);\n /**\n * Append frame event.\n *\n * @event Image#appendframe\n * @type {object}\n * @property {string} type The event type.\n */\n this.#fireEvent({\n type: 'appendframe'\n });\n // memory will be updated at the first appendSlice or appendFrameBuffer\n }\n\n /**\n * Get the data range.\n *\n * @returns {NumberRange} The data range.\n */\n getDataRange() {\n if (!this.#dataRange) {\n this.#dataRange = this.calculateDataRange();\n }\n return this.#dataRange;\n }\n\n /**\n * Get the rescaled data range.\n *\n * @returns {NumberRange} The rescaled data range.\n */\n getRescaledDataRange() {\n if (!this.#rescaledDataRange) {\n this.#rescaledDataRange = this.calculateRescaledDataRange();\n }\n return this.#rescaledDataRange;\n }\n\n /**\n * Get the histogram.\n *\n * @returns {Array} The histogram.\n */\n getHistogram() {\n if (!this.#histogram) {\n const res = this.calculateHistogram();\n this.#dataRange = res.dataRange;\n this.#rescaledDataRange = res.rescaledDataRange;\n this.#histogram = res.histogram;\n }\n return this.#histogram;\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n // ****************************************\n // image data modifiers... carefull...\n // ****************************************\n\n /**\n * Set the inner buffer values at given offsets.\n *\n * @param {number[]} offsets List of offsets where to set the data.\n * @param {number|RGB} value The value to set at the given offsets.\n * @fires Image#imagecontentchange\n */\n setAtOffsets(offsets, value) {\n // value to array\n let bufferValue;\n if (typeof value === 'number') {\n if (this.#numberOfComponents !== 1) {\n throw new Error(\n 'Number of components is not 1 for setting single value.');\n }\n bufferValue = [value];\n } else if (typeof value.r !== 'undefined' &&\n typeof value.g !== 'undefined' &&\n typeof value.b !== 'undefined') {\n if (this.#numberOfComponents !== 3) {\n throw new Error(\n 'Number of components is not 3 for setting RGB value.');\n }\n bufferValue = [value.r, value.g, value.b];\n }\n\n let offset;\n for (let i = 0, leni = offsets.length; i < leni; ++i) {\n offset = offsets[i];\n for (let j = 0; j < this.#numberOfComponents; ++j) {\n this.#buffer[offset + j] = bufferValue[j];\n }\n }\n // fire imagecontentchange\n this.#fireEvent({type: 'imagecontentchange'});\n }\n\n /**\n * Set the inner buffer values at given offsets.\n *\n * @param {number[][]} offsetsLists List of offset lists where\n * to set the data.\n * @param {number} value The value to set at the given offsets.\n * @returns {Array} A list of objects representing the original values before\n * replacing them.\n * @fires Image#imagecontentchange\n */\n setAtOffsetsAndGetOriginals(offsetsLists, value) {\n const originalValuesLists = [];\n\n // update and store\n for (let j = 0; j < offsetsLists.length; ++j) {\n const offsets = offsetsLists[j];\n // first value\n let offset = offsets[0];\n let previousValue = this.#buffer[offset];\n // original value storage\n const originalValues = [];\n originalValues.push({\n index: 0,\n value: previousValue\n });\n for (let i = 0; i < offsets.length; ++i) {\n offset = offsets[i];\n const currentValue = this.#buffer[offset];\n // check if new value\n if (previousValue !== currentValue) {\n // store new value\n originalValues.push({\n index: i,\n value: currentValue\n });\n previousValue = currentValue;\n }\n // write update value\n this.#buffer[offset] = value;\n }\n originalValuesLists.push(originalValues);\n }\n // fire imagecontentchange\n this.#fireEvent({type: 'imagecontentchange'});\n return originalValuesLists;\n }\n\n /**\n * Set the inner buffer values at given offsets.\n *\n * @param {number[][]} offsetsLists List of offset lists\n * where to set the data.\n * @param {number|Array} value The value to set at the given offsets.\n * @fires Image#imagecontentchange\n */\n setAtOffsetsWithIterator(offsetsLists, value) {\n const isValueArray = Array.isArray(value);\n\n for (let j = 0; j < offsetsLists.length; ++j) {\n const offsets = offsetsLists[j];\n let iterator;\n if (isValueArray) {\n // input value is a list of iterators\n // created by setAtOffsetsAndGetOriginals\n iterator = valueRange(\n value[j], offsets.length);\n } else {\n // input value is a simple color\n iterator = valueRange(\n [{index: 0, value: value}], offsets.length);\n }\n\n // set values\n let ival = iterator.next();\n while (!ival.done) {\n const offset = offsets[ival.index];\n this.#buffer[offset] = ival.value;\n ival = iterator.next();\n }\n }\n /**\n * Image content change event.\n *\n * @event Image#imagecontentchange\n * @type {object}\n * @property {string} type The event type.\n */\n this.#fireEvent({type: 'imagecontentchange'});\n }\n\n /**\n * Get the value of the image at a specific coordinate.\n *\n * @param {number} i The X index.\n * @param {number} j The Y index.\n * @param {number} k The Z index.\n * @param {number} f The frame number.\n * @returns {number} The value at the desired position.\n * Warning: No size check...\n */\n getValue(i, j, k, f) {\n const frame = (f || 0);\n const index = new Index([i, j, k, frame]);\n return this.getValueAtOffset(\n this.getGeometry().getSize().indexToOffset(index));\n }\n\n /**\n * Get the value of the image at a specific index.\n *\n * @param {Index} index The index.\n * @returns {number} The value at the desired position.\n * Warning: No size check...\n */\n getValueAtIndex(index) {\n return this.getValueAtOffset(\n this.getGeometry().getSize().indexToOffset(index));\n }\n\n /**\n * Get the rescaled value of the image at a specific position.\n *\n * @param {number} i The X index.\n * @param {number} j The Y index.\n * @param {number} k The Z index.\n * @param {number} f The frame number.\n * @returns {number} The rescaled value at the desired position.\n * Warning: No size check...\n */\n getRescaledValue(i, j, k, f) {\n if (typeof f === 'undefined') {\n f = 0;\n }\n let val = this.getValue(i, j, k, f);\n if (!this.isIdentityRSI()) {\n if (this.isConstantRSI()) {\n val = this.getRescaleSlopeAndIntercept().apply(val);\n } else {\n const values = [i, j, k, f];\n const index = new Index(values);\n val = this.getRescaleSlopeAndIntercept(index).apply(val);\n }\n }\n return val;\n }\n\n /**\n * Get the rescaled value of the image at a specific index.\n *\n * @param {Index} index The index.\n * @returns {number} The rescaled value at the desired position.\n * Warning: No size check...\n */\n getRescaledValueAtIndex(index) {\n return this.getRescaledValueAtOffset(\n this.getGeometry().getSize().indexToOffset(index)\n );\n }\n\n /**\n * Get the rescaled value of the image at a specific offset.\n *\n * @param {number} offset The desired offset.\n * @returns {number} The rescaled value at the desired offset.\n * Warning: No size check...\n */\n getRescaledValueAtOffset(offset) {\n let val = this.getValueAtOffset(offset);\n if (!this.isIdentityRSI()) {\n if (this.isConstantRSI()) {\n val = this.getRescaleSlopeAndIntercept().apply(val);\n } else {\n const index = this.getGeometry().getSize().offsetToIndex(offset);\n val = this.getRescaleSlopeAndIntercept(index).apply(val);\n }\n }\n return val;\n }\n\n /**\n * Calculate the data range of the image.\n * WARNING: for speed reasons, only calculated on the first frame...\n *\n * @returns {object} The range {min, max}.\n */\n calculateDataRange() {\n let min = this.getValueAtOffset(0);\n let max = min;\n let value = 0;\n const size = this.getGeometry().getSize();\n let leni = size.getTotalSize();\n // max to 3D\n if (size.length() >= 3) {\n leni = size.getDimSize(3);\n }\n for (let i = 0; i < leni; ++i) {\n value = this.getValueAtOffset(i);\n if (value > max) {\n max = value;\n }\n if (value < min) {\n min = value;\n }\n }\n // return\n return {min: min, max: max};\n }\n\n /**\n * Calculate the rescaled data range of the image.\n * WARNING: for speed reasons, only calculated on the first frame...\n *\n * @returns {object} The range {min, max}.\n */\n calculateRescaledDataRange() {\n if (this.isIdentityRSI()) {\n return this.getDataRange();\n } else if (this.isConstantRSI()) {\n const range = this.getDataRange();\n const resmin = this.getRescaleSlopeAndIntercept().apply(range.min);\n const resmax = this.getRescaleSlopeAndIntercept().apply(range.max);\n return {\n min: ((resmin < resmax) ? resmin : resmax),\n max: ((resmin > resmax) ? resmin : resmax)\n };\n } else {\n let rmin = this.getRescaledValueAtOffset(0);\n let rmax = rmin;\n let rvalue = 0;\n const size = this.getGeometry().getSize();\n let leni = size.getTotalSize();\n // max to 3D\n if (size.length() === 3) {\n leni = size.getDimSize(3);\n }\n for (let i = 0; i < leni; ++i) {\n rvalue = this.getRescaledValueAtOffset(i);\n if (rvalue > rmax) {\n rmax = rvalue;\n }\n if (rvalue < rmin) {\n rmin = rvalue;\n }\n }\n // return\n return {min: rmin, max: rmax};\n }\n }\n\n /**\n * Calculate the histogram of the image.\n *\n * @returns {object} The histogram, data range and rescaled data range.\n */\n calculateHistogram() {\n const size = this.getGeometry().getSize();\n const histo = [];\n let min = this.getValueAtOffset(0);\n let max = min;\n let value = 0;\n let rmin = this.getRescaledValueAtOffset(0);\n let rmax = rmin;\n let rvalue = 0;\n for (let i = 0, leni = size.getTotalSize(); i < leni; ++i) {\n value = this.getValueAtOffset(i);\n if (value > max) {\n max = value;\n }\n if (value < min) {\n min = value;\n }\n rvalue = this.getRescaledValueAtOffset(i);\n if (rvalue > rmax) {\n rmax = rvalue;\n }\n if (rvalue < rmin) {\n rmin = rvalue;\n }\n histo[rvalue] = (histo[rvalue] || 0) + 1;\n }\n // set data range\n const dataRange = {min: min, max: max};\n const rescaledDataRange = {min: rmin, max: rmax};\n // generate data for plotting\n const histogram = [];\n for (let b = rmin; b <= rmax; ++b) {\n histogram.push([b, (histo[b] || 0)]);\n }\n // return\n return {\n dataRange: dataRange,\n rescaledDataRange: rescaledDataRange,\n histogram: histogram\n };\n }\n\n /**\n * Convolute the image with a given 2D kernel.\n *\n * Note: Uses raw buffer values.\n *\n * @param {number[]} weights The weights of the 2D kernel as a 3x3 matrix.\n * @returns {Image} The convoluted image.\n */\n convolute2D(weights) {\n if (weights.length !== 9) {\n throw new Error(\n 'The convolution matrix does not have a length of 9; it has ' +\n weights.length);\n }\n\n const newImage = this.clone();\n const newBuffer = newImage.getBuffer();\n\n const imgSize = this.getGeometry().getSize();\n const dimOffset = imgSize.getDimSize(2) * this.getNumberOfComponents();\n for (let k = 0; k < imgSize.get(2); ++k) {\n this.convoluteBuffer(weights, newBuffer, k * dimOffset);\n }\n\n return newImage;\n }\n\n /**\n * Convolute an image buffer with a given 2D kernel.\n *\n * Note: Uses raw buffer values.\n *\n * @param {number[]} weights The weights of the 2D kernel as a 3x3 matrix.\n * @param {TypedArray} buffer The buffer to convolute.\n * @param {number} startOffset The index to start at.\n */\n convoluteBuffer(\n weights, buffer, startOffset) {\n const imgSize = this.getGeometry().getSize();\n const ncols = imgSize.get(0);\n const nrows = imgSize.get(1);\n const ncomp = this.getNumberOfComponents();\n\n // number of component and planar configuration vars\n let factor = 1;\n let componentOffset = 1;\n if (ncomp === 3) {\n if (this.getPlanarConfiguration() === 0) {\n factor = 3;\n } else {\n componentOffset = imgSize.getDimSize(2);\n }\n }\n\n // allow special indent for matrices\n /*jshint indent:false */\n\n // default weight offset matrix\n const wOff = [];\n wOff[0] = (-ncols - 1) * factor;\n wOff[1] = (-ncols) * factor;\n wOff[2] = (-ncols + 1) * factor;\n wOff[3] = -factor;\n wOff[4] = 0;\n wOff[5] = 1 * factor;\n wOff[6] = (ncols - 1) * factor;\n wOff[7] = (ncols) * factor;\n wOff[8] = (ncols + 1) * factor;\n\n // border weight offset matrices\n // borders are extended (see http://en.wikipedia.org/wiki/Kernel_%28image_processing%29)\n\n // i=0, j=0\n const wOff00 = [];\n wOff00[0] = wOff[4]; wOff00[1] = wOff[4]; wOff00[2] = wOff[5];\n wOff00[3] = wOff[4]; wOff00[4] = wOff[4]; wOff00[5] = wOff[5];\n wOff00[6] = wOff[7]; wOff00[7] = wOff[7]; wOff00[8] = wOff[8];\n // i=0, j=*\n const wOff0x = [];\n wOff0x[0] = wOff[1]; wOff0x[1] = wOff[1]; wOff0x[2] = wOff[2];\n wOff0x[3] = wOff[4]; wOff0x[4] = wOff[4]; wOff0x[5] = wOff[5];\n wOff0x[6] = wOff[7]; wOff0x[7] = wOff[7]; wOff0x[8] = wOff[8];\n // i=0, j=nrows\n const wOff0n = [];\n wOff0n[0] = wOff[1]; wOff0n[1] = wOff[1]; wOff0n[2] = wOff[2];\n wOff0n[3] = wOff[4]; wOff0n[4] = wOff[4]; wOff0n[5] = wOff[5];\n wOff0n[6] = wOff[4]; wOff0n[7] = wOff[4]; wOff0n[8] = wOff[5];\n\n // i=*, j=0\n const wOffx0 = [];\n wOffx0[0] = wOff[3]; wOffx0[1] = wOff[4]; wOffx0[2] = wOff[5];\n wOffx0[3] = wOff[3]; wOffx0[4] = wOff[4]; wOffx0[5] = wOff[5];\n wOffx0[6] = wOff[6]; wOffx0[7] = wOff[7]; wOffx0[8] = wOff[8];\n // i=*, j=* -> wOff\n // i=*, j=nrows\n const wOffxn = [];\n wOffxn[0] = wOff[0]; wOffxn[1] = wOff[1]; wOffxn[2] = wOff[2];\n wOffxn[3] = wOff[3]; wOffxn[4] = wOff[4]; wOffxn[5] = wOff[5];\n wOffxn[6] = wOff[3]; wOffxn[7] = wOff[4]; wOffxn[8] = wOff[5];\n\n // i=ncols, j=0\n const wOffn0 = [];\n wOffn0[0] = wOff[3]; wOffn0[1] = wOff[4]; wOffn0[2] = wOff[4];\n wOffn0[3] = wOff[3]; wOffn0[4] = wOff[4]; wOffn0[5] = wOff[4];\n wOffn0[6] = wOff[6]; wOffn0[7] = wOff[7]; wOffn0[8] = wOff[7];\n // i=ncols, j=*\n const wOffnx = [];\n wOffnx[0] = wOff[0]; wOffnx[1] = wOff[1]; wOffnx[2] = wOff[1];\n wOffnx[3] = wOff[3]; wOffnx[4] = wOff[4]; wOffnx[5] = wOff[4];\n wOffnx[6] = wOff[6]; wOffnx[7] = wOff[7]; wOffnx[8] = wOff[7];\n // i=ncols, j=nrows\n const wOffnn = [];\n wOffnn[0] = wOff[0]; wOffnn[1] = wOff[1]; wOffnn[2] = wOff[1];\n wOffnn[3] = wOff[3]; wOffnn[4] = wOff[4]; wOffnn[5] = wOff[4];\n wOffnn[6] = wOff[3]; wOffnn[7] = wOff[4]; wOffnn[8] = wOff[4];\n\n // restore indent for rest of method\n /*jshint indent:4 */\n\n // loop vars\n let pixelOffset = startOffset;\n let newValue = 0;\n let wOffFinal = [];\n for (let c = 0; c < ncomp; ++c) {\n // component offset\n pixelOffset += c * componentOffset;\n for (let j = 0; j < nrows; ++j) {\n for (let i = 0; i < ncols; ++i) {\n wOffFinal = wOff;\n // special border cases\n if (i === 0 && j === 0) {\n wOffFinal = wOff00;\n } else if (i === 0 && j === (nrows - 1)) {\n wOffFinal = wOff0n;\n } else if (i === (ncols - 1) && j === 0) {\n wOffFinal = wOffn0;\n } else if (i === (ncols - 1) && j === (nrows - 1)) {\n wOffFinal = wOffnn;\n } else if (i === 0 && j !== (nrows - 1) && j !== 0) {\n wOffFinal = wOff0x;\n } else if (i === (ncols - 1) && j !== (nrows - 1) && j !== 0) {\n wOffFinal = wOffnx;\n } else if (i !== 0 && i !== (ncols - 1) && j === 0) {\n wOffFinal = wOffx0;\n } else if (i !== 0 && i !== (ncols - 1) && j === (nrows - 1)) {\n wOffFinal = wOffxn;\n }\n // calculate the weighed sum of the source image pixels that\n // fall under the convolution matrix\n newValue = 0;\n for (let wi = 0; wi < 9; ++wi) {\n newValue += this.getValueAtOffset(\n pixelOffset + wOffFinal[wi]) * weights[wi];\n }\n buffer[pixelOffset] = newValue;\n // increment pixel offset\n pixelOffset += factor;\n }\n }\n }\n }\n\n /**\n * Transform an image using a specific operator.\n * WARNING: no size check!\n *\n * @param {Function} operator The operator to use when transforming.\n * @returns {Image} The transformed image.\n * Note: Uses the raw buffer values.\n */\n transform(operator) {\n const newImage = this.clone();\n const newBuffer = newImage.getBuffer();\n for (let i = 0, leni = newBuffer.length; i < leni; ++i) {\n newBuffer[i] = operator(newImage.getValueAtOffset(i));\n }\n return newImage;\n }\n\n /**\n * Compose this image with another one and using a specific operator.\n * WARNING: no size check!\n *\n * @param {Image} rhs The image to compose with.\n * @param {Function} operator The operator to use when composing.\n * @returns {Image} The composed image.\n * Note: Uses the raw buffer values.\n */\n compose(rhs, operator) {\n const newImage = this.clone();\n const newBuffer = newImage.getBuffer();\n for (let i = 0, leni = newBuffer.length; i < leni; ++i) {\n // using the operator on the local buffer, i.e. the\n // latest (not original) data\n newBuffer[i] = Math.floor(\n operator(this.getValueAtOffset(i), rhs.getValueAtOffset(i))\n );\n }\n return newImage;\n }\n\n} // class Image\n","import {View} from './view';\nimport {\n WindowLevel,\n defaultPresets\n} from './windowLevel';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * {@link View} factory.\n */\nexport class ViewFactory {\n\n /**\n * Get an View object from the read DICOM file.\n *\n * @param {Object} dataElements The DICOM tags.\n * @param {Image} image The associated image.\n * @returns {View} The new View.\n */\n create(dataElements, image) {\n // view\n const view = new View(image);\n\n // default color map\n if (image.getPhotometricInterpretation() === 'MONOCHROME1') {\n view.setColourMap('invPlain');\n }\n\n // window level presets\n let windowPresets = {};\n // image presets\n if (typeof image.getMeta().windowPresets !== 'undefined') {\n windowPresets = image.getMeta().windowPresets;\n }\n // min/max\n // Not filled yet since it is stil too costly to calculate min/max\n // for each slice... It will be filled at first use\n // (see view.setWindowLevelPreset).\n // Order is important, if no wl from DICOM, this will be the default.\n windowPresets.minmax = {name: 'minmax'};\n // optional modality presets\n if (typeof defaultPresets !== 'undefined') {\n const modality = image.getMeta().Modality;\n for (const key in defaultPresets[modality]) {\n const preset = defaultPresets[modality][key];\n windowPresets[key] = {\n wl: [new WindowLevel(preset.center, preset.width)],\n name: key\n };\n }\n }\n\n // store\n view.setWindowPresets(windowPresets);\n\n // initialise the view\n view.init();\n\n return view;\n }\n\n} // class ViewFactory\n","import {Index} from '../math/index';\nimport {ModalityLut} from './modalityLut';\nimport {WindowLut} from './windowLut';\nimport {luts} from './luts';\nimport {VoiLut} from './voiLut';\nimport {WindowLevel} from './windowLevel';\nimport {generateImageDataMonochrome} from './viewMonochrome';\nimport {generateImageDataPaletteColor} from './viewPaletteColor';\nimport {generateImageDataRgb} from './viewRgb';\nimport {generateImageDataYbrFull} from './viewYbrFull';\nimport {ViewFactory} from './viewFactory';\nimport {isIdentityMat33} from '../math/matrix';\nimport {getSliceIterator} from '../image/iterator';\nimport {ListenerHandler} from '../utils/listen';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {RescaleSlopeAndIntercept} from './rsi';\nimport {ColourMap} from './luts';\nimport {Matrix33} from '../math/matrix';\nimport {\n Point,\n Point3D\n} from '../math/point';\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * List of view event names.\n *\n * @type {string[]}\n */\nexport const viewEventNames = [\n 'wlchange',\n 'wlpresetadd',\n 'colourmapchange',\n 'positionchange',\n 'opacitychange',\n 'alphafuncchange'\n];\n\n/**\n * Create a View from DICOM elements and image.\n *\n * @param {Object} elements The DICOM elements.\n * @param {Image} image The associated image.\n * @returns {View} The View object.\n */\nexport function createView(elements, image) {\n const factory = new ViewFactory();\n return factory.create(elements, image);\n}\n\n/**\n * View class.\n *\n * Need to set the window lookup table once created\n * (either directly or with helper methods).\n *\n * @example\n * // XMLHttpRequest onload callback\n * const onload = function (event) {\n * // parse the dicom buffer\n * const dicomParser = new dwv.DicomParser();\n * dicomParser.parse(event.target.response);\n * // create the image object\n * const image = dwv.createImage(dicomParser.getDicomElements());\n * // create the view\n * const view = dwv.createView(dicomParser.getDicomElements(), image);\n * // setup canvas\n * const canvas = document.createElement('canvas');\n * canvas.width = 256;\n * canvas.height = 256;\n * const ctx = canvas.getContext(\"2d\");\n * // update the image data\n * const imageData = ctx.createImageData(256, 256);\n * view.generateImageData(imageData);\n * ctx.putImageData(imageData, 0, 0);\n * // update html\n * const div = document.getElementById('dwv');\n * div.appendChild(canvas);;\n * };\n * // DICOM file request\n * const request = new XMLHttpRequest();\n * const url = 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm';\n * request.open('GET', url);\n * request.responseType = 'arraybuffer';\n * request.onload = onload;\n * request.send();\n */\nexport class View {\n\n /**\n * The associated image.\n *\n * @type {Image}\n */\n #image;\n\n /**\n * Window lookup tables, indexed per Rescale Slope and Intercept (RSI).\n *\n * @type {WindowLut}\n */\n #windowLut;\n\n /**\n * Flag for image constant RSI.\n *\n * @type {boolean}\n */\n #isConstantRSI;\n\n /**\n * Window presets.\n * Minmax will be filled at first use (see view.setWindowLevelPreset).\n *\n * @type {object}\n */\n #windowPresets = {minmax: {name: 'minmax'}};\n\n /**\n * Current window preset name.\n *\n * @type {string}\n */\n #currentPresetName = null;\n\n /**\n * Current window level.\n *\n * @type {WindowLevel}\n */\n #currentWl;\n\n /**\n * Colour map name.\n *\n * @type {string}\n */\n #colourMapName = 'plain';\n\n /**\n * Current position as a Point.\n * Store position and not index to stay geometry independent.\n *\n * @type {Point}\n */\n #currentPosition = null;\n\n /**\n * View orientation. Undefined will use the original slice ordering.\n *\n * @type {Matrix33}\n */\n #orientation;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * @param {Image} image The associated image.\n */\n constructor(image) {\n this.#image = image;\n\n // listen to appendframe event to update the current position\n // to add the extra dimension\n this.#image.addEventListener('appendframe', () => {\n // update current position if first appendFrame\n const index = this.getCurrentIndex();\n if (index.length() === 3) {\n // add dimension\n const values = index.getValues();\n values.push(0);\n this.setCurrentIndex(new Index(values));\n }\n });\n }\n\n /**\n * Get the associated image.\n *\n * @returns {Image} The associated image.\n */\n getImage() {\n return this.#image;\n }\n\n /**\n * Set the associated image.\n *\n * @param {Image} inImage The associated image.\n */\n setImage(inImage) {\n this.#image = inImage;\n }\n\n /**\n * Get the view orientation.\n *\n * @returns {Matrix33} The orientation matrix.\n */\n getOrientation() {\n return this.#orientation;\n }\n\n /**\n * Set the view orientation.\n *\n * @param {Matrix33} mat33 The orientation matrix.\n */\n setOrientation(mat33) {\n this.#orientation = mat33;\n }\n\n /**\n * Initialise the view: set initial index.\n */\n init() {\n this.setInitialIndex();\n }\n\n /**\n * Set the initial index to the middle position.\n */\n setInitialIndex() {\n const geometry = this.#image.getGeometry();\n const size = geometry.getSize();\n const values = new Array(size.length());\n values.fill(0);\n // middle\n values[0] = Math.floor(size.get(0) / 2);\n values[1] = Math.floor(size.get(1) / 2);\n values[2] = Math.floor(size.get(2) / 2);\n this.setCurrentIndex(new Index(values), true);\n }\n\n /**\n * Get the milliseconds per frame from frame rate.\n *\n * @param {number} recommendedDisplayFrameRate Recommended Display Frame Rate.\n * @returns {number} The milliseconds per frame.\n */\n getPlaybackMilliseconds(recommendedDisplayFrameRate) {\n if (!recommendedDisplayFrameRate) {\n // Default to 10 FPS if none is found in the meta\n recommendedDisplayFrameRate = 10;\n }\n // round milliseconds per frame to nearest whole number\n return Math.round(1000 / recommendedDisplayFrameRate);\n }\n\n /**\n * Per value alpha function.\n *\n * @param {number[]|number} _value The pixel value.\n * Can be a number for monochrome data or an array for RGB data.\n * @param {number} _index The index of the value.\n * @returns {number} The coresponding alpha [0,255].\n */\n #alphaFunction = function (_value, _index) {\n // default always returns fully visible\n return 0xff;\n };\n\n /**\n * @callback alphaFn\n * @param {number[]|number} value The pixel value.\n * @param {number} index The values' index.\n * @returns {number} The opacity of the input value.\n */\n\n /**\n * Get the alpha function.\n *\n * @returns {alphaFn} The function.\n */\n getAlphaFunction() {\n return this.#alphaFunction;\n }\n\n /**\n * Set alpha function.\n *\n * @param {alphaFn} func The function.\n * @fires View#alphafuncchange\n */\n setAlphaFunction(func) {\n this.#alphaFunction = func;\n /**\n * Alpha func change event.\n *\n * @event View#alphafuncchange\n * @type {object}\n * @property {string} type The event type.\n */\n this.#fireEvent({\n type: 'alphafuncchange'\n });\n }\n\n /**\n * Get the window LUT of the image.\n * Warning: can be undefined in no window/level was set.\n *\n * @returns {WindowLut} The window LUT of the image.\n * @fires View#wlchange\n */\n #getCurrentWindowLut() {\n // special case for 'perslice' presets\n if (this.#currentPresetName &&\n typeof this.#windowPresets[this.#currentPresetName] !== 'undefined' &&\n typeof this.#windowPresets[this.#currentPresetName].perslice !==\n 'undefined' &&\n this.#windowPresets[this.#currentPresetName].perslice === true) {\n // check position\n if (!this.getCurrentIndex()) {\n this.setInitialIndex();\n }\n // get the slice window level\n const currentIndex = this.getCurrentIndex();\n const offset = this.#image.getSecondaryOffset(currentIndex);\n const currentPreset = this.#windowPresets[this.#currentPresetName];\n const sliceWl = currentPreset.wl[offset];\n // set window level: will send a change event, mark it as silent as\n // this change is always triggered by a position change\n this.setWindowLevel(sliceWl, this.#currentPresetName, true);\n }\n\n // if no current, use first id\n if (typeof this.#currentWl === 'undefined') {\n this.setWindowLevelPresetById(0, true);\n }\n\n // get the window lut\n if (typeof this.#isConstantRSI === 'undefined' ||\n this.#image.isConstantRSI() !== this.#isConstantRSI) {\n this.#isConstantRSI = this.#image.isConstantRSI();\n // set or update windowLut if isConstantRSI has changed\n // (can be different at first slice and after having loaded\n // the full volume...)\n let rsi;\n let isDiscrete;\n if (this.#isConstantRSI) {\n rsi = this.#image.getRescaleSlopeAndIntercept();\n isDiscrete = true;\n } else {\n rsi = new RescaleSlopeAndIntercept(1, 0);\n isDiscrete = false;\n }\n // create the rescale lookup table\n const modalityLut = new ModalityLut(\n rsi,\n this.#image.getMeta().BitsStored);\n // create the window lookup table\n this.#windowLut = new WindowLut(\n modalityLut,\n this.#image.getMeta().IsSigned,\n isDiscrete);\n }\n\n // update VOI lut if not present or its window level\n // is different from the current one\n const voiLut = this.#windowLut.getVoiLut();\n let voiLutWl;\n if (typeof voiLut !== 'undefined') {\n voiLutWl = voiLut.getWindowLevel();\n }\n if (typeof voiLut === 'undefined' ||\n !this.#currentWl.equals(voiLutWl)) {\n // set lut window level\n const voiLut = new VoiLut(this.#currentWl);\n this.#windowLut.setVoiLut(voiLut);\n }\n\n // return\n return this.#windowLut;\n }\n\n /**\n * Get the window presets.\n *\n * @returns {object} The window presets.\n */\n getWindowPresets() {\n return this.#windowPresets;\n }\n\n /**\n * Get the window presets names.\n *\n * @returns {string[]} The list of window presets names.\n */\n getWindowPresetsNames() {\n return Object.keys(this.#windowPresets);\n }\n\n /**\n * Set the window presets.\n *\n * @param {object} presets The window presets.\n */\n setWindowPresets(presets) {\n this.#windowPresets = presets;\n }\n\n /**\n * Add window presets to the existing ones.\n *\n * @param {object} presets The window presets.\n */\n addWindowPresets(presets) {\n const keys = Object.keys(presets);\n let key = null;\n for (let i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (typeof this.#windowPresets[key] !== 'undefined') {\n if (typeof this.#windowPresets[key].perslice !== 'undefined' &&\n this.#windowPresets[key].perslice === true) {\n throw new Error('Cannot add perslice preset');\n } else {\n // update existing\n this.#windowPresets[key] = presets[key];\n }\n } else {\n // add new\n this.#windowPresets[key] = presets[key];\n // fire event\n /**\n * Window/level add preset event.\n *\n * @event View#wlpresetadd\n * @type {object}\n * @property {string} type The event type.\n * @property {string} name The name of the preset.\n */\n this.#fireEvent({\n type: 'wlpresetadd',\n name: key\n });\n }\n }\n }\n\n /**\n * Get the current window level preset name.\n *\n * @returns {string} The preset name.\n */\n getCurrentWindowPresetName() {\n return this.#currentPresetName;\n }\n\n /**\n * Get the colour map of the image.\n *\n * @returns {string} The colour map name.\n */\n getColourMap() {\n return this.#colourMapName;\n }\n\n /**\n * Get the colour map object.\n *\n * @returns {ColourMap} The colour map.\n */\n #getColourMapLut() {\n return luts[this.#colourMapName];\n }\n\n /**\n * Set the colour map of the image.\n *\n * @param {string} name The colour map name.\n * @fires View#colourmapchange\n */\n setColourMap(name) {\n // check if we have it\n if (!luts[name]) {\n throw new Error('Unknown colour map: \\'' + name + '\\'');\n }\n\n this.#colourMapName = name;\n\n /**\n * Color change event.\n *\n * @event View#colourmapchange\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} value The changed value.\n */\n this.#fireEvent({\n type: 'colourmapchange',\n value: [name]\n });\n }\n\n /**\n * Get the current position.\n *\n * @returns {Point} The current position.\n */\n getCurrentPosition() {\n return this.#currentPosition;\n }\n\n /**\n * Get the current index.\n *\n * @returns {Index} The current index.\n */\n getCurrentIndex() {\n const position = this.getCurrentPosition();\n if (!position) {\n return null;\n }\n const geometry = this.getImage().getGeometry();\n return geometry.worldToIndex(position);\n }\n\n /**\n * Get the SOP image UID of the current image.\n *\n * @returns {string} The UID.\n */\n getCurrentImageUid() {\n return this.#image.getImageUid(this.getCurrentIndex());\n }\n\n /**\n * Get the image origin for a image UID.\n *\n * @param {string} uid The UID.\n * @returns {Point3D|undefined} The origin.\n */\n getOriginForImageUid(uid) {\n return this.#image.getOriginForImageUid(uid);\n }\n\n /**\n * Check if the image includes an UID.\n *\n * @param {string} uid The UID.\n * @returns {boolean} True if present.\n */\n includesImageUid(uid) {\n return this.#image.includesImageUid(uid);\n }\n\n /**\n * Check if the current position (default) or\n * the provided position is in bounds.\n *\n * @param {Point} [position] Optional position.\n * @returns {boolean} True is the position is in bounds.\n */\n isPositionInBounds(position) {\n if (typeof position === 'undefined') {\n position = this.#currentPosition;\n }\n const geometry = this.#image.getGeometry();\n const index = geometry.worldToIndex(position);\n const dirs = [this.getScrollIndex()];\n if (index.length() === 4) {\n dirs.push(3);\n }\n return geometry.isIndexInBounds(index, dirs);\n }\n\n /**\n * Get the first origin or at a given position.\n *\n * @param {Point} [position] Optional position.\n * @returns {Point3D} The origin.\n */\n getOrigin(position) {\n const geometry = this.#image.getGeometry();\n let originIndex = 0;\n if (typeof position !== 'undefined') {\n const index = geometry.worldToIndex(position);\n // index is reoriented, 2 is scroll index\n originIndex = index.get(2);\n }\n return geometry.getOrigins()[originIndex];\n }\n\n /**\n * Set the current position.\n *\n * @param {Point} position The new position.\n * @param {boolean} [silent] Flag to fire event or not.\n * @returns {boolean} False if not in bounds.\n * @fires View#positionchange\n */\n setCurrentPosition(position, silent) {\n // send invalid event if not in bounds\n const geometry = this.#image.getGeometry();\n const index = geometry.worldToIndex(position);\n const dirs = [this.getScrollIndex()];\n if (index.length() === 4) {\n dirs.push(3);\n }\n if (!geometry.isIndexInBounds(index, dirs)) {\n if (!silent) {\n this.#currentPosition = position;\n // fire event with valid: false\n this.#fireEvent({\n type: 'positionchange',\n value: [\n index.getValues(),\n position.getValues(),\n ],\n valid: false\n });\n }\n return false;\n }\n return this.setCurrentIndex(index, silent);\n }\n\n /**\n * Set the current index.\n *\n * @param {Index} index The new index.\n * @param {boolean} [silent] Flag to fire event or not.\n * @returns {boolean} False if not in bounds.\n * @fires View#positionchange\n */\n setCurrentIndex(index, silent) {\n // check input\n if (typeof silent === 'undefined') {\n silent = false;\n }\n\n const geometry = this.#image.getGeometry();\n const position = geometry.indexToWorld(index);\n\n // check if possible\n const dirs = [this.getScrollIndex()];\n if (index.length() === 4) {\n dirs.push(3);\n }\n if (!geometry.isIndexInBounds(index, dirs)) {\n if (!silent) {\n this.#currentPosition = position;\n // fire event with valid: false\n this.#fireEvent({\n type: 'positionchange',\n value: [\n index.getValues(),\n position.getValues(),\n ],\n valid: false\n });\n }\n\n // do no send invalid positionchange event: avoid empty repaint\n return false;\n }\n\n // calculate diff dims before updating internal\n let diffDims = null;\n let currentIndex = null;\n if (this.getCurrentPosition()) {\n currentIndex = this.getCurrentIndex();\n }\n if (currentIndex) {\n if (currentIndex.canCompare(index)) {\n diffDims = currentIndex.compare(index);\n } else {\n diffDims = [];\n const minLen = Math.min(currentIndex.length(), index.length());\n for (let i = 0; i < minLen; ++i) {\n if (currentIndex.get(i) !== index.get(i)) {\n diffDims.push(i);\n }\n }\n const maxLen = Math.max(currentIndex.length(), index.length());\n for (let j = minLen; j < maxLen; ++j) {\n diffDims.push(j);\n }\n }\n } else {\n diffDims = [];\n for (let k = 0; k < index.length(); ++k) {\n diffDims.push(k);\n }\n }\n\n // assign\n this.#currentPosition = position;\n\n if (!silent) {\n /**\n * Position change event.\n *\n * @event View#positionchange\n * @type {object}\n * @property {Array} value The changed value as [index, pixelValue].\n * @property {number[]} diffDims An array of modified indices.\n */\n const posEvent = {\n type: 'positionchange',\n value: [\n index.getValues(),\n position.getValues(),\n ],\n diffDims: diffDims,\n data: {\n imageUid: this.#image.getImageUid(index)\n }\n };\n\n // add value if possible\n if (this.#image.canQuantify()) {\n const pixValue = this.#image.getRescaledValueAtIndex(index);\n posEvent.value.push(pixValue);\n }\n\n // fire\n this.#fireEvent(posEvent);\n }\n\n // all good\n return true;\n }\n\n /**\n * Set the view window/level.\n *\n * @param {WindowLevel} wl The window and level.\n * @param {string} [name] Associated preset name, defaults to 'manual'.\n * Warning: uses the latest set rescale LUT or the default linear one.\n * @param {boolean} [silent] Flag to launch events with skipGenerate.\n * @fires View#wlchange\n */\n setWindowLevel(wl, name, silent) {\n // check input\n if (typeof name === 'undefined') {\n name = 'manual';\n }\n if (name !== 'manual' &&\n typeof this.#windowPresets[name] === 'undefined') {\n throw new Error('Unknown window level preset: \\'' + name + '\\'');\n }\n if (typeof silent === 'undefined') {\n silent = false;\n }\n\n // check if new wl\n const isNewWl = !wl.equals(this.#currentWl);\n // check if new name\n const isNewName = this.#currentPresetName !== name;\n\n // compare to previous if present\n if (isNewWl || isNewName) {\n // assign\n this.#currentWl = wl;\n this.#currentPresetName = name;\n\n // update manual\n if (name === 'manual') {\n if (typeof this.#windowPresets[name] !== 'undefined') {\n this.#windowPresets[name].wl[0] = wl;\n } else {\n // add if not present\n this.addWindowPresets({\n manual: {\n wl: [wl],\n name: 'manual'\n }\n });\n }\n }\n\n /**\n * Window/level change event.\n *\n * @event View#wlchange\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} value The changed value.\n * @property {number} wc The new window center value.\n * @property {number} ww The new window wdth value.\n * @property {boolean} skipGenerate Flag to skip view generation.\n */\n this.#fireEvent({\n type: 'wlchange',\n value: [wl.center, wl.width, name],\n wc: wl.center,\n ww: wl.width,\n skipGenerate: silent\n });\n }\n }\n\n /**\n * Get the window/level.\n *\n * @returns {WindowLevel} The window and level.\n */\n getWindowLevel() {\n // same as #currentWl...\n const windowLut = this.#getCurrentWindowLut();\n return windowLut.getVoiLut().getWindowLevel();\n }\n\n /**\n * Set the window level to the preset with the input name.\n *\n * @param {string} name The name of the preset to activate.\n * @param {boolean} [silent] Flag to launch events with skipGenerate.\n */\n setWindowLevelPreset(name, silent) {\n const preset = this.getWindowPresets()[name];\n if (typeof preset === 'undefined') {\n throw new Error('Unknown window level preset: \\'' + name + '\\'');\n }\n // special min/max\n if (name === 'minmax' && typeof preset.wl === 'undefined') {\n preset.wl = [this.getWindowLevelMinMax()];\n }\n // default to first\n let wl = preset.wl[0];\n // check if 'perslice' case\n if (typeof preset.perslice !== 'undefined' &&\n preset.perslice === true) {\n const offset = this.#image.getSecondaryOffset(this.getCurrentIndex());\n wl = preset.wl[offset];\n }\n // set w/l\n this.setWindowLevel(wl, name, silent);\n }\n\n /**\n * Set the window level to the preset with the input id.\n *\n * @param {number} id The id of the preset to activate.\n * @param {boolean} [silent] Flag to launch events with skipGenerate.\n */\n setWindowLevelPresetById(id, silent) {\n const keys = Object.keys(this.getWindowPresets());\n this.setWindowLevelPreset(keys[id], silent);\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n /**\n * Get the image window/level that covers the full data range.\n * Warning: uses the latest set rescale LUT or the default linear one.\n *\n * @returns {WindowLevel} A min/max window level.\n */\n getWindowLevelMinMax() {\n const range = this.getImage().getRescaledDataRange();\n const min = range.min;\n const max = range.max;\n let width = max - min;\n // full black / white images, defaults to 1.\n if (width < 1) {\n logger.warn('Zero or negative window width, defaulting to one.');\n width = 1;\n }\n const center = min + width / 2;\n return new WindowLevel(center, width);\n }\n\n /**\n * Set the image window/level to cover the full data range.\n * Warning: uses the latest set rescale LUT or the default linear one.\n */\n setWindowLevelMinMax() {\n // calculate center and width\n const wl = this.getWindowLevelMinMax();\n // set window level\n this.setWindowLevel(wl, 'minmax');\n }\n\n /**\n * Generate display image data to be given to a canvas.\n *\n * @param {ImageData} data The iamge data to fill in.\n * @param {Index} index Optional index at which to generate,\n * otherwise generates at current index.\n */\n generateImageData(data, index) {\n // check index\n if (typeof index === 'undefined') {\n if (!this.getCurrentIndex()) {\n this.setInitialIndex();\n }\n index = this.getCurrentIndex();\n }\n\n const image = this.getImage();\n const isRescaled = !image.isConstantRSI();\n const iterator = getSliceIterator(\n image, index, isRescaled, this.getOrientation());\n\n const photoInterpretation = image.getPhotometricInterpretation();\n switch (photoInterpretation) {\n case 'MONOCHROME1':\n case 'MONOCHROME2':\n generateImageDataMonochrome(\n data,\n iterator,\n this.getAlphaFunction(),\n this.#getCurrentWindowLut(),\n this.#getColourMapLut()\n );\n break;\n\n case 'PALETTE COLOR':\n generateImageDataPaletteColor(\n data,\n iterator,\n this.getAlphaFunction(),\n image.getPaletteColourMap(),\n image.getMeta().BitsStored === 16\n );\n break;\n\n case 'RGB':\n generateImageDataRgb(\n data,\n iterator,\n this.getAlphaFunction()\n );\n break;\n\n case 'YBR_FULL':\n generateImageDataYbrFull(\n data,\n iterator,\n this.getAlphaFunction()\n );\n break;\n\n default:\n throw new Error(\n 'Unsupported photometric interpretation: ' + photoInterpretation);\n }\n }\n\n /**\n * Get the scroll dimension index.\n *\n * @returns {number} The index.\n */\n getScrollIndex() {\n let index = null;\n const orientation = this.getOrientation();\n if (typeof orientation !== 'undefined') {\n index = orientation.getThirdColMajorDirection();\n } else {\n index = 2;\n }\n return index;\n }\n\n /**\n * Is this view in the same orientation as the image aquisition.\n *\n * @returns {boolean} True if in aquisition plane.\n */\n isAquisitionOrientation() {\n return isIdentityMat33(this.#orientation);\n }\n\n} // class View\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {WindowLut} from './windowLut';\nimport {ColourMap} from './luts';\n/* eslint-enable no-unused-vars */\n\n/**\n * Generate image data for 'MONOCHROME*' photometric interpretation.\n *\n * @param {ImageData} array The array to store the outut data.\n * @param {object} iterator Position iterator.\n * @param {Function} alphaFunc The alpha function.\n * @param {WindowLut} windowLut The window/level LUT.\n * @param {ColourMap} colourMap The colour map.\n */\nexport function generateImageDataMonochrome(\n array,\n iterator,\n alphaFunc,\n windowLut,\n colourMap) {\n let index = 0;\n let pxValue = 0;\n let ival = iterator.next();\n while (!ival.done) {\n // pixel value\n pxValue = windowLut.getValue(ival.value);\n // store data\n array.data[index] = colourMap.red[pxValue];\n array.data[index + 1] = colourMap.green[pxValue];\n array.data[index + 2] = colourMap.blue[pxValue];\n array.data[index + 3] = alphaFunc(ival.value, ival.index);\n // increment\n index += 4;\n ival = iterator.next();\n }\n}\n","import {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {ColourMap} from './luts';\n/* eslint-enable no-unused-vars */\n\n/**\n * Generate image data for 'PALETTE COLOR' photometric interpretation.\n *\n * @param {ImageData} array The array to store the outut data.\n * @param {object} iterator Position iterator.\n * @param {Function} alphaFunc The alpha function.\n * @param {ColourMap} colourMap The colour map.\n * @param {boolean} is16BitsStored Flag to know if the data is 16bits.\n */\nexport function generateImageDataPaletteColor(\n array,\n iterator,\n alphaFunc,\n colourMap,\n is16BitsStored) {\n // right shift 8\n const to8 = function (value) {\n return value >> 8;\n };\n\n if (is16BitsStored) {\n logger.info('Scaling 16bits data to 8bits.');\n }\n\n let index = 0;\n let pxValue = 0;\n let ival = iterator.next();\n while (!ival.done) {\n // pixel value\n pxValue = ival.value;\n // store data\n // TODO check pxValue fits in lut\n if (is16BitsStored) {\n array.data[index] = to8(colourMap.red[pxValue]);\n array.data[index + 1] = to8(colourMap.green[pxValue]);\n array.data[index + 2] = to8(colourMap.blue[pxValue]);\n } else {\n array.data[index] = colourMap.red[pxValue];\n array.data[index + 1] = colourMap.green[pxValue];\n array.data[index + 2] = colourMap.blue[pxValue];\n }\n array.data[index + 3] = alphaFunc(pxValue, ival.index);\n // increment\n index += 4;\n ival = iterator.next();\n }\n}\n","/**\n * Generate image data for 'RGB' photometric interpretation.\n *\n * @param {ImageData} array The array to store the outut data.\n * @param {object} iterator Position iterator.\n * @param {Function} alphaFunc The alpha function.\n */\nexport function generateImageDataRgb(\n array,\n iterator,\n alphaFunc) {\n let index = 0;\n let ival = iterator.next();\n while (!ival.done) {\n // store data\n array.data[index] = ival.value[0];\n array.data[index + 1] = ival.value[1];\n array.data[index + 2] = ival.value[2];\n array.data[index + 3] = alphaFunc(ival.value, ival.index);\n // increment\n index += 4;\n ival = iterator.next();\n }\n}\n","import {ybrToRgb} from '../utils/colour';\n\n/**\n * Generate image data for 'YBR_FULL' photometric interpretation.\n *\n * @param {ImageData} array The array to store the outut data.\n * @param {object} iterator Position iterator.\n * @param {Function} alphaFunc The alpha function.\n */\nexport function generateImageDataYbrFull(\n array,\n iterator,\n alphaFunc) {\n let index = 0;\n let rgb = null;\n let ival = iterator.next();\n while (!ival.done) {\n // convert ybr to rgb\n rgb = ybrToRgb(ival.value[0], ival.value[1], ival.value[2]);\n // store data\n array.data[index] = rgb.r;\n array.data[index + 1] = rgb.g;\n array.data[index + 2] = rgb.b;\n array.data[index + 3] = alphaFunc(ival.value, ival.index);\n // increment\n index += 4;\n ival = iterator.next();\n }\n}\n","import {Vector3D} from '../math/vector';\nimport {Point3D, Point2D} from '../math/point';\nimport {isIdentityMat33} from '../math/matrix';\nimport {\n getCosinesFromOrientation,\n getTargetOrientation\n} from '../math/orientation';\nimport {getOrientedArray3D, getDeOrientedArray3D} from './geometry';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point} from '../math/point';\nimport {Index} from '../math/index';\nimport {Geometry} from '../image/geometry';\nimport {Matrix33} from '../math/matrix';\nimport {Spacing} from './spacing';\nimport {Scalar2D, Scalar3D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Plane geometry helper.\n */\nexport class PlaneHelper {\n\n /**\n * The image geometry.\n *\n * @type {Geometry}\n */\n #imageGeometry;\n\n /**\n * The associated spacing.\n *\n * @type {Spacing}\n */\n #spacing;\n\n /**\n * The image orientation.\n *\n * @type {Matrix33}\n */\n #imageOrientation;\n\n /**\n * The viewe orientation.\n *\n * @type {Matrix33}\n */\n #viewOrientation;\n\n /**\n * The target orientation.\n *\n * @type {Matrix33}\n */\n #targetOrientation;\n\n /**\n * @param {Geometry} imageGeometry The image geometry.\n * @param {Matrix33} viewOrientation The view orientation.\n */\n constructor(imageGeometry, viewOrientation) {\n this.#imageGeometry = imageGeometry;\n this.#spacing = imageGeometry.getRealSpacing();\n this.#imageOrientation = imageGeometry.getOrientation();\n this.#viewOrientation = viewOrientation;\n\n this.#targetOrientation = getTargetOrientation(\n this.#imageOrientation, viewOrientation);\n }\n\n /**\n * Get the view orientation.\n *\n * @returns {Matrix33} The orientation matrix.\n */\n getViewOrientation() {\n return this.#viewOrientation;\n }\n\n /**\n * Get the target orientation.\n *\n * @returns {Matrix33} The orientation matrix.\n */\n getTargetOrientation() {\n return this.#targetOrientation;\n }\n\n /**\n * Get a 3D offset from a plane one.\n *\n * @param {Scalar2D} offset2D The plane offset as {x,y}.\n * @returns {Vector3D} The 3D world offset.\n */\n getOffset3DFromPlaneOffset(offset2D) {\n // make 3D\n const planeOffset = new Vector3D(\n offset2D.x, offset2D.y, 0);\n // de-orient\n const pixelOffset = this.getTargetDeOrientedVector3D(planeOffset);\n // ~indexToWorld\n return new Vector3D(\n pixelOffset.getX() * this.#spacing.get(0),\n pixelOffset.getY() * this.#spacing.get(1),\n pixelOffset.getZ() * this.#spacing.get(2));\n }\n\n /**\n * Get a plane offset from a 3D one.\n *\n * @param {Scalar3D} offset3D The 3D offset as {x,y,z}.\n * @returns {Scalar2D} The plane offset as {x,y}.\n */\n getPlaneOffsetFromOffset3D(offset3D) {\n // ~worldToIndex\n const pixelOffset = new Vector3D(\n offset3D.x / this.#spacing.get(0),\n offset3D.y / this.#spacing.get(1),\n offset3D.z / this.#spacing.get(2));\n // orient\n const planeOffset = this.getTargetOrientedVector3D(pixelOffset);\n // make 2D\n return {\n x: planeOffset.getX(),\n y: planeOffset.getY()\n };\n }\n\n /**\n * Orient an input vector from real to target space.\n *\n * @param {Vector3D} vector The input vector.\n * @returns {Vector3D} The oriented vector.\n */\n getTargetOrientedVector3D(vector) {\n let planeVector = vector;\n if (typeof this.#targetOrientation !== 'undefined') {\n planeVector =\n this.#targetOrientation.getInverse().multiplyVector3D(vector);\n }\n return planeVector;\n }\n\n /**\n * De-orient an input vector from target to real space.\n *\n * @param {Vector3D} planeVector The input vector.\n * @returns {Vector3D} The de-orienteded vector.\n */\n getTargetDeOrientedVector3D(planeVector) {\n let vector = planeVector;\n if (typeof this.#targetOrientation !== 'undefined') {\n vector = this.#targetOrientation.multiplyVector3D(planeVector);\n }\n return vector;\n }\n\n /**\n * De-orient an input point from target to real space.\n *\n * @param {Point3D} planePoint The input point.\n * @returns {Point3D} The de-orienteded point.\n */\n getTargetDeOrientedPoint3D(planePoint) {\n let point = planePoint;\n if (typeof this.#targetOrientation !== 'undefined') {\n point = this.#targetOrientation.multiplyPoint3D(planePoint);\n }\n return point;\n }\n\n /**\n * Orient an input vector from target to image space.\n *\n * @param {Vector3D} planeVector The input vector.\n * @returns {Vector3D} The orienteded vector.\n */\n getImageOrientedVector3D(planeVector) {\n let vector = planeVector;\n if (typeof this.#viewOrientation !== 'undefined') {\n // image oriented => view de-oriented\n const values = getDeOrientedArray3D(\n [\n planeVector.getX(),\n planeVector.getY(),\n planeVector.getZ()\n ],\n this.#viewOrientation);\n vector = new Vector3D(\n values[0],\n values[1],\n values[2]\n );\n }\n return vector;\n }\n\n /**\n * Orient an input point from target to image space.\n *\n * @param {Point3D} planePoint The input vector.\n * @returns {Point3D} The orienteded vector.\n */\n getImageOrientedPoint3D(planePoint) {\n let point = planePoint;\n if (typeof this.#viewOrientation !== 'undefined') {\n // image oriented => view de-oriented\n const values = getDeOrientedArray3D(\n [\n planePoint.getX(),\n planePoint.getY(),\n planePoint.getZ()\n ],\n this.#viewOrientation);\n point = new Point3D(\n values[0],\n values[1],\n values[2]\n );\n }\n return point;\n }\n\n /**\n * De-orient an input vector from image to target space.\n *\n * @param {Vector3D} vector The input vector.\n * @returns {Vector3D} The de-orienteded vector.\n */\n getImageDeOrientedVector3D(vector) {\n let planeVector = vector;\n if (typeof this.#viewOrientation !== 'undefined') {\n // image de-oriented => view oriented\n const orientedValues = getOrientedArray3D(\n [\n vector.getX(),\n vector.getY(),\n vector.getZ()\n ],\n this.#viewOrientation);\n planeVector = new Vector3D(\n orientedValues[0],\n orientedValues[1],\n orientedValues[2]\n );\n }\n return planeVector;\n }\n\n /**\n * De-orient an input point from image to target space.\n *\n * @param {Point3D} point The input point.\n * @returns {Point3D} The de-orienteded point.\n */\n getImageDeOrientedPoint3D(point) {\n let planePoint = point;\n if (typeof this.#viewOrientation !== 'undefined') {\n // image de-oriented => view oriented\n const orientedValues = getOrientedArray3D(\n [\n point.getX(),\n point.getY(),\n point.getZ()\n ],\n this.#viewOrientation);\n planePoint = new Point3D(\n orientedValues[0],\n orientedValues[1],\n orientedValues[2]\n );\n }\n return planePoint;\n }\n\n /**\n * Get a world position from a 2D plane position.\n *\n * @param {Point2D} point2D The plane point.\n * @param {number} k The slice index.\n * @returns {Point3D} The world position.\n */\n getPositionFromPlanePoint(point2D, k) {\n const planePoint = new Point3D(point2D.getX(), point2D.getY(), k);\n // de-orient\n const point = this.getImageOrientedPoint3D(planePoint);\n // ~indexToWorld to not loose precision\n return this.#imageGeometry.pointToWorld(point);\n }\n\n /**\n * Get a 2D plane position from a world position.\n *\n * @param {Point} point The world position.\n * @returns {Point3D} The plane point.\n */\n getPlanePointFromPosition(point) {\n const point3D = this.#imageGeometry.worldToPoint(point);\n return this.getImageDeOrientedPoint3D(point3D);\n }\n\n /**\n * Get the cosines of this plane.\n *\n * @returns {number[]} The 2 cosines vectors (3D).\n */\n getCosines() {\n return getCosinesFromOrientation(this.#targetOrientation);\n }\n\n /**\n * Get a list of points that define the plane at input position,\n * given this classes orientation.\n *\n * @param {Point} position The position.\n * @returns {Point3D[]} An origin and 2 cosines vectors.\n */\n getPlanePoints(position) {\n // get plane point\n const planePoint = this.getPlanePointFromPosition(position);\n // get origin\n const planeOrigin = this.getPositionFromPlanePoint(\n new Point2D(0, 0), planePoint.getZ());\n\n // plane cosines\n const cosines = this.getCosines();\n\n return [\n planeOrigin,\n new Point3D(cosines[0], cosines[1], cosines[2]),\n new Point3D(cosines[3], cosines[4], cosines[5])\n ];\n }\n\n /**\n * Image world to index.\n *\n * @param {Point} point The input point.\n * @returns {Index} The corresponding index.\n */\n worldToIndex(point) {\n return this.#imageGeometry.worldToIndex(point);\n }\n\n /**\n * Is this view in the same orientation as the image aquisition.\n *\n * @returns {boolean} True if in aquisition plane.\n */\n isAquisitionOrientation() {\n return isIdentityMat33(this.#viewOrientation);\n }\n\n /**\n * Reorder values to follow target orientation.\n *\n * @param {Scalar3D} values Values as {x,y,z}.\n * @returns {Scalar3D} Reoriented values as {x,y,z}.\n */\n getTargetOrientedPositiveXYZ(values) {\n const orientedValues = getOrientedArray3D(\n [\n values.x,\n values.y,\n values.z\n ],\n this.#targetOrientation);\n return {\n x: orientedValues[0],\n y: orientedValues[1],\n z: orientedValues[2]\n };\n }\n\n /**\n * Get the (view) scroll dimension index.\n *\n * @returns {number} The index.\n */\n getScrollIndex() {\n let index = null;\n if (typeof this.#viewOrientation !== 'undefined') {\n index = this.#viewOrientation.getThirdColMajorDirection();\n } else {\n index = 2;\n }\n return index;\n }\n\n /**\n * Get the native (image) scroll dimension index.\n *\n * @returns {number} The index.\n */\n getNativeScrollIndex() {\n let index = null;\n if (typeof this.#imageOrientation !== 'undefined') {\n index = this.#imageOrientation.getThirdColMajorDirection();\n } else {\n index = 2;\n }\n return index;\n }\n\n} // class PlaneHelper\n","import {Index} from '../math/index';\nimport {Vector3D} from '../math/vector';\nimport {Point3D} from '../math/point';\nimport {isIdentityMat33} from '../math/matrix';\nimport {Size} from '../image/size';\nimport {Spacing} from '../image/spacing';\nimport {Image} from '../image/image';\nimport {Geometry} from '../image/geometry';\nimport {PlaneHelper} from '../image/planeHelper';\nimport {\n getSliceIterator,\n getIteratorValues,\n getRegionSliceIterator,\n getVariableRegionSliceIterator\n} from '../image/iterator';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {View} from '../image/view';\nimport {WindowLevel} from '../image/windowLevel';\nimport {Point, Point2D} from '../math/point';\nimport {Scalar2D} from '../math/scalar';\nimport {Matrix33} from '../math/matrix';\nimport {ViewLayer} from '../gui/viewLayer';\n/* eslint-enable no-unused-vars */\n\n/**\n * View controller.\n */\nexport class ViewController {\n\n /**\n * Associated View.\n *\n * @type {View}\n */\n #view;\n\n /**\n * Plane helper.\n *\n * @type {PlaneHelper}\n */\n #planeHelper;\n\n /**\n * Third dimension player ID (created by setInterval).\n *\n * @type {number|undefined}\n */\n #playerID;\n\n /**\n * Is DICOM seg mask flag.\n *\n * @type {boolean}\n */\n #isMask = false;\n\n /**\n * @param {View} view The associated view.\n */\n constructor(view) {\n // check view\n if (typeof view.getImage() === 'undefined') {\n throw new Error('View does not have an image, cannot setup controller');\n }\n\n this.#view = view;\n\n // setup the plane helper\n this.#planeHelper = new PlaneHelper(\n view.getImage().getGeometry(),\n view.getOrientation()\n );\n\n // mask segment helper\n if (view.getImage().getMeta().Modality === 'SEG') {\n this.#isMask = true;\n }\n }\n\n /**\n * Get the plane helper.\n *\n * @returns {PlaneHelper} The helper.\n */\n getPlaneHelper() {\n return this.#planeHelper;\n }\n\n /**\n * Check is the associated image is a mask.\n *\n * @returns {boolean} True if the associated image is a mask.\n */\n isMask() {\n return this.#isMask;\n }\n\n /**\n * Initialise the controller.\n */\n initialise() {\n // set window/level to first preset\n this.setWindowLevelPresetById(0);\n // default position\n this.setCurrentPosition(this.getPositionFromPlanePoint(\n new Point2D(0, 0)\n ));\n }\n\n /**\n * Get the image modality.\n *\n * @returns {string} The modality.\n */\n getModality() {\n return this.#view.getImage().getMeta().Modality;\n }\n\n /**\n * Get the window/level presets names.\n *\n * @returns {string[]} The presets names.\n */\n getWindowLevelPresetsNames() {\n return this.#view.getWindowPresetsNames();\n }\n\n /**\n * Add window/level presets to the view.\n *\n * @param {object} presets A preset object.\n * @returns {object} The list of presets.\n */\n addWindowLevelPresets(presets) {\n return this.#view.addWindowPresets(presets);\n }\n\n /**\n * Set the window level to the preset with the input name.\n *\n * @param {string} name The name of the preset to activate.\n */\n setWindowLevelPreset(name) {\n this.#view.setWindowLevelPreset(name);\n }\n\n /**\n * Set the window level to the preset with the input id.\n *\n * @param {number} id The id of the preset to activate.\n */\n setWindowLevelPresetById(id) {\n this.#view.setWindowLevelPresetById(id);\n }\n\n /**\n * Check if the controller is playing.\n *\n * @returns {boolean} True if the controler is playing.\n */\n isPlaying() {\n return (typeof this.#playerID !== 'undefined');\n }\n\n /**\n * Get the current position.\n *\n * @returns {Point} The position.\n */\n getCurrentPosition() {\n return this.#view.getCurrentPosition();\n }\n\n /**\n * Get the current index.\n *\n * @returns {Index} The current index.\n */\n getCurrentIndex() {\n return this.#view.getCurrentIndex();\n }\n\n /**\n * Get the SOP image UID of the current image.\n *\n * @returns {string} The UID.\n */\n getCurrentImageUid() {\n return this.#view.getCurrentImageUid();\n }\n\n /**\n * Get the image origin for a image UID.\n *\n * @param {string} uid The UID.\n * @returns {Point3D|undefined} The origin.\n */\n getOriginForImageUid(uid) {\n return this.#view.getOriginForImageUid(uid);\n }\n\n /**\n * Check if the image includes an UID.\n *\n * @param {string} uid The UID.\n * @returns {boolean} True if present.\n */\n includesImageUid(uid) {\n return this.#view.includesImageUid(uid);\n }\n\n /**\n * Get the current oriented index.\n *\n * @returns {Index} The index.\n */\n getCurrentOrientedIndex() {\n let res = this.#view.getCurrentIndex();\n if (typeof this.#view.getOrientation() !== 'undefined') {\n // view oriented => image de-oriented\n const vector = this.#planeHelper.getImageDeOrientedVector3D(\n new Vector3D(res.get(0), res.get(1), res.get(2))\n );\n res = new Index([\n vector.getX(), vector.getY(), vector.getZ()\n ]);\n }\n return res;\n }\n\n /**\n * Get the scroll index.\n *\n * @returns {number} The index.\n */\n getScrollIndex() {\n return this.#view.getScrollIndex();\n }\n\n /**\n * Get the current scroll index value.\n *\n * @returns {object} The value.\n */\n getCurrentScrollIndexValue() {\n return this.#view.getCurrentIndex().get(this.#view.getScrollIndex());\n }\n\n /**\n * Get the first origin or at a given position.\n *\n * @param {Point} [position] Optional position.\n * @returns {Point3D} The origin.\n */\n getOrigin(position) {\n return this.#view.getOrigin(position);\n }\n\n /**\n * Is this view in the same orientation as the image aquisition.\n *\n * @returns {boolean} True if in aquisition plane.\n */\n isAquisitionOrientation() {\n return this.#view.isAquisitionOrientation();\n }\n\n /**\n * Get a list of points that define the plane at input position,\n * given this classes orientation.\n *\n * @param {Point} position The position.\n * @returns {Point3D[]} An origin and 2 cosines vectors.\n */\n getPlanePoints(position) {\n return this.#planeHelper.getPlanePoints(position);\n }\n\n /**\n * Get the current scroll position value.\n *\n * @returns {number} The value.\n */\n getCurrentScrollPosition() {\n const scrollIndex = this.#view.getScrollIndex();\n return this.#view.getCurrentPosition().get(scrollIndex);\n }\n\n /**\n * Generate display image data to be given to a canvas.\n *\n * @param {ImageData} array The array to fill in.\n * @param {Index} [index] Optional index at which to generate,\n * otherwise generates at current index.\n */\n generateImageData(array, index) {\n this.#view.generateImageData(array, index);\n }\n\n /**\n * Set the associated image.\n *\n * @param {Image} img The associated image.\n */\n setImage(img) {\n this.#view.setImage(img);\n }\n\n /**\n * Get the current view (2D) spacing.\n *\n * @returns {Scalar2D} The spacing as a 2D array.\n */\n get2DSpacing() {\n const spacing = this.#view.getImage().getGeometry().getSpacing(\n this.#view.getOrientation());\n return spacing.get2D();\n }\n\n /**\n * Get the image rescaled value at the input position.\n *\n * @param {Point} position The input position.\n * @returns {number|undefined} The image value or undefined if out of bounds\n * or no quantifiable (for ex RGB).\n */\n getRescaledImageValue(position) {\n const image = this.#view.getImage();\n if (!image.canQuantify()) {\n return;\n }\n const geometry = image.getGeometry();\n const index = geometry.worldToIndex(position);\n let value;\n if (geometry.isIndexInBounds(index)) {\n value = image.getRescaledValueAtIndex(index);\n }\n return value;\n }\n\n /**\n * Get the image pixel unit.\n *\n * @returns {string} The unit.\n */\n getPixelUnit() {\n return this.#view.getImage().getMeta().pixelUnit;\n }\n\n /**\n * Extract a slice from an image at the given index and orientation.\n *\n * @param {Image} image The image to parse.\n * @param {Index} index The current index.\n * @param {boolean} isRescaled Flag for rescaled values (default false).\n * @param {Matrix33} orientation The desired orientation.\n * @returns {Image} The extracted slice.\n */\n #getSlice(image, index, isRescaled, orientation) {\n // generate slice values\n const sliceIter = getSliceIterator(\n image,\n index,\n isRescaled,\n orientation\n );\n const sliceValues = getIteratorValues(sliceIter);\n // oriented geometry\n const orientedSize = image.getGeometry().getSize(orientation);\n const sizeValues = orientedSize.getValues();\n sizeValues[2] = 1;\n const sliceSize = new Size(sizeValues);\n const orientedSpacing = image.getGeometry().getSpacing(orientation);\n const spacingValues = orientedSpacing.getValues();\n spacingValues[2] = 1;\n const sliceSpacing = new Spacing(spacingValues);\n const sliceOrigin = new Point3D(0, 0, 0);\n const sliceGeometry =\n new Geometry(sliceOrigin, sliceSize, sliceSpacing);\n // slice image\n // @ts-ignore\n return new Image(sliceGeometry, sliceValues);\n }\n\n /**\n * Get some values from the associated image in a region.\n *\n * @param {Point2D} min Minimum point.\n * @param {Point2D} max Maximum point.\n * @returns {Array} A list of values.\n */\n getImageRegionValues(min, max) {\n let image = this.#view.getImage();\n const orientation = this.#view.getOrientation();\n let currentIndex = this.getCurrentIndex();\n let rescaled = true;\n\n // create oriented slice if needed\n if (!isIdentityMat33(orientation)) {\n image = this.#getSlice(image, currentIndex, rescaled, orientation);\n // update position\n currentIndex = new Index([0, 0, 0]);\n rescaled = false;\n }\n\n // get region values\n const iter = getRegionSliceIterator(\n image, currentIndex, rescaled, min, max);\n let values = [];\n if (iter) {\n values = getIteratorValues(iter);\n }\n return values;\n }\n\n /**\n * Get some values from the associated image in variable regions.\n *\n * @param {number[][][]} regions A list of [x, y] pairs (min, max).\n * @returns {Array} A list of values.\n */\n getImageVariableRegionValues(regions) {\n let image = this.#view.getImage();\n const orientation = this.#view.getOrientation();\n let currentIndex = this.getCurrentIndex();\n let rescaled = true;\n\n // create oriented slice if needed\n if (!isIdentityMat33(orientation)) {\n image = this.#getSlice(image, currentIndex, rescaled, orientation);\n // update position\n currentIndex = new Index([0, 0, 0]);\n rescaled = false;\n }\n\n // get region values\n const iter = getVariableRegionSliceIterator(\n image, currentIndex, rescaled, regions);\n let values = [];\n if (iter) {\n values = getIteratorValues(iter);\n }\n return values;\n }\n\n /**\n * Can the image values be quantified?\n *\n * @returns {boolean} True if possible.\n */\n canQuantifyImage() {\n return this.#view.getImage().canQuantify();\n }\n\n /**\n * Can window and level be applied to the data?\n *\n * @returns {boolean} True if possible.\n * @deprecated Since v0.33, please use isMonochrome instead.\n */\n canWindowLevel() {\n return this.isMonochrome();\n }\n\n /**\n * Is the data monochrome.\n *\n * @returns {boolean} True if the data is monochrome.\n */\n isMonochrome() {\n return this.#view.getImage().isMonochrome();\n }\n\n /**\n * Can the data be scrolled?\n *\n * @returns {boolean} True if the data has either the third dimension\n * or above greater than one.\n */\n canScroll() {\n return this.#view.getImage().canScroll(this.#view.getOrientation());\n }\n\n /**\n * Get the oriented image size.\n *\n * @returns {Size} The size.\n */\n getImageSize() {\n return this.#view.getImage().getGeometry().getSize(\n this.#view.getOrientation());\n }\n\n\n /**\n * Is the data size larger than one in the given dimension?\n *\n * @param {number} dim The dimension.\n * @returns {boolean} True if the image size is larger than one\n * in the given dimension.\n */\n moreThanOne(dim) {\n return this.getImageSize().moreThanOne(dim);\n }\n\n /**\n * Get the image world (mm) 2D size.\n *\n * @returns {Scalar2D} The 2D size as {x,y}.\n */\n getImageWorldSize() {\n const geometry = this.#view.getImage().getGeometry();\n const size = geometry.getSize(this.#view.getOrientation()).get2D();\n const spacing = geometry.getSpacing(this.#view.getOrientation()).get2D();\n return {\n x: size.x * spacing.x,\n y: size.y * spacing.y\n };\n }\n\n /**\n * Get the image rescaled data range.\n *\n * @returns {object} The range as {min, max}.\n */\n getImageRescaledDataRange() {\n return this.#view.getImage().getRescaledDataRange();\n }\n\n /**\n * Compare the input meta data to the associated image one.\n *\n * @param {object} meta The meta data.\n * @returns {boolean} True if the associated image has equal meta data.\n */\n equalImageMeta(meta) {\n const imageMeta = this.#view.getImage().getMeta();\n // loop through input meta keys\n const metaKeys = Object.keys(meta);\n for (let i = 0; i < metaKeys.length; ++i) {\n const metaKey = metaKeys[i];\n if (typeof imageMeta[metaKey] === 'undefined') {\n return false;\n }\n if (imageMeta[metaKey] !== meta[metaKey]) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Check if the current position (default) or\n * the provided position is in bounds.\n *\n * @param {Point} [position] Optional position.\n * @returns {boolean} True is the position is in bounds.\n */\n isPositionInBounds(position) {\n return this.#view.isPositionInBounds(position);\n }\n\n /**\n * Set the current position.\n *\n * @param {Point} pos The position.\n * @param {boolean} [silent] If true, does not fire a\n * positionchange event.\n * @returns {boolean} False if not in bounds.\n */\n setCurrentPosition(pos, silent) {\n return this.#view.setCurrentPosition(pos, silent);\n }\n\n /**\n * Get a world position from a 2D plane position.\n *\n * @param {Point2D} point2D The input point.\n * @param {number} [k] Optional slice index,\n * if undefined, uses the current one.\n * @returns {Point} The associated position.\n */\n getPositionFromPlanePoint(point2D, k) {\n // keep third direction\n if (typeof k === 'undefined') {\n k = this.getCurrentScrollIndexValue();\n }\n const planePoint = new Point3D(point2D.getX(), point2D.getY(), k);\n // de-orient\n const point = this.#planeHelper.getImageOrientedPoint3D(planePoint);\n // ~indexToWorld to not loose precision\n const geometry = this.#view.getImage().getGeometry();\n const point3D = geometry.pointToWorld(point);\n // merge with current position to keep extra dimensions\n return this.getCurrentPosition().mergeWith3D(point3D);\n }\n\n /**\n * Get a 2D plane position from a world position.\n *\n * @param {Point} point The 3D position.\n * @returns {Point2D} The 2D position.\n */\n getPlanePositionFromPosition(point) {\n // orient\n const geometry = this.#view.getImage().getGeometry();\n // ~worldToIndex to not loose precision\n const point3D = geometry.worldToPoint(point);\n const planePoint = this.#planeHelper.getImageDeOrientedPoint3D(point3D);\n // return\n return new Point2D(\n planePoint.getX(),\n planePoint.getY(),\n );\n }\n\n /**\n * Get the index of a world position.\n *\n * @param {Point} point The 3D position.\n * @returns {Index} The index.\n */\n getIndexFromPosition(point) {\n // orient\n const geometry = this.#view.getImage().getGeometry();\n // ~worldToIndex to not loose precision\n return geometry.worldToIndex(point);\n }\n\n /**\n * Set the current index.\n *\n * @param {Index} index The index.\n * @param {boolean} [silent] If true, does not fire a positionchange event.\n * @returns {boolean} False if not in bounds.\n */\n setCurrentIndex(index, silent) {\n return this.#view.setCurrentIndex(index, silent);\n }\n\n /**\n * Get a plane 3D position from a plane 2D position: does not compensate\n * for the image origin. Needed for setting the scale center...\n *\n * @param {Point2D} point2D The 2D position.\n * @returns {Point3D} The 3D point.\n */\n getPlanePositionFromPlanePoint(point2D) {\n // keep third direction\n const k = this.getCurrentScrollIndexValue();\n const planePoint = new Point3D(point2D.getX(), point2D.getY(), k);\n // de-orient\n const point = this.#planeHelper.getTargetDeOrientedPoint3D(planePoint);\n // ~indexToWorld to not loose precision\n const geometry = this.#view.getImage().getGeometry();\n const spacing = geometry.getRealSpacing();\n return new Point3D(\n point.getX() * spacing.get(0),\n point.getY() * spacing.get(1),\n point.getZ() * spacing.get(2));\n }\n\n /**\n * Get a 3D offset from a plane one.\n *\n * @param {Scalar2D} offset2D The plane offset as {x,y}.\n * @returns {Vector3D} The 3D world offset.\n */\n getOffset3DFromPlaneOffset(offset2D) {\n return this.#planeHelper.getOffset3DFromPlaneOffset(offset2D);\n }\n\n /**\n * Get the current index incremented in the input direction.\n *\n * @param {number} dim The direction in which to increment.\n * @returns {Index} The resulting index.\n */\n #getIncrementIndex(dim) {\n const index = this.getCurrentIndex();\n const values = new Array(index.length());\n values.fill(0);\n if (dim < values.length) {\n values[dim] = 1;\n } else {\n console.warn('Cannot increment given index: ', dim, values.length);\n }\n const incr = new Index(values);\n return index.add(incr);\n }\n\n /**\n * Get the current index decremented in the input direction.\n *\n * @param {number} dim The direction in which to decrement.\n * @returns {Index} The resulting index.\n */\n #getDecrementIndex(dim) {\n const index = this.getCurrentIndex();\n const values = new Array(index.length());\n values.fill(0);\n if (dim < values.length) {\n values[dim] = -1;\n } else {\n console.warn('Cannot decrement given index: ', dim, values.length);\n }\n const incr = new Index(values);\n return index.add(incr);\n }\n\n /**\n * Get the current index incremented in the scroll direction.\n *\n * @returns {Index} The resulting index.\n */\n #getIncrementScrollIndex() {\n return this.#getIncrementIndex(this.getScrollIndex());\n }\n\n /**\n * Get the current index decremented in the scroll direction.\n *\n * @returns {Index} The resulting index.\n */\n #getDecrementScrollIndex() {\n return this.#getDecrementIndex(this.getScrollIndex());\n }\n\n /**\n * Get the current position incremented in the input direction.\n *\n * @param {number} dim The direction in which to increment.\n * @returns {Point} The resulting point.\n */\n getIncrementPosition(dim) {\n const geometry = this.#view.getImage().getGeometry();\n return geometry.indexToWorld(this.#getIncrementIndex(dim));\n }\n\n /**\n * Get the current position decremented in the input direction.\n *\n * @param {number} dim The direction in which to decrement.\n * @returns {Point} The resulting point.\n */\n getDecrementPosition(dim) {\n const geometry = this.#view.getImage().getGeometry();\n return geometry.indexToWorld(this.#getDecrementIndex(dim));\n }\n\n /**\n * Get the current position decremented in the scroll direction.\n *\n * @returns {Point} The resulting point.\n */\n getIncrementScrollPosition() {\n const geometry = this.#view.getImage().getGeometry();\n return geometry.indexToWorld(this.#getIncrementScrollIndex());\n }\n\n /**\n * Get the current position decremented in the scroll direction.\n *\n * @returns {Point} The resulting point.\n */\n getDecrementScrollPosition() {\n const geometry = this.#view.getImage().getGeometry();\n return geometry.indexToWorld(this.#getDecrementScrollIndex());\n }\n\n /**\n * Increment the provided dimension.\n *\n * @param {number} dim The dimension to increment.\n * @param {boolean} [silent] Do not send event.\n * @returns {boolean} False if not in bounds.\n */\n incrementIndex(dim, silent) {\n return this.setCurrentIndex(this.#getIncrementIndex(dim), silent);\n }\n\n /**\n * Decrement the provided dimension.\n *\n * @param {number} dim The dimension to increment.\n * @param {boolean} [silent] Do not send event.\n * @returns {boolean} False if not in bounds.\n */\n decrementIndex(dim, silent) {\n return this.setCurrentIndex(this.#getDecrementIndex(dim), silent);\n }\n\n /**\n * Decrement the scroll dimension index.\n *\n * @param {boolean} [silent] Do not send event.\n * @returns {boolean} False if not in bounds.\n */\n decrementScrollIndex(silent) {\n return this.setCurrentIndex(this.#getDecrementScrollIndex(), silent);\n }\n\n /**\n * Increment the scroll dimension index.\n *\n * @param {boolean} [silent] Do not send event.\n * @returns {boolean} False if not in bounds.\n */\n incrementScrollIndex(silent) {\n return this.setCurrentIndex(this.#getIncrementScrollIndex(), silent);\n }\n\n /**\n * Scroll play: loop through all slices.\n */\n play() {\n // ensure data is scrollable: dim >= 3\n if (!this.canScroll()) {\n return;\n }\n if (typeof this.#playerID === 'undefined') {\n const image = this.#view.getImage();\n const recommendedDisplayFrameRate =\n image.getMeta().RecommendedDisplayFrameRate;\n const milliseconds = this.#view.getPlaybackMilliseconds(\n recommendedDisplayFrameRate);\n const size = image.getGeometry().getSize();\n const canScroll3D = size.canScroll3D();\n\n this.#playerID = window.setInterval(() => {\n let canDoMore = false;\n if (canScroll3D) {\n canDoMore = this.incrementScrollIndex();\n } else {\n canDoMore = this.incrementIndex(3);\n }\n // end of scroll, loop back\n if (!canDoMore) {\n const pos1 = this.getCurrentIndex();\n const values = pos1.getValues();\n const orientation = this.#view.getOrientation();\n if (canScroll3D) {\n values[orientation.getThirdColMajorDirection()] = 0;\n } else {\n values[3] = 0;\n }\n const index = new Index(values);\n const geometry = this.#view.getImage().getGeometry();\n this.setCurrentPosition(geometry.indexToWorld(index));\n }\n }, milliseconds);\n } else {\n this.stop();\n }\n }\n\n /**\n * Stop scroll playing.\n */\n stop() {\n if (typeof this.#playerID !== 'undefined') {\n clearInterval(this.#playerID);\n this.#playerID = undefined;\n }\n }\n\n /**\n * Get the window/level.\n *\n * @returns {WindowLevel} The window and level.\n */\n getWindowLevel() {\n return this.#view.getWindowLevel();\n }\n\n /**\n * Get the current window level preset name.\n *\n * @returns {string} The preset name.\n */\n getCurrentWindowPresetName() {\n return this.#view.getCurrentWindowPresetName();\n }\n\n /**\n * Set the window and level.\n *\n * @param {WindowLevel} wl The window and level.\n */\n setWindowLevel(wl) {\n this.#view.setWindowLevel(wl);\n }\n\n /**\n * Get the colour map.\n *\n * @returns {string} The colour map name.\n */\n getColourMap() {\n return this.#view.getColourMap();\n }\n\n /**\n * Set the colour map.\n *\n * @param {string} name The colour map name.\n */\n setColourMap(name) {\n this.#view.setColourMap(name);\n }\n\n /**\n * @callback alphaFn\n * @param {number[]|number} value The pixel value.\n * @param {number} index The values' index.\n * @returns {number} The opacity of the input value.\n */\n\n /**\n * Set the view per value alpha function.\n *\n * @param {alphaFn} func The function.\n */\n setViewAlphaFunction(func) {\n this.#view.setAlphaFunction(func);\n }\n\n /**\n * Bind the view image to the provided layer.\n *\n * @param {ViewLayer} viewLayer The layer to bind.\n */\n bindImageAndLayer(viewLayer) {\n const image = this.#view.getImage();\n image.addEventListener('imagecontentchange',\n viewLayer.onimagecontentchange\n );\n image.addEventListener('imagegeometrychange',\n viewLayer.onimagegeometrychange\n );\n }\n\n /**\n * Unbind the view image to the provided layer.\n *\n * @param {ViewLayer} viewLayer The layer to bind.\n */\n unbindImageAndLayer(viewLayer) {\n const image = this.#view.getImage();\n image.removeEventListener('imagecontentchange',\n viewLayer.onimagecontentchange\n );\n image.removeEventListener('imagegeometrychange',\n viewLayer.onimagegeometrychange\n );\n }\n\n} // class ViewController\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get a normalised spin speed in the Y direction to try to support\n * trackpads (small and large deltaY) and mouse wheel (large deltaY).\n * Should return 1 or -1 for a single mouse wheel tick.\n *\n * @param {object} event The wheel event.\n * @returns {number} The normalised spin Y.\n */\nfunction getSpinY(event) {\n // (notes of 03/2024)\n\n // firefox seems to change the value of deltaY\n // if you ask for deltaMode before (?????)\n\n // deltaY (for a single mouse wheel tick):\n // - chrome: [linux] 120, [mac]: 4\n // - firefox: [linux] 132, [mac]: 16\n\n // wheelDelta (for a single mouse wheel tick):\n // - chrome: [linux] 120, [mac]: 240\n // - firefox: [linux] 120, [mac]: 48\n\n // -> using wheelDelta for mouse wheel detection as\n // it is consistently larger than trackpad scroll\n\n // wheelDeltaY and deltaY do not go in the same direction,\n // using -deltaY so that they do...\n\n if (typeof event.wheelDeltaY === 'undefined') {\n //logger.warn('No wheel delta, scroll could be tricky...);\n return -event.deltaY;\n } else {\n const threshold = 45;\n if (event.wheelDeltaY > threshold) {\n return 1;\n } else if (event.wheelDeltaY < -threshold) {\n return -1;\n } else {\n return -event.deltaY / 60;\n }\n }\n}\n\n/**\n * Class to sum wheel events and know if that sum\n * corresponds to a 'tick'.\n */\nclass ScrollSum {\n /**\n * The scroll sum.\n *\n * @type {number}\n */\n #sum = 0;\n\n /**\n * Get the scroll sum.\n *\n * @returns {number} The scroll sum.\n */\n getSum() {\n return this.#sum;\n }\n\n /**\n * Add scroll.\n *\n * @param {object} event The wheel event.\n */\n add(event) {\n this.#sum += getSpinY(event);\n }\n\n /**\n * Clear the scroll sum.\n */\n clear() {\n this.#sum = 0;\n }\n\n /**\n * Does the accumulated scroll correspond to a 'tick'.\n *\n * @returns {boolean} True if the sum corresponds to a 'tick'.\n */\n isTick() {\n return Math.abs(this.#sum) >= 1;\n }\n}\n\n/**\n * Scroll wheel class: provides a wheel event handler\n * that scroll the corresponding data.\n */\nexport class ScrollWheel {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Accumulated scroll.\n *\n * @type {ScrollSum}\n */\n #scrollSum = new ScrollSum();\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Handle mouse wheel event.\n *\n * @param {WheelEvent} event The mouse wheel event.\n */\n wheel(event) {\n this.#scrollSum.add(event);\n const up = this.#scrollSum.getSum() >= 0;\n\n // exit if no tick\n if (!this.#scrollSum.isTick()) {\n return;\n } else {\n this.#scrollSum.clear();\n }\n\n // prevent default page scroll\n event.preventDefault();\n\n const layerDetails = getLayerDetailsFromEvent(event);\n const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n let newPosition;\n if (layerGroup.canScroll()) {\n if (up) {\n newPosition = viewController.getIncrementScrollPosition();\n } else {\n newPosition = viewController.getDecrementScrollPosition();\n }\n } else if (layerGroup.moreThanOne(3)) {\n if (up) {\n newPosition = viewController.getIncrementPosition(3);\n } else {\n newPosition = viewController.getDecrementPosition(3);\n }\n }\n\n // set all layers if at least one can be set\n if (typeof newPosition !== 'undefined' &&\n layerGroup.isPositionInBounds(newPosition)) {\n viewController.setCurrentPosition(newPosition);\n }\n }\n\n} // ScrollWheel class\n","import {Point2D} from './point';\nimport {\n isSimilar,\n REAL_WORLD_EPSILON,\n} from './matrix';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {ViewController} from '../app/viewController';\nimport {Scalar2D} from './scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Line shape.\n */\nexport class Line {\n\n /**\n * Line begin point.\n *\n * @type {Point2D}\n */\n #begin;\n\n /**\n * Line end point.\n *\n * @type {Point2D}\n */\n #end;\n\n /**\n * @param {Point2D} begin A Point2D representing the beginning\n * of the line.\n * @param {Point2D} end A Point2D representing the end of the line.\n */\n constructor(begin, end) {\n this.#begin = begin;\n this.#end = end;\n }\n\n /**\n * Get the begin point of the line.\n *\n * @returns {Point2D} The beginning point of the line.\n */\n getBegin() {\n return this.#begin;\n }\n\n /**\n * Get the end point of the line.\n *\n * @returns {Point2D} The ending point of the line.\n */\n getEnd() {\n return this.#end;\n }\n\n /**\n * Check for equality.\n *\n * @param {Line} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.getBegin().equals(rhs.getBegin()) &&\n this.getEnd().equals(rhs.getEnd());\n }\n\n /**\n * Get the line delta in the X direction.\n *\n * @returns {number} The delta in the X direction.\n */\n getDeltaX() {\n return this.getEnd().getX() - this.getBegin().getX();\n }\n\n /**\n * Get the line delta in the Y direction.\n *\n * @returns {number} The delta in the Y direction.\n */\n getDeltaY() {\n return this.getEnd().getY() - this.getBegin().getY();\n }\n\n /**\n * Get the length of the line.\n *\n * @returns {number} The length of the line.\n */\n getLength() {\n return Math.sqrt(\n this.getDeltaX() * this.getDeltaX() +\n this.getDeltaY() * this.getDeltaY()\n );\n }\n\n /**\n * Get the length of the line according to a spacing.\n *\n * @param {Scalar2D} spacing2D The 2D spacing.\n * @returns {number} The length of the line with spacing\n * or null for null spacings.\n */\n getWorldLength(spacing2D) {\n let wlen = null;\n if (spacing2D !== null) {\n const dxs = this.getDeltaX() * spacing2D.x;\n const dys = this.getDeltaY() * spacing2D.y;\n wlen = Math.sqrt(dxs * dxs + dys * dys);\n }\n return wlen;\n }\n\n /**\n * Get the mid point of the line.\n *\n * @returns {Point2D} The mid point of the line.\n */\n getMidpoint() {\n return new Point2D(\n (this.getBegin().getX() + this.getEnd().getX()) / 2,\n (this.getBegin().getY() + this.getEnd().getY()) / 2\n );\n }\n\n /**\n * Get the centroid of the line.\n *\n * @returns {Point2D} THe centroid point.\n */\n getCentroid() {\n return this.getMidpoint();\n }\n\n /**\n * Get the slope of the line.\n *\n * @returns {number} The slope of the line.\n */\n getSlope() {\n return this.getDeltaY() / this.getDeltaX();\n }\n\n /**\n * Get the intercept of the line.\n *\n * @returns {number} The slope of the line.\n */\n getIntercept() {\n return (\n this.getEnd().getX() * this.getBegin().getY() -\n this.getBegin().getX() * this.getEnd().getY()\n ) / this.getDeltaX();\n }\n\n /**\n * Get the inclination of the line.\n *\n * @returns {number} The inclination of the line.\n */\n getInclination() {\n // tan(theta) = slope\n const angle =\n Math.atan2(this.getDeltaY(), this.getDeltaX()) * 180 / Math.PI;\n // shift?\n return 180 - angle;\n }\n\n /**\n * Quantify a line according to view information.\n *\n * @param {ViewController} viewController The associated view controller.\n * @returns {object} A quantification object.\n */\n quantify(viewController) {\n const quant = {};\n // length\n const spacing2D = viewController.get2DSpacing();\n const length = this.getWorldLength(spacing2D);\n if (length !== null) {\n quant.length = {value: length, unit: 'unit.mm'};\n }\n // return\n return quant;\n }\n\n} // Line class\n\n/**\n * Get the angle between two lines in degree.\n *\n * @param {Line} line0 The first line.\n * @param {Line} line1 The second line.\n * @returns {number} The angle.\n */\nexport function getAngle(line0, line1) {\n const dx0 = line0.getDeltaX();\n const dy0 = line0.getDeltaY();\n const dx1 = line1.getDeltaX();\n const dy1 = line1.getDeltaY();\n // dot = ||a||*||b||*cos(theta)\n const dot = dx0 * dx1 + dy0 * dy1;\n // cross = ||a||*||b||*sin(theta)\n const det = dx0 * dy1 - dy0 * dx1;\n // tan = sin / cos\n const angle = Math.atan2(det, dot) * 180 / Math.PI;\n // complementary angle\n // shift?\n return 360 - (180 - angle);\n}\n\n/**\n * Check if two lines are orthogonal.\n *\n * @param {Line} line0 The first line.\n * @param {Line} line1 The second line.\n * @returns {boolean} True if both lines are orthogonal.\n */\nexport function areOrthogonal(line0, line1) {\n const dx0 = line0.getDeltaX();\n const dy0 = line0.getDeltaY();\n const dx1 = line1.getDeltaX();\n const dy1 = line1.getDeltaY();\n // dot = ||a||*||b||*cos(theta)\n return (dx0 * dx1 + dy0 * dy1) === 0;\n}\n\n/**\n * Check if a point is in a line coordinate range.\n *\n * @param {Point2D} point The input point.\n * @param {Line} line The input line.\n * @returns {boolean} True if the input point is in the line coordinate range.\n */\nexport function isPointInLineRange(point, line) {\n const minX = Math.min(line.getBegin().getX(), line.getEnd().getX());\n const maxX = Math.max(line.getBegin().getX(), line.getEnd().getX());\n const minY = Math.min(line.getBegin().getY(), line.getEnd().getY());\n const maxY = Math.max(line.getBegin().getY(), line.getEnd().getY());\n return point.getX() >= minX &&\n point.getX() <= maxX &&\n point.getY() >= minY &&\n point.getY() <= maxY;\n}\n\n/**\n * Get a perpendicular line to an input one at a given point.\n *\n * @param {Line} line The line to be perpendicular to.\n * @param {Point2D} point The middle point of the perpendicular line.\n * @param {number} length The length of the perpendicular line.\n * @param {Scalar2D} [spacing] Optional image spacing, default to [1,1].\n * @returns {Line} The perpendicular line.\n */\nexport function getPerpendicularLine(line, point, length, spacing) {\n if (typeof spacing === 'undefined') {\n spacing = {x: 1, y: 1};\n }\n const sx2 = spacing.x * spacing.x;\n const sy2 = spacing.y * spacing.y;\n // a0 * a1 = -1 (in square space)\n const perpSlope = -sx2 / (sy2 * line.getSlope());\n // y0 = a1*x0 + b1 -> b1 = y0 - a1*x0\n const prepIntercept = point.getY() - perpSlope * point.getX();\n // return\n return getLineFromEquation(perpSlope, prepIntercept, point, length, spacing);\n}\n\n/**\n * Get a perpendicular line to an input one at a given distance\n * of its begin point.\n *\n * @param {Line} line The line to be perpendicular to.\n * @param {number} distance The distance to the input line begin point.\n * @param {number} length The length of the perpendicular line.\n * @param {Scalar2D} [spacing] Optional image spacing, default to [1,1].\n * @returns {Line} The perpendicular line.\n */\nexport function getPerpendicularLineAtDistance(\n line, distance, length, spacing) {\n // get a line along the input one and centered on begin point\n const lineFromEq = getLineFromEquation(\n line.getSlope(),\n line.getIntercept(),\n line.getBegin(),\n distance,\n spacing\n );\n // select the point on the input line\n let startPoint;\n if (isPointInLineRange(lineFromEq.getBegin(), line)) {\n startPoint = lineFromEq.getBegin();\n } else {\n startPoint = lineFromEq.getEnd();\n }\n // use it as base for a perpendicular line\n return getPerpendicularLine(line, startPoint, length, spacing);\n}\n\n/**\n * Get a line from an equation, a middle point and a length.\n *\n * @param {number} slope The line slope.\n * @param {number} intercept The line intercept.\n * @param {Point2D} point The middle point of the line.\n * @param {number} length The line length.\n * @param {Scalar2D} [spacing] Optional image spacing, default to [1,1].\n * @returns {Line} The resulting line.\n */\nexport function getLineFromEquation(slope, intercept, point, length, spacing) {\n if (typeof spacing === 'undefined') {\n spacing = {x: 1, y: 1};\n }\n // begin point\n let beginX = 0;\n let beginY = 0;\n // end point\n let endX = 0;\n let endY = 0;\n\n if (isSimilar(slope, 0, REAL_WORLD_EPSILON)) {\n // slope = ~0 -> horizontal input line\n beginX = point.getX() - length / (2 * spacing.x);\n beginY = point.getY();\n endX = point.getX() + length / (2 * spacing.x);\n endY = point.getY();\n } else if (Math.abs(slope) > 1e6) {\n // slope = ~(+/-)Infinity -> vertical input line\n beginX = point.getX();\n beginY = point.getY() - length / (2 * spacing.y);\n endX = point.getX();\n endY = point.getY() + length / (2 * spacing.y);\n } else {\n const sx2 = spacing.x * spacing.x;\n const sy2 = spacing.y * spacing.y;\n\n // 1. [length] sx^2 * (x - x0)^2 + sy^2 * (y - y0)^2 = d^2\n // 2. [slope] a = (y - y0) / (x - x0) -> y - y0 = a*(x - x0)\n // -> sx^2 * (x - x0)^2 + sy^2 * a^2 * (x - x0)^2 = d^2\n // -> (x - x0)^2 = d^2 / (sx^2 + sy^2 * a^2)\n // -> x = x0 +- d / sqrt(sx^2 + sy^2 * a^2)\n\n // length is the distance between begin and end,\n // point is half way between both -> d = length / 2\n const dx = length / (2 * Math.sqrt(sx2 + sy2 * slope * slope));\n\n // begin point\n beginX = point.getX() - dx;\n beginY = slope * beginX + intercept;\n // end point\n endX = point.getX() + dx;\n endY = slope * endX + intercept;\n }\n return new Line(\n new Point2D(beginX, beginY),\n new Point2D(endX, endY));\n}\n","import {logger} from '../utils/logger';\nimport {ListenerHandler} from '../utils/listen';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Annotation} from './annotation';\nimport {ViewController} from '../app/viewController';\n/* eslint-enable no-unused-vars */\n\n/**\n * Annotation group.\n */\nexport class AnnotationGroup {\n /**\n * @type {Annotation[]}\n */\n #list;\n\n /**\n * Annotation meta data.\n *\n * @type {Object}\n */\n #meta = {};\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Editable flag.\n *\n * @type {boolean}\n */\n #editable;\n\n /**\n * Group colour as hex string. If defined, it will be used as\n * default colour for new annotations in draw tool.\n *\n * @type {string|undefined}\n */\n #colour;\n\n /**\n * @param {Annotation[]} [list] Optional list, will\n * create new if not provided.\n */\n constructor(list) {\n if (typeof list !== 'undefined') {\n this.#list = list;\n } else {\n this.#list = [];\n }\n this.#editable = true;\n }\n\n /**\n * Get the annotation group as an array.\n *\n * @returns {Annotation[]} The array.\n */\n getList() {\n return this.#list;\n }\n\n /**\n * Get the number of annotations of this list.\n *\n * @returns {number} The number of annotations.\n */\n getLength() {\n return this.#list.length;\n }\n\n /**\n * Check if the annotation group is editable.\n *\n * @returns {boolean} True if editable.\n */\n isEditable() {\n return this.#editable;\n }\n\n /**\n * Set the annotation group editability.\n *\n * @param {boolean} flag True to make the annotation group editable.\n */\n setEditable(flag) {\n this.#editable = flag;\n /**\n * Annotation group editable flag change event.\n *\n * @event AnnotationGroup#annotationgroupeditablechange\n * @type {object}\n * @property {string} type The event type.\n * @property {boolean} data The value of the editable flag.\n */\n this.#fireEvent({\n type: 'annotationgroupeditablechange',\n data: flag\n });\n }\n\n /**\n * Get the group colour.\n *\n * @returns {string} The colour as hex string.\n */\n getColour() {\n return this.#colour;\n }\n\n /**\n * Set the group colour.\n *\n * @param {string} colour The colour as hex string.\n */\n setColour(colour) {\n this.#colour = colour;\n }\n\n /**\n * Add a new annotation.\n *\n * @param {Annotation} annotation The annotation to add.\n */\n add(annotation) {\n this.#list.push(annotation);\n /**\n * Annotation add event.\n *\n * @event AnnotationGroup#annotationadd\n * @type {object}\n * @property {string} type The event type.\n * @property {Annotation} data The added annnotation.\n */\n this.#fireEvent({\n type: 'annotationadd',\n data: annotation\n });\n }\n\n /**\n * Update an existing annotation.\n *\n * @param {Annotation} annotation The annotation to update.\n * @param {string[]} [propKeys] Optional properties that got updated.\n */\n update(annotation, propKeys) {\n const index = this.#list.findIndex((item) => item.id === annotation.id);\n if (index !== -1) {\n this.#list[index] = annotation;\n /**\n * Annotation update event.\n *\n * @event AnnotationGroup#annotationupdate\n * @type {object}\n * @property {string} type The event type.\n * @property {Annotation} data The added annnotation.\n * @property {string[]} keys The properties that were updated.\n */\n this.#fireEvent({\n type: 'annotationupdate',\n data: annotation,\n keys: propKeys\n });\n } else {\n logger.warn('Cannot find annotation to update');\n }\n }\n\n /**\n * Remove an annotation.\n *\n * @param {string} id The id of the annotation to remove.\n */\n remove(id) {\n const index = this.#list.findIndex((item) => item.id === id);\n if (index !== -1) {\n const annotation = this.#list.splice(index, 1)[0];\n /**\n * Annotation update event.\n *\n * @event AnnotationGroup#annotationremove\n * @type {object}\n * @property {string} type The event type.\n * @property {Annotation} data The added annnotation.\n * @property {string[]} keys The properties that were updated.\n */\n this.#fireEvent({\n type: 'annotationremove',\n data: annotation\n });\n } else {\n logger.warn('Cannot find annotation to remove');\n }\n }\n\n /**\n * Set the associated view controller.\n *\n * @param {ViewController} viewController The associated view controller.\n */\n setViewController(viewController) {\n for (const item of this.#list) {\n item.setViewController(viewController);\n item.updateQuantification();\n }\n }\n\n /**\n * Find an annotation.\n *\n * @param {string} id The id of the annotation to find.\n * @returns {Annotation|undefined} The found annotation.\n */\n find(id) {\n return this.#list.find((item) => item.id === id);\n }\n\n /**\n * Get the meta data.\n *\n * @returns {Object} The meta data.\n */\n getMeta() {\n return this.#meta;\n }\n\n /**\n * Check if this list contains a meta data value.\n *\n * @param {string} key The key to check.\n * @returns {boolean} True if the meta data is present.\n */\n hasMeta(key) {\n return typeof this.#meta[key] !== 'undefined';\n }\n\n /**\n * Get a meta data value.\n *\n * @param {string} key The meta data key.\n * @returns {string|object} The meta data value.\n */\n getMetaValue(key) {\n return this.#meta[key];\n }\n\n /**\n * Set a meta data.\n *\n * @param {string} key The meta data key.\n * @param {string|object} value The value of the meta data.\n */\n setMetaValue(key, value) {\n this.#meta[key] = value;\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n}\n","import {AnnotationGroup} from '../image/annotationGroup';\nimport {\n RemoveAnnotationCommand,\n UpdateAnnotationCommand\n} from '../tools/drawCommands';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Draw controller.\n */\nexport class DrawController {\n\n /**\n * The annotation group.\n *\n * @type {AnnotationGroup}\n */\n #annotationGroup;\n\n /**\n * Get an annotation.\n *\n * @param {string} id The annotation id.\n * @returns {Annotation|undefined} The annotation.\n */\n getAnnotation(id) {\n return this.#annotationGroup.find(id);\n }\n\n /**\n * Get the annotation group.\n *\n * @returns {AnnotationGroup} The list.\n */\n getAnnotationGroup() {\n return this.#annotationGroup;\n }\n\n /**\n * Check if the annotation group is editable.\n *\n * @returns {boolean} True if editable.\n */\n isAnnotationGroupEditable() {\n return this.#annotationGroup.isEditable();\n }\n\n /**\n * Set the annotation group editability.\n *\n * @param {boolean} flag True to make the annotation group editable.\n */\n setAnnotationGroupEditable(flag) {\n this.#annotationGroup.setEditable(flag);\n }\n\n /**\n * Add an annotation.\n *\n * @param {Annotation} annotation The annotation to add.\n */\n addAnnotation(annotation) {\n this.#annotationGroup.add(annotation);\n }\n\n /**\n * Update an anotation from the list.\n *\n * @param {Annotation} annotation The annotation to update.\n * @param {string[]} [propKeys] Optional properties that got updated.\n */\n updateAnnotation(annotation, propKeys) {\n this.#annotationGroup.update(annotation, propKeys);\n }\n\n /**\n * Remove an anotation for the list.\n *\n * @param {string} id The id of the annotation to remove.\n */\n removeAnnotation(id) {\n this.#annotationGroup.remove(id);\n }\n\n /**\n * Remove an annotation via a remove command (triggers draw actions).\n *\n * @param {string} id The annotation id.\n * @param {Function} exeCallback The undo stack callback.\n */\n removeAnnotationWithCommand(id, exeCallback) {\n const annotation = this.getAnnotation(id);\n if (typeof annotation === 'undefined') {\n logger.warn(\n 'Cannot create remove command for undefined annotation: ' + id);\n return;\n }\n // create remove annotation command\n const command = new RemoveAnnotationCommand(annotation, this);\n // add command to undo stack\n exeCallback(command);\n // execute command: triggers draw remove\n command.execute();\n }\n\n /**\n * Update an annotation via an update command (triggers draw actions).\n *\n * @param {string} id The annotation id.\n * @param {object} originalProps The original annotation properties\n * that will be updated.\n * @param {object} newProps The new annotation properties\n * that will replace the original ones.\n * @param {Function} exeCallback The undo stack callback.\n */\n updateAnnotationWithCommand(id, originalProps, newProps, exeCallback) {\n const annotation = this.getAnnotation(id);\n if (typeof annotation === 'undefined') {\n logger.warn(\n 'Cannot create update command for undefined annotation: ' + id);\n return;\n }\n // create remove annotation command\n const command = new UpdateAnnotationCommand(\n annotation, originalProps, newProps, this);\n // add command to undo stack\n exeCallback(command);\n // execute command: triggers draw remove\n command.execute();\n }\n\n /**\n * Remove all annotations via remove commands (triggers draw actions).\n *\n * @param {Function} exeCallback The undo stack callback.\n */\n removeAllAnnotationsWithCommand(exeCallback) {\n for (const annotation of this.#annotationGroup.getList()) {\n this.removeAnnotationWithCommand(annotation.id, exeCallback);\n }\n }\n\n /**\n * @param {AnnotationGroup} [group] Optional annotation group.\n */\n constructor(group) {\n if (typeof group !== 'undefined') {\n this.#annotationGroup = group;\n } else {\n this.#annotationGroup = new AnnotationGroup();\n }\n }\n\n /**\n * Check if the annotation group contains a meta data value.\n *\n * @param {string} key The key to check.\n * @returns {boolean} True if the meta data is present.\n */\n hasAnnotationMeta(key) {\n return this.#annotationGroup.hasMeta(key);\n }\n\n /**\n * Set an annotation meta data.\n *\n * @param {string} key The meta data to set.\n * @param {string} value The value of the meta data.\n */\n setAnnotationMeta(key, value) {\n this.#annotationGroup.setMetaValue(key, value);\n }\n\n} // class DrawController\n","import {getShadowColour} from '../utils/colour';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Scalar2D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Style class.\n */\nexport class Style {\n /**\n * Font size.\n *\n * @type {number}\n */\n #fontSize = 10;\n\n /**\n * Font family.\n *\n * @type {string}\n */\n #fontFamily = 'Verdana';\n\n /**\n * Text colour.\n *\n * @type {string}\n */\n #textColour = '#fff';\n\n /**\n * Line colour.\n *\n * @type {string}\n */\n #lineColour = '#ffff80';\n\n /**\n * Base scale.\n *\n * @type {Scalar2D}\n */\n #baseScale = {x: 1, y: 1};\n\n /**\n * Zoom scale.\n *\n * @type {Scalar2D}\n */\n #zoomScale = {x: 1, y: 1};\n\n /**\n * Stroke width.\n *\n * @type {number}\n */\n #strokeWidth = 2;\n\n /**\n * Shadow offset.\n *\n * @type {Scalar2D}\n */\n #shadowOffset = {x: 0.25, y: 0.25};\n\n /**\n * Tag opacity.\n *\n * @type {number}\n */\n #tagOpacity = 0.2;\n\n /**\n * Text padding.\n *\n * @type {number}\n */\n #textPadding = 3;\n\n /**\n * Get the font family.\n *\n * @returns {string} The font family.\n */\n getFontFamily() {\n return this.#fontFamily;\n }\n\n /**\n * Get the font size.\n *\n * @returns {number} The font size.\n */\n getFontSize() {\n return this.#fontSize;\n }\n\n /**\n * Get the stroke width.\n *\n * @returns {number} The stroke width.\n */\n getStrokeWidth() {\n return this.#strokeWidth;\n }\n\n /**\n * Get the text colour.\n *\n * @returns {string} The text colour.\n */\n getTextColour() {\n return this.#textColour;\n }\n\n /**\n * Get the line colour.\n *\n * @returns {string} The line colour.\n */\n getLineColour() {\n return this.#lineColour;\n }\n\n /**\n * Set the line colour.\n *\n * @param {string} colour The line colour.\n */\n setLineColour(colour) {\n this.#lineColour = colour;\n }\n\n /**\n * Set the base scale.\n *\n * @param {Scalar2D} scale The scale as {x,y}.\n */\n setBaseScale(scale) {\n this.#baseScale = scale;\n }\n\n /**\n * Set the zoom scale.\n *\n * @param {Scalar2D} scale The scale as {x,y}.\n */\n setZoomScale(scale) {\n this.#zoomScale = scale;\n }\n\n /**\n * Get the base scale.\n *\n * @returns {Scalar2D} The scale as {x,y}.\n */\n getBaseScale() {\n return this.#baseScale;\n }\n\n /**\n * Get the zoom scale.\n *\n * @returns {Scalar2D} The scale as {x,y}.\n */\n getZoomScale() {\n return this.#zoomScale;\n }\n\n /**\n * Scale an input value using the base scale.\n *\n * @param {number} value The value to scale.\n * @returns {number} The scaled value.\n */\n scale(value) {\n // TODO: 2D?\n return value / this.#baseScale.x;\n }\n\n /**\n * Apply zoom scale on an input value.\n *\n * @param {number} value The value to scale.\n * @returns {Scalar2D} The scaled value as {x,y}.\n */\n applyZoomScale(value) {\n return {\n x: value / this.#zoomScale.x,\n y: value / this.#zoomScale.y\n };\n }\n\n /**\n * Multiply an input value by the zoom ratio (zx/zy).\n *\n * @param {number} value The value to scale.\n * @returns {number} The scaled value.\n */\n applyZoomRatio(value) {\n return value * this.#zoomScale.x / this.#zoomScale.y;\n }\n\n /**\n * Get the shadow offset.\n *\n * @returns {Scalar2D} The offset as {x,y}.\n */\n getShadowOffset() {\n return this.#shadowOffset;\n }\n\n /**\n * Get the tag opacity.\n *\n * @returns {number} The opacity.\n */\n getTagOpacity() {\n return this.#tagOpacity;\n }\n\n /**\n * Get the text padding.\n *\n * @returns {number} The padding.\n */\n getTextPadding() {\n return this.#textPadding;\n }\n\n /**\n * Get the font definition string.\n *\n * @returns {string} The font definition string.\n */\n getFontStr() {\n return ('normal ' + this.getFontSize() + 'px sans-serif');\n }\n\n /**\n * Get the line height.\n *\n * @returns {number} The line height.\n */\n getLineHeight() {\n return (this.getFontSize() + this.getFontSize() / 5);\n }\n\n /**\n * Get the font size scaled to the display.\n *\n * @returns {number} The scaled font size.\n */\n getScaledFontSize() {\n return this.scale(this.getFontSize());\n }\n\n /**\n * Get the stroke width scaled to the display.\n *\n * @returns {number} The scaled stroke width.\n */\n getScaledStrokeWidth() {\n return this.scale(this.getStrokeWidth());\n }\n\n /**\n * Get the shadow line colour.\n *\n * @returns {string} The shadow line colour.\n */\n getShadowLineColour() {\n return getShadowColour(this.getLineColour());\n }\n\n} // class Style\n","import {Point2D} from '../math/point';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Scalar2D} from '../math/scalar';\nimport {Style} from '../gui/style';\n// external\nimport Konva from 'konva';\n/* eslint-enable no-unused-vars */\n\n/**\n * Is an input node's name 'label'.\n *\n * @param {Konva.Node} node A Konva node.\n * @returns {boolean} True if the node's name is 'label'.\n */\nexport function isNodeNameLabel(node) {\n return node.name() === 'label';\n}\n\n/**\n * Is an input node's name 'shape'.\n *\n * @param {Konva.Node} node A Konva node.\n * @returns {boolean} True if the node's name is 'shape'.\n */\nexport function isNodeNameShape(node) {\n return node.name() === 'shape';\n}\n\n/**\n * Is an input node a position node.\n *\n * @param {Konva.Node} node A Konva node.\n * @returns {boolean} True if the node's name is 'position-group'.\n */\nexport function isPositionNode(node) {\n return node.name() === 'position-group';\n}\n\n/**\n * Get a Konva.Line shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Line|undefined} The shape.\n */\nexport function getLineShape(group) {\n const kshape = group.getChildren(isNodeNameShape)[0];\n if (!(kshape instanceof Konva.Line)) {\n return;\n }\n return kshape;\n}\n\n/**\n * Get a Konva.Ellipse anchor shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @param {number} index The anchor index.\n * @returns {Konva.Ellipse|undefined} The anchor shape.\n */\nexport function getAnchorShape(group, index) {\n const kshape = group.getChildren(function (node) {\n return node.id() === 'anchor' + index;\n })[0];\n if (!(kshape instanceof Konva.Ellipse)) {\n return;\n }\n return kshape;\n}\n\n/**\n * @callback testFn\n * @param {Konva.Node} node The node.\n * @returns {boolean} True if the node passes the test.\n */\n\n/**\n * Get a lambda to check a node's id.\n *\n * @param {string} id The id to check.\n * @returns {testFn} A function to check a node's id.\n */\nexport function isNodeWithId(id) {\n return function (node) {\n return node.id() === id;\n };\n}\n\n/**\n * Draw Debug flag.\n */\nexport const DRAW_DEBUG = false;\n\n/**\n * Get the default anchor shape.\n *\n * @param {number} x The X position.\n * @param {number} y The Y position.\n * @param {string} id The shape id.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse} The default anchor shape.\n */\nexport function getDefaultAnchor(x, y, id, style) {\n const radius = style.applyZoomScale(6);\n const absRadius = {\n x: Math.abs(radius.x),\n y: Math.abs(radius.y)\n };\n return new Konva.Ellipse({\n x: x,\n y: y,\n stroke: '#999',\n fill: 'rgba(100,100,100,0.7',\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n radius: absRadius,\n radiusX: absRadius.x,\n radiusY: absRadius.y,\n name: 'anchor',\n id: id.toString(),\n dragOnTop: false,\n draggable: true,\n visible: false\n });\n}\n\n/**\n * Get an anchor index from its id.\n *\n * @param {string} id The anchor id as 'anchor#'.\n * @returns {number} The anchor index.\n */\nexport function getAnchorIndex(id) {\n // 'anchor'.length = 6\n return parseInt(id.substring(6), 10);\n}\n\n/**\n * Bound a node position.\n *\n * @param {Konva.Node} node The node to bound the position.\n * @param {Point2D} min The minimum position.\n * @param {Point2D} max The maximum position.\n * @returns {boolean} True if the position was corrected.\n */\nfunction boundNodePosition(node, min, max) {\n let changed = false;\n if (node.x() < min.getX()) {\n node.x(min.getX());\n changed = true;\n } else if (node.x() > max.getX()) {\n node.x(max.getX());\n changed = true;\n }\n if (node.y() < min.getY()) {\n node.y(min.getY());\n changed = true;\n } else if (node.y() > max.getY()) {\n node.y(max.getY());\n changed = true;\n }\n return changed;\n}\n\n/**\n * Get a shape top left position range.\n *\n * @param {Scalar2D} stageSize The stage size as {x,y}.\n * @param {Konva.Shape} shape The shape to evaluate.\n * @returns {object} The range as {min, max}.\n */\nexport function getShapePositionRange(stageSize, shape) {\n const min = new Point2D(0, 0);\n const max = new Point2D(\n stageSize.x - Math.abs(shape.width()),\n stageSize.y - Math.abs(shape.height())\n );\n\n return {min: min, max: max};\n}\n\n/**\n * Is an input shape top left position in the input range.\n *\n * @param {Konva.Shape} shape The shape to evaluate.\n * @param {Point2D} min The minimum top left position.\n * @param {Point2D} max The maximum top left position.\n * @returns {boolean} True if in range.\n */\nexport function isShapeInRange(shape, min, max) {\n // use client rect to get the shape's top left position\n const boundRect = shape.getClientRect({relativeTo: shape.getParent()});\n return boundRect.x > min.getX() &&\n boundRect.x < max.getX() &&\n boundRect.y > min.getY() &&\n boundRect.y < max.getY();\n}\n\n/**\n * Validate an anchor position.\n *\n * @param {Scalar2D} stageSize The stage size {x,y}.\n * @param {Konva.Shape} anchor The anchor to evaluate.\n * @returns {boolean} True if the position was corrected.\n */\nexport function validateAnchorPosition(stageSize, anchor) {\n const group = anchor.getParent();\n\n const min = new Point2D(\n -group.x(),\n -group.y()\n );\n const max = new Point2D(\n stageSize.x - group.x(),\n stageSize.y - group.y()\n );\n\n return boundNodePosition(anchor, min, max);\n}\n","import {Point2D} from './point';\nimport {getStats} from './stats';\nimport {Index} from './index';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {ViewController} from '../app/viewController';\nimport {Scalar2D} from './scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Mulitply the three inputs if the last two are not null.\n *\n * @param {number} a The first input.\n * @param {number} b The second input.\n * @param {number} c The third input.\n * @returns {number} The multiplication of the three inputs or\n * null if one of the last two is null.\n */\nfunction mulABC(a, b, c) {\n let res = null;\n if (b !== null && c !== null) {\n res = a * b * c;\n }\n return res;\n}\n\n/**\n * Rectangle shape.\n */\nexport class Rectangle {\n\n /**\n * Rectangle begin point.\n *\n * @type {Point2D}\n */\n #begin;\n\n /**\n * Rectangle end point.\n *\n * @type {Point2D}\n */\n #end;\n\n /**\n * @param {Point2D} begin A Point2D representing the beginning\n * of the rectangle.\n * @param {Point2D} end A Point2D representing the end\n * of the rectangle.\n */\n constructor(begin, end) {\n this.#begin = new Point2D(\n Math.min(begin.getX(), end.getX()),\n Math.min(begin.getY(), end.getY())\n );\n this.#end = new Point2D(\n Math.max(begin.getX(), end.getX()),\n Math.max(begin.getY(), end.getY())\n );\n }\n\n /**\n * Get the begin point of the rectangle.\n *\n * @returns {Point2D} The begin point of the rectangle.\n */\n getBegin() {\n return this.#begin;\n }\n\n /**\n * Get the end point of the rectangle.\n *\n * @returns {Point2D} The end point of the rectangle.\n */\n getEnd() {\n return this.#end;\n }\n\n /**\n * Check for equality.\n *\n * @param {Rectangle} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.getBegin().equals(rhs.getBegin()) &&\n this.getEnd().equals(rhs.getEnd());\n }\n\n /**\n * Get the surface of the rectangle.\n *\n * @returns {number} The surface of the rectangle.\n */\n getSurface() {\n const begin = this.getBegin();\n const end = this.getEnd();\n return Math.abs(end.getX() - begin.getX()) *\n Math.abs(end.getY() - begin.getY());\n }\n\n /**\n * Get the surface of the rectangle according to a spacing.\n *\n * @param {Scalar2D} spacing2D The 2D spacing.\n * @returns {number} The surface of the rectangle multiplied by the given\n * spacing or null for null spacings.\n */\n getWorldSurface(spacing2D) {\n return mulABC(this.getSurface(), spacing2D.x, spacing2D.y);\n }\n\n /**\n * Get the real width of the rectangle.\n *\n * @returns {number} The real width of the rectangle.\n */\n getRealWidth() {\n return this.getEnd().getX() - this.getBegin().getX();\n }\n\n /**\n * Get the real height of the rectangle.\n *\n * @returns {number} The real height of the rectangle.\n */\n getRealHeight() {\n return this.getEnd().getY() - this.getBegin().getY();\n }\n\n /**\n * Get the width of the rectangle.\n *\n * @returns {number} The width of the rectangle.\n */\n getWidth() {\n return Math.abs(this.getRealWidth());\n }\n\n /**\n * Get the height of the rectangle.\n *\n * @returns {number} The height of the rectangle.\n */\n getHeight() {\n return Math.abs(this.getRealHeight());\n }\n\n /**\n * Get the rounded limits of the rectangle.\n *\n * @returns {object} The rounded limits as {min, max} (Point2D).\n */\n getRound() {\n const roundBegin = new Point2D(\n Math.round(this.getBegin().getX()),\n Math.round(this.getBegin().getY())\n );\n const roundEnd = new Point2D(\n Math.round(this.getEnd().getX()),\n Math.round(this.getEnd().getY())\n );\n return {\n min: roundBegin,\n max: roundEnd\n };\n }\n\n /**\n * Get the centroid of the rectangle.\n *\n * @returns {Point2D} The centroid point.\n */\n getCentroid() {\n return new Point2D(\n this.getBegin().getX() + this.getWidth() / 2,\n this.getBegin().getY() + this.getHeight() / 2\n );\n }\n\n /**\n * Quantify a rectangle according to view information.\n *\n * @param {ViewController} viewController The associated view controller.\n * @param {string[]} flags A list of stat values to calculate.\n * @returns {object} A quantification object.\n */\n quantify(viewController, flags) {\n const quant = {};\n // shape quantification\n const spacing2D = viewController.get2DSpacing();\n quant.width = {\n value: this.getWidth() * spacing2D.x,\n unit: 'unit.mm'\n };\n quant.height = {\n value: this.getHeight() * spacing2D.y,\n unit: 'unit.mm'\n };\n const surface = this.getWorldSurface(spacing2D);\n if (surface !== null) {\n quant.surface = {\n value: surface / 100,\n unit: 'unit.cm2'\n };\n }\n\n // pixel values quantification\n if (viewController.canQuantifyImage()) {\n const round = this.getRound();\n const values = viewController.getImageRegionValues(round.min, round.max);\n const unit = viewController.getPixelUnit();\n const quantif = getStats(values, flags);\n quant.min = {value: quantif.min, unit: unit};\n quant.max = {value: quantif.max, unit: unit};\n quant.mean = {value: quantif.mean, unit: unit};\n quant.stdDev = {value: quantif.stdDev, unit: unit};\n if (typeof quantif.median !== 'undefined') {\n quant.median = {value: quantif.median, unit: unit};\n }\n if (typeof quantif.p25 !== 'undefined') {\n quant.p25 = {value: quantif.p25, unit: unit};\n }\n if (typeof quantif.p75 !== 'undefined') {\n quant.p75 = {value: quantif.p75, unit: unit};\n }\n }\n\n // return\n return quant;\n }\n\n} // Rectangle class\n\n/**\n * Get the indices that form a rectangle.\n *\n * @param {Index} center The rectangle center.\n * @param {number[]} size The 2 rectangle sizes.\n * @param {number[]} dir The 2 rectangle directions.\n * @returns {Index[]} The indices of the rectangle.\n */\nexport function getRectangleIndices(center, size, dir) {\n const centerValues = center.getValues();\n // keep all values for possible extra dimensions\n const values = centerValues.slice();\n const indices = [];\n const sizeI = size[0];\n const halfSizeI = Math.floor(sizeI / 2);\n const sizeJ = size[1];\n const halfSizeJ = Math.floor(sizeJ / 2);\n const di = dir[0];\n const dj = dir[1];\n for (let j = 0; j < sizeJ; ++j) {\n values[dj] = centerValues[dj] - halfSizeJ + j;\n for (let i = 0; i < sizeI; ++i) {\n values[di] = centerValues[di] - halfSizeI + i;\n indices.push(new Index(values.slice()));\n }\n }\n return indices;\n}\n","import {Point2D} from '../math/point';\n\n/**\n * Region Of Interest shape.\n * Note: should be a closed path.\n */\nexport class ROI {\n\n /**\n * List of points.\n *\n * @type {Point2D[]}\n */\n #points = [];\n\n /**\n * @param {Point2D[]} [points] Optional initial point list.\n */\n constructor(points) {\n if (typeof points !== 'undefined') {\n this.#points = points;\n }\n }\n\n /**\n * Get a point of the list at a given index.\n *\n * @param {number} index The index of the point to get\n * (beware, no size check).\n * @returns {Point2D|undefined} The Point2D at the given index.\n */\n getPoint(index) {\n return this.#points[index];\n }\n\n /**\n * Get the point list.\n *\n * @returns {Point2D[]} The list.\n */\n getPoints() {\n return this.#points;\n }\n\n /**\n * Get the length of the point list.\n *\n * @returns {number} The length of the point list.\n */\n getLength() {\n return this.#points.length;\n }\n\n /**\n * Add a point to the ROI.\n *\n * @param {Point2D} point The Point2D to add.\n */\n addPoint(point) {\n this.#points.push(point);\n }\n\n /**\n * Add points to the ROI.\n *\n * @param {Point2D[]} rhs The array of POints2D to add.\n */\n addPoints(rhs) {\n this.#points = this.#points.concat(rhs);\n }\n\n /**\n * Get the centroid of the roi. Only valid for\n * a non-self-intersecting closed polygon.\n * Ref: {@link https://en.wikipedia.org/wiki/Centroid#Of_a_polygon}.\n *\n * @returns {Point2D} The centroid point.\n */\n getCentroid() {\n let a = 0;\n let cx = 0;\n let cy = 0;\n for (let i = 0; i < this.#points.length; ++i) {\n const pi = this.#points[i];\n let pi1;\n if (i === this.#points.length - 1) {\n pi1 = this.#points[0];\n } else {\n pi1 = this.#points[i + 1];\n }\n const ai = pi.getX() * pi1.getY() - pi1.getX() * pi.getY();\n a += ai;\n cx += (pi.getX() + pi1.getX()) * ai;\n cy += (pi.getY() + pi1.getY()) * ai;\n }\n a *= 0.5;\n const a1 = 1 / (6 * a);\n cx *= a1;\n cy *= a1;\n\n return new Point2D(cx, cy);\n }\n\n} // ROI class\n","import {Line, getAngle} from './line';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\nimport {ViewController} from '../app/viewController';\n/* eslint-enable no-unused-vars */\n\n/**\n * Protractor shape: 3 points from which to calculate an angle.\n */\nexport class Protractor {\n\n /**\n * List of points.\n *\n * @type {Point2D[]}\n */\n #points;\n\n /**\n * @param {Point2D[]} points The list of Point2D that make\n * the protractor.\n */\n constructor(points) {\n if (points.length > 3) {\n throw new Error('Too many points for a protractor');\n }\n this.#points = points.slice(0, 3);\n }\n\n /**\n * Get a point of the list.\n *\n * @param {number} index The index of the point\n * to get (beware, no size check).\n * @returns {Point2D|undefined} The Point2D at the given index.\n */\n getPoint(index) {\n return this.#points[index];\n }\n\n /**\n * Get the length of the path (should be 3).\n *\n * @returns {number} The length of the path.\n */\n getLength() {\n return this.#points.length;\n }\n\n /**\n * Get the centroid of the protractor.\n *\n * @returns {Point2D} THe centroid point.\n */\n getCentroid() {\n return this.#points[1];\n }\n\n /**\n * Quantify a path according to view information.\n *\n * @param {ViewController} _viewController The associated view controller.\n * @param {string[]} _flags A list of stat values to calculate.\n * @returns {object} A quantification object.\n */\n quantify(_viewController, _flags) {\n const quant = {};\n if (this.#points.length === 3) {\n const line0 = new Line(this.#points[0], this.#points[1]);\n const line1 = new Line(this.#points[1], this.#points[2]);\n let angle = getAngle(line0, line1);\n if (angle > 180) {\n angle = 360 - angle;\n }\n quant.angle = {\n value: angle,\n unit: 'unit.degree'\n };\n }\n return quant;\n }\n\n} // Protractor class\n","import {getStats} from './stats';\nimport {Index} from './index';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\nimport {ViewController} from '../app/viewController';\nimport {Scalar2D} from './scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Mulitply the three inputs if the last two are not null.\n *\n * @param {number} a The first input.\n * @param {number} b The second input.\n * @param {number} c The third input.\n * @returns {number} The multiplication of the three inputs or\n * null if one of the last two is null.\n */\nfunction mulABC(a, b, c) {\n let res = null;\n if (b !== null && c !== null) {\n res = a * b * c;\n }\n return res;\n}\n\n/**\n * Ellipse shape.\n */\nexport class Ellipse {\n\n /**\n * Ellipse centre.\n *\n * @type {Point2D}\n */\n #centre;\n\n /**\n * Ellipse horizontal radius.\n *\n * @type {number}\n */\n #a;\n\n /**\n * Ellipse vertical radius.\n *\n * @type {number}\n */\n #b;\n\n /**\n * @param {Point2D} centre A Point2D representing the centre\n * of the ellipse.\n * @param {number} a The radius of the ellipse on the horizontal axe.\n * @param {number} b The radius of the ellipse on the vertical axe.\n */\n constructor(centre, a, b) {\n this.#centre = centre;\n this.#a = a;\n this.#b = b;\n }\n\n /**\n * Get the centre (point) of the ellipse.\n *\n * @returns {Point2D} The center (point) of the ellipse.\n */\n getCenter() {\n return this.#centre;\n }\n\n /**\n * Get the centroid of the ellipse.\n *\n * @returns {Point2D} The centroid point.\n */\n getCentroid() {\n return this.#centre;\n }\n\n /**\n * Get the radius of the ellipse on the horizontal axe.\n *\n * @returns {number} The radius of the ellipse on the horizontal axe.\n */\n getA() {\n return this.#a;\n }\n\n /**\n * Get the radius of the ellipse on the vertical axe.\n *\n * @returns {number} The radius of the ellipse on the vertical axe.\n */\n getB() {\n return this.#b;\n }\n\n /**\n * Check for equality.\n *\n * @param {Ellipse} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.getCenter().equals(rhs.getCenter()) &&\n this.getA() === rhs.getA() &&\n this.getB() === rhs.getB();\n }\n\n /**\n * Get the surface of the ellipse.\n *\n * @returns {number} The surface of the ellipse.\n */\n getSurface() {\n return Math.PI * this.getA() * this.getB();\n }\n\n /**\n * Get the surface of the ellipse according to a spacing.\n *\n * @param {Scalar2D} spacing2D The 2D spacing.\n * @returns {number} The surface of the ellipse multiplied by the given\n * spacing or null for null spacings.\n */\n getWorldSurface(spacing2D) {\n return mulABC(this.getSurface(), spacing2D.x, spacing2D.y);\n }\n\n /**\n * Get the rounded limits of the ellipse.\n *\n * See: {@link https://en.wikipedia.org/wiki/Ellipse#Standard_equation}.\n *\n * Ellipse formula: `x*x / a*a + y*y / b*b = 1`.\n *\n * Implies: `y = (+-)(b/a) * sqrt(a*a - x*x)`.\n *\n * @returns {number[][][]} The rounded limits:\n * list of [x, y] pairs (min, max).\n */\n getRound() {\n const centerX = this.getCenter().getX();\n const centerY = this.getCenter().getY();\n const radiusX = this.getA();\n const radiusY = this.getB();\n const radiusRatio = radiusX / radiusY;\n const rySquare = Math.pow(radiusY, 2);\n // Y bounds\n const minY = centerY - radiusY;\n const maxY = centerY + radiusY;\n const regions = [];\n // loop through lines and store limits\n for (let y = minY; y < maxY; ++y) {\n const diff = rySquare - Math.pow(y - centerY, 2);\n // remove small values (possibly negative)\n if (Math.abs(diff) < 1e-7) {\n continue;\n }\n const transX = radiusRatio * Math.sqrt(diff);\n // remove small values\n if (transX < 0.5) {\n continue;\n }\n regions.push([\n [Math.round(centerX - transX), Math.round(y)],\n [Math.round(centerX + transX), Math.round(y)]\n ]);\n }\n return regions;\n }\n\n /**\n * Quantify an ellipse according to view information.\n *\n * @param {ViewController} viewController The associated view controller.\n * @param {string[]} flags A list of stat values to calculate.\n * @returns {object} A quantification object.\n */\n quantify(viewController, flags) {\n const quant = {};\n // shape quantification\n const spacing2D = viewController.get2DSpacing();\n quant.a = {\n value: this.getA() * spacing2D.x,\n unit: 'unit.mm'\n };\n quant.b = {\n value: this.getB() * spacing2D.y,\n unit: 'unit.mm'\n };\n const surface = this.getWorldSurface(spacing2D);\n if (surface !== null) {\n quant.surface = {\n value: surface / 100,\n unit: 'unit.cm2'\n };\n }\n\n // pixel values quantification\n if (viewController.canQuantifyImage()) {\n const regions = this.getRound();\n if (regions.length !== 0) {\n const values = viewController.getImageVariableRegionValues(regions);\n const unit = viewController.getPixelUnit();\n const quantif = getStats(values, flags);\n quant.min = {value: quantif.min, unit: unit};\n quant.max = {value: quantif.max, unit: unit};\n quant.mean = {value: quantif.mean, unit: unit};\n quant.stdDev = {value: quantif.stdDev, unit: unit};\n if (typeof quantif.median !== 'undefined') {\n quant.median = {value: quantif.median, unit: unit};\n }\n if (typeof quantif.p25 !== 'undefined') {\n quant.p25 = {value: quantif.p25, unit: unit};\n }\n if (typeof quantif.p75 !== 'undefined') {\n quant.p75 = {value: quantif.p75, unit: unit};\n }\n }\n }\n\n // return\n return quant;\n }\n\n} // Ellipse class\n\n/**\n * Get the indices that form a ellpise.\n *\n * @param {Index} center The ellipse center.\n * @param {number[]} radius The 2 ellipse radiuses.\n * @param {number[]} dir The 2 ellipse directions.\n * @returns {Index[]} The indices of the ellipse.\n */\nexport function getEllipseIndices(center, radius, dir) {\n const centerValues = center.getValues();\n // keep all values for possible extra dimensions\n const values = centerValues.slice();\n const indices = [];\n const radiusI = radius[0];\n const radiusJ = radius[1];\n const radiusRatio = radiusI / radiusJ;\n const radiusJ2 = Math.pow(radiusJ, 2);\n const di = dir[0];\n const dj = dir[1];\n // deduce 4 positions from top right\n for (let j = 0; j < radiusJ; ++j) {\n // right triangle formed by radiuses, j and len\n // ellipse: i*i / a*a + j*j / b*b = 1\n // -> i = a/b * sqrt(b*b - j*j)\n const len = Math.round(\n radiusRatio * Math.sqrt(radiusJ2 - Math.pow(j, 2)));\n const jmax = centerValues[dj] + j;\n const jmin = centerValues[dj] - j;\n for (let i = 0; i < len; ++i) {\n const imax = centerValues[di] + i;\n const imin = centerValues[di] - i;\n\n // right\n values[di] = imax;\n // right - top\n values[dj] = jmax;\n indices.push(new Index(values.slice()));\n // right - bottom\n if (jmin !== jmax) {\n values[dj] = jmin;\n indices.push(new Index(values.slice()));\n }\n\n // left\n if (imin !== imax) {\n values[di] = imin;\n // left - top\n values[dj] = jmax;\n indices.push(new Index(values.slice()));\n // left - bottom\n if (jmin !== jmax) {\n values[dj] = jmin;\n indices.push(new Index(values.slice()));\n }\n }\n }\n }\n return indices;\n}\n","import {getStats} from './stats';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\nimport {ViewController} from '../app/viewController';\nimport {Scalar2D} from './scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Mulitply the three inputs if the last two are not null.\n *\n * @param {number} a The first input.\n * @param {number} b The second input.\n * @param {number} c The third input.\n * @returns {number} The multiplication of the three inputs or\n * null if one of the last two is null.\n */\nfunction mulABC(a, b, c) {\n let res = null;\n if (b !== null && c !== null) {\n res = a * b * c;\n }\n return res;\n}\n\n/**\n * Circle shape.\n */\nexport class Circle {\n\n /**\n * Circle centre.\n *\n * @type {Point2D}\n */\n #centre;\n\n /**\n * Circle radius.\n *\n * @type {number}\n */\n #radius;\n\n /**\n * @param {Point2D} centre A Point2D representing the centre\n * of the circle.\n * @param {number} radius The radius of the circle.\n */\n constructor(centre, radius) {\n this.#centre = centre;\n this.#radius = radius;\n }\n\n /**\n * Get the centre (point) of the circle.\n *\n * @returns {Point2D} The center (point) of the circle.\n */\n getCenter() {\n return this.#centre;\n }\n\n /**\n * Get the centroid of the circle.\n *\n * @returns {Point2D} The centroid point.\n */\n getCentroid() {\n return this.#centre;\n }\n\n /**\n * Get the radius of the circle.\n *\n * @returns {number} The radius of the circle.\n */\n getRadius() {\n return this.#radius;\n }\n\n\n /**\n * Check for equality.\n *\n * @param {Circle} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.getCenter().equals(rhs.getCenter()) &&\n this.getRadius() === rhs.getRadius();\n }\n\n /**\n * Get the surface of the circle.\n *\n * @returns {number} The surface of the circle.\n */\n getSurface() {\n return Math.PI * this.getRadius() * this.getRadius();\n }\n\n /**\n * Get the surface of the circle according to a spacing.\n *\n * @param {Scalar2D} spacing2D The 2D spacing.\n * @returns {number} The surface of the circle multiplied by the given\n * spacing or null for null spacings.\n */\n getWorldSurface(spacing2D) {\n return mulABC(this.getSurface(), spacing2D.x, spacing2D.y);\n }\n\n /**\n * Get the rounded limits of the circle.\n *\n * See: {@link https://en.wikipedia.org/wiki/Circle#Equations}.\n *\n * Circle formula: `x*x + y*y = r*r`.\n *\n * Implies: `y = (+-) sqrt(r*r - x*x)`.\n *\n * @returns {number[][][]} The rounded limits:\n * list of [x, y] pairs (min, max).\n */\n getRound() {\n const centerX = this.getCenter().getX();\n const centerY = this.getCenter().getY();\n const radius = this.getRadius();\n const rSquare = Math.pow(radius, 2);\n // Y bounds\n const minY = centerY - radius;\n const maxY = centerY + radius;\n const regions = [];\n // loop through lines and store limits\n for (let y = minY; y < maxY; ++y) {\n const diff = rSquare - Math.pow(y - centerY, 2);\n // remove small values (possibly negative)\n if (Math.abs(diff) < 1e-7) {\n continue;\n }\n const transX = Math.sqrt(diff);\n // remove small values\n if (transX < 0.5) {\n continue;\n }\n regions.push([\n [Math.round(centerX - transX), Math.round(y)],\n [Math.round(centerX + transX), Math.round(y)]\n ]);\n }\n return regions;\n }\n\n /**\n * Quantify an circle according to view information.\n *\n * @param {ViewController} viewController The associated view controller.\n * @param {string[]} flags A list of stat values to calculate.\n * @returns {object} A quantification object.\n */\n quantify(viewController, flags) {\n const quant = {};\n // shape quantification\n const spacing2D = viewController.get2DSpacing();\n quant.radius = {\n value: this.getRadius() * spacing2D.x,\n unit: 'unit.mm'\n };\n const surface = this.getWorldSurface(spacing2D);\n if (surface !== null) {\n quant.surface = {\n value: surface / 100,\n unit: 'unit.cm2'\n };\n }\n\n // pixel values quantification\n if (viewController.canQuantifyImage()) {\n const regions = this.getRound();\n if (regions.length !== 0) {\n const values = viewController.getImageVariableRegionValues(regions);\n const unit = viewController.getPixelUnit();\n const quantif = getStats(values, flags);\n quant.min = {value: quantif.min, unit: unit};\n quant.max = {value: quantif.max, unit: unit};\n quant.mean = {value: quantif.mean, unit: unit};\n quant.stdDev = {value: quantif.stdDev, unit: unit};\n if (typeof quantif.median !== 'undefined') {\n quant.median = {value: quantif.median, unit: unit};\n }\n if (typeof quantif.p25 !== 'undefined') {\n quant.p25 = {value: quantif.p25, unit: unit};\n }\n if (typeof quantif.p75 !== 'undefined') {\n quant.p75 = {value: quantif.p75, unit: unit};\n }\n }\n }\n\n // return\n return quant;\n }\n\n} // Circle class\n","import {logger} from '../utils/logger';\nimport {UpdateAnnotationCommand} from './drawCommands';\nimport {validateAnchorPosition} from './drawBounds';\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {DrawLayer} from '../gui/drawLayer';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Draw shape editor.\n */\nexport class DrawShapeEditor {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Event callback.\n *\n * @type {Function}\n */\n #eventCallback;\n\n /**\n * @param {App} app The associated application.\n * @param {Function} eventCallback Event callback.\n */\n constructor(app, eventCallback) {\n this.#app = app;\n this.#eventCallback = eventCallback;\n }\n\n /**\n * Current shape factory.\n *\n * @type {object}\n */\n #currentFactory = null;\n\n /**\n * Edited shape.\n *\n * @type {Konva.Shape}\n */\n #shape = null;\n\n /**\n * Associated draw layer. Used to bound anchor move.\n *\n * @type {DrawLayer}\n */\n #drawLayer;\n\n /**\n * The associated annotation.\n *\n * @type {Annotation}\n */\n #annotation;\n\n /**\n * Active flag.\n *\n * @type {boolean}\n */\n #isActive = false;\n\n /**\n * @callback eventFn\n * @param {object} event The event.\n */\n\n /**\n * Set the shape to edit.\n *\n * @param {Konva.Shape} inshape The shape to edit.\n * @param {DrawLayer} drawLayer The associated draw layer.\n * @param {Annotation} annotation The associated annotation.\n */\n setShape(inshape, drawLayer, annotation) {\n this.#shape = inshape;\n this.#drawLayer = drawLayer;\n this.#annotation = annotation;\n\n if (this.#shape) {\n // remove old anchors\n this.#removeAnchors();\n\n this.#currentFactory = annotation.getFactory();\n if (this.#currentFactory === null) {\n throw new Error('Could not find a factory to update shape.');\n }\n\n // add new anchors\n this.#addAnchors();\n }\n }\n\n /**\n * Get the edited shape.\n *\n * @returns {Konva.Shape} The edited shape.\n */\n getShape() {\n return this.#shape;\n }\n\n /**\n * Get the edited annotation.\n *\n * @returns {Annotation} The annotation.\n */\n getAnnotation() {\n return this.#annotation;\n }\n\n /**\n * Get the active flag.\n *\n * @returns {boolean} The active flag.\n */\n isActive() {\n return this.#isActive;\n }\n\n /**\n * Enable the editor. Redraws the layer.\n */\n enable() {\n this.#isActive = true;\n if (this.#shape) {\n this.#setAnchorsVisible(true);\n if (this.#shape.getLayer()) {\n this.#shape.getLayer().draw();\n }\n }\n }\n\n /**\n * Disable the editor. Redraws the layer.\n */\n disable() {\n this.#isActive = false;\n if (this.#shape) {\n this.#setAnchorsVisible(false);\n if (this.#shape.getLayer()) {\n this.#shape.getLayer().draw();\n }\n }\n }\n\n /**\n * Reset the editor.\n */\n reset() {\n this.#shape = undefined;\n this.#drawLayer = undefined;\n this.#annotation = undefined;\n }\n\n /**\n * Reset the anchors.\n */\n resetAnchors() {\n // remove previous controls\n this.#removeAnchors();\n // add anchors\n this.#addAnchors();\n // set them visible\n this.#setAnchorsVisible(true);\n }\n\n /**\n * Apply a function on all anchors.\n *\n * @param {object} func A f(shape) function.\n */\n #applyFuncToAnchors(func) {\n if (this.#shape && this.#shape.getParent()) {\n const anchors = this.#shape.getParent().find('.anchor');\n anchors.forEach(func);\n }\n }\n\n /**\n * Set anchors visibility.\n *\n * @param {boolean} flag The visible flag.\n */\n #setAnchorsVisible(flag) {\n this.#applyFuncToAnchors(function (anchor) {\n anchor.visible(flag);\n });\n }\n\n /**\n * Set anchors active.\n *\n * @param {boolean} flag The active (on/off) flag.\n */\n setAnchorsActive(flag) {\n let func = null;\n if (flag) {\n func = (anchor) => {\n this.#setAnchorOn(anchor);\n };\n } else {\n func = (anchor) => {\n this.#setAnchorOff(anchor);\n };\n }\n this.#applyFuncToAnchors(func);\n }\n\n /**\n * Remove anchors.\n */\n #removeAnchors() {\n this.#applyFuncToAnchors(function (anchor) {\n anchor.remove();\n });\n }\n\n /**\n * Add the shape anchors.\n */\n #addAnchors() {\n // exit if no shape or no layer\n if (!this.#shape || !this.#shape.getLayer()) {\n return;\n }\n // get shape group\n const group = this.#shape.getParent();\n\n // activate and add anchors to group\n const anchors =\n this.#currentFactory.getAnchors(this.#shape, this.#app.getStyle());\n for (let i = 0; i < anchors.length; ++i) {\n // set anchor on\n this.#setAnchorOn(anchors[i]);\n // add the anchor to the group\n group.add(anchors[i]);\n }\n }\n\n /**\n * Set the anchor on listeners.\n *\n * @param {Konva.Ellipse} anchor The anchor to set on.\n */\n #setAnchorOn(anchor) {\n let originalProps;\n\n // drag start listener\n anchor.on('dragstart.edit', (event) => {\n // prevent bubbling upwards\n event.cancelBubble = true;\n // store original properties\n originalProps = {\n mathShape: this.#annotation.mathShape,\n referencePoints: this.#annotation.referencePoints\n };\n });\n // drag move listener\n anchor.on('dragmove.edit', (event) => {\n const anchor = event.target;\n if (!(anchor instanceof Konva.Shape)) {\n return;\n }\n // validate the anchor position\n validateAnchorPosition(this.#drawLayer.getBaseSize(), anchor);\n if (typeof this.#currentFactory.constrainAnchorMove !== 'undefined') {\n this.#currentFactory.constrainAnchorMove(anchor);\n }\n\n // udpate annotation\n this.#currentFactory.updateAnnotationOnAnchorMove(\n this.#annotation, anchor);\n // udpate shape\n this.#currentFactory.updateShapeGroupOnAnchorMove(\n this.#annotation, anchor, this.#app.getStyle());\n\n // redraw\n if (anchor.getLayer()) {\n anchor.getLayer().draw();\n } else {\n logger.warn('No layer to draw the anchor!');\n }\n // prevent bubbling upwards\n event.cancelBubble = true;\n });\n // drag end listener\n anchor.on('dragend.edit', (event) => {\n // update annotation command\n const newProps = {\n mathShape: this.#annotation.mathShape,\n referencePoints: this.#annotation.referencePoints\n };\n const command = new UpdateAnnotationCommand(\n this.#annotation,\n originalProps,\n newProps,\n this.#drawLayer.getDrawController()\n );\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // fire event manually since command is not executed\n this.#eventCallback({\n type: 'annotationupdate',\n data: this.#annotation,\n dataid: this.#drawLayer.getDataId(),\n keys: Object.keys(newProps)\n });\n // update original properties\n originalProps = {\n mathShape: newProps.mathShape,\n referencePoints: newProps.referencePoints\n };\n\n // prevent bubbling upwards\n event.cancelBubble = true;\n });\n // mouse down listener\n anchor.on('mousedown touchstart', (event) => {\n const anchor = event.target;\n anchor.moveToTop();\n });\n // mouse over styling\n anchor.on('mouseover.edit', (event) => {\n const anchor = event.target;\n if (!(anchor instanceof Konva.Shape)) {\n return;\n }\n // style is handled by the group\n anchor.stroke('#ddd');\n if (anchor.getLayer()) {\n anchor.getLayer().draw();\n } else {\n logger.warn('No layer to draw the anchor!');\n }\n });\n // mouse out styling\n anchor.on('mouseout.edit', (event) => {\n const anchor = event.target;\n if (!(anchor instanceof Konva.Shape)) {\n return;\n }\n // style is handled by the group\n anchor.stroke('#999');\n if (anchor.getLayer()) {\n anchor.getLayer().draw();\n } else {\n logger.warn('No layer to draw the anchor!');\n }\n });\n }\n\n /**\n * Set the anchor off listeners.\n *\n * @param {Konva.Ellipse} anchor The anchor to set off.\n */\n #setAnchorOff(anchor) {\n anchor.off('dragstart.edit');\n anchor.off('dragmove.edit');\n anchor.off('dragend.edit');\n anchor.off('mousedown touchstart');\n anchor.off('mouseover.edit');\n anchor.off('mouseout.edit');\n }\n\n} // class Editor\n","import Konva from 'konva';\n\n/* eslint-disable no-unused-vars */\nimport {Scalar2D} from '../math/scalar';\nimport {DrawLayer} from '../gui/drawLayer';\n/* eslint-enable no-unused-vars */\n\nexport class DrawTrash {\n /**\n * Trash draw: a cross.\n *\n * @type {Konva.Group}\n */\n #trash;\n\n constructor() {\n this.createTrashIcon();\n\n }\n\n /**\n * Creates the trash icon o positionates it.\n */\n createTrashIcon() {\n this.#trash = new Konva.Group();\n // first line of the cross\n const trashLine1 = new Konva.Line({\n points: [-10, -10, 10, 10],\n stroke: 'red'\n });\n // second line of the cross\n const trashLine2 = new Konva.Line({\n points: [10, -10, -10, 10],\n stroke: 'red'\n });\n this.#trash.width(20);\n this.#trash.height(20);\n this.#trash.add(trashLine1);\n this.#trash.add(trashLine2);\n }\n\n /**\n *\n * Activates the trash, by showing the icon into the layer draw layer.\n *\n * @param {DrawLayer} drawLayer The draw layer where to draw.\n */\n activate(drawLayer) {\n const stage = drawLayer.getKonvaStage();\n const scale = stage.scale();\n const konvaLayer = drawLayer.getKonvaLayer();\n const invscale = {x: 1 / scale.x, y: 1 / scale.y};\n this.#trash.x(stage.offset().x + (stage.width() / (2 * scale.x)));\n this.#trash.y(stage.offset().y + (stage.height() / (15 * scale.y)));\n this.#trash.scale(invscale);\n konvaLayer.add(this.#trash);\n // draw\n konvaLayer.draw();\n }\n\n /**\n *\n * Change colour on trash over.\n *\n * @param {Scalar2D} eventPosition The event drag move position.\n * @param {Konva.Group} shapeGroup The shape group whose colour\n * must be change.\n * @param {string} originalShapeColour The original shape colour.\n */\n changeChildrenColourOnTrashHover(eventPosition,\n shapeGroup, originalShapeColour) {\n if (this.isOverTrash(eventPosition)) {\n this.changeGroupChildrenColour(this.#trash, 'orange');\n this.changeGroupChildrenColour(shapeGroup, 'red');\n return;\n\n }\n this.changeGroupChildrenColour(this.#trash, 'red');\n this.changeGroupChildrenColour(shapeGroup, originalShapeColour);\n }\n\n /**\n * Change colour on trash out.\n *\n * @param {Konva.Group} group The group whose colour must be change.\n * @param {string} colour The new colour to be set.\n */\n changeGroupChildrenColour(group, colour) {\n group.getChildren().forEach(function (tshape) {\n if (tshape instanceof Konva.Shape &&\n typeof tshape.stroke !== 'undefined') {\n tshape.stroke(colour);\n }\n });\n }\n\n /**\n * Removes the trash from the draw layer.\n */\n remove() {\n this.#trash.remove();\n }\n\n /**\n * Determines if the event is over trash.\n *\n * @param {Scalar2D} eventPosition The event position.\n * @returns {boolean} True if the event is over trash.\n */\n isOverTrash(eventPosition) {\n const trashHalfWidth =\n this.#trash.width() * Math.abs(this.#trash.scaleX()) / 2;\n const trashHalfHeight =\n this.#trash.height() * Math.abs(this.#trash.scaleY()) / 2;\n return Math.abs(eventPosition.x - this.#trash.x()) < trashHalfWidth &&\n Math.abs(eventPosition.y - this.#trash.y()) < trashHalfHeight;\n }\n\n}","import {\n getMousePoint,\n customUI\n} from '../gui/generic';\nimport {\n RemoveAnnotationCommand,\n UpdateAnnotationCommand\n} from './drawCommands';\nimport {\n isNodeNameShape,\n isNodeNameLabel,\n getShapePositionRange,\n isShapeInRange\n} from './drawBounds';\nimport {DrawShapeEditor} from './drawShapeEditor';\nimport {DrawTrash} from './drawTrash';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {Scalar2D} from '../math/scalar';\nimport {DrawLayer} from '../gui/drawLayer';\nimport {Annotation} from '../image/annotation';\nimport {Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * Draw shape handler: handle action on existing shapes.\n */\nexport class DrawShapeHandler {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Shape editor.\n *\n * @type {DrawShapeEditor}\n */\n #shapeEditor;\n\n /**\n * Trash draw: a cross.\n *\n * @type {DrawTrash}\n */\n #trash;\n\n /**\n * Mouse cursor.\n *\n * @type {string}\n */\n #mouseOverCursor = 'pointer';\n\n /**\n * Original mouse cursor.\n *\n * @type {string}\n */\n #originalCursor;\n\n /**\n * Shape with mouse over.\n *\n * @type {Konva.Group}\n */\n #mouseOverShapeGroup;\n\n /**\n * Event callback.\n *\n * @type {Function}\n */\n #eventCallback;\n\n /**\n * @callback eventFn\n * @param {object} event The event.\n */\n\n /**\n * @param {App} app The associated application.\n * @param {Function} eventCallback Event callback.\n */\n constructor(app, eventCallback) {\n this.#app = app;\n this.#eventCallback = eventCallback;\n this.#shapeEditor = new DrawShapeEditor(app, eventCallback);\n this.#trash = new DrawTrash();\n }\n\n /**\n * Set the draw editor shape.\n *\n * @param {Konva.Shape} shape The shape to edit.\n * @param {DrawLayer} drawLayer The layer the shape belongs to.\n */\n setEditorShape(shape, drawLayer) {\n const drawController = drawLayer.getDrawController();\n if (shape &&\n shape instanceof Konva.Shape &&\n shape !== this.#shapeEditor.getShape() &&\n drawController.isAnnotationGroupEditable()) {\n // disable\n this.#shapeEditor.disable();\n // set shape\n this.#shapeEditor.setShape(\n shape,\n drawLayer,\n drawLayer.getDrawController().getAnnotation(shape.getParent().id()));\n // enable\n this.#shapeEditor.enable();\n }\n }\n\n /**\n * Get the currently edited shape group.\n *\n * @returns {Konva.Group|undefined} The edited group.\n */\n getEditorShapeGroup() {\n let res;\n if (this.#shapeEditor.isActive()) {\n res = this.#shapeEditor.getShape().getParent();\n if (!(res instanceof Konva.Group)) {\n return;\n }\n }\n return res;\n }\n\n /**\n * Get the currently edited annotation.\n *\n * @returns {Annotation|undefined} The edited annotation.\n */\n getEditorAnnotation() {\n let res;\n if (this.#shapeEditor.isActive()) {\n res = this.#shapeEditor.getAnnotation();\n }\n return res;\n }\n\n /**\n * Disable and reset the shape editor.\n */\n disableAndResetEditor() {\n this.#shapeEditor.disable();\n this.#shapeEditor.reset();\n }\n\n /**\n * Get the real position from an event.\n * TODO: use layer method?\n *\n * @param {Scalar2D} index The input index as {x,y}.\n * @param {DrawLayer} drawLayer The origin draw layer.\n * @returns {Scalar2D} The real position in the image as {x,y}.\n */\n #getRealPosition(index, drawLayer) {\n const stage = drawLayer.getKonvaStage();\n return {\n x: stage.offset().x + index.x / stage.scale().x,\n y: stage.offset().y + index.y / stage.scale().y\n };\n }\n\n /**\n * Store specific mouse over cursor.\n *\n * @param {string} cursor The cursor name.\n */\n storeMouseOverCursor(cursor) {\n this.#mouseOverCursor = cursor;\n }\n\n /**\n * Handle shape group mouseover.\n */\n #onMouseOverShapeGroup() {\n // mouse cursor\n this.#originalCursor = document.body.style.cursor;\n document.body.style.cursor = this.#mouseOverCursor;\n // shape opacity\n this.#mouseOverShapeGroup.opacity(0.75);\n }\n\n /**\n * Handle shape group mouseout.\n */\n onMouseOutShapeGroup() {\n // mouse cursor\n if (typeof this.#originalCursor !== 'undefined') {\n document.body.style.cursor = this.#originalCursor;\n this.#originalCursor = undefined;\n }\n // shape opacity\n if (typeof this.#mouseOverShapeGroup !== 'undefined') {\n this.#mouseOverShapeGroup.opacity(1);\n }\n }\n\n /**\n * Add shape group mouse over and out listeners: updates\n * shape group opacity and cursor.\n *\n * @param {Konva.Group} shapeGroup The shape group.\n */\n #addShapeOverListeners(shapeGroup) {\n // handle mouse over\n shapeGroup.on('mouseover', () => {\n this.#mouseOverShapeGroup = shapeGroup;\n this.#onMouseOverShapeGroup();\n });\n\n // handle mouse out\n shapeGroup.on('mouseout', () => {\n this.onMouseOutShapeGroup();\n this.#mouseOverShapeGroup = undefined;\n });\n }\n\n /**\n * Remove shape group mouse over and out listeners.\n *\n * @param {Konva.Group} shapeGroup The shape group.\n */\n #removeShapeOverListeners(shapeGroup) {\n shapeGroup.off('mouseover');\n shapeGroup.off('mouseout');\n }\n\n /**\n * Add shape group listeners.\n *\n * @param {Konva.Group} shapeGroup The shape group to set on.\n * @param {Annotation} annotation The associated annotation.\n * @param {DrawLayer} drawLayer The origin draw layer.\n */\n addShapeGroupListeners(shapeGroup, annotation, drawLayer) {\n // shape mouse over\n this.#addShapeOverListeners(shapeGroup);\n\n // make shape draggable\n this.#addShapeListeners(shapeGroup, annotation, drawLayer);\n\n // make label draggable\n this.#addLabelListeners(shapeGroup, annotation, drawLayer);\n\n // double click handling: update annotation text\n shapeGroup.on('dblclick', () => {\n // original text expr\n const originalTextExpr = annotation.textExpr;\n\n const onSaveCallback = (annotation) => {\n // new text expr\n const newTextExpr = annotation.textExpr;\n // create annotation update command\n const command = new UpdateAnnotationCommand(\n annotation,\n {textExpr: originalTextExpr},\n {textExpr: newTextExpr},\n drawLayer.getDrawController()\n );\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // execute command\n command.execute();\n };\n\n // call roi dialog\n customUI.openRoiDialog(annotation, onSaveCallback);\n });\n }\n\n /**\n * Add shape listeners.\n *\n * @param {Konva.Group} shapeGroup The shape group to get the shape from.\n * @param {Annotation} annotation The associated annotation.\n * @param {DrawLayer} drawLayer The origin draw layer.\n */\n #addShapeListeners(shapeGroup, annotation, drawLayer) {\n const konvaLayer = drawLayer.getKonvaLayer();\n\n const shape = shapeGroup.getChildren(isNodeNameShape)[0];\n if (!(shape instanceof Konva.Shape)) {\n return;\n }\n shape.draggable(true);\n\n // cache vars\n let dragStartPos;\n let previousPos;\n let originalProps;\n let colour;\n\n // drag start event handling\n shape.on('dragstart.draw', (event) => {\n // store colour\n colour = shape.stroke();\n // store pos\n dragStartPos = {\n x: shape.x(),\n y: shape.y()\n };\n previousPos = {\n x: event.target.x(),\n y: event.target.y()\n };\n // store original properties\n originalProps = {\n mathShape: annotation.mathShape,\n referencePoints: annotation.referencePoints\n };\n\n // display trash\n this.#trash.activate(drawLayer);\n // deactivate anchors to avoid events on null shape\n this.#shapeEditor.setAnchorsActive(false);\n // draw\n konvaLayer.draw();\n });\n\n // drag move event handling\n shape.on('dragmove.draw', (event) => {\n // if out of range, reset shape position and exit\n const range = getShapePositionRange(drawLayer.getBaseSize(), shape);\n if (range && !isShapeInRange(shape, range.min, range.max)) {\n shape.x(previousPos.x);\n shape.y(previousPos.y);\n return;\n }\n\n // move associated shapes (but not label)\n const diff = {\n x: event.target.x() - previousPos.x,\n y: event.target.y() - previousPos.y\n };\n const children = shapeGroup.getChildren();\n const labelWithDefaultPosition =\n typeof annotation.labelPosition === 'undefined';\n for (const child of children) {\n // skip shape and label with defined position\n if (child === event.target ||\n (child.name() === 'label' && !labelWithDefaultPosition) ||\n child.name() === 'connector'\n ) {\n continue;\n }\n // move other nodes\n child.move(diff);\n }\n\n // store pos\n previousPos = {\n x: event.target.x(),\n y: event.target.y()\n };\n\n // get appropriate factory\n const factory = annotation.getFactory();\n // update annotation\n factory.updateAnnotationOnTranslation(annotation, diff);\n // update label\n factory.updateLabelContent(annotation, shapeGroup, this.#app.getStyle());\n // update connector\n factory.updateConnector(shapeGroup);\n // highlight trash when on it\n const mousePoint = getMousePoint(event.evt);\n const offset = {\n x: mousePoint.getX(),\n y: mousePoint.getY()\n };\n const eventPos = this.#getRealPosition(offset, drawLayer);\n this.#trash.changeChildrenColourOnTrashHover(eventPos,\n shapeGroup, colour);\n // draw\n konvaLayer.draw();\n });\n\n // drag end event handling\n shape.on('dragend.draw', (event) => {\n // remove trash\n this.#trash.remove();\n // activate(false) will also trigger a dragend.draw\n if (typeof event === 'undefined' ||\n typeof event.evt === 'undefined') {\n return;\n }\n const pos = {x: shape.x(), y: shape.y()};\n // delete case\n const mousePoint = getMousePoint(event.evt);\n const offset = {\n x: mousePoint.getX(),\n y: mousePoint.getY()\n };\n const eventPos = this.#getRealPosition(offset, drawLayer);\n if (this.#trash.isOverTrash(eventPos)) {\n // compensate for the drag translation\n shapeGroup.x(dragStartPos.x);\n shapeGroup.y(dragStartPos.y);\n // disable editor\n this.#shapeEditor.disable();\n this.#shapeEditor.reset();\n this.#trash.changeGroupChildrenColour(shapeGroup, colour);\n // reset math shape (for undo)\n annotation.mathShape = originalProps.mathShape;\n annotation.referencePoints = originalProps.referencePoints;\n\n // create remove annotation command\n const command = new RemoveAnnotationCommand(\n annotation,\n drawLayer.getDrawController()\n );\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // execute command: triggers draw remove\n command.execute();\n\n // reset cursor\n this.onMouseOutShapeGroup();\n } else {\n const translation = {\n x: pos.x - dragStartPos.x,\n y: pos.y - dragStartPos.y\n };\n if (translation.x !== 0 || translation.y !== 0) {\n // update annotation command\n const newProps = {\n mathShape: annotation.mathShape,\n referencePoints: annotation.referencePoints\n };\n const command = new UpdateAnnotationCommand(\n annotation,\n originalProps,\n newProps,\n drawLayer.getDrawController()\n );\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // fire event manually since command is not executed\n this.#eventCallback({\n type: 'annotationupdate',\n data: annotation,\n dataid: drawLayer.getDataId(),\n keys: Object.keys(newProps)\n });\n // update original shape\n originalProps = {\n mathShape: newProps.mathShape,\n referencePoints: newProps.referencePoints\n };\n }\n // reset anchors\n this.#shapeEditor.setAnchorsActive(true);\n this.#shapeEditor.resetAnchors();\n }\n // draw\n konvaLayer.draw();\n // reset start position\n dragStartPos = {\n x: shape.x(),\n y: shape.y()\n };\n });\n }\n\n /**\n * Add label listeners.\n *\n * @param {Konva.Group} shapeGroup The shape group to get the label from.\n * @param {Annotation} annotation The associated annotation.\n * @param {DrawLayer} drawLayer The origin draw layer.\n */\n #addLabelListeners(shapeGroup, annotation, drawLayer) {\n const label = shapeGroup.getChildren(isNodeNameLabel)[0];\n if (!(label instanceof Konva.Label)) {\n return;\n }\n label.draggable(true);\n\n // cache vars\n let dragStartPos;\n let originalLabelPosition;\n\n // drag start event handling\n label.on('dragstart.draw', (/*event*/) => {\n // store pos\n dragStartPos = {\n x: label.x(),\n y: label.y()\n };\n // store original position\n originalLabelPosition = annotation.labelPosition;\n });\n\n // drag move event handling\n label.on('dragmove.draw', (/*event*/) => {\n // get factory\n const factory = annotation.getFactory();\n // update label\n factory.updateConnector(shapeGroup);\n });\n\n // drag end event handling\n label.on('dragend.draw', (/*event*/) => {\n const translation = {\n x: label.x() - dragStartPos.x,\n y: label.y() - dragStartPos.y\n };\n if (translation.x !== 0 || translation.y !== 0) {\n const newLabelPosition = new Point2D(label.x(), label.y());\n // set label position\n annotation.labelPosition = newLabelPosition;\n // update annotation command\n const command = new UpdateAnnotationCommand(\n annotation,\n {labelPosition: originalLabelPosition},\n {labelPosition: newLabelPosition},\n drawLayer.getDrawController()\n );\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // fire event manually since command is not executed\n this.#eventCallback({\n type: 'annotationupdate',\n data: annotation,\n dataid: drawLayer.getDataId(),\n keys: ['labelPosition']\n });\n // update original position\n originalLabelPosition = newLabelPosition;\n }\n dragStartPos = {x: label.x(), y: label.y()};\n });\n }\n\n /**\n * Remove shape group listeners.\n *\n * @param {Konva.Group} shapeGroup The shape group to set off.\n */\n removeShapeListeners(shapeGroup) {\n // mouse over\n this.#removeShapeOverListeners(shapeGroup);\n // double click\n shapeGroup.off('dblclick');\n // remove listeners from shape\n const shape = shapeGroup.getChildren(isNodeNameShape)[0];\n if (shape instanceof Konva.Shape) {\n shape.draggable(false);\n shape.off('dragstart.draw');\n shape.off('dragmove.draw');\n shape.off('dragend.draw');\n }\n // remove listeners from label\n const label = shapeGroup.getChildren(isNodeNameLabel)[0];\n if (label instanceof Konva.Label) {\n label.draggable(false);\n label.off('dragstart.draw');\n label.off('dragend.draw');\n }\n }\n} // DrawShapeHandler class","import {ListenerHandler} from '../utils/listen';\nimport {DrawController} from '../app/drawController';\nimport {getScaledOffset} from './layerGroup';\nimport {InteractionEventNames} from './generic';\nimport {logger} from '../utils/logger';\nimport {toStringId} from '../utils/array';\nimport {precisionRound} from '../utils/string';\nimport {AddAnnotationCommand} from '../tools/drawCommands';\nimport {\n isNodeWithId,\n isPositionNode,\n isNodeNameShape,\n isNodeNameLabel\n} from '../tools/drawBounds';\nimport {Style} from '../gui/style';\nimport {Line} from '../math/line';\nimport {Rectangle} from '../math/rectangle';\nimport {ROI} from '../math/roi';\nimport {Protractor} from '../math/protractor';\nimport {Ellipse} from '../math/ellipse';\nimport {Circle} from '../math/circle';\nimport {Point2D} from '../math/point';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point, Point3D} from '../math/point';\nimport {Index} from '../math/index';\nimport {Vector3D} from '../math/vector';\nimport {Scalar2D, Scalar3D} from '../math/scalar';\nimport {PlaneHelper} from '../image/planeHelper';\nimport {Annotation} from '../image/annotation';\nimport {AnnotationGroup} from '../image/annotationGroup';\nimport {DrawShapeHandler} from '../tools/drawShapeHandler';\n/* eslint-enable no-unused-vars */\n\n/**\n * Debug function to output the layer hierarchy as text.\n *\n * @param {object} layer The Konva layer.\n * @param {string} prefix A display prefix (used in recursion).\n * @returns {string} A text representation of the hierarchy.\n */\n// function getHierarchyLog(layer, prefix) {\n// if (typeof prefix === 'undefined') {\n// prefix = '';\n// }\n// const kids = layer.getChildren();\n// let log = prefix + '|__ ' + layer.name() + ': ' + layer.id() + '\\n';\n// for (let i = 0; i < kids.length; ++i) {\n// log += getHierarchyLog(kids[i], prefix + ' ');\n// }\n// return log;\n// }\n\n/**\n * Draw layer.\n */\nexport class DrawLayer {\n\n /**\n * The container div.\n *\n * @type {HTMLDivElement}\n */\n #containerDiv;\n\n /**\n * Konva stage.\n *\n * @type {Konva.Stage}\n */\n #konvaStage = null;\n\n /**\n * The layer base size as {x,y}.\n *\n * @type {Scalar2D}\n */\n #baseSize;\n\n /**\n * The layer base spacing as {x,y}.\n *\n * @type {Scalar2D}\n */\n #baseSpacing;\n\n /**\n * The layer fit scale.\n *\n * @type {Scalar2D}\n */\n #fitScale = {x: 1, y: 1};\n\n /**\n * The layer flip scale.\n *\n * @type {Scalar3D}\n */\n #flipScale = {x: 1, y: 1, z: 1};\n\n /**\n * The base layer offset.\n *\n * @type {Scalar2D}\n */\n #baseOffset = {x: 0, y: 0};\n\n /**\n * The view offset.\n *\n * @type {Scalar2D}\n */\n #viewOffset = {x: 0, y: 0};\n\n /**\n * The zoom offset.\n *\n * @type {Scalar2D}\n */\n #zoomOffset = {x: 0, y: 0};\n\n /**\n * The flip offset.\n *\n * @type {Scalar2D}\n */\n #flipOffset = {x: 0, y: 0};\n\n /**\n * The draw controller.\n *\n * @type {DrawController}\n */\n #drawController;\n\n /**\n * The plane helper.\n *\n * @type {PlaneHelper}\n */\n #planeHelper;\n\n /**\n * The associated data id.\n *\n * @type {string}\n */\n #dataId;\n\n /**\n * The reference layer id.\n *\n * @type {string}\n */\n #referenceLayerId;\n\n /**\n * Current position group id.\n *\n * @type {string|undefined}\n */\n #currentPosGroupId;\n\n /**\n * Draw shape handler.\n *\n * @type {DrawShapeHandler|undefined}\n */\n #shapeHandler;\n\n /**\n * Visible labels flag.\n *\n * @type {boolean}\n */\n #visibleLabels = true;\n\n /**\n * @param {HTMLDivElement} containerDiv The layer div, its id will be used\n * as this layer id.\n */\n constructor(containerDiv) {\n this.#containerDiv = containerDiv;\n // specific css class name\n this.#containerDiv.className += ' drawLayer';\n }\n\n /**\n * Set the draw shape handler.\n *\n * @param {DrawShapeHandler|undefined} handler The shape handler.\n */\n setShapeHandler(handler) {\n this.#shapeHandler = handler;\n }\n\n /**\n * Get the associated data id.\n *\n * @returns {string} The id.\n */\n getDataId() {\n return this.#dataId;\n }\n\n /**\n * Get the reference data id.\n *\n * @returns {string} The id.\n */\n getReferenceLayerId() {\n return this.#referenceLayerId;\n }\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Get the Konva stage.\n *\n * @returns {Konva.Stage} The stage.\n */\n getKonvaStage() {\n return this.#konvaStage;\n }\n\n /**\n * Get the Konva layer.\n *\n * @returns {Konva.Layer} The layer.\n */\n getKonvaLayer() {\n // there should only be one layer\n return this.#konvaStage.getLayers()[0];\n }\n\n /**\n * Get the draw controller.\n *\n * @returns {DrawController} The controller.\n */\n getDrawController() {\n return this.#drawController;\n }\n\n /**\n * Set the plane helper.\n *\n * @param {PlaneHelper} helper The helper.\n */\n setPlaneHelper(helper) {\n this.#planeHelper = helper;\n }\n\n // common layer methods [start] ---------------\n\n /**\n * Get the id of the layer.\n *\n * @returns {string} The string id.\n */\n getId() {\n return this.#containerDiv.id;\n }\n\n /**\n * Remove the HTML element from the DOM.\n */\n removeFromDOM() {\n this.#containerDiv.remove();\n }\n\n /**\n * Get the layer base size (without scale).\n *\n * @returns {Scalar2D} The size as {x,y}.\n */\n getBaseSize() {\n return this.#baseSize;\n }\n\n /**\n * Get the layer opacity.\n *\n * @returns {number} The opacity ([0:1] range).\n */\n getOpacity() {\n return this.#konvaStage.opacity();\n }\n\n /**\n * Set the layer opacity.\n *\n * @param {number} alpha The opacity ([0:1] range).\n */\n setOpacity(alpha) {\n this.#konvaStage.opacity(Math.min(Math.max(alpha, 0), 1));\n }\n\n /**\n * Add a flip offset along the layer X axis.\n */\n addFlipOffsetX() {\n // flip offset\n const scale = this.#konvaStage.scale();\n const size = this.#konvaStage.size();\n this.#flipOffset.x += size.width / scale.x;\n // apply\n const offset = this.#konvaStage.offset();\n offset.x += this.#flipOffset.x;\n this.#konvaStage.offset(offset);\n }\n\n /**\n * Add a flip offset along the layer Y axis.\n */\n addFlipOffsetY() {\n // flip offset\n const scale = this.#konvaStage.scale();\n const size = this.#konvaStage.size();\n this.#flipOffset.y += size.height / scale.y;\n // apply\n const offset = this.#konvaStage.offset();\n offset.y += this.#flipOffset.y;\n this.#konvaStage.offset(offset);\n }\n\n /**\n * Flip the scale along the layer X axis.\n */\n flipScaleX() {\n this.#flipScale.x *= -1;\n }\n\n /**\n * Flip the scale along the layer Y axis.\n */\n flipScaleY() {\n this.#flipScale.y *= -1;\n }\n\n /**\n * Flip the scale along the layer Z axis.\n */\n flipScaleZ() {\n this.#flipScale.z *= -1;\n }\n\n /**\n * Set the layer scale.\n *\n * @param {Scalar3D} newScale The scale as {x,y,z}.\n * @param {Point3D} [center] The scale center.\n */\n setScale(newScale, center) {\n const orientedNewScale =\n this.#planeHelper.getTargetOrientedPositiveXYZ({\n x: newScale.x * this.#flipScale.x,\n y: newScale.y * this.#flipScale.y,\n z: newScale.z * this.#flipScale.z,\n });\n const finalNewScale = {\n x: this.#fitScale.x * orientedNewScale.x,\n y: this.#fitScale.y * orientedNewScale.y\n };\n\n const offset = this.#konvaStage.offset();\n\n if (Math.abs(newScale.x) === 1 &&\n Math.abs(newScale.y) === 1 &&\n Math.abs(newScale.z) === 1) {\n // reset zoom offset for scale=1\n const resetOffset = {\n x: offset.x - this.#zoomOffset.x,\n y: offset.y - this.#zoomOffset.y\n };\n // store new offset\n this.#zoomOffset = {x: 0, y: 0};\n this.#konvaStage.offset(resetOffset);\n } else {\n if (typeof center !== 'undefined') {\n let worldCenter = this.#planeHelper.getPlaneOffsetFromOffset3D({\n x: center.getX(),\n y: center.getY(),\n z: center.getZ()\n });\n // center was obtained with viewLayer.displayToMainPlanePos\n // compensated for baseOffset\n // TODO: justify...\n worldCenter = {\n x: worldCenter.x + this.#baseOffset.x,\n y: worldCenter.y + this.#baseOffset.y\n };\n\n const newOffset = getScaledOffset(\n offset, this.#konvaStage.scale(), finalNewScale, worldCenter);\n\n const newZoomOffset = {\n x: this.#zoomOffset.x + newOffset.x - offset.x,\n y: this.#zoomOffset.y + newOffset.y - offset.y\n };\n // store new offset\n this.#zoomOffset = newZoomOffset;\n this.#konvaStage.offset(newOffset);\n }\n }\n\n this.#konvaStage.scale(finalNewScale);\n // update labels\n this.#updateLabelScale(finalNewScale);\n }\n\n /**\n * Initialise the layer scale.\n *\n * @param {Scalar3D} newScale The scale as {x,y,z}.\n * @param {Scalar2D} absoluteZoomOffset The zoom offset as {x,y}\n * without the fit scale (as provided by getAbsoluteZoomOffset).\n */\n initScale(newScale, absoluteZoomOffset) {\n const orientedNewScale = this.#planeHelper.getTargetOrientedPositiveXYZ({\n x: newScale.x * this.#flipScale.x,\n y: newScale.y * this.#flipScale.y,\n z: newScale.z * this.#flipScale.z,\n });\n const finalNewScale = {\n x: this.#fitScale.x * orientedNewScale.x,\n y: this.#fitScale.y * orientedNewScale.y\n };\n this.#konvaStage.scale(finalNewScale);\n\n this.#zoomOffset = {\n x: absoluteZoomOffset.x / this.#fitScale.x,\n y: absoluteZoomOffset.y / this.#fitScale.y\n };\n const offset = this.#konvaStage.offset();\n this.#konvaStage.offset({\n x: offset.x + this.#zoomOffset.x,\n y: offset.y + this.#zoomOffset.y\n });\n }\n\n /**\n * Set the layer offset.\n *\n * @param {Scalar3D} newOffset The offset as {x,y,z}.\n */\n setOffset(newOffset) {\n const planeNewOffset =\n this.#planeHelper.getPlaneOffsetFromOffset3D(newOffset);\n this.#konvaStage.offset({\n x: planeNewOffset.x +\n this.#viewOffset.x +\n this.#baseOffset.x +\n this.#zoomOffset.x +\n this.#flipOffset.x,\n y: planeNewOffset.y +\n this.#viewOffset.y +\n this.#baseOffset.y +\n this.#zoomOffset.y +\n this.#flipOffset.y\n });\n }\n\n /**\n * Set the base layer offset. Updates the layer offset.\n *\n * @param {Vector3D} scrollOffset The scroll offset vector.\n * @param {Vector3D} planeOffset The plane offset vector.\n * @returns {boolean} True if the offset was updated.\n */\n setBaseOffset(scrollOffset, planeOffset) {\n const scrollIndex = this.#planeHelper.getNativeScrollIndex();\n const newOffset = this.#planeHelper.getPlaneOffsetFromOffset3D({\n x: scrollIndex === 0 ? scrollOffset.getX() : planeOffset.getX(),\n y: scrollIndex === 1 ? scrollOffset.getY() : planeOffset.getY(),\n z: scrollIndex === 2 ? scrollOffset.getZ() : planeOffset.getZ(),\n });\n const needsUpdate = this.#baseOffset.x !== newOffset.x ||\n this.#baseOffset.y !== newOffset.y;\n // reset offset if needed\n if (needsUpdate) {\n const offset = this.#konvaStage.offset();\n this.#konvaStage.offset({\n x: offset.x - this.#baseOffset.x + newOffset.x,\n y: offset.y - this.#baseOffset.y + newOffset.y\n });\n this.#baseOffset = newOffset;\n }\n return needsUpdate;\n }\n\n /**\n * Display the layer.\n *\n * @param {boolean} flag Whether to display the layer or not.\n */\n display(flag) {\n this.#containerDiv.style.display = flag ? '' : 'none';\n }\n\n /**\n * Check if the layer is visible.\n *\n * @returns {boolean} True if the layer is visible.\n */\n isVisible() {\n return this.#containerDiv.style.display === '';\n }\n\n /**\n * Draw the content (imageData) of the layer.\n * The imageData variable needs to be set.\n */\n draw() {\n this.#konvaStage.draw();\n }\n\n /**\n * Initialise the layer: set the canvas and context.\n *\n * @param {Scalar2D} size The image size as {x,y}.\n * @param {Scalar2D} spacing The image spacing as {x,y}.\n * @param {string} refLayerId The reference image dataId.\n */\n initialise(size, spacing, refLayerId) {\n // set locals\n this.#baseSize = size;\n this.#baseSpacing = spacing;\n this.#referenceLayerId = refLayerId;\n\n // create stage\n this.#konvaStage = new Konva.Stage({\n container: this.#containerDiv,\n width: this.#baseSize.x,\n height: this.#baseSize.y,\n listening: false\n });\n // reset style\n // (avoids a not needed vertical scrollbar)\n this.#konvaStage.getContent().setAttribute('style', '');\n\n // create layer\n const konvaLayer = new Konva.Layer({\n listening: false,\n visible: true\n });\n this.#konvaStage.add(konvaLayer);\n }\n\n /**\n * Set the annotation group.\n *\n * @param {AnnotationGroup} annotationGroup The annotation group.\n * @param {string} dataId The associated data id.\n * @param {object} exeCallback The undo stack callback.\n */\n setAnnotationGroup(annotationGroup, dataId, exeCallback) {\n this.#dataId = dataId;\n // local listeners\n annotationGroup.addEventListener('annotationadd', (event) => {\n // draw annotation\n this.#addAnnotationDraw(event.data, true);\n this.getKonvaLayer().draw();\n });\n annotationGroup.addEventListener('annotationupdate', (event) => {\n // update annotation draw\n this.#updateAnnotationDraw(event.data);\n this.getKonvaLayer().draw();\n });\n annotationGroup.addEventListener('annotationremove', (event) => {\n // remove annotation draw\n this.#removeAnnotationDraw(event.data);\n this.getKonvaLayer().draw();\n });\n annotationGroup.addEventListener(\n 'annotationgroupeditablechange',\n (event) => {\n this.activateCurrentPositionShapes(event.data);\n }\n );\n\n // create draw controller\n this.#drawController = new DrawController(annotationGroup);\n\n // annotations are allready in the annotation list,\n // -> no need to add them, just draw and save command\n if (annotationGroup.getLength() !== 0) {\n for (const annotation of annotationGroup.getList()) {\n // draw annotation\n this.#addAnnotationDraw(annotation, false);\n // create the draw command\n const command = new AddAnnotationCommand(\n annotation, this.getDrawController());\n // add command to undo stack\n exeCallback(command);\n }\n }\n }\n\n /**\n * Activate shapes at current position.\n *\n * @param {boolean} flag The flag to activate or not.\n */\n activateCurrentPositionShapes(flag) {\n const konvaLayer = this.getKonvaLayer();\n\n // stop listening\n this.#konvaStage.listening(false);\n\n if (typeof this.#shapeHandler !== 'undefined') {\n // reset shape editor (remove anchors)\n this.#shapeHandler.disableAndResetEditor();\n // remove listeners for all position groups\n const allPosGroups = konvaLayer.getChildren();\n for (const posGroup of allPosGroups) {\n if (posGroup instanceof Konva.Group) {\n posGroup.getChildren().forEach((group) => {\n if (group instanceof Konva.Group) {\n this.#shapeHandler.removeShapeListeners(group);\n }\n });\n }\n }\n }\n\n // activate shape listeners if possible\n const drawController = this.getDrawController();\n if (flag &&\n drawController.getAnnotationGroup().isEditable()) {\n // shape groups at the current position\n const shapeGroups =\n this.getCurrentPosGroup().getChildren();\n // listen if we have shapes\n if (shapeGroups.length !== 0) {\n this.#konvaStage.listening(true);\n konvaLayer.listening(true);\n }\n // add listeners for position group\n if (typeof this.#shapeHandler !== 'undefined') {\n shapeGroups.forEach((group) => {\n if (group instanceof Konva.Group) {\n const annotation = drawController.getAnnotation(group.id());\n this.#shapeHandler.addShapeGroupListeners(group, annotation, this);\n }\n });\n }\n }\n\n konvaLayer.draw();\n }\n\n /**\n * Get the position group id for an annotation.\n *\n * @param {Annotation} annotation The target annotation.\n * @returns {string|undefined} The group id.\n */\n #getAnnotationPosGroupId(annotation) {\n let points;\n // annotation planePoints are only present\n // for non aquisition plane\n if (typeof annotation.planePoints !== 'undefined') {\n // use plane points\n points = annotation.planePoints;\n } else {\n // just use plane origin\n points = [annotation.planeOrigin];\n }\n return this.#getPositionId(points);\n }\n\n /**\n * Get a string id from input plane points.\n *\n * @param {Point3D[]} points A list of points that defined a plane.\n * @returns {string} The string id.\n */\n #getPositionId(points) {\n let res = '';\n for (const point of points) {\n if (res.length !== 0) {\n res += '-';\n }\n const posValues = [\n precisionRound(point.getX(), 2),\n precisionRound(point.getY(), 2),\n precisionRound(point.getZ(), 2),\n ];\n res += toStringId(posValues);\n }\n return res;\n }\n\n /**\n * Find the shape group associated to an annotation.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Konva.Group|undefined} The shape group.\n */\n #findShapeGroup(annotation) {\n let res;\n\n const posGroupId = this.#getAnnotationPosGroupId(annotation);\n const layerChildren = this.getKonvaLayer().getChildren(\n isNodeWithId(posGroupId));\n if (layerChildren.length !== 0) {\n const posGroup = layerChildren[0];\n if (!(posGroup instanceof Konva.Group)) {\n return;\n }\n const posChildren = posGroup.getChildren(\n isNodeWithId(annotation.id));\n if (posChildren.length !== 0 &&\n posChildren[0] instanceof Konva.Group) {\n res = posChildren[0];\n }\n }\n return res;\n }\n\n /**\n * Draw an annotation: create the shape group and add it to\n * the Konva layer.\n *\n * @param {Annotation} annotation The annotation to draw.\n * @param {boolean} visible The position group visibility.\n */\n #addAnnotationDraw(annotation, visible) {\n // check for compatible view\n if (!annotation.isCompatibleView(this.#planeHelper)) {\n return;\n }\n const posGroupId = this.#getAnnotationPosGroupId(annotation);\n // Get or create position-group if it does not exist and\n // append it to konvaLayer\n let posGroup = this.getKonvaLayer().getChildren(\n isNodeWithId(posGroupId))[0];\n if (typeof posGroup === 'undefined') {\n posGroup = new Konva.Group({\n id: posGroupId,\n name: 'position-group',\n visible: visible\n });\n this.getKonvaLayer().add(posGroup);\n }\n if (!(posGroup instanceof Konva.Group)) {\n return;\n };\n\n const style = new Style();\n const stage = this.getKonvaStage();\n style.setZoomScale(stage.scale());\n\n // shape group (use first one since it will be removed from\n // the group when we change it)\n const factory = annotation.getFactory();\n const shapeGroup = factory.createShapeGroup(annotation, style);\n // add group to posGroup (switches its parent)\n posGroup.add(shapeGroup);\n\n // activate shape if possible\n if (visible &&\n typeof this.#shapeHandler !== 'undefined'\n ) {\n this.#shapeHandler.addShapeGroupListeners(shapeGroup, annotation, this);\n }\n // set label visibility\n this.setLabelVisibility(shapeGroup);\n }\n\n /**\n * Remove an annotation draw.\n *\n * @param {Annotation} annotation The annotation to remove.\n * @returns {boolean} True if the shape group has been found and removed.\n */\n #removeAnnotationDraw(annotation) {\n const shapeGroup = this.#findShapeGroup(annotation);\n if (!(shapeGroup instanceof Konva.Group)) {\n logger.debug('No shape group to remove');\n return false;\n };\n shapeGroup.remove();\n return true;\n }\n\n /**\n * Update an annotation draw.\n *\n * @param {Annotation} annotation The annotation to update.\n */\n #updateAnnotationDraw(annotation) {\n // update quantification after math shape update\n annotation.updateQuantification();\n // update draw if needed\n if (this.#removeAnnotationDraw(annotation)) {\n this.#addAnnotationDraw(annotation, true);\n }\n }\n\n /**\n * Fit the layer to its parent container.\n *\n * @param {Scalar2D} containerSize The container size as {x,y}.\n * @param {number} divToWorldSizeRatio The div to world size ratio.\n * @param {Scalar2D} fitOffset The fit offset as {x,y}.\n */\n fitToContainer(containerSize, divToWorldSizeRatio, fitOffset) {\n // update konva\n this.#konvaStage.width(containerSize.x);\n this.#konvaStage.height(containerSize.y);\n\n // fit scale\n const divToImageSizeRatio = {\n x: divToWorldSizeRatio * this.#baseSpacing.x,\n y: divToWorldSizeRatio * this.#baseSpacing.y\n };\n // #scale = inputScale * fitScale * flipScale\n // flipScale does not change here, we can omit it\n // newScale = (#scale / fitScale) * newFitScale\n const newScale = {\n x: this.#konvaStage.scale().x * divToImageSizeRatio.x / this.#fitScale.x,\n y: this.#konvaStage.scale().y * divToImageSizeRatio.y / this.#fitScale.y\n };\n\n // set scales if different from previous\n if (this.#konvaStage.scale().x !== newScale.x ||\n this.#konvaStage.scale().y !== newScale.y) {\n this.#fitScale = divToImageSizeRatio;\n this.#konvaStage.scale(newScale);\n }\n\n // view offset\n const newViewOffset = {\n x: fitOffset.x / divToImageSizeRatio.x,\n y: fitOffset.y / divToImageSizeRatio.y\n };\n // flip offset\n const scaledImageSize = {\n x: containerSize.x / divToImageSizeRatio.x,\n y: containerSize.y / divToImageSizeRatio.y\n };\n const newFlipOffset = {\n x: this.#flipOffset.x !== 0 ? scaledImageSize.x : 0,\n y: this.#flipOffset.y !== 0 ? scaledImageSize.y : 0,\n };\n\n // set offsets if different from previous\n if (this.#viewOffset.x !== newViewOffset.x ||\n this.#viewOffset.y !== newViewOffset.y ||\n this.#flipOffset.x !== newFlipOffset.x ||\n this.#flipOffset.y !== newFlipOffset.y) {\n // update global offset\n this.#konvaStage.offset({\n x: this.#konvaStage.offset().x +\n newViewOffset.x - this.#viewOffset.x +\n newFlipOffset.x - this.#flipOffset.x,\n y: this.#konvaStage.offset().y +\n newViewOffset.y - this.#viewOffset.y +\n newFlipOffset.y - this.#flipOffset.y,\n });\n // update private local offsets\n this.#flipOffset = newFlipOffset;\n this.#viewOffset = newViewOffset;\n }\n }\n\n /**\n * Check the visibility of an annotation.\n *\n * @param {string} id The id of the annotation.\n * @returns {boolean} True if the annotation is visible.\n */\n isAnnotationVisible(id) {\n // get the group (annotation and group have same id)\n const group = this.getGroup(id);\n if (typeof group === 'undefined') {\n return false;\n }\n // get visibility\n return group.isVisible();\n }\n\n /**\n * Set the visibility of an annotation.\n *\n * @param {string} id The id of the annotation.\n * @param {boolean} [visible] True to set to visible,\n * will toggle visibility if not defined.\n * @returns {boolean} False if the annotation shape cannot be found.\n */\n setAnnotationVisibility(id, visible) {\n // get the group (annotation and group have same id)\n const group = this.getGroup(id);\n if (typeof group === 'undefined') {\n return false;\n }\n // if not set, toggle visibility\n if (typeof visible === 'undefined') {\n visible = !group.isVisible();\n }\n group.visible(visible);\n\n // udpate\n this.draw();\n\n return true;\n }\n\n /**\n * Set the visibility of all labels.\n *\n * @param {boolean} [visible] True to set to visible,\n * will toggle visibility if not defined.\n */\n setLabelsVisibility(visible) {\n this.#visibleLabels = visible;\n\n const posGroups = this.getKonvaLayer().getChildren();\n for (const posGroup of posGroups) {\n if (posGroup instanceof Konva.Group) {\n const shapeGroups = posGroup.getChildren();\n for (const shapeGroup of shapeGroups) {\n if (shapeGroup instanceof Konva.Group) {\n this.#setLabelVisibility(shapeGroup, visible);\n }\n }\n }\n }\n }\n\n /**\n * Set a shape group label visibility.\n *\n * @param {Konva.Group} shapeGroup The shape group.\n * @param {boolean} [visible] True to set to visible,\n * will toggle visibility if not defined.\n */\n #setLabelVisibility(shapeGroup, visible) {\n const label = shapeGroup.getChildren(isNodeNameLabel)[0];\n if (!(label instanceof Konva.Label)) {\n return;\n }\n // if not set, toggle visibility\n if (typeof visible === 'undefined') {\n visible = !label.isVisible();\n }\n // set visible only for non empty text\n if (typeof label.getText() !== 'undefined' &&\n label.getText().text().length !== 0) {\n label.visible(visible);\n const connector = shapeGroup.getChildren(node =>\n (node.className === 'Line') && node.name() === 'connector')[0];\n if (connector) {\n connector.visible(visible);\n }\n }\n }\n\n /**\n * Set a shape group label visibility according to\n * this layer setting.\n *\n * @param {Konva.Group} shapeGroup The shape group.\n */\n setLabelVisibility(shapeGroup) {\n this.#setLabelVisibility(shapeGroup, this.#visibleLabels);\n }\n\n /**\n * Delete a Draw from the stage.\n *\n * @deprecated Since v0.34, please switch to `annotationGroup.remove`.\n * @param {string} _id The id of the group to delete.\n * @param {Function} _exeCallback The callback to call once the\n * DeleteCommand has been executed.\n */\n deleteDraw(_id, _exeCallback) {\n // does nothing\n }\n\n /**\n * Delete all Draws from the stage.\n *\n * @deprecated Since v0.34, please switch to `annotationGroup.remove`.\n * @param {Function} _exeCallback The callback to call once the\n * DeleteCommand has been executed.\n */\n deleteDraws(_exeCallback) {\n // does nothing\n }\n\n /**\n * Get the total number of draws of this layer\n * (at all positions).\n *\n * @returns {number|undefined} The total number of draws.\n */\n getNumberOfDraws() {\n const posGroups = this.getKonvaLayer().getChildren();\n let count = 0;\n for (const posGroup of posGroups) {\n if (posGroup instanceof Konva.Group) {\n count += posGroup.getChildren().length;\n }\n }\n return count;\n }\n\n /**\n * Enable and listen to container interaction events.\n */\n bindInteraction() {\n this.#konvaStage.listening(true);\n // allow pointer events\n this.#containerDiv.style.pointerEvents = 'auto';\n // interaction events\n const names = InteractionEventNames;\n for (let i = 0; i < names.length; ++i) {\n this.#containerDiv.addEventListener(names[i], this.#fireEvent);\n }\n }\n\n /**\n * Disable and stop listening to container interaction events.\n */\n unbindInteraction() {\n this.#konvaStage.listening(false);\n // disable pointer events\n this.#containerDiv.style.pointerEvents = 'none';\n // interaction events\n const names = InteractionEventNames;\n for (let i = 0; i < names.length; ++i) {\n this.#containerDiv.removeEventListener(names[i], this.#fireEvent);\n }\n }\n\n /**\n * Set the current position.\n *\n * @param {Point} position The new position.\n * @param {Index} [index] Optional coresponding index.\n * @returns {boolean} True if the position was updated.\n */\n setCurrentPosition(position, index) {\n if (typeof index === 'undefined') {\n index = this.#planeHelper.worldToIndex(position);\n }\n const planePoints = this.#planeHelper.getPlanePoints(position);\n let points;\n if (this.#planeHelper.isAquisitionOrientation()) {\n // just use plane origin\n points = [planePoints[0]];\n } else {\n // use plane points\n points = planePoints;\n }\n const posGroupId = this.#getPositionId(points);\n\n this.#activateDrawLayer(posGroupId);\n // TODO: add check\n this.#fireEvent({\n type: 'positionchange',\n value: [\n index.getValues(),\n position.getValues(),\n ],\n valid: true\n });\n\n return true;\n }\n\n /**\n * Activate the current draw layer.\n *\n * @param {string} posGroupId The position group ID.\n */\n #activateDrawLayer(posGroupId) {\n this.#currentPosGroupId = posGroupId;\n\n // get all position groups\n const posGroups = this.getKonvaLayer().getChildren(isPositionNode);\n // reset or set the visible property\n let visible;\n for (let i = 0, leni = posGroups.length; i < leni; ++i) {\n visible = false;\n if (typeof posGroupId !== 'undefined' &&\n posGroups[i].id() === posGroupId) {\n visible = true;\n }\n // group members inherit the visible property\n posGroups[i].visible(visible);\n }\n\n // show current draw layer\n this.getKonvaLayer().draw();\n }\n\n /**\n * Get the current position group.\n *\n * @returns {Konva.Group|undefined} The Konva.Group.\n */\n getCurrentPosGroup() {\n if (typeof this.#currentPosGroupId === 'undefined') {\n return;\n }\n // get position groups\n const posGroups = this.getKonvaLayer().getChildren((node) => {\n return node.id() === this.#currentPosGroupId;\n });\n // if one group, use it\n // if no group, create one\n let posGroup;\n if (posGroups.length === 1) {\n if (posGroups[0] instanceof Konva.Group) {\n posGroup = posGroups[0];\n }\n } else if (posGroups.length === 0) {\n posGroup = new Konva.Group();\n posGroup.name('position-group');\n posGroup.id(this.#currentPosGroupId);\n posGroup.visible(true); // dont inherit\n // add new group to layer\n this.getKonvaLayer().add(posGroup);\n } else {\n logger.warn('Unexpected number of draw position groups');\n }\n // return\n return posGroup;\n }\n\n /**\n * Get a Konva group using its id.\n *\n * @param {string} id The group id.\n * @returns {object|undefined} The Konva group.\n */\n getGroup(id) {\n const group = this.getKonvaLayer().findOne('#' + id);\n if (typeof group === 'undefined') {\n logger.warn('Cannot find node with id: ' + id);\n }\n return group;\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n event.srclayerid = this.getId();\n event.dataid = this.#dataId;\n this.#listenerHandler.fireEvent(event);\n };\n\n // common layer methods [end] ---------------\n\n /**\n * Update label scale: compensate for it so\n * that label size stays visually the same.\n *\n * @param {Scalar2D} scale The scale to compensate for as {x,y}.\n */\n #updateLabelScale(scale) {\n // same formula as in labelFactory::create\n // compensate for scale and times 2 so that font 10 looks like a 10\n const ratioX = 2 / scale.x;\n const ratioY = 2 / scale.y;\n // compensate scale for labels\n const labels = this.#konvaStage.find('Label');\n for (let i = 0; i < labels.length; ++i) {\n labels[i].scale({x: ratioX, y: ratioY});\n }\n }\n\n} // DrawLayer class\n\n// *************************\n// legacy code to allow to convert old state into annotation\n// *************************\n\n/**\n * Draw meta data.\n */\nexport class DrawMeta {\n /**\n * Draw quantification.\n *\n * @type {object}\n */\n quantification;\n\n /**\n * Draw text expression. Can contain variables surrounded with '{}' that will\n * be extracted from the quantification object.\n *\n * @type {string}\n */\n textExpr;\n}\n\n/**\n * Draw details.\n */\nexport class DrawDetails {\n /**\n * The draw ID.\n *\n * @type {number}\n */\n id;\n\n /**\n * The draw position: an Index converted to string.\n *\n * @type {string}\n */\n position;\n\n /**\n * The draw type.\n *\n * @type {string}\n */\n type;\n\n /**\n * The draw color: for example 'green', '#00ff00' or 'rgb(0,255,0)'.\n *\n * @type {string}\n */\n color;\n\n /**\n * The draw meta.\n *\n * @type {DrawMeta}\n */\n meta;\n}\n\n/**\n * Convert a KonvaLayer object to a list of annotations.\n *\n * @param {Array} drawings An array of drawings stored\n * with 'KonvaLayer().toObject()'.\n * @param {DrawDetails[]} drawingsDetails An array of drawings details.\n * @returns {Annotation[]} The associated list of annotations.\n */\nexport function konvaToAnnotation(drawings, drawingsDetails) {\n const annotations = [];\n\n // regular Konva deserialize\n const stateLayer = Konva.Node.create(drawings);\n\n // get all position groups\n const statePosGroups = stateLayer.getChildren(isPositionNode);\n\n for (let i = 0, leni = statePosGroups.length; i < leni; ++i) {\n const statePosGroup = statePosGroups[i];\n const statePosKids = statePosGroup.getChildren();\n for (let j = 0, lenj = statePosKids.length; j < lenj; ++j) {\n const annotation = new Annotation();\n\n // shape group (use first one since it will be removed from\n // the group when we change it)\n const stateGroup = statePosKids[0];\n // annotation id\n annotation.id = stateGroup.id();\n\n // shape\n const shape = stateGroup.getChildren(isNodeNameShape)[0];\n // annotation colour\n annotation.colour = shape.stroke();\n\n if (stateGroup.name() === 'line-group') {\n const points = shape.points();\n annotation.mathShape = new Point2D(points[0], points[1]);\n annotation.referencePoints = [\n new Point2D(points[2], points[3])\n ];\n } else if (stateGroup.name() === 'ruler-group') {\n const points = shape.points();\n annotation.mathShape = new Line(\n new Point2D(points[0], points[1]),\n new Point2D(points[2], points[3])\n );\n } else if (stateGroup.name() === 'rectangle-group') {\n annotation.mathShape = new Rectangle(\n new Point2D(shape.x(), shape.y()),\n new Point2D(shape.x() + shape.width(), shape.y() + shape.height())\n );\n } else if (stateGroup.name() === 'roi-group') {\n const points = shape.points();\n const pointsArray = [];\n for (let i = 0; i < points.length; i = i + 2) {\n pointsArray.push(new Point2D(points[i], points[i + 1]));\n }\n annotation.mathShape = new ROI(pointsArray);\n } else if (stateGroup.name() === 'freeHand-group') {\n logger.warn('Converting freehand into ROI shape');\n const points = shape.points();\n const pointsArray = [];\n for (let i = 0; i < points.length; i = i + 2) {\n pointsArray.push(new Point2D(points[i], points[i + 1]));\n }\n annotation.mathShape = new ROI(pointsArray);\n } else if (stateGroup.name() === 'protractor-group') {\n const points = shape.points();\n annotation.mathShape = new Protractor([\n new Point2D(points[0], points[1]),\n new Point2D(points[2], points[3]),\n new Point2D(points[4], points[5])\n ]);\n } else if (stateGroup.name() === 'ellipse-group') {\n const absPosition = shape.absolutePosition();\n annotation.mathShape = new Ellipse(\n new Point2D(absPosition.x, absPosition.y),\n shape.radiusX(),\n shape.radiusY()\n );\n } else if (stateGroup.name() === 'circle-group') {\n const absPosition = shape.absolutePosition();\n annotation.mathShape = new Circle(\n new Point2D(absPosition.x, absPosition.y),\n shape.radius()\n );\n }\n\n // details\n if (drawingsDetails) {\n const details = drawingsDetails[stateGroup.id()];\n annotation.textExpr = details.meta.textExpr;\n annotation.quantification = details.meta.quantification;\n }\n\n annotations.push(annotation);\n }\n }\n\n return annotations;\n}\n","// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DrawLayer} from '../gui/drawLayer';\nimport {Annotation} from '../image/annotation';\nimport {DrawController} from '../app/drawController';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get the display name of the input shape.\n *\n * @param {Konva.Shape} shape The Konva shape.\n * @returns {string} The display name.\n */\nexport function getShapeDisplayName(shape) {\n let displayName = 'shape';\n if (shape instanceof Konva.Line) {\n if (shape.points().length === 4) {\n displayName = 'line';\n } else if (shape.points().length === 6) {\n displayName = 'protractor';\n } else {\n displayName = 'roi';\n }\n } else if (shape instanceof Konva.Rect) {\n displayName = 'rectangle';\n } else if (shape instanceof Konva.Ellipse) {\n displayName = 'ellipse';\n }\n // return\n return displayName;\n}\n\n/**\n * Add annotation command.\n */\nexport class AddAnnotationCommand {\n /**\n * @type {Annotation}\n */\n #annotation;\n\n /**\n * @type {DrawController}\n */\n #drawController;\n\n /**\n * @param {Annotation} annotation The annotation to add.\n * @param {DrawController} drawController The associated draw controller.\n */\n constructor(annotation, drawController) {\n this.#annotation = annotation;\n this.#drawController = drawController;\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'AddAnnotation-' + this.#annotation.id;\n }\n\n /**\n * Execute the command.\n */\n execute() {\n this.#drawController.addAnnotation(this.#annotation);\n }\n\n /**\n * Undo the command.\n */\n undo() {\n this.#drawController.removeAnnotation(this.#annotation.id);\n }\n}\n\n/**\n * Remove annotation command.\n */\nexport class RemoveAnnotationCommand {\n /**\n * @type {Annotation}\n */\n #annotation;\n\n /**\n * @type {DrawController}\n */\n #drawController;\n\n /**\n * @param {Annotation} annotation The annotation to remove.\n * @param {DrawController} drawController The associated draw controller.\n */\n constructor(annotation, drawController) {\n this.#annotation = annotation;\n this.#drawController = drawController;\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'RemoveAnnotation-' + this.#annotation.id;\n }\n\n /**\n * Execute the command.\n */\n execute() {\n this.#drawController.removeAnnotation(this.#annotation.id);\n }\n\n /**\n * Undo the command.\n */\n undo() {\n this.#drawController.addAnnotation(this.#annotation);\n }\n}\n\n/**\n * Update annotation command.\n */\nexport class UpdateAnnotationCommand {\n /**\n * @type {Annotation}\n */\n #annotation;\n\n /**\n * @type {DrawController}\n */\n #drawController;\n\n /**\n * Original annotation properties.\n *\n * @type {object}\n */\n #originalProps;\n\n /**\n * New annotation properties.\n *\n * @type {object}\n */\n #newProps;\n\n /**\n * @param {Annotation} annotation The annotation to update.\n * @param {object} originaProps The original annotation properties.\n * @param {object} newProps The new annotation properties.\n * @param {DrawController} drawController The associated draw controller.\n */\n constructor(annotation, originaProps, newProps, drawController) {\n this.#annotation = annotation;\n this.#drawController = drawController;\n this.#originalProps = originaProps;\n this.#newProps = newProps;\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'UpdateAnnotation-' + this.#annotation.id;\n }\n\n /**\n * Execute the command.\n */\n execute() {\n const keys = Object.keys(this.#newProps);\n for (const key of keys) {\n this.#annotation[key] = this.#newProps[key];\n }\n this.#drawController.updateAnnotation(this.#annotation, keys);\n }\n\n /**\n * Undo the command.\n */\n undo() {\n const keys = Object.keys(this.#originalProps);\n for (const key of keys) {\n this.#annotation[key] = this.#originalProps[key];\n }\n this.#drawController.updateAnnotation(this.#annotation, keys);\n }\n}\n/**\n * Draw group command.\n *\n * TODO: remove.\n */\nexport class DrawGroupCommand {\n\n /**\n * The group to draw.\n *\n * @type {Konva.Group}\n */\n #group;\n\n /**\n * The shape display name.\n *\n * @type {string}\n */\n #name;\n\n /**\n * The draw layer.\n *\n * @type {DrawLayer}\n */\n #layer;\n\n /**\n * Flag to send events.\n *\n * @type {boolean}\n */\n #isSilent;\n\n /**\n * The group parent.\n *\n * @type {object}\n */\n #parent;\n\n /**\n * @param {Konva.Group} group The group draw.\n * @param {string} name The shape display name.\n * @param {DrawLayer} layer The layer where to draw the group.\n * @param {boolean} [silent] Whether to send a creation event or not.\n */\n constructor(group, name, layer, silent) {\n this.#group = group;\n this.#name = name;\n this.#layer = layer;\n this.#isSilent = (typeof silent === 'undefined') ? false : silent;\n this.#parent = group.getParent();\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'Draw-' + this.#name;\n }\n\n /**\n * Execute the command.\n *\n * @fires DrawGroupCommand#drawcreate\n */\n execute() {\n // add the group to the parent (in case of undo/redo)\n this.#parent.add(this.#group);\n // draw\n this.#layer.getKonvaLayer().draw();\n // callback\n if (!this.#isSilent) {\n /**\n * Draw create event.\n *\n * @event DrawGroupCommand#drawcreate\n * @type {object}\n * @property {string} id The id of the created draw.\n * @property {string} srclayerid The id of the layer of the draw.\n * @property {string} dataid The associated data id.\n */\n this.onExecute({\n type: 'drawcreate',\n id: this.#group.id(),\n srclayerid: this.#layer.getId(),\n dataid: this.#layer.getDataId()\n });\n }\n }\n\n /**\n * Undo the command.\n *\n * @fires DeleteGroupCommand#drawdelete\n */\n undo() {\n // remove the group from the parent layer\n this.#group.remove();\n // draw\n this.#layer.getKonvaLayer().draw();\n // callback\n this.onUndo({\n type: 'drawdelete',\n id: this.#group.id(),\n srclayerid: this.#layer.getId(),\n dataid: this.#layer.getDataId()\n });\n }\n\n /**\n * Handle an execute event.\n *\n * @param {object} _event The execute event with type and id.\n */\n onExecute(_event) {\n // default does nothing.\n }\n\n /**\n * Handle an undo event.\n *\n * @param {object} _event The undo event with type and id.\n */\n onUndo(_event) {\n // default does nothing.\n }\n\n} // DrawGroupCommand class\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * Path shape.\n */\nexport class Path {\n\n /**\n * @param {Point2D[]} [inputPointArray] The list of Point2D that make\n * the path (optional).\n * @param {number[]} [inputControlPointIndexArray] The list of control\n * point of path, as indexes (optional).\n * Note: first and last point do not need to be equal.\n */\n constructor(inputPointArray, inputControlPointIndexArray) {\n /**\n * List of points.\n *\n * @type {Point2D[]}\n */\n this.pointArray = inputPointArray ? inputPointArray.slice() : [];\n /**\n * List of control points.\n *\n * @type {number[]}\n */\n this.controlPointIndexArray = inputControlPointIndexArray\n ? inputControlPointIndexArray.slice() : [];\n }\n\n /**\n * Get a point of the list.\n *\n * @param {number} index The index of the point\n * to get (beware, no size check).\n * @returns {Point2D} The Point2D at the given index.\n */\n getPoint(index) {\n return this.pointArray[index];\n }\n\n /**\n * Is the given point a control point.\n *\n * @param {Point2D} point The Point2D to check.\n * @returns {boolean} True if a control point.\n */\n isControlPoint(point) {\n const index = this.pointArray.indexOf(point);\n if (index !== -1) {\n return this.controlPointIndexArray.indexOf(index) !== -1;\n } else {\n throw new Error('Error: isControlPoint called with not in list point.');\n }\n }\n\n /**\n * Get the length of the path.\n *\n * @returns {number} The length of the path.\n */\n getLength() {\n return this.pointArray.length;\n }\n\n /**\n * Add a point to the path.\n *\n * @param {Point2D} point The Point2D to add.\n */\n addPoint(point) {\n this.pointArray.push(point);\n }\n\n /**\n * Add a control point to the path.\n *\n * @param {Point2D} point The Point2D to make a control point.\n */\n addControlPoint(point) {\n const index = this.pointArray.indexOf(point);\n if (index !== -1) {\n this.controlPointIndexArray.push(index);\n } else {\n throw new Error(\n 'Cannot mark a non registered point as control point.');\n }\n }\n\n /**\n * Add points to the path.\n *\n * @param {Point2D[]} newPointArray The list of Point2D to add.\n */\n addPoints(newPointArray) {\n this.pointArray = this.pointArray.concat(newPointArray);\n }\n\n /**\n * Append a Path to this one.\n *\n * @param {Path} other The Path to append.\n */\n appenPath(other) {\n const oldSize = this.pointArray.length;\n this.pointArray = this.pointArray.concat(other.pointArray);\n const indexArray = [];\n for (let i = 0; i < other.controlPointIndexArray.length; ++i) {\n indexArray[i] = other.controlPointIndexArray[i] + oldSize;\n }\n this.controlPointIndexArray =\n this.controlPointIndexArray.concat(indexArray);\n }\n\n} // Path class\n","/**\n * Circular Bucket Queue.\n *\n * Returns input'd points in sorted order. All operations run in roughly O(1)\n * time (for input with small cost values), but it has a strict requirement:\n *\n * If the most recent point had a cost of c, any points added should have a cost\n * c' in the range c <= c' <= c + (capacity - 1).\n */\nexport class BucketQueue {\n\n /**\n * @param {number} bits Number of bits.\n * @param {Function} cost_functor The cost functor.\n */\n constructor(bits, cost_functor) {\n this.bucketCount = 1 << bits; // # of buckets = 2^bits\n this.mask = this.bucketCount - 1; // 2^bits - 1 = index mask\n this.size = 0;\n\n this.loc = 0; // Current index in bucket list\n // Cost defaults to item value\n this.cost = (typeof (cost_functor) !== 'undefined')\n ? cost_functor : function (item) {\n return item;\n };\n this.buckets = this.buildArray(this.bucketCount);\n }\n\n push(item) {\n // Prepend item to the list in the appropriate bucket\n const bucket = this.getBucket(item);\n item.next = this.buckets[bucket];\n this.buckets[bucket] = item;\n\n this.size++;\n }\n\n pop() {\n if (this.size === 0) {\n throw new Error('Cannot pop, bucketQueue is empty.');\n }\n\n // Find first empty bucket\n while (this.buckets[this.loc] === null) {\n this.loc = (this.loc + 1) % this.bucketCount;\n }\n\n // All items in bucket have same cost, return the first one\n const ret = this.buckets[this.loc];\n this.buckets[this.loc] = ret.next;\n ret.next = null;\n\n this.size--;\n return ret;\n }\n\n // TODO: needs at least two items...\n remove(item) {\n // Tries to remove item from queue. Returns true on success, false otherwise\n if (!item) {\n return false;\n }\n\n // To find node, go to bucket and search through unsorted list.\n const bucket = this.getBucket(item);\n let node = this.buckets[bucket];\n\n while (node !== null &&\n !(node.next !== null &&\n item.x === node.next.x &&\n item.y === node.next.y)) {\n node = node.next;\n }\n\n if (node === null) {\n // Item not in list, ergo item not in queue\n return false;\n } else {\n // Found item, do standard list node deletion\n node.next = node.next.next;\n\n this.size--;\n return true;\n }\n }\n\n isEmpty() {\n return this.size === 0;\n }\n\n getBucket(item) {\n // Bucket index is the masked cost\n return this.cost(item) & this.mask;\n }\n\n buildArray(newSize) {\n // Create array and initialze pointers to null\n const buckets = new Array(newSize);\n\n for (let i = 0; i < buckets.length; i++) {\n buckets[i] = null;\n }\n\n return buckets;\n }\n\n} // class BucketQueue\n","import {BucketQueue} from './bucketQueue';\n\n// Pre-created to reduce allocation in inner loops\nconst __twothirdpi = (2 / (3 * Math.PI));\n\n/**\n * Compute grey scale.\n *\n * @param {Array} data The input data.\n * @param {number} width The width of the output.\n * @param {number} height The height of the output.\n * @returns {object} A greyscale object.\n */\nfunction computeGreyscale(data, width, height) {\n // Returns 2D augmented array containing greyscale data\n // Greyscale values found by averaging colour channels\n // Input should be in a flat RGBA array, with values between 0 and 255\n const greyscale = {\n data: []\n };\n\n // Compute actual values\n for (let y = 0; y < height; y++) {\n greyscale.data[y] = [];\n\n for (let x = 0; x < width; x++) {\n const p = (y * width + x) * 4;\n greyscale.data[y][x] = (data[p] + data[p + 1] + data[p + 2]) / (3 * 255);\n }\n }\n\n // Augment with convenience functions\n greyscale.dx = function (x, y) {\n if (x + 1 === this.data[y].length) {\n // If we're at the end, back up one\n x--;\n }\n return this.data[y][x + 1] - this.data[y][x];\n };\n\n greyscale.dy = function (x, y) {\n if (y + 1 === this.data.length) {\n // If we're at the end, back up one\n y--;\n }\n return this.data[y][x] - this.data[y + 1][x];\n };\n\n greyscale.gradMagnitude = function (x, y) {\n const dx = this.dx(x, y);\n const dy = this.dy(x, y);\n return Math.sqrt(dx * dx + dy * dy);\n };\n\n greyscale.laplace = function (x, y) {\n // Laplacian of Gaussian\n let lap = -16 * this.data[y][x];\n lap += this.data[y - 2][x];\n lap += this.data[y - 1][x - 1] +\n 2 * this.data[y - 1][x] +\n this.data[y - 1][x + 1];\n lap += this.data[y][x - 2] +\n 2 * this.data[y][x - 1] +\n 2 * this.data[y][x + 1] +\n this.data[y][x + 2];\n lap += this.data[y + 1][x - 1] +\n 2 * this.data[y + 1][x] +\n this.data[y + 1][x + 1];\n lap += this.data[y + 2][x];\n\n return lap;\n };\n\n return greyscale;\n}\n\n/**\n * Compute gradient.\n *\n * @param {object} greyscale The input greyscale.\n * @returns {object} A gradient object.\n */\nfunction computeGradient(greyscale) {\n // Returns a 2D array of gradient magnitude values for greyscale. The values\n // are scaled between 0 and 1, and then flipped, so that it works as a cost\n // function.\n const gradient = [];\n\n let max = 0; // Maximum gradient found, for scaling purposes\n\n let x = 0;\n let y = 0;\n\n for (y = 0; y < greyscale.data.length - 1; y++) {\n gradient[y] = [];\n\n for (x = 0; x < greyscale.data[y].length - 1; x++) {\n gradient[y][x] = greyscale.gradMagnitude(x, y);\n max = Math.max(gradient[y][x], max);\n }\n\n gradient[y][greyscale.data[y].length - 1] =\n gradient[y][greyscale.data.length - 2];\n }\n\n gradient[greyscale.data.length - 1] = [];\n for (let i = 0; i < gradient[0].length; i++) {\n gradient[greyscale.data.length - 1][i] =\n gradient[greyscale.data.length - 2][i];\n }\n\n // Flip and scale.\n for (y = 0; y < gradient.length; y++) {\n for (x = 0; x < gradient[y].length; x++) {\n // @ts-ignore\n gradient[y][x] = 1 - (gradient[y][x] / max);\n }\n }\n\n return gradient;\n}\n\n/**\n * @param {object} greyscale The input greyscale.\n * @returns {object} A laplace object.\n */\nfunction computeLaplace(greyscale) {\n // Returns a 2D array of Laplacian of Gaussian values\n const laplace = [];\n\n // Make the edges low cost here.\n\n laplace[0] = [];\n laplace[1] = [];\n for (let i = 1; i < greyscale.data.length; i++) {\n // Pad top, since we can't compute Laplacian\n laplace[0][i] = 1;\n laplace[1][i] = 1;\n }\n\n for (let y = 2; y < greyscale.data.length - 2; y++) {\n laplace[y] = [];\n // Pad left, ditto\n laplace[y][0] = 1;\n laplace[y][1] = 1;\n\n for (let x = 2; x < greyscale.data[y].length - 2; x++) {\n // Threshold needed to get rid of clutter.\n laplace[y][x] = (greyscale.laplace(x, y) > 0.33) ? 0 : 1;\n }\n\n // Pad right, ditto\n laplace[y][greyscale.data[y].length - 2] = 1;\n laplace[y][greyscale.data[y].length - 1] = 1;\n }\n\n laplace[greyscale.data.length - 2] = [];\n laplace[greyscale.data.length - 1] = [];\n for (let j = 1; j < greyscale.data.length; j++) {\n // Pad bottom, ditto\n laplace[greyscale.data.length - 2][j] = 1;\n laplace[greyscale.data.length - 1][j] = 1;\n }\n\n return laplace;\n}\n\n/**\n * Compute the X gradient.\n *\n * @param {object} greyscale The values.\n * @returns {Array} The gradient.\n */\nfunction computeGradX(greyscale) {\n // Returns 2D array of x-gradient values for greyscale\n const gradX = [];\n\n for (let y = 0; y < greyscale.data.length; y++) {\n gradX[y] = [];\n\n for (let x = 0; x < greyscale.data[y].length - 1; x++) {\n gradX[y][x] = greyscale.dx(x, y);\n }\n\n gradX[y][greyscale.data[y].length - 1] =\n gradX[y][greyscale.data[y].length - 2];\n }\n\n return gradX;\n}\n\n/**\n * Compute the Y gradient.\n *\n * @param {object} greyscale The values.\n * @returns {Array} The gradient.\n */\nfunction computeGradY(greyscale) {\n // Returns 2D array of y-gradient values for greyscale\n const gradY = [];\n\n for (let y = 0; y < greyscale.data.length - 1; y++) {\n gradY[y] = [];\n\n for (let x = 0; x < greyscale.data[y].length; x++) {\n gradY[y][x] = greyscale.dy(x, y);\n }\n }\n\n gradY[greyscale.data.length - 1] = [];\n for (let i = 0; i < greyscale.data[0].length; i++) {\n gradY[greyscale.data.length - 1][i] = gradY[greyscale.data.length - 2][i];\n }\n\n return gradY;\n}\n\n/**\n * Compute the gradient unit vector.\n *\n * @param {Array} gradX The X gradient.\n * @param {Array} gradY The Y gradient.\n * @param {number} px The point X.\n * @param {number} py The point Y.\n * @param {object} out The result.\n */\nfunction gradUnitVector(gradX, gradY, px, py, out) {\n // Returns the gradient vector at (px,py), scaled to a magnitude of 1\n const ox = gradX[py][px];\n const oy = gradY[py][px];\n\n let gvm = Math.sqrt(ox * ox + oy * oy);\n gvm = Math.max(gvm, 1e-100); // To avoid possible divide-by-0 errors\n\n out.x = ox / gvm;\n out.y = oy / gvm;\n}\n\n/**\n * Compute the gradient direction.\n *\n * @param {Array} gradX The X gradient.\n * @param {Array} gradY The Y gradient.\n * @param {number} px The point X.\n * @param {number} py The point Y.\n * @param {number} qx The q X.\n * @param {number} qy The q Y.\n * @returns {number} The direction.\n */\nfunction gradDirection(gradX, gradY, px, py, qx, qy) {\n const __dgpuv = {x: -1, y: -1};\n const __gdquv = {x: -1, y: -1};\n // Compute the gradiant direction, in radians, between to points\n gradUnitVector(gradX, gradY, px, py, __dgpuv);\n gradUnitVector(gradX, gradY, qx, qy, __gdquv);\n\n let dp = __dgpuv.y * (qx - px) - __dgpuv.x * (qy - py);\n let dq = __gdquv.y * (qx - px) - __gdquv.x * (qy - py);\n\n // Make sure dp is positive, to keep things consistant\n if (dp < 0) {\n dp = -dp;\n dq = -dq;\n }\n\n if (px !== qx && py !== qy) {\n // We're going diagonally between pixels\n dp *= Math.SQRT1_2;\n dq *= Math.SQRT1_2;\n }\n\n return __twothirdpi * (Math.acos(dp) + Math.acos(dq));\n}\n\n/**\n * Compute the sides.\n *\n * @param {number} dist The distance.\n * @param {Array} gradX The X gradient.\n * @param {Array} gradY The Y gradient.\n * @param {object} greyscale The value.\n * @returns {object} The sides.\n */\nfunction computeSides(dist, gradX, gradY, greyscale) {\n // Returns 2 2D arrays, containing inside and outside greyscale values.\n // These greyscale values are the intensity just a little bit along the\n // gradient vector, in either direction, from the supplied point. These\n // values are used when using active-learning Intelligent Scissors\n\n const sides = {};\n sides.inside = [];\n sides.outside = [];\n\n const guv = {x: -1, y: -1}; // Current gradient unit vector\n\n for (let y = 0; y < gradX.length; y++) {\n sides.inside[y] = [];\n sides.outside[y] = [];\n\n for (let x = 0; x < gradX[y].length; x++) {\n gradUnitVector(gradX, gradY, x, y, guv);\n\n //(x, y) rotated 90 = (y, -x)\n\n let ix = Math.round(x + dist * guv.y);\n let iy = Math.round(y - dist * guv.x);\n let ox = Math.round(x - dist * guv.y);\n let oy = Math.round(y + dist * guv.x);\n\n ix = Math.max(Math.min(ix, gradX[y].length - 1), 0);\n ox = Math.max(Math.min(ox, gradX[y].length - 1), 0);\n iy = Math.max(Math.min(iy, gradX.length - 1), 0);\n oy = Math.max(Math.min(oy, gradX.length - 1), 0);\n\n sides.inside[y][x] = greyscale.data[iy][ix];\n sides.outside[y][x] = greyscale.data[oy][ox];\n }\n }\n\n return sides;\n}\n\n/**\n * Gaussian blur an input buffer.\n *\n * @param {Array} buffer The input buffer.\n * @param {Array} out The result.\n */\nfunction gaussianBlur(buffer, out) {\n // Smooth values over to fill in gaps in the mapping\n out[0] = 0.4 * buffer[0] + 0.5 * buffer[1] + 0.1 * buffer[1];\n out[1] = 0.25 * buffer[0] + 0.4 * buffer[1] + 0.25 * buffer[2] +\n 0.1 * buffer[3];\n\n for (let i = 2; i < buffer.length - 2; i++) {\n out[i] = 0.05 * buffer[i - 2] + 0.25 * buffer[i - 1] +\n 0.4 * buffer[i] + 0.25 * buffer[i + 1] + 0.05 * buffer[i + 2];\n }\n\n const len = buffer.length;\n out[len - 2] = 0.25 * buffer[len - 1] + 0.4 * buffer[len - 2] +\n 0.25 * buffer[len - 3] + 0.1 * buffer[len - 4];\n out[len - 1] = 0.4 * buffer[len - 1] + 0.5 * buffer[len - 2] +\n 0.1 * buffer[len - 3];\n}\n\n/**\n * Scissors.\n *\n * Ref: Eric N. Mortensen, William A. Barrett, Interactive Segmentation with\n * Intelligent Scissors, Graphical Models and Image Processing, Volume 60,\n * Issue 5, September 1998, Pages 349-384, ISSN 1077-3169,\n * DOI: 10.1006/gmip.1998.0480.\n *\n * See: {@link http://www.sciencedirect.com/science/article/B6WG4-45JB8WN-9/2/6fe59d8089fd1892c2bfb82283065579}.\n *\n * Highly inspired from: {@link http://code.google.com/p/livewire-javascript/}.\n */\nexport class Scissors {\n\n constructor() {\n this.width = -1;\n this.height = -1;\n\n this.curPoint = null; // Corrent point we're searching on.\n this.searchGranBits = 8; // Bits of resolution for BucketQueue.\n this.searchGran = 1 << this.searchGranBits; //bits.\n this.pointsPerPost = 500;\n\n // Precomputed image data. All in ranges 0 >= x >= 1 and\n // all inverted (1 - x).\n this.greyscale = null; // Greyscale of image\n this.laplace = null; // Laplace zero-crossings (either 0 or 1).\n this.gradient = null; // Gradient magnitudes.\n this.gradX = null; // X-differences.\n this.gradY = null; // Y-differences.\n\n // Matrix mapping point => parent along shortest-path to root.\n this.parents = null;\n\n this.working = false; // Currently computing shortest paths?\n\n // Begin Training:\n this.trained = false;\n this.trainingPoints = null;\n\n this.edgeWidth = 2;\n this.trainingLength = 32;\n\n this.edgeGran = 256;\n this.edgeTraining = null;\n\n this.gradPointsNeeded = 32;\n this.gradGran = 1024;\n this.gradTraining = null;\n\n this.insideGran = 256;\n this.insideTraining = null;\n\n this.outsideGran = 256;\n this.outsideTraining = null;\n }\n // End Training\n\n\n // Begin training methods //\n getTrainingIdx(granularity, value) {\n return Math.round((granularity - 1) * value);\n }\n\n getTrainedEdge(edge) {\n return this.edgeTraining[this.getTrainingIdx(this.edgeGran, edge)];\n }\n\n getTrainedGrad(grad) {\n return this.gradTraining[this.getTrainingIdx(this.gradGran, grad)];\n }\n\n getTrainedInside(inside) {\n return this.insideTraining[this.getTrainingIdx(this.insideGran, inside)];\n }\n\n getTrainedOutside(outside) {\n return this.outsideTraining[this.getTrainingIdx(this.outsideGran, outside)];\n }\n // End training methods //\n\n setWorking(working) {\n // Sets working flag\n this.working = working;\n }\n\n setDimensions(width, height) {\n this.width = width;\n this.height = height;\n }\n\n setData(data) {\n if (this.width === -1 || this.height === -1) {\n // The width and height should have already been set\n throw new Error('Dimensions have not been set.');\n }\n\n this.greyscale = computeGreyscale(data, this.width, this.height);\n this.laplace = computeLaplace(this.greyscale);\n this.gradient = computeGradient(this.greyscale);\n this.gradX = computeGradX(this.greyscale);\n this.gradY = computeGradY(this.greyscale);\n\n const sides = computeSides(\n this.edgeWidth, this.gradX, this.gradY, this.greyscale);\n this.inside = sides.inside;\n this.outside = sides.outside;\n this.edgeTraining = [];\n this.gradTraining = [];\n this.insideTraining = [];\n this.outsideTraining = [];\n }\n\n findTrainingPoints(p) {\n // Grab the last handful of points for training\n const points = [];\n\n if (this.parents !== null) {\n for (let i = 0; i < this.trainingLength && p; i++) {\n points.push(p);\n p = this.parents[p.y][p.x];\n }\n }\n\n return points;\n }\n\n resetTraining() {\n this.trained = false; // Training is ignored with this flag set\n }\n\n doTraining(p) {\n // Compute training weights and measures\n this.trainingPoints = this.findTrainingPoints(p);\n\n if (this.trainingPoints.length < 8) {\n return; // Not enough points, I think. It might crash if length = 0.\n }\n\n const buffer = [];\n this.calculateTraining(\n buffer, this.edgeGran, this.greyscale, this.edgeTraining);\n this.calculateTraining(\n buffer, this.gradGran, this.gradient, this.gradTraining);\n this.calculateTraining(\n buffer, this.insideGran, this.inside, this.insideTraining);\n this.calculateTraining(\n buffer, this.outsideGran, this.outside, this.outsideTraining);\n\n if (this.trainingPoints.length < this.gradPointsNeeded) {\n // If we have two few training points, the gradient weight map might not\n // be smooth enough, so average with normal weights.\n this.addInStaticGrad(this.trainingPoints.length, this.gradPointsNeeded);\n }\n\n this.trained = true;\n }\n\n calculateTraining(\n buffer, granularity, input, output) {\n let i = 0;\n // Build a map of raw-weights to trained-weights by favoring input values\n buffer.length = granularity;\n for (i = 0; i < granularity; i++) {\n buffer[i] = 0;\n }\n\n let maxVal = 1;\n for (i = 0; i < this.trainingPoints.length; i++) {\n const p = this.trainingPoints[i];\n const idx = this.getTrainingIdx(granularity, input[p.y][p.x]);\n buffer[idx] += 1;\n\n maxVal = Math.max(maxVal, buffer[idx]);\n }\n\n // Invert and scale.\n for (i = 0; i < granularity; i++) {\n buffer[i] = 1 - buffer[i] / maxVal;\n }\n\n // Blur it, as suggested. Gets rid of static.\n gaussianBlur(buffer, output);\n }\n\n addInStaticGrad(have, need) {\n // Average gradient raw-weights to trained-weights map with standard weight\n // map so that we don't end up with something to spiky\n for (let i = 0; i < this.gradGran; i++) {\n this.gradTraining[i] = Math.min(\n this.gradTraining[i],\n 1 - i * (need - have) / (need * this.gradGran)\n );\n }\n }\n\n gradDirection(px, py, qx, qy) {\n return gradDirection(this.gradX, this.gradY, px, py, qx, qy);\n }\n\n dist(px, py, qx, qy) {\n // The grand culmunation of most of the code: the weighted distance function\n let grad = this.gradient[qy][qx];\n\n if (px === qx || py === qy) {\n // The distance is Euclidean-ish; non-diagonal edges should be shorter\n grad *= Math.SQRT1_2;\n }\n\n const lap = this.laplace[qy][qx];\n const dir = this.gradDirection(px, py, qx, qy);\n\n if (this.trained) {\n // Apply training magic\n const gradT = this.getTrainedGrad(grad);\n const edgeT = this.getTrainedEdge(this.greyscale.data[py][px]);\n const insideT = this.getTrainedInside(this.inside[py][px]);\n const outsideT = this.getTrainedOutside(this.outside[py][px]);\n\n return 0.3 * gradT + 0.3 * lap + 0.1 * (dir + edgeT + insideT + outsideT);\n } else {\n // Normal weights\n return 0.43 * grad + 0.43 * lap + 0.11 * dir;\n }\n }\n\n adj(p) {\n const list = [];\n\n const sx = Math.max(p.x - 1, 0);\n const sy = Math.max(p.y - 1, 0);\n const ex = Math.min(p.x + 1, this.greyscale.data[0].length - 1);\n const ey = Math.min(p.y + 1, this.greyscale.data.length - 1);\n\n let idx = 0;\n for (let y = sy; y <= ey; y++) {\n for (let x = sx; x <= ex; x++) {\n if (x !== p.x || y !== p.y) {\n list[idx++] = {x: x, y: y};\n }\n }\n }\n\n return list;\n }\n\n #costFunction = (p) => {\n return Math.round(this.searchGran * this.cost[p.y][p.x]);\n };\n\n setPoint(sp) {\n this.setWorking(true);\n\n this.curPoint = sp;\n\n let x = 0;\n let y = 0;\n\n this.visited = [];\n for (y = 0; y < this.height; y++) {\n this.visited[y] = [];\n for (x = 0; x < this.width; x++) {\n this.visited[y][x] = false;\n }\n }\n\n this.parents = [];\n for (y = 0; y < this.height; y++) {\n this.parents[y] = [];\n }\n\n this.cost = [];\n for (y = 0; y < this.height; y++) {\n this.cost[y] = [];\n for (x = 0; x < this.width; x++) {\n this.cost[y][x] = Number.MAX_VALUE;\n }\n }\n this.cost[sp.y][sp.x] = 0;\n\n this.pq = new BucketQueue(this.searchGranBits, this.#costFunction);\n this.pq.push(sp);\n }\n\n doWork() {\n if (!this.working) {\n return;\n }\n\n this.timeout = null;\n\n let pointCount = 0;\n const newPoints = [];\n while (!this.pq.isEmpty() && pointCount < this.pointsPerPost) {\n const p = this.pq.pop();\n newPoints.push(p);\n newPoints.push(this.parents[p.y][p.x]);\n\n this.visited[p.y][p.x] = true;\n\n const adjList = this.adj(p);\n for (let i = 0; i < adjList.length; i++) {\n const q = adjList[i];\n\n const pqCost = this.cost[p.y][p.x] + this.dist(p.x, p.y, q.x, q.y);\n\n if (pqCost < this.cost[q.y][q.x]) {\n if (this.cost[q.y][q.x] !== Number.MAX_VALUE) {\n // Already in PQ, must remove it so we can re-add it.\n this.pq.remove(q);\n }\n\n this.cost[q.y][q.x] = pqCost;\n this.parents[q.y][q.x] = p;\n this.pq.push(q);\n }\n }\n\n pointCount++;\n }\n\n return newPoints;\n }\n\n} // Scissors class\n","// linting 'type {Object.}' will give:\n// warning Use object shorthand or index signatures instead of `Object`,\n// e.g., `{[key: string]: string}` jsdoc/check-types\n// pb: jsdoc does not support the object shorthand\n// and ignoring will give vscode warning since the doc linting is not\n// activated by default.\n\n// Overridable default object.\nexport const defaults = {\n /**\n * List of default window level presets.\n *\n * @type {Object.>}\n */\n labelText: {\n arrow: {\n '*': ''\n },\n circle: {\n '*': '{surface}'\n },\n ellipse: {\n '*': '{surface}'\n },\n protractor: {\n '*': '{angle}'\n },\n rectangle: {\n '*': '{surface}'\n },\n roi: {\n '*': ''\n },\n ruler: {\n '*': '{length}'\n }\n }\n};\n","// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Label factory to create and update shape label.\n */\nexport class LabelFactory {\n\n /**\n * Default position getter.\n *\n * @type {Function}\n */\n #defaultPositionGetter;\n\n /**\n * @param {Function} positionGetter Default position getter.\n */\n constructor(positionGetter) {\n this.#defaultPositionGetter = positionGetter;\n }\n\n /**\n * Get the annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n getPosition(annotation) {\n let position = annotation.labelPosition;\n if (typeof position === 'undefined') {\n position = this.#defaultPositionGetter(annotation);\n }\n return position;\n }\n\n /**\n * Creates the konva label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Label} The Konva label.\n */\n create(annotation, style) {\n // konva text\n const ktext = new Konva.Text({\n fontSize: style.getFontSize(),\n fontFamily: style.getFontFamily(),\n fill: annotation.colour,\n padding: style.getTextPadding(),\n shadowColor: style.getShadowLineColour(),\n shadowOffset: style.getShadowOffset(),\n name: 'text'\n });\n const labelText = annotation.getText();\n ktext.setText(labelText);\n\n // times 2 so that the font size 10 looks like a 10...\n // (same logic as in the DrawController::updateLabelScale)\n const zoomScale = style.applyZoomScale(1);\n const labelScale = {\n x: 2 * zoomScale.x,\n y: 2 * zoomScale.y\n };\n\n // konva label\n const labelPosition = this.getPosition(annotation);\n const klabel = new Konva.Label({\n x: labelPosition.getX(),\n y: labelPosition.getY(),\n scale: labelScale,\n visible: labelText.length !== 0,\n name: 'label'\n });\n klabel.add(ktext);\n klabel.add(new Konva.Tag({\n fill: annotation.colour,\n opacity: style.getTagOpacity()\n }));\n\n return klabel;\n }\n\n /**\n * Update the shape label position.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n */\n updatePosition(annotation, group) {\n // associated label\n const klabel = group.getChildren(function (node) {\n return node.name() === 'label';\n })[0];\n if (!(klabel instanceof Konva.Label)) {\n return;\n }\n // update position\n const labelPosition = this.getPosition(annotation);\n klabel.position({\n x: labelPosition.getX(),\n y: labelPosition.getY()\n });\n }\n\n /**\n * Get the anchors positions for the label.\n *\n * @param {Konva.Label} label The label.\n * @returns {Point2D[]} The connectors positions.\n */\n getLabelAnchorsPosition(label) {\n const lx = label.x();\n const ly = label.y();\n const dx = label.width() * label.scale().x;\n const dy = label.height() * label.scale().y;\n return [\n new Point2D(lx + dx / 2, ly),\n new Point2D(lx, ly + dy / 2),\n new Point2D(lx + dx / 2, ly + dy),\n new Point2D(lx + dx, ly + dy / 2),\n ];\n }\n\n /**\n * Get the two closest points of two points lists.\n *\n * @param {Point2D[]} points1 The first point list.\n * @param {Point2D[]} points2 The second point list.\n * @returns {Point2D[]} The closests points.\n */\n getClosestPoints(points1, points2) {\n let minDist = points1[0].getDistance(points2[0]);\n let p1 = points1[0];\n let p2 = points2[0];\n for (const point1 of points1) {\n for (const point2 of points2) {\n const dist = point1.getDistance(point2);\n if (dist < minDist) {\n minDist = dist;\n p1 = point1;\n p2 = point2;\n }\n }\n }\n return [p1, p2];\n }\n\n /**\n * Get the connector between this label and its shape.\n *\n * @param {Point2D[]} connectorsPos The shape connectors positions.\n * @param {Konva.Label} label The label.\n * @param {Style} style The drawing style.\n * @returns {Konva.Line} The connector.\n */\n getConnector(connectorsPos, label, style) {\n const labelAnchorsPos = this.getLabelAnchorsPosition(label);\n const anchorPoints = this.getClosestPoints(\n connectorsPos, labelAnchorsPos);\n return new Konva.Line({\n points: [\n anchorPoints[0].getX(),\n anchorPoints[0].getY(),\n anchorPoints[1].getX(),\n anchorPoints[1].getY()\n ],\n stroke: label.getText().fill(),\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n visible: label.visible(),\n dash: [10, 7],\n name: 'connector'\n });\n }\n\n /**\n * Update the connector between a label and its shape.\n *\n * @param {Konva.Group} group The associated shape group.\n * @param {Point2D[]} connectorsPos The shape connectors positions.\n */\n updateConnector(group, connectorsPos) {\n // associated label\n const klabel = group.getChildren(function (node) {\n return node.name() === 'label';\n })[0];\n if (!(klabel instanceof Konva.Label)) {\n return;\n }\n\n const labelAnchorsPos = this.getLabelAnchorsPosition(klabel);\n\n const anchors = this.getClosestPoints(connectorsPos, labelAnchorsPos);\n\n const kconnect = group.getChildren(function (node) {\n return node.name() === 'connector';\n })[0];\n if (!(kconnect instanceof Konva.Line)) {\n return;\n }\n\n kconnect.points([\n anchors[0].getX(),\n anchors[0].getY(),\n anchors[1].getX(),\n anchors[1].getY()\n ]);\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n */\n updateContent(annotation, group) {\n // associated label\n const klabel = group.getChildren(function (node) {\n return node.name() === 'label';\n })[0];\n if (!(klabel instanceof Konva.Label)) {\n return;\n }\n // update text\n const text = annotation.getText();\n const ktext = klabel.getText();\n ktext.setText(text);\n // hide if visible and empty\n if (klabel.visible()) {\n klabel.visible(text.length !== 0);\n }\n }\n\n} // LabelFactory","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\n/* eslint-enable no-unused-vars */\n\n/**\n * Threshold an image between an input minimum and maximum.\n */\nexport class ThresholdFilter {\n /**\n * Threshold minimum.\n *\n * @type {number}\n */\n #min = 0;\n\n /**\n * Threshold maximum.\n *\n * @type {number}\n */\n #max = 0;\n\n /**\n * Get the threshold minimum.\n *\n * @returns {number} The threshold minimum.\n */\n getMin() {\n return this.#min;\n }\n\n /**\n * Set the threshold minimum.\n *\n * @param {number} val The threshold minimum.\n */\n setMin(val) {\n this.#min = val;\n }\n\n /**\n * Get the threshold maximum.\n *\n * @returns {number} The threshold maximum.\n */\n getMax() {\n return this.#max;\n }\n\n /**\n * Set the threshold maximum.\n *\n * @param {number} val The threshold maximum.\n */\n setMax(val) {\n this.#max = val;\n }\n\n /**\n * Get the name of the filter.\n *\n * @returns {string} The name of the filter.\n */\n getName() {\n return 'Threshold';\n }\n\n /**\n * Original image.\n *\n * @type {Image}\n */\n #originalImage = null;\n\n /**\n * Set the original image.\n *\n * @param {Image} image The original image.\n */\n setOriginalImage(image) {\n this.#originalImage = image;\n }\n\n /**\n * Get the original image.\n *\n * @returns {Image} The original image.\n */\n getOriginalImage() {\n return this.#originalImage;\n }\n\n /**\n * Transform the main image using this filter.\n *\n * @returns {Image} The transformed image.\n */\n update() {\n const image = this.getOriginalImage();\n const imageMin = image.getDataRange().min;\n const threshFunction = (value) => {\n if (value < this.getMin() || value > this.getMax()) {\n return imageMin;\n } else {\n return value;\n }\n };\n return image.transform(threshFunction);\n }\n\n} // class Threshold\n\n/**\n * Sharpen an image using a sharpen convolution matrix.\n */\nexport class SharpenFilter {\n /**\n * Get the name of the filter.\n *\n * @returns {string} The name of the filter.\n */\n getName() {\n return 'Sharpen';\n }\n\n /**\n * Original image.\n *\n * @type {Image}\n */\n #originalImage = null;\n\n /**\n * Set the original image.\n *\n * @param {Image} image The original image.\n */\n setOriginalImage(image) {\n this.#originalImage = image;\n }\n\n /**\n * Get the original image.\n *\n * @returns {Image} The original image.\n */\n getOriginalImage() {\n return this.#originalImage;\n }\n\n /**\n * Transform the main image using this filter.\n *\n * @returns {Image} The transformed image.\n */\n update() {\n const image = this.getOriginalImage();\n /* eslint-disable @stylistic/js/array-element-newline */\n return image.convolute2D([\n 0, -1, 0,\n -1, 5, -1,\n 0, -1, 0\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n }\n\n} // class Sharpen\n\n/**\n * Apply a Sobel filter to an image.\n */\nexport class SobelFilter {\n /**\n * Get the name of the filter.\n *\n * @returns {string} The name of the filter.\n */\n getName() {\n return 'Sobel';\n }\n\n /**\n * Original image.\n *\n * @type {Image}\n */\n #originalImage = null;\n\n /**\n * Set the original image.\n *\n * @param {Image} image The original image.\n */\n setOriginalImage(image) {\n this.#originalImage = image;\n }\n\n /**\n * Get the original image.\n *\n * @returns {Image} The original image.\n */\n getOriginalImage() {\n return this.#originalImage;\n }\n\n /**\n * Transform the main image using this filter.\n *\n * @returns {Image} The transformed image.\n */\n update() {\n const image = this.getOriginalImage();\n /* eslint-disable @stylistic/js/array-element-newline */\n const gradX = image.convolute2D([\n 1, 0, -1,\n 2, 0, -2,\n 1, 0, -1\n ]);\n const gradY = image.convolute2D([\n 1, 2, 1,\n 0, 0, 0,\n -1, -2, -1\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n return gradX.compose(gradY, function (x, y) {\n return Math.sqrt(x * x + y * y);\n });\n }\n\n} // class Sobel\n","import {ListenerHandler} from '../utils/listen';\nimport {\n ThresholdFilter,\n SobelFilter,\n SharpenFilter\n} from '../image/filter';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Filter tool.\n */\nexport class Filter {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Filter list.\n *\n * @type {object}\n */\n #filterList = null;\n\n /**\n * Selected filter.\n *\n * @type {object}\n */\n #selectedFilter = 0;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Activate the tool.\n *\n * @param {boolean} bool Flag to activate or not.\n */\n activate(bool) {\n // setup event listening\n for (const key in this.#filterList) {\n if (bool) {\n this.#filterList[key].addEventListener('filterrun', this.#fireEvent);\n this.#filterList[key].addEventListener('filter-undo', this.#fireEvent);\n } else {\n this.#filterList[key].removeEventListener(\n 'filterrun', this.#fireEvent);\n this.#filterList[key].removeEventListener(\n 'filter-undo', this.#fireEvent);\n }\n }\n }\n\n /**\n * Set the tool options.\n *\n * @param {object} options The list of filter names amd classes.\n */\n setOptions(options) {\n this.#filterList = {};\n // try to instanciate filters from the options\n for (const key in options) {\n this.#filterList[key] = new options[key](this.#app);\n }\n }\n\n /**\n * Get the type of tool options: here 'instance' since the filter\n * list contains instances of each possible filter.\n *\n * @returns {string} The type.\n */\n getOptionsType() {\n return 'instance';\n }\n\n /**\n * Initialise the filter. Called once the image is loaded.\n */\n init() {\n // setup event listening\n for (const key in this.#filterList) {\n this.#filterList[key].init();\n }\n }\n\n /**\n * Handle keydown event.\n *\n * @param {object} event The keydown event.\n */\n keydown = (event) => {\n event.context = 'Filter';\n this.#app.onKeydown(event);\n };\n\n /**\n * Get the list of event names that this tool can fire.\n *\n * @returns {string[]} The list of event names.\n */\n getEventNames() {\n return ['filterrun', 'filterundo'];\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n /**\n * Get the selected filter.\n *\n * @returns {object} The selected filter.\n */\n getSelectedFilter() {\n return this.#selectedFilter;\n }\n\n /**\n * Set the tool live features: filter name.\n *\n * @param {object} features The list of features.\n */\n setFeatures(features) {\n if (typeof features.filterName !== 'undefined') {\n // check if we have it\n if (!this.hasFilter(features.filterName)) {\n throw new Error('Unknown filter: \\'' + features.filterName + '\\'');\n }\n // de-activate last selected\n if (this.#selectedFilter) {\n this.#selectedFilter.activate(false);\n }\n // enable new one\n this.#selectedFilter = this.#filterList[features.filterName];\n // activate the selected filter\n this.#selectedFilter.activate(true);\n }\n if (typeof features.run !== 'undefined' && features.run) {\n let args = {};\n if (typeof features.runArgs !== 'undefined') {\n args = features.runArgs;\n }\n this.getSelectedFilter().run(args);\n }\n }\n\n /**\n * Get the list of filters.\n *\n * @returns {Array} The list of filter objects.\n */\n getFilterList() {\n return this.#filterList;\n }\n\n /**\n * Check if a filter is in the filter list.\n *\n * @param {string} name The name to check.\n * @returns {string} The filter list element for the given name.\n */\n hasFilter(name) {\n return this.#filterList[name];\n }\n\n} // class Filter\n\n/**\n * Threshold filter tool.\n */\nexport class Threshold {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Associated filter.\n *\n * @type {object}\n */\n #filter = new ThresholdFilter();\n\n /**\n * Flag to know wether to reset the image or not.\n *\n * @type {boolean}\n */\n #resetImage = true;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Activate the filter.\n *\n * @param {boolean} bool Flag to activate or not.\n */\n activate(bool) {\n // reset the image when the tool is activated\n if (bool) {\n this.#resetImage = true;\n }\n }\n\n /**\n * Initialise the filter. Called once the image is loaded.\n */\n init() {\n // does nothing\n }\n\n /**\n * Run the filter.\n *\n * @param {*} args The filter arguments.\n */\n run(args) {\n if (typeof args.dataId === 'undefined') {\n throw new Error('No dataId to run threshod filter on.');\n }\n this.#filter.setMin(args.min);\n this.#filter.setMax(args.max);\n // reset the image if asked\n if (this.#resetImage) {\n const image = this.#app.getData(args.dataId).image;\n this.#filter.setOriginalImage(image);\n this.#resetImage = false;\n }\n const command = new RunFilterCommand(this.#filter, args.dataId, this.#app);\n command.onExecute = this.#fireEvent;\n command.onUndo = this.#fireEvent;\n command.execute();\n // save command in undo stack\n this.#app.addToUndoStack(command);\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n} // class Threshold\n\n/**\n * Sharpen filter tool.\n */\nexport class Sharpen {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Activate the filter.\n *\n * @param {boolean} _bool Flag to activate or not.\n */\n activate(_bool) {\n // does nothing\n }\n\n /**\n * Initialise the filter. Called once the image is loaded.\n */\n init() {\n // does nothing\n }\n\n /**\n * Run the filter.\n *\n * @param {*} args The filter arguments.\n */\n run(args) {\n if (typeof args.dataId === 'undefined') {\n throw new Error('No dataId to run sharpen filter on.');\n }\n const filter = new SharpenFilter();\n const image = this.#app.getData(args.dataId).image;\n filter.setOriginalImage(image);\n const command = new RunFilterCommand(filter, args.dataId, this.#app);\n command.onExecute = this.#fireEvent;\n command.onUndo = this.#fireEvent;\n command.execute();\n // save command in undo stack\n this.#app.addToUndoStack(command);\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n} // filter.Sharpen\n\n/**\n * Sobel filter tool.\n */\nexport class Sobel {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Activate the filter.\n *\n * @param {boolean} _bool Flag to activate or not.\n */\n activate(_bool) {\n // does nothing\n }\n\n /**\n * Initialise the filter. Called once the image is loaded.\n */\n init() {\n // does nothing\n }\n\n /**\n * Run the filter.\n *\n * @param {*} args The filter arguments.\n */\n run(args) {\n if (typeof args.dataId === 'undefined') {\n throw new Error('No dataId to run sobel filter on.');\n }\n const filter = new SobelFilter();\n const image = this.#app.getData(args.dataId).image;\n filter.setOriginalImage(image);\n const command = new RunFilterCommand(filter, args.dataId, this.#app);\n command.onExecute = this.#fireEvent;\n command.onUndo = this.#fireEvent;\n command.execute();\n // save command in undo stack\n this.#app.addToUndoStack(command);\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n} // class filter.Sobel\n\n/**\n * Run filter command.\n */\nexport class RunFilterCommand {\n\n /**\n * The filter to run.\n *\n * @type {object}\n */\n #filter;\n\n /**\n * Data id.\n *\n * @type {string}\n */\n #dataId;\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {object} filter The filter to run.\n * @param {string} dataId The data to filter.\n * @param {App} app The associated application.\n */\n constructor(filter, dataId, app) {\n this.#filter = filter;\n this.#dataId = dataId;\n this.#app = app;\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'Filter-' + this.#filter.getName();\n }\n\n /**\n * Execute the command.\n *\n * @fires RunFilterCommand#filterrun\n */\n execute() {\n // run filter and set app image\n this.#app.setImage(this.#dataId, this.#filter.update());\n // update display\n this.#app.render(this.#dataId);\n /**\n * Filter run event.\n *\n * @event RunFilterCommand#filterrun\n * @type {object}\n * @property {string} type The event type: filterrun.\n * @property {number} id The id of the run command.\n */\n const event = {\n type: 'filterrun',\n id: this.getName(),\n dataId: this.#dataId\n };\n // callback\n this.onExecute(event);\n }\n\n /**\n * Undo the command.\n *\n * @fires RunFilterCommand#filterundo\n */\n undo() {\n // reset the image\n this.#app.setImage(this.#dataId, this.#filter.getOriginalImage());\n // update display\n this.#app.render(this.#dataId);\n /**\n * Filter undo event.\n *\n * @event RunFilterCommand#filterundo\n * @type {object}\n * @property {string} type The event type: filterundo.\n * @property {number} id The id of the undone run command.\n */\n const event = {\n type: 'filterundo',\n id: this.getName(),\n dataid: this.#dataId\n }; // callback\n this.onUndo(event);\n }\n\n /**\n * Handle an execute event.\n *\n * @param {object} _event The execute event with type and id.\n */\n onExecute(_event) {\n // default does nothing.\n }\n\n /**\n * Handle an undo event.\n *\n * @param {object} _event The undo event with type and id.\n */\n onUndo(_event) {\n // default does nothing.\n }\n\n} // RunFilterCommand class\n","import {WindowLevel} from './windowLevel';\nimport {Scroll} from './scroll';\nimport {ZoomAndPan} from './zoomPan';\nimport {Opacity} from './opacity';\nimport {Draw} from './draw';\nimport {Floodfill} from './floodfill';\nimport {Livewire} from './livewire';\n\nimport {ArrowFactory} from './arrow';\nimport {CircleFactory} from './circle';\nimport {EllipseFactory} from './ellipse';\nimport {ProtractorFactory} from './protractor';\nimport {RectangleFactory} from './rectangle';\nimport {RoiFactory} from './roi';\nimport {RulerFactory} from './ruler';\n\nimport {Filter, Threshold, Sobel, Sharpen} from './filter';\n\n/**\n * List of client provided tools to be added to\n * the default ones.\n *\n * @example\n * // custom tool\n * class AlertTool {\n * mousedown() {alert('AlertTool mousedown');}\n * init() {}\n * activate() {}\n * }\n * // pass it to dwv tool list\n * dwv.toolList['Alert'] = AlertTool;\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Alert: {}};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n * app.setTool('Alert');\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n *\n * @type {Object}\n */\nexport const toolList = {};\n\n/**\n * List of client provided tool options to be added to\n * the default ones.\n *\n * @example\n * // custom factory\n * class LoveFactory {\n * getName() {return 'love';}\n * static supports(mathShape) {return mathShape instanceof ROI;}\n * getNPoints() {return 1;}\n * getTimeout() {return 0;}\n * setAnnotationMathShape(annotation, points) {\n * const px = points[0].getX();\n * const py = points[0].getY();\n * annotation.mathShape = new dwv.ROI([\n * new dwv.Point2D(px+15,py), new dwv.Point2D(px+10,py-10),\n * new dwv.Point2D(px,py), new dwv.Point2D(px-10,py-10),\n * new dwv.Point2D(px-15,py), new dwv.Point2D(px,py+20)\n * ]);\n * annotation.getFactory = function () {return new LoveFactory();}\n * }\n * createShapeGroup(annotation, style) {\n * const roi = annotation.mathShape;\n * // konva line\n * const arr = [];\n * for (let i = 0; i < roi.getLength(); ++i) {\n * arr.push(roi.getPoint(i).getX());\n * arr.push(roi.getPoint(i).getY());\n * }\n * const shape = new Konva.Line({\n * name: 'shape', points: arr,\n * stroke: 'red', strokeWidth: 2,\n * closed: true\n * });\n * // konva group\n * const group = new Konva.Group();\n * group.name('love-group');\n * group.visible(true);\n * group.id(annotation.id);\n * group.add(shape);\n * return group;\n * }\n * }\n * // pass it to dwv option list\n * dwv.toolOptions['draw'] = {LoveFactory};\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Draw: {options: ['Love']}};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n * app.setTool('Draw');\n * app.setToolFeatures({shapeName: 'Love'});\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n *\n * @type {Object>}\n */\nexport const toolOptions = {};\n\n/**\n * Default tool list.\n *\n * @type {Object}\n */\nexport const defaultToolList = {\n WindowLevel,\n Scroll,\n ZoomAndPan,\n Opacity,\n Draw,\n Filter,\n Floodfill,\n Livewire\n};\n\n/**\n * Default tool options.\n *\n * @type {Object>}\n */\nexport const defaultToolOptions = {\n draw: {\n ArrowFactory,\n CircleFactory,\n EllipseFactory,\n ProtractorFactory,\n RectangleFactory,\n RoiFactory,\n RulerFactory\n },\n filter: {\n Threshold,\n Sobel,\n Sharpen\n }\n};","import {ScrollWheel} from './scrollWheel';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\nimport {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {\n validateWindowWidth,\n WindowLevel as WindowLevelValues\n} from '../image/windowLevel';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * WindowLevel tool: handle window/level related events.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {WindowLevel: new dwv.ToolConfig()};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n * app.setTool('WindowLevel');\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\nexport class WindowLevel {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #started = false;\n\n /**\n * Start point.\n *\n * @type {Point2D}\n */\n #startPoint;\n\n /**\n * Scroll wheel handler.\n *\n * @type {ScrollWheel}\n */\n #scrollWhell;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n this.#scrollWhell = new ScrollWheel(app);\n }\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n * @param {string} divId The layer group divId.\n */\n #start(point, divId) {\n // check if possible\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n if (!viewController.isMonochrome()) {\n return;\n }\n\n this.#started = true;\n this.#startPoint = point;\n }\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #update(point, divId) {\n // check start flag\n if (!this.#started) {\n return;\n }\n\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n\n // difference to last position\n const diffX = point.getX() - this.#startPoint.getX();\n const diffY = this.#startPoint.getY() - point.getY();\n // data range\n const range = viewController.getImageRescaledDataRange();\n // 1/1000 seems to give reasonable results...\n const pixelToIntensity = (range.max - range.min) * 0.01;\n\n // calculate new window level\n const center = viewController.getWindowLevel().center;\n const width = viewController.getWindowLevel().width;\n const windowCenter = center + Math.round(diffY * pixelToIntensity);\n let windowWidth = width + Math.round(diffX * pixelToIntensity);\n // bound window width\n windowWidth = validateWindowWidth(windowWidth);\n // set\n const wl = new WindowLevelValues(windowCenter, windowWidth);\n viewController.setWindowLevel(wl);\n\n // store position\n this.#startPoint = point;\n }\n\n /**\n * Finish tool interaction.\n */\n #finish() {\n if (this.#started) {\n this.#started = false;\n }\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} _event The mouse up event.\n */\n mouseup = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle mouse out event.\n *\n * @param {object} _event The mouse out event.\n */\n mouseout = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} _event The touch end event.\n */\n touchend = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle double click event.\n *\n * @param {object} event The double click event.\n */\n dblclick = (event) => {\n const layerDetails = getLayerDetailsFromEvent(event);\n const mousePoint = getMousePoint(event);\n\n const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const index = viewLayer.displayToPlaneIndex(mousePoint);\n const viewController = viewLayer.getViewController();\n // exit if not possible\n if (!viewController.isMonochrome()) {\n return;\n }\n\n // update view controller\n const image = this.#app.getData(viewLayer.getDataId()).image;\n const wl = new WindowLevelValues(\n image.getRescaledValueAtIndex(\n viewController.getCurrentIndex().getWithNew2D(\n index.get(0),\n index.get(1)\n )\n ),\n viewController.getWindowLevel().width\n );\n viewController.setWindowLevel(wl);\n };\n\n /**\n * Handle mouse wheel event.\n *\n * @param {WheelEvent} event The mouse wheel event.\n */\n wheel = (event) => {\n this.#scrollWhell.wheel(event);\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n event.context = 'WindowLevel';\n this.#app.onKeydown(event);\n };\n\n /**\n * Activate the tool.\n *\n * @param {boolean} _bool The flag to activate or not.\n */\n activate(_bool) {\n // does nothing\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n /**\n * Set the tool live features: does nothing.\n *\n * @param {object} _features The list of features.\n */\n setFeatures(_features) {\n // does nothing\n }\n\n} // WindowLevel class\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\nimport {ScrollWheel} from './scrollWheel';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * Scroll class.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Scroll: new dwv.ToolConfig()};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n * app.setTool('Scroll');\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm',\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323707.dcm',\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323563.dcm'\n * ]);\n * @example Example with slider\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Scroll: new dwv.ToolConfig()};\n * app.init(options);\n * // create range\n * const range = document.createElement('input');\n * range.type = 'range';\n * range.min = 0;\n * range.id = 'sliceRange';\n * document.body.appendChild(range);\n * // update app on slider change\n * range.oninput = function () {\n * const lg = app.getLayerGroupByDivId('layerGroup0');\n * const vc = lg.getActiveViewLayer().getViewController();\n * const index = vc.getCurrentIndex();\n * const values = index.getValues();\n * values[2] = this.value;\n * vc.setCurrentIndex(new dwv.Index(values));\n * }\n * // activate tool and update range max on load\n * app.addEventListener('load', function () {\n * app.setTool('Scroll');\n * const size = app.getData(0).image.getGeometry().getSize();\n * range.max = size.get(2) - 1;\n * });\n * // update slider on slice change (for ex via mouse wheel)\n * app.addEventListener('positionchange', function () {\n * const lg = app.getLayerGroupByDivId('layerGroup0');\n * const vc = lg.getActiveViewLayer().getViewController();\n * range.value = vc.getCurrentIndex().get(2);\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm',\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323707.dcm',\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323563.dcm'\n * ]);\n */\nexport class Scroll {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #started = false;\n\n /**\n * Start point.\n *\n * @type {Point2D}\n */\n #startPoint;\n\n /**\n * Scroll wheel handler.\n *\n * @type {ScrollWheel}\n */\n #scrollWhell;\n\n /**\n * Touch timer ID (created by setTimeout).\n *\n * @type {number}\n */\n #touchTimerID;\n\n /**\n * Option to show or not a value tooltip on mousemove.\n *\n * @type {boolean}\n */\n #displayTooltip = false;\n\n /**\n * Current layer group div id.\n *\n * @type {string}\n */\n #currentDivId;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n this.#scrollWhell = new ScrollWheel(app);\n }\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n * @param {string} divId The layer group divId.\n */\n #start(point, divId) {\n // optional tooltip\n this.#removeTooltipDiv();\n\n // stop viewer if playing\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n if (viewController.isPlaying()) {\n viewController.stop();\n }\n\n // start flag\n this.#started = true;\n this.#startPoint = point;\n\n // update controller position\n const planePos = viewLayer.displayToPlanePos(point);\n const position = viewController.getPositionFromPlanePoint(planePos);\n viewController.setCurrentPosition(position);\n }\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #update(point, divId) {\n if (!this.#started) {\n // optional tooltip\n if (this.#displayTooltip) {\n this.#showTooltip(point, divId);\n }\n return;\n }\n\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n\n let newPosition;\n\n // difference to last Y position\n const diffY = point.getY() - this.#startPoint.getY();\n const yMove = (Math.abs(diffY) > 15);\n // do not trigger for small moves\n if (yMove && layerGroup.canScroll()) {\n // update view controller\n if (diffY > 0) {\n newPosition = viewController.getDecrementScrollPosition();\n } else {\n newPosition = viewController.getIncrementScrollPosition();\n }\n }\n\n // difference to last X position\n const diffX = point.getX() - this.#startPoint.getX();\n const xMove = (Math.abs(diffX) > 15);\n // do not trigger for small moves\n if (xMove && layerGroup.moreThanOne(3)) {\n // update view controller\n if (diffX > 0) {\n newPosition = viewController.getIncrementPosition(3);\n } else {\n newPosition = viewController.getDecrementPosition(3);\n }\n }\n\n // set all layers if at least one can be set\n if (typeof newPosition !== 'undefined' &&\n layerGroup.isPositionInBounds(newPosition)) {\n viewController.setCurrentPosition(newPosition);\n }\n\n // reset origin point\n if (xMove || yMove) {\n this.#startPoint = point;\n }\n }\n\n /**\n * Finish tool interaction.\n */\n #finish() {\n if (this.#started) {\n this.#started = false;\n }\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} _event The mouse up event.\n */\n mouseup = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle mouse out event.\n *\n * @param {object} _event The mouse out event.\n */\n mouseout = (_event) => {\n this.#finish();\n // remove possible tooltip div\n this.#removeTooltipDiv();\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n // long touch triggers the dblclick\n // @ts-ignore\n this.#touchTimerID = setTimeout(() => {\n this.dblclick(event);\n }, 500);\n // call start\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n // abort timer if move\n if (this.#touchTimerID !== null) {\n clearTimeout(this.#touchTimerID);\n this.#touchTimerID = null;\n }\n // call update\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} _event The touch end event.\n */\n touchend = (_event) => {\n // abort timer\n if (this.#touchTimerID !== null) {\n clearTimeout(this.#touchTimerID);\n this.#touchTimerID = null;\n }\n // call mouse equivalent\n this.#finish();\n };\n\n /**\n * Handle mouse wheel event.\n *\n * @param {WheelEvent} event The mouse wheel event.\n */\n wheel = (event) => {\n this.#scrollWhell.wheel(event);\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n event.context = 'Scroll';\n this.#app.onKeydown(event);\n };\n\n /**\n * Handle double click.\n *\n * @param {object} event The key down event.\n */\n dblclick = (event) => {\n const layerDetails = getLayerDetailsFromEvent(event);\n\n const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n viewController.play();\n };\n\n /**\n * Display a tooltip at the given point.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #showTooltip(point, divId) {\n // get layer group\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n this.#currentDivId = divId;\n // show new tooltip\n layerGroup.showTooltip(point);\n }\n\n /**\n * Remove the last tooltip html div.\n */\n #removeTooltipDiv() {\n if (typeof this.#currentDivId !== 'undefined') {\n const layerGroup = this.#app.getLayerGroupByDivId(this.#currentDivId);\n layerGroup.removeTooltipDiv();\n this.#currentDivId = undefined;\n }\n }\n\n /**\n * Activate the tool.\n *\n * @param {boolean} _bool The flag to activate or not.\n */\n activate(_bool) {\n // remove tooltip html when deactivating\n if (!_bool) {\n this.#removeTooltipDiv();\n }\n }\n\n /**\n * Set the tool live features: disaply tooltip.\n *\n * @param {object} features The list of features.\n */\n setFeatures(features) {\n if (typeof features.displayTooltip !== 'undefined') {\n this.#displayTooltip = features.displayTooltip;\n }\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n} // Scroll class\n","import {Point2D} from '../math/point';\nimport {Line} from '../math/line';\nimport {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * ZoomAndPan class.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {ZoomAndPan: new dwv.ToolConfig()};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n * app.setTool('ZoomAndPan');\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\nexport class ZoomAndPan {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #started = false;\n\n /**\n * Start point.\n *\n * @type {Point2D}\n */\n #startPoint;\n\n /**\n * Move flag: true if mouse or touch move.\n *\n * @type {boolean}\n */\n #hasMoved;\n\n /**\n * Line between input points.\n *\n * @type {Line}\n */\n #pointsLine;\n\n /**\n * PointsLine midpoint.\n *\n * @type {Point2D}\n */\n #midPoint;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n */\n #start(point) {\n this.#started = true;\n this.#startPoint = point;\n this.#hasMoved = false;\n }\n\n /**\n * Two touch start.\n *\n * @param {Point2D[]} points The start points.\n */\n #twoTouchStart = (points) => {\n this.#started = true;\n this.#startPoint = points[0];\n this.#hasMoved = false;\n // points line\n this.#pointsLine = new Line(points[0], points[1]);\n this.#midPoint = this.#pointsLine.getMidpoint();\n };\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #update(point, divId) {\n if (!this.#started) {\n return;\n }\n this.#hasMoved = true;\n\n // calculate translation\n const tx = point.getX() - this.#startPoint.getX();\n const ty = point.getY() - this.#startPoint.getY();\n // apply translation\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n const planeOffset = viewLayer.displayToPlaneScale(\n new Point2D(tx, ty)\n );\n const offset3D = viewController.getOffset3DFromPlaneOffset({\n x: planeOffset.getX(),\n y: planeOffset.getY()\n });\n layerGroup.addTranslation({\n x: offset3D.getX(),\n y: offset3D.getY(),\n z: offset3D.getZ()\n });\n layerGroup.draw();\n // reset origin point\n this.#startPoint = point;\n }\n\n /**\n * Two touch update.\n *\n * @param {Point2D[]} points The update points.\n * @param {string} divId The layer group divId.\n */\n #twoTouchUpdate = (points, divId) => {\n if (!this.#started) {\n return;\n }\n this.#hasMoved = true;\n\n const newLine = new Line(points[0], points[1]);\n const lineRatio = newLine.getLength() / this.#pointsLine.getLength();\n\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n\n if (lineRatio === 1) {\n // scroll mode\n // difference to last position\n const diffY = points[0].getY() - this.#startPoint.getY();\n // do not trigger for small moves\n if (Math.abs(diffY) < 15) {\n return;\n }\n // update view controller\n if (layerGroup.canScroll()) {\n let newPosition;\n if (diffY > 0) {\n newPosition = viewController.getIncrementScrollPosition();\n } else {\n newPosition = viewController.getDecrementScrollPosition();\n }\n // set all layers if at least one can be set\n if (typeof newPosition !== 'undefined' &&\n layerGroup.isPositionInBounds(newPosition)) {\n viewController.setCurrentPosition(newPosition);\n }\n }\n } else {\n // zoom mode\n const zoom = (lineRatio - 1) / 10;\n if (Math.abs(zoom) % 0.1 <= 0.05 &&\n typeof this.#midPoint !== 'undefined') {\n const planePos = viewLayer.displayToMainPlanePos(this.#midPoint);\n const center = viewController.getPlanePositionFromPlanePoint(planePos);\n layerGroup.addScale(zoom, center);\n layerGroup.draw();\n }\n }\n };\n\n /**\n * Set the current position.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #setCurrentPosition(point, divId) {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n const planePos = viewLayer.displayToPlanePos(point);\n const position = viewController.getPositionFromPlanePoint(planePos);\n viewController.setCurrentPosition(position);\n }\n\n /**\n * Finish tool interaction.\n */\n #finish() {\n if (this.#started) {\n this.#started = false;\n }\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n const mousePoint = getMousePoint(event);\n this.#start(mousePoint);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} event The mouse up event.\n */\n mouseup = (event) => {\n // update position if no move\n if (!this.#hasMoved) {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#setCurrentPosition(mousePoint, layerDetails.groupDivId);\n }\n this.#finish();\n };\n\n /**\n * Handle mouse out event.\n *\n * @param {object} _event The mouse out event.\n */\n mouseout = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n const touchPoints = getTouchPoints(event);\n if (touchPoints.length === 1) {\n this.#start(touchPoints[0]);\n } else if (touchPoints.length === 2) {\n this.#twoTouchStart(touchPoints);\n }\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n if (touchPoints.length === 1) {\n this.#update(touchPoints[0], layerDetails.groupDivId);\n } else if (touchPoints.length === 2) {\n this.#twoTouchUpdate(touchPoints, layerDetails.groupDivId);\n }\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} event The touch end event.\n */\n touchend = (event) => {\n // update position if no move\n if (!this.#hasMoved) {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#setCurrentPosition(mousePoint, layerDetails.groupDivId);\n }\n this.#finish();\n };\n\n /**\n * Handle mouse wheel event.\n *\n * @param {object} event The mouse wheel event.\n */\n wheel = (event) => {\n // prevent default page scroll\n event.preventDefault();\n\n const step = -event.deltaY / 500;\n\n const layerDetails = getLayerDetailsFromEvent(event);\n const mousePoint = getMousePoint(event);\n\n const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n const planePos = viewLayer.displayToMainPlanePos(mousePoint);\n const center = viewController.getPlanePositionFromPlanePoint(planePos);\n layerGroup.addScale(step, center);\n layerGroup.draw();\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n event.context = 'ZoomAndPan';\n this.#app.onKeydown(event);\n };\n\n /**\n * Activate the tool.\n *\n * @param {boolean} _bool The flag to activate or not.\n */\n activate(_bool) {\n // does nothing\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n /**\n * Set the tool live features: does nothing.\n *\n * @param {object} _features The list of features.\n */\n setFeatures(_features) {\n // does nothing\n }\n\n} // ZoomAndPan class\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {ScrollWheel} from './scrollWheel';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * Opacity class.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Opacity: new dwv.ToolConfig()};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n * app.setTool('Opacity');\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\nexport class Opacity {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #started = false;\n\n /**\n * Start point.\n *\n * @type {Point2D}\n */\n #startPoint;\n\n /**\n * Scroll wheel handler.\n *\n * @type {ScrollWheel}\n */\n #scrollWhell;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n this.#scrollWhell = new ScrollWheel(app);\n }\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n */\n #start(point) {\n this.#started = true;\n this.#startPoint = point;\n }\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #update(point, divId) {\n if (!this.#started) {\n return;\n }\n\n // difference to last X position\n const diffX = point.getX() - this.#startPoint.getX();\n const xMove = (Math.abs(diffX) > 15);\n // do not trigger for small moves\n if (xMove) {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const op = viewLayer.getOpacity();\n viewLayer.setOpacity(op + (diffX / 200));\n viewLayer.draw();\n\n // reset origin point\n this.#startPoint = point;\n }\n }\n\n /**\n * Finish tool interaction.\n */\n #finish() {\n if (this.#started) {\n this.#started = false;\n }\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n const mousePoint = getMousePoint(event);\n this.#start(mousePoint);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} _event The mouse up event.\n */\n mouseup = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle mouse out event.\n *\n * @param {object} _event The mouse out event.\n */\n mouseout = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n const touchPoints = getTouchPoints(event);\n this.#start(touchPoints[0]);\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} _event The touch end event.\n */\n touchend = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle mouse wheel event.\n *\n * @param {object} event The mouse wheel event.\n */\n wheel = (event) => {\n this.#scrollWhell.wheel(event);\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n event.context = 'Opacity';\n this.#app.onKeydown(event);\n };\n\n /**\n * Activate the tool.\n *\n * @param {boolean} _bool The flag to activate or not.\n */\n activate(_bool) {\n // does nothing\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n /**\n * Set the tool live features: does nothing.\n *\n * @param {object} _features The list of features.\n */\n setFeatures(_features) {\n // does nothing\n }\n\n} // Opacity class\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\nimport {guid} from '../math/stats';\nimport {logger} from '../utils/logger';\nimport {\n AddAnnotationCommand,\n RemoveAnnotationCommand\n} from './drawCommands';\nimport {\n isNodeNameShape,\n} from './drawBounds';\nimport {Annotation} from '../image/annotation';\nimport {ScrollWheel} from './scrollWheel';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {Style} from '../gui/style';\nimport {LayerGroup} from '../gui/layerGroup';\nimport {Point2D} from '../math/point';\nimport {DrawLayer} from '../gui/drawLayer';\nimport {DrawShapeHandler} from './drawShapeHandler';\n/* eslint-enable no-unused-vars */\n\n/**\n * Drawing tool.\n *\n * This tool is responsible for the draw of layer group structure.\n *\n * ```\n * drawLayer\n * |_ positionGroup: {name=\"position-group\", id=\"#2-0#_#3-1\"}\n * |_ shapeGroup: {name=\"{shape name}-group\", id=\"#\"}\n * |_ shape: {name=\"shape\"},\n * |_ label: {name=\"label\"},\n * |_ extra: line tick, protractor arc...\n * ```\n *\n * Discussion:\n * - posGroup > shapeGroup:\n * (pro) slice/frame display: 1 loop -\n * (cons) multi-slice shape splitted in positionGroups.\n * - shapeGroup > posGroup:\n * (pros) more logical -\n * (cons) slice/frame display: 2 loops.\n */\nexport class Draw {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Scroll wheel handler.\n *\n * @type {ScrollWheel}\n */\n #scrollWhell;\n\n /**\n * Drawing style.\n *\n * @type {Style}\n */\n #style;\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #isDrawing = false;\n\n /**\n * Shape factory list.\n *\n * @type {object}\n */\n #shapeFactoryList = null;\n\n /**\n * Current shape factory.\n *\n * @type {object}\n */\n #currentFactory = null;\n\n /**\n * Current shape group.\n *\n * @type {object}\n */\n #tmpShapeGroup = null;\n\n /**\n * Shape name.\n *\n * @type {string}\n */\n #shapeName;\n\n /**\n * List of points.\n *\n * @type {Point2D[]}\n */\n #points = [];\n\n /**\n * Last selected point.\n *\n * @type {Point2D}\n */\n #lastPoint = null;\n\n /**\n * With scroll flag.\n *\n * @type {boolean}\n */\n #withScroll = true;\n\n /**\n * Black list: list of dataIds for which draw layer creation\n * is forbidden.\n */\n #blacklist = [];\n\n /**\n * Shape handler: activate listeners on existing shape.\n *\n * @type {DrawShapeHandler}\n */\n #shapeHandler;\n\n /**\n * Auto shape colour: will use defaults colours and\n * vary them according to the layer.\n *\n * @type {boolean}\n */\n #autoShapeColour = false;\n\n /**\n * Event listeners.\n */\n #listeners = {};\n\n /**\n * Flag to know if the last added point was made by mouse move.\n *\n * @type {boolean}\n */\n #lastIsMouseMovePoint = false;\n\n /**\n * Callback store to allow attach/detach.\n *\n * @type {Array}\n */\n #callbackStore = [];\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n this.#scrollWhell = new ScrollWheel(app);\n this.#shapeHandler = new DrawShapeHandler(app, this.#fireEvent);\n\n this.#style = app.getStyle();\n }\n\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n * @param {string} divId The layer group divId.\n */\n #switchEditOrCreateShapeGroup(point, divId) {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n let drawLayer = layerGroup.getActiveDrawLayer();\n\n if (typeof drawLayer === 'undefined') {\n const viewLayer = layerGroup.getActiveViewLayer();\n const refDataId = viewLayer.getDataId();\n const refData = this.#app.getData(refDataId);\n const refMeta = refData.image.getMeta();\n const seriesInstanceUID = refMeta.SeriesInstanceUID;\n // check black list\n if (this.#blacklist.includes(seriesInstanceUID)) {\n /**\n * Warn event.\n *\n * @event Draw#warn\n * @type {object}\n * @property {string} type The event type.\n * @property {string} message The warning message.\n */\n this.#fireEvent({\n type: 'warn',\n message: 'Cannot create draw layer, data is in black list'\n });\n return;\n }\n // create new data\n const data = this.#app.createAnnotationData(refDataId);\n // render (will create draw layer)\n this.#app.addAndRenderAnnotationData(data, divId, refDataId);\n // get draw layer\n drawLayer = layerGroup.getActiveDrawLayer();\n // set the layer shape handler\n drawLayer.setShapeHandler(this.#shapeHandler);\n // set active to bind to toolboxController\n layerGroup.setActiveDrawLayerByDataId(drawLayer.getDataId());\n }\n\n // data should exist / be created\n const data = drawLayer.getDrawController().getAnnotationGroup();\n\n const stage = drawLayer.getKonvaStage();\n\n // update scale\n this.#style.setZoomScale(stage.scale());\n\n if (data.isEditable()) {\n // determine if the click happened on an existing shape or not\n const kshape = stage.getIntersection({\n x: point.getX(),\n y: point.getY()\n });\n if (kshape) {\n // select shape for edition\n this.#selectShapeGroup(drawLayer, kshape);\n } else {\n // create new shape\n this.#startShapeGroupCreation(layerGroup, point);\n }\n }\n }\n\n /**\n * Initializes the new shape creation:\n * - Updates the started variable,\n * - Gets the factory,\n * - Initializes the points array.\n *\n * @param {LayerGroup} layerGroup The layer group where the user clicks.\n * @param {Point2D} point The start point where the user clicks.\n */\n #startShapeGroupCreation(layerGroup, point) {\n // disable edition\n this.#shapeHandler.disableAndResetEditor();\n this.#setToDrawingState();\n // store point\n const viewLayer = layerGroup.getActiveViewLayer();\n this.#lastPoint = viewLayer.displayToPlanePos(point);\n this.#points.push(this.#lastPoint);\n }\n\n /**\n * Sets the variables to drawing state:\n * - Updates is drawing variable,\n * - Initializes the current factory,\n * - Resets points.\n */\n #setToDrawingState() {\n // start storing points\n this.#isDrawing = true;\n // set factory\n this.#currentFactory = new this.#shapeFactoryList[this.#shapeName]();\n // clear array\n this.#points = [];\n }\n\n /**\n * Resets the variables to not drawing state:\n * - Destroys tmp shape group,\n * - Updates is drawing variable,\n * - Resets points.\n */\n #setToNotDrawingState() {\n this.#isDrawing = false;\n this.#points = [];\n }\n\n /**\n * Selects a shape group.\n *\n * @param {DrawLayer} drawLayer The draw layer where to draw.\n * @param {Konva.Shape} kshape The shape that has been selected.\n */\n #selectShapeGroup(drawLayer, kshape) {\n let group = kshape.getParent();\n // kshape: Konva.Tag -> parent: Konva.Label -> parent: Konva.Group\n if (kshape instanceof Konva.Tag) {\n group = group.getParent();\n }\n const selectedShape = group.find('.shape')[0];\n if (!(selectedShape instanceof Konva.Shape)) {\n return;\n }\n /**\n * Annotation select event.\n *\n * @event Draw#annotationselect\n * @type {object}\n * @property {string} type The event type.\n * @property {string} annotationid The annotation id.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'annotationselect',\n annotationid: group.id(),\n dataid: drawLayer.getDataId()\n });\n this.#shapeHandler.setEditorShape(selectedShape, drawLayer);\n }\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #updateShapeGroupCreation(point, divId) {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const pos = viewLayer.displayToPlanePos(point);\n\n // draw line to current pos\n if (Math.abs(pos.getX() - this.#lastPoint.getX()) > 0 ||\n Math.abs(pos.getY() - this.#lastPoint.getY()) > 0) {\n // clear last mouse move point\n if (this.#lastIsMouseMovePoint) {\n this.#points.pop();\n }\n // current point\n this.#lastPoint = pos;\n // mark it as temporary\n this.#lastIsMouseMovePoint = true;\n // add it to the list\n this.#points.push(this.#lastPoint);\n // update points\n this.#onNewPoints(this.#points, layerGroup);\n }\n }\n\n /**\n * Finish tool interaction.\n *\n * @param {string} divId The layer group divId.\n */\n #finishShapeGroupCreation(divId) {\n // exit if no points\n if (this.#points.length === 0) {\n logger.warn('Draw mouseup but no points...');\n return;\n }\n\n // do we have all the needed points\n if (this.#points.length === this.#currentFactory.getNPoints()) {\n // store points\n const layerGroup =\n this.#app.getLayerGroupByDivId(divId);\n this.#onFinalPoints(this.#points, layerGroup);\n this.#setToNotDrawingState();\n }\n\n // reset mouse move point flag\n this.#lastIsMouseMovePoint = false;\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n // exit if not started draw\n if (this.#isDrawing) {\n return;\n }\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#switchEditOrCreateShapeGroup(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n // exit if not started draw\n if (!this.#isDrawing) {\n return;\n }\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#updateShapeGroupCreation(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} event The mouse up event.\n */\n mouseup = (event) => {\n // exit if not started draw\n if (!this.#isDrawing) {\n return;\n }\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#finishShapeGroupCreation(layerDetails.groupDivId);\n };\n\n /**\n * Handle double click event: some tools use it to finish interaction.\n *\n * @param {object} event The double click event.\n */\n dblclick = (event) => {\n // only end by double click undefined NPoints\n if (this.#currentFactory &&\n typeof this.#currentFactory.getNPoints() !== 'undefined') {\n return;\n }\n // exit if not started draw\n if (!this.#isDrawing) {\n return;\n }\n // exit if no points\n if (this.#points.length === 0) {\n logger.warn('Draw dblclick but no points...');\n return;\n }\n\n // store points\n const layerDetails = getLayerDetailsFromEvent(event);\n const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n this.#onFinalPoints(this.#points, layerGroup);\n this.#setToNotDrawingState();\n };\n\n /**\n * Handle mouse out event.\n *\n * @param {object} event The mouse out event.\n */\n mouseout = (event) => {\n // exit if not started draw\n if (!this.#isDrawing) {\n return;\n }\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#finishShapeGroupCreation(layerDetails.groupDivId);\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n // exit if not started draw\n if (this.#isDrawing) {\n return;\n }\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#switchEditOrCreateShapeGroup(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n // exit if not started draw\n if (!this.#isDrawing) {\n return;\n }\n\n const layerDetails = getLayerDetailsFromEvent(event);\n const touchPoints = getTouchPoints(event);\n\n const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const pos = viewLayer.displayToPlanePos(touchPoints[0]);\n\n if (Math.abs(pos.getX() - this.#lastPoint.getX()) > 0 ||\n Math.abs(pos.getY() - this.#lastPoint.getY()) > 0) {\n // clear last added point from the list (but not the first one)\n if (this.#points.length !== 1) {\n this.#points.pop();\n }\n // current point\n this.#lastPoint = pos;\n // add current one to the list\n this.#points.push(this.#lastPoint);\n // allow for anchor points\n if (this.#points.length < this.#currentFactory.getNPoints()) {\n clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.#points.push(this.#lastPoint);\n }, this.#currentFactory.getTimeout());\n }\n // update points\n this.#onNewPoints(this.#points, layerGroup);\n }\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} event The touch end event.\n */\n touchend = (event) => {\n this.dblclick(event);\n };\n\n /**\n * Handle mouse wheel event.\n *\n * @param {WheelEvent} event The mouse wheel event.\n */\n wheel = (event) => {\n if (this.#withScroll) {\n this.#scrollWhell.wheel(event);\n }\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n // call app handler if we are not in the middle of a draw\n if (!this.#isDrawing) {\n event.context = 'Draw';\n this.#app.onKeydown(event);\n }\n\n // press delete or backspace key\n const annotation = this.#shapeHandler.getEditorAnnotation();\n if ((event.key === 'Delete' ||\n event.key === 'Backspace') &&\n typeof annotation !== 'undefined') {\n const layerGroup = this.#app.getActiveLayerGroup();\n const drawLayer = layerGroup.getActiveDrawLayer();\n const drawController = drawLayer.getDrawController();\n\n // create remove annotation command\n const command = new RemoveAnnotationCommand(annotation, drawController);\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // execute command: triggers draw remove\n command.execute();\n\n // reset cursor\n this.#shapeHandler.onMouseOutShapeGroup();\n }\n\n // escape key: exit shape creation\n if (event.key === 'Escape' && this.#tmpShapeGroup !== null) {\n const konvaLayer = this.#tmpShapeGroup.getLayer();\n // reset temporary shape group\n this.#tmpShapeGroup.destroy();\n this.#tmpShapeGroup = null;\n // set state\n this.#setToNotDrawingState();\n // redraw\n konvaLayer.draw();\n }\n };\n\n /**\n * Update the current draw with new points.\n *\n * @param {Point2D[]} tmpPoints The array of new points.\n * @param {LayerGroup} layerGroup The origin layer group.\n */\n #onNewPoints(tmpPoints, layerGroup) {\n // remove temporary shape draw\n if (this.#tmpShapeGroup) {\n this.#tmpShapeGroup.destroy();\n this.#tmpShapeGroup = null;\n }\n\n const drawLayer = layerGroup.getActiveDrawLayer();\n const drawController = drawLayer.getDrawController();\n const konvaLayer = drawLayer.getKonvaLayer();\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n\n // auto mode: vary shape colour with layer id\n if (this.#autoShapeColour) {\n const colours = [\n '#ffff80', '#ff80ff', '#80ffff', '#80ff80', '8080ff', 'ff8080'\n ];\n // warning: depends on layer id nomenclature\n const drawLayerId = drawLayer.getId();\n const layerId = drawLayerId.substring(drawLayerId.length - 1);\n const layerIndex = parseInt(layerId, 10) - 1;\n const colour = colours[layerIndex];\n if (typeof colour !== 'undefined') {\n this.#style.setLineColour(colour);\n }\n }\n\n // create tmp annotation\n const annotation = new Annotation();\n // use group colour if defined\n const groupColour = drawController.getAnnotationGroup().getColour();\n if (typeof groupColour !== 'undefined') {\n annotation.colour = groupColour;\n } else {\n annotation.colour = this.#style.getLineColour();\n }\n annotation.init(viewController);\n // set annotation shape\n this.#currentFactory.setAnnotationMathShape(annotation, tmpPoints);\n // create shape group\n this.#tmpShapeGroup =\n this.#currentFactory.createShapeGroup(annotation, this.#style);\n // set the label visibility\n drawLayer.setLabelVisibility(this.#tmpShapeGroup);\n\n // do not listen during creation\n const shape = this.#tmpShapeGroup.getChildren(isNodeNameShape)[0];\n shape.listening(false);\n konvaLayer.listening(false);\n // draw shape\n konvaLayer.add(this.#tmpShapeGroup);\n konvaLayer.draw();\n }\n\n /**\n * Create the final shape from a point list.\n *\n * @param {Point2D[]} finalPoints The array of points.\n * @param {LayerGroup} layerGroup The origin layer group.\n */\n #onFinalPoints(finalPoints, layerGroup) {\n // remove temporary shape draw\n // (has to be done before sending add event)\n if (this.#tmpShapeGroup) {\n this.#tmpShapeGroup.destroy();\n this.#tmpShapeGroup = null;\n }\n\n const drawLayer = layerGroup.getActiveDrawLayer();\n const konvaLayer = drawLayer.getKonvaLayer();\n const drawController = drawLayer.getDrawController();\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n\n // create final annotation\n const annotation = new Annotation();\n // use group colour if defined\n const groupColour = drawController.getAnnotationGroup().getColour();\n if (typeof groupColour !== 'undefined') {\n annotation.colour = groupColour;\n } else {\n annotation.colour = this.#style.getLineColour();\n }\n annotation.id = guid();\n annotation.init(viewController);\n // set annotation shape\n this.#currentFactory.setAnnotationMathShape(annotation, finalPoints);\n\n // create add annotation command\n const command = new AddAnnotationCommand(annotation, drawController);\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // execute command: triggers draw creation\n command.execute();\n\n // re-activate layer\n konvaLayer.listening(true);\n }\n\n /**\n * Get a DrawLayer position callback.\n *\n * TODO: check need for store item removal.\n *\n * @param {DrawLayer} layer The layer to update.\n * @returns {Function} The callback.\n */\n #getPositionCallback(layer) {\n const layerId = layer.getId();\n if (typeof this.#callbackStore[layerId] === 'undefined') {\n this.#callbackStore[layerId] = () => {\n layer.activateCurrentPositionShapes(true);\n };\n }\n return this.#callbackStore[layerId];\n }\n\n /**\n * Activate a draw layer.\n *\n * @param {DrawLayer} drawLayer The layer to update.\n * @param {boolean} flag The flag to activate or not.\n */\n #activateLayer(drawLayer, flag) {\n drawLayer.setShapeHandler(this.#shapeHandler);\n drawLayer.activateCurrentPositionShapes(flag);\n // update on position change\n if (flag) {\n this.#app.addEventListener('positionchange',\n this.#getPositionCallback(drawLayer)\n );\n } else {\n this.#app.removeEventListener('positionchange',\n this.#getPositionCallback(drawLayer)\n );\n }\n }\n\n /**\n * Activate the tool.\n *\n * @param {boolean} flag The flag to activate or not.\n */\n activate(flag) {\n // force cursor if deactivate\n if (!flag) {\n this.#shapeHandler.onMouseOutShapeGroup();\n }\n // update draw layers\n const drawLayers = this.#app.getDrawLayers();\n for (const drawLayer of drawLayers) {\n if (typeof drawLayer !== 'undefined') {\n this.#activateLayer(drawLayer, flag);\n }\n }\n // activate newly added layers\n this.#app.addEventListener('drawlayeradd', (event) => {\n const drawLayers = this.#app.getDrawLayers(function (item) {\n return item.getId() === event.layerid;\n });\n // should be just one\n if (drawLayers.length === 1) {\n this.#activateLayer(drawLayers[0], flag);\n }\n });\n\n }\n\n /**\n * Set the tool configuration options.\n *\n * @param {object} options The list of shape names amd classes.\n */\n setOptions(options) {\n // save the options as the shape factory list\n this.#shapeFactoryList = options;\n }\n\n /**\n * Get the type of tool options: here 'factory' since the shape\n * list contains factories to create each possible shape.\n *\n * @returns {string} The type.\n */\n getOptionsType() {\n return 'factory';\n }\n\n /**\n * Set the tool live features: shape colour and shape name.\n *\n * @param {object} features The list of features.\n */\n setFeatures(features) {\n if (typeof features.autoShapeColour !== 'undefined') {\n this.#autoShapeColour = features.autoShapeColour;\n }\n if (typeof features.shapeColour !== 'undefined') {\n this.#style.setLineColour(features.shapeColour);\n this.#autoShapeColour = false;\n }\n if (typeof features.shapeName !== 'undefined') {\n // check if we have it\n if (!this.hasShape(features.shapeName)) {\n throw new Error('Unknown shape: \\'' + features.shapeName + '\\'');\n }\n this.#shapeName = features.shapeName;\n }\n if (typeof features.mouseOverCursor !== 'undefined') {\n this.#shapeHandler.storeMouseOverCursor(features.mouseOverCursor);\n }\n if (typeof features.withScroll !== 'undefined') {\n this.#withScroll = features.withScroll;\n }\n if (typeof features.blacklist !== 'undefined') {\n this.#blacklist = features.blacklist;\n }\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n /**\n * Get the list of event names that this tool can fire.\n *\n * @returns {string[]} The list of event names.\n */\n getEventNames() {\n return [\n 'annotationupdate', 'annotationselect', 'warn'\n ];\n }\n\n /**\n * Add an event listener on the app.\n *\n * @param {string} type The event type.\n * @param {Function} listener The function associated with the provided\n * event type.\n */\n addEventListener(type, listener) {\n if (typeof this.#listeners[type] === 'undefined') {\n this.#listeners[type] = [];\n }\n this.#listeners[type].push(listener);\n }\n\n /**\n * Remove an event listener from the app.\n *\n * @param {string} type The event type.\n * @param {Function} listener The function associated with the provided\n * event type.\n */\n removeEventListener(type, listener) {\n if (typeof this.#listeners[type] === 'undefined') {\n return;\n }\n for (let i = 0; i < this.#listeners[type].length; ++i) {\n if (this.#listeners[type][i] === listener) {\n this.#listeners[type].splice(i, 1);\n }\n }\n }\n\n // Private Methods -----------------------------------------------------------\n\n /**\n * Fire an event: call all associated listeners.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n if (typeof this.#listeners[event.type] === 'undefined') {\n return;\n }\n for (let i = 0; i < this.#listeners[event.type].length; ++i) {\n this.#listeners[event.type][i](event);\n }\n };\n\n /**\n * Check if the shape is in the shape list.\n *\n * @param {string} name The name of the shape.\n * @returns {boolean} True if there is a factory for the shape.\n */\n hasShape(name) {\n return typeof this.#shapeFactoryList[name] !== 'undefined';\n }\n\n} // Draw class\n","import {Annotation} from '../image/annotation';\nimport {\n AddAnnotationCommand,\n UpdateAnnotationCommand\n} from '../tools/drawCommands';\n//import {RoiFactory} from '../tools/roi';\nimport {ROI} from '../math/roi';\nimport {guid} from '../math/stats';\nimport {Point2D} from '../math/point';\nimport {Style} from '../gui/style';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\nimport {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {ListenerHandler} from '../utils/listen';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {LayerGroup} from '../gui/layerGroup';\nimport {Scalar2D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * The magic wand namespace.\n *\n * Ref: {@link https://github.com/Tamersoul/magic-wand-js}.\n *\n * @external MagicWand\n */\nimport MagicWand from 'magic-wand-tool';\n\n/**\n * Floodfill painting tool.\n */\nexport class Floodfill {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Original variables from external library. Used as in the lib example.\n *\n * @type {number}\n */\n #blurRadius = 5;\n /**\n * Original variables from external library. Used as in the lib example.\n *\n * @type {number}\n */\n #simplifyTolerant = 0;\n\n /**\n * Original variables from external library. Used as in the lib example.\n *\n * @type {number}\n */\n #simplifyCount = 2000;\n\n /**\n * Canvas info.\n *\n * @type {object}\n */\n #imageInfo = null;\n\n /**\n * Object created by MagicWand lib containing border points.\n *\n * @type {object}\n */\n #mask = null;\n\n /**\n * Threshold default tolerance of the tool border.\n *\n * @type {number}\n */\n #initialthreshold = 10;\n\n /**\n * Threshold tolerance of the tool border.\n *\n * @type {number}\n */\n #currentthreshold = null;\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #started = false;\n\n /**\n * Current annotation.\n *\n * @type {Annotation}\n */\n #annotation;\n\n /**\n * Coordinates of the fist mousedown event.\n *\n * @type {object}\n */\n #initialpoint;\n\n /**\n * Floodfill border.\n *\n * @type {object}\n */\n #border = null;\n\n /**\n * List of parent points.\n *\n * @type {Point2D[]}\n */\n #parentPoints = [];\n\n /**\n * Assistant variable to paint border on all slices.\n *\n * @type {boolean}\n */\n #extender = false;\n\n /**\n * Drawing style.\n *\n * @type {Style}\n */\n #style = new Style();\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Set extend option for painting border on all slices.\n *\n * @param {boolean} bool The option to set.\n */\n setExtend(bool) {\n this.#extender = bool;\n }\n\n /**\n * Get extend option for painting border on all slices.\n *\n * @returns {boolean} The actual value of of the variable to use Floodfill\n * on museup.\n */\n getExtend() {\n return this.#extender;\n }\n\n /**\n * Get (x, y) coordinates referenced to the canvas.\n *\n * @param {Point2D} point The start point.\n * @param {string} divId The layer group divId.\n * @returns {Scalar2D} The coordinates as a {x,y}.\n */\n #getIndex = (point, divId) => {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const index = viewLayer.displayToPlaneIndex(point);\n return {\n x: index.get(0),\n y: index.get(1)\n };\n };\n\n /**\n * Calculate border.\n *\n * @param {object} points The input points.\n * @param {number} threshold The threshold of the floodfill.\n * @param {boolean} simple Return first points or a list.\n * @returns {Point2D[]} The parent points.\n */\n #calcBorder(points, threshold, simple) {\n\n this.#parentPoints = [];\n const image = {\n data: this.#imageInfo.data,\n width: this.#imageInfo.width,\n height: this.#imageInfo.height,\n bytes: 4\n };\n\n this.#mask = MagicWand.floodFill(image, points.x, points.y, threshold);\n this.#mask = MagicWand.gaussBlurOnlyBorder(this.#mask, this.#blurRadius);\n\n let cs = MagicWand.traceContours(this.#mask);\n cs = MagicWand.simplifyContours(\n cs, this.#simplifyTolerant, this.#simplifyCount);\n\n if (cs.length > 0 && cs[0].points[0].x) {\n if (simple) {\n return cs[0].points;\n }\n for (let j = 0, icsl = cs[0].points.length; j < icsl; j++) {\n this.#parentPoints.push(new Point2D(\n cs[0].points[j].x,\n cs[0].points[j].y\n ));\n }\n return this.#parentPoints;\n } else {\n return [];\n }\n }\n\n /**\n * Paint Floodfill.\n *\n * @param {object} point The start point.\n * @param {number} threshold The border threshold.\n * @param {LayerGroup} layerGroup The origin layer group.\n * @returns {boolean} False if no border.\n */\n #paintBorder(point, threshold, layerGroup) {\n // Calculate the border\n this.#border = this.#calcBorder(point, threshold, false);\n // Paint the border\n if (this.#border.length !== 0) {\n const drawLayer = layerGroup.getActiveDrawLayer();\n const drawController = drawLayer.getDrawController();\n\n const newMathShape = new ROI(this.#border);\n\n let command;\n if (typeof this.#annotation === 'undefined') {\n // create annotation\n this.#annotation = new Annotation();\n this.#annotation.colour = this.#style.getLineColour();\n this.#annotation.id = guid();\n\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n this.#annotation.init(viewController);\n\n this.#annotation.mathShape = newMathShape;\n command = new AddAnnotationCommand(\n this.#annotation,\n drawController\n );\n } else {\n // update annotation\n const originalMathShape = this.#annotation.mathShape;\n command = new UpdateAnnotationCommand(\n this.#annotation,\n {mathShape: originalMathShape},\n {mathShape: newMathShape},\n drawController\n );\n }\n\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // execute command: triggers draw creation\n command.execute();\n }\n\n return this.#border.length !== 0;\n }\n\n /**\n * Create Floodfill in all the prev and next slices while border is found.\n *\n * @param {number} ini The first slice to extend to.\n * @param {number} end The last slice to extend to.\n * @param {object} layerGroup The origin layer group.\n */\n extend(ini, end, layerGroup) {\n //avoid errors\n if (!this.#initialpoint) {\n throw '\\'initialpoint\\' not found. User must click before use extend!';\n }\n\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n\n const pos = viewController.getCurrentIndex();\n const imageSize = viewController.getImageSize();\n const threshold = this.#currentthreshold || this.#initialthreshold;\n\n // Iterate over the next images and paint border on each slice.\n for (let i = pos.get(2),\n len = end\n ? end : imageSize.get(2);\n i < len; i++) {\n if (!this.#paintBorder(this.#initialpoint, threshold, layerGroup)) {\n break;\n }\n viewController.incrementIndex(2);\n }\n viewController.setCurrentPosition(pos);\n\n // Iterate over the prev images and paint border on each slice.\n for (let j = pos.get(2), jl = ini ? ini : 0; j > jl; j--) {\n if (!this.#paintBorder(this.#initialpoint, threshold, layerGroup)) {\n break;\n }\n viewController.decrementIndex(2);\n }\n viewController.setCurrentPosition(pos);\n }\n\n /**\n * Event fired when threshold change.\n *\n * @param {number} _value Current threshold.\n */\n onThresholdChange(_value) {\n // Defaults do nothing\n }\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n * @param {string} divId The layer group divId.\n */\n #start(point, divId) {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n let drawLayer = layerGroup.getActiveDrawLayer();\n\n if (typeof drawLayer === 'undefined') {\n const viewLayer = layerGroup.getActiveViewLayer();\n const refDataId = viewLayer.getDataId();\n // create new data\n const data = this.#app.createAnnotationData(refDataId);\n // render (will create draw layer)\n this.#app.addAndRenderAnnotationData(data, divId, refDataId);\n // get draw layer\n drawLayer = layerGroup.getActiveDrawLayer();\n // set active to bind to toolboxController\n layerGroup.setActiveDrawLayerByDataId(drawLayer.getDataId());\n }\n\n this.#imageInfo = viewLayer.getImageData();\n if (!this.#imageInfo) {\n logger.error('No image found');\n return;\n }\n\n // update zoom scale\n this.#style.setZoomScale(\n drawLayer.getKonvaLayer().getAbsoluteScale());\n\n this.#started = true;\n this.#initialpoint = this.#getIndex(point, divId);\n this.#paintBorder(this.#initialpoint, this.#initialthreshold, layerGroup);\n this.onThresholdChange(this.#initialthreshold);\n }\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #update(point, divId) {\n if (!this.#started) {\n return;\n }\n\n const movedpoint = this.#getIndex(point, divId);\n this.#currentthreshold = Math.round(Math.sqrt(\n Math.pow((this.#initialpoint.x - movedpoint.x), 2) +\n Math.pow((this.#initialpoint.y - movedpoint.y), 2)) / 2);\n this.#currentthreshold = this.#currentthreshold < this.#initialthreshold\n ? this.#initialthreshold\n : this.#currentthreshold - this.#initialthreshold;\n\n this.#paintBorder(\n this.#initialpoint,\n this.#currentthreshold,\n this.#app.getLayerGroupByDivId(divId)\n );\n\n this.onThresholdChange(this.#currentthreshold);\n }\n\n /**\n * Finish tool interaction.\n */\n #finish() {\n if (this.#started) {\n this.#started = false;\n }\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} _event The mouse up event.\n */\n mouseup = (_event) => {\n this.#finish();\n // TODO: re-activate\n // if (this.#extender) {\n // const layerDetails = getLayerDetailsFromEvent(event);\n // const layerGroup =\n // this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n // this.extend(layerGroup);\n // }\n };\n\n /**\n * Handle mouse out event.\n *\n * @param {object} _event The mouse out event.\n */\n mouseout = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} _event The touch end event.\n */\n touchend = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n event.context = 'Floodfill';\n this.#app.onKeydown(event);\n };\n\n /**\n * Activate the tool.\n *\n * @param {boolean} bool The flag to activate or not.\n */\n activate(bool) {\n if (bool) {\n // init with the app window scale\n this.#style.setBaseScale(this.#app.getBaseScale());\n // set the default to the first in the list\n this.setFeatures({shapeColour: this.#style.getLineColour()});\n }\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n /**\n * Get the list of event names that this tool can fire.\n *\n * @returns {Array} The list of event names.\n */\n getEventNames() {\n return ['drawcreate', 'drawchange', 'drawmove', 'drawdelete'];\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n // #fireEvent = (event) => {\n // this.#listenerHandler.fireEvent(event);\n // };\n\n /**\n * Set the tool live features: shape colour.\n *\n * @param {object} features The list of features.\n */\n setFeatures(features) {\n if (typeof features.shapeColour !== 'undefined') {\n this.#style.setLineColour(features.shapeColour);\n }\n }\n\n} // Floodfill class\n","import {Style} from '../gui/style';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\nimport {Point2D} from '../math/point';\nimport {Path} from '../math/path';\nimport {Scissors} from '../math/scissors';\nimport {guid} from '../math/stats';\nimport {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {ListenerHandler} from '../utils/listen';\nimport {ROI} from '../math/roi';\nimport {Annotation} from '../image/annotation';\nimport {\n AddAnnotationCommand,\n UpdateAnnotationCommand\n} from '../tools/drawCommands';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Livewire painting tool.\n */\nexport class Livewire {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #started = false;\n\n /**\n * Start point.\n *\n * @type {Point2D}\n */\n #startPoint;\n\n /**\n * Current annotation.\n *\n * @type {Annotation}\n */\n #annotation;\n\n /**\n * Drawing style.\n *\n * @type {Style}\n */\n #style = new Style();\n\n /**\n * Path storage. Paths are stored in reverse order.\n *\n * @type {Path}\n */\n #path = new Path();\n\n /**\n * Current path storage. Paths are stored in reverse order.\n *\n * @type {Path}\n */\n #currentPath = new Path();\n\n /**\n * List of parent points.\n *\n * @type {Array}\n */\n #parentPoints = [];\n\n /**\n * Tolerance.\n *\n * @type {number}\n */\n #tolerance = 5;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Clear the parent points list.\n *\n * @param {object} imageSize The image size.\n */\n #clearParentPoints(imageSize) {\n const nrows = imageSize.get(1);\n for (let i = 0; i < nrows; ++i) {\n this.#parentPoints[i] = [];\n }\n }\n\n /**\n * Clear the stored paths.\n */\n #clearPaths() {\n this.#path = new Path();\n this.#currentPath = new Path();\n }\n\n /**\n * Scissor representation.\n *\n * @type {Scissors}\n */\n #scissors = new Scissors();\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n * @param {string} divId The layer group divId.\n */\n #start(point, divId) {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const imageSize = viewLayer.getViewController().getImageSize();\n const index = viewLayer.displayToPlaneIndex(point);\n\n // first time\n if (!this.#started) {\n this.#started = true;\n this.#startPoint = new Point2D(index.get(0), index.get(1));\n // clear vars\n this.#clearPaths();\n this.#clearParentPoints(imageSize);\n // get draw layer\n let drawLayer = layerGroup.getActiveDrawLayer();\n if (typeof drawLayer === 'undefined') {\n const viewLayer = layerGroup.getActiveViewLayer();\n const refDataId = viewLayer.getDataId();\n // create new data\n const data = this.#app.createAnnotationData(refDataId);\n // render (will create draw layer)\n this.#app.addAndRenderAnnotationData(data, divId, refDataId);\n // get draw layer\n drawLayer = layerGroup.getActiveDrawLayer();\n // set active to bind to toolboxController\n layerGroup.setActiveDrawLayerByDataId(drawLayer.getDataId());\n }\n // update zoom scale\n this.#style.setZoomScale(\n drawLayer.getKonvaLayer().getAbsoluteScale());\n // do the training from the first point\n const p = {x: index.get(0), y: index.get(1)};\n this.#scissors.doTraining(p);\n // add the initial point to the path\n const p0 = new Point2D(index.get(0), index.get(1));\n this.#path.addPoint(p0);\n this.#path.addControlPoint(p0);\n } else {\n const diffX = Math.abs(index.get(0) - this.#startPoint.getX());\n const diffY = Math.abs(index.get(1) - this.#startPoint.getY());\n // final point: at 'tolerance' of the initial point\n if (diffX < this.#tolerance &&\n diffY < this.#tolerance) {\n // finish\n this.#finishShape();\n } else {\n // anchor point\n this.#path = this.#currentPath;\n this.#clearParentPoints(imageSize);\n const pn = {x: index.get(0), y: index.get(1)};\n this.#scissors.doTraining(pn);\n this.#path.addControlPoint(this.#currentPath.getPoint(0));\n }\n }\n }\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #update(point, divId) {\n if (!this.#started) {\n return;\n }\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const index = viewLayer.displayToPlaneIndex(point);\n\n // set the point to find the path to\n let p = {x: index.get(0), y: index.get(1)};\n this.#scissors.setPoint(p);\n // do the work\n let results = [];\n let stop = false;\n while (!this.#parentPoints[p.y][p.x] && !stop) {\n results = this.#scissors.doWork();\n\n if (results.length === 0) {\n stop = true;\n } else {\n // fill parents\n for (let i = 0; i < results.length - 1; i += 2) {\n const _p = results[i];\n const _q = results[i + 1];\n this.#parentPoints[_p.y][_p.x] = _q;\n }\n }\n }\n\n // get the path\n this.#currentPath = new Path();\n stop = false;\n while (p && !stop) {\n this.#currentPath.addPoint(new Point2D(p.x, p.y));\n if (!this.#parentPoints[p.y]) {\n stop = true;\n } else {\n if (!this.#parentPoints[p.y][p.x]) {\n stop = true;\n } else {\n p = this.#parentPoints[p.y][p.x];\n }\n }\n }\n this.#currentPath.appenPath(this.#path);\n\n const drawLayer = layerGroup.getActiveDrawLayer();\n const drawController = drawLayer.getDrawController();\n\n const newMathShape = new ROI(this.#currentPath.pointArray);\n\n let command;\n if (typeof this.#annotation === 'undefined') {\n // create annotation\n this.#annotation = new Annotation();\n this.#annotation.colour = this.#style.getLineColour();\n this.#annotation.id = guid();\n\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n this.#annotation.init(viewController);\n\n this.#annotation.mathShape = newMathShape;\n command = new AddAnnotationCommand(\n this.#annotation,\n drawController\n );\n } else {\n // update annotation\n const originalMathShape = this.#annotation.mathShape;\n command = new UpdateAnnotationCommand(\n this.#annotation,\n {mathShape: originalMathShape},\n {mathShape: newMathShape},\n drawController\n );\n }\n\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // execute command: triggers draw creation\n command.execute();\n }\n\n /**\n * Finish a livewire (roi) shape.\n */\n #finishShape() {\n // set flag\n this.#started = false;\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} _event The mouse up event.\n */\n mouseup(_event) {\n // nothing to do\n }\n\n /**\n * Handle mouse out event.\n *\n * @param {object} _event The mouse out event.\n */\n mouseout = (_event) => {\n // nothing to do\n };\n\n /**\n * Handle double click event.\n *\n * @param {object} _event The double click event.\n */\n dblclick = (_event) => {\n this.#finishShape();\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} _event The touch end event.\n */\n touchend = (_event) => {\n // nothing to do\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n event.context = 'Livewire';\n this.#app.onKeydown(event);\n };\n\n /**\n * Activate the tool.\n *\n * @param {boolean} bool The flag to activate or not.\n */\n activate(bool) {\n // start scissors if displayed\n if (bool) {\n const layerGroup = this.#app.getActiveLayerGroup();\n const viewLayer = layerGroup.getActiveViewLayer();\n\n //scissors = new Scissors();\n const imageSize = viewLayer.getViewController().getImageSize();\n this.#scissors.setDimensions(\n imageSize.get(0),\n imageSize.get(1));\n this.#scissors.setData(viewLayer.getImageData().data);\n\n // init with the app window scale\n this.#style.setBaseScale(this.#app.getBaseScale());\n // set the default to the first in the list\n this.setFeatures({shapeColour: this.#style.getLineColour()});\n }\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n /**\n * Get the list of event names that this tool can fire.\n *\n * @returns {Array} The list of event names.\n */\n getEventNames() {\n return ['drawcreate', 'drawchange', 'drawmove', 'drawdelete'];\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n // #fireEvent = (event) => {\n // this.#listenerHandler.fireEvent(event);\n // };\n\n /**\n * Set the tool live features: shape colour.\n *\n * @param {object} features The list of features.\n */\n setFeatures(features) {\n if (typeof features.shapeColour !== 'undefined') {\n this.#style.setLineColour(features.shapeColour);\n }\n }\n\n} // Livewire class\n","import {\n Line,\n getPerpendicularLine,\n getPerpendicularLineAtDistance\n} from '../math/line';\nimport {Point2D} from '../math/point';\nimport {defaults} from '../app/defaults';\nimport {logger} from '../utils/logger';\nimport {\n getLineShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorShape\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Arrow factory.\n */\nexport class ArrowFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'arrow';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof Point2D;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number} The number of points.\n */\n getNPoints() {\n return 2;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 0;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.referencePoints = [points[1]];\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create a line shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(shape);\n // extras\n const extras = this.#createShapeExtras(annotation, style);\n for (const extra of extras) {\n group.add(extra);\n }\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(label);\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n return group;\n }\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n const centerX = (points[0] + points[2]) / 2 + sx;\n const centerY = (points[1] + points[3]) / 2 + sy;\n return [new Point2D(centerX, centerY)];\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n return [\n new Point2D(points[0] + sx, points[1] + sy),\n new Point2D(points[2] + sx, points[3] + sy)\n ];\n }\n\n /**\n * Get anchors to update a line shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} _anchor The active anchor.\n */\n constrainAnchorMove(_anchor) {\n // no constraints\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kline = this.#getShape(group);\n // find anchors\n const begin = getAnchorShape(group, 0);\n const end = getAnchorShape(group, 1);\n\n // math shape\n // compensate for possible shape drag\n const pointBegin = new Point2D(\n begin.x() - kline.x(),\n begin.y() - kline.y()\n );\n const pointEnd = new Point2D(\n end.x() - kline.x(),\n end.y() - kline.y()\n );\n annotation.mathShape = pointBegin;\n annotation.referencePoints = [pointEnd];\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const point = annotation.mathShape;\n const endPoint = annotation.referencePoints[0];\n const line = new Line(point, endPoint);\n\n const begin = line.getBegin();\n const newBegin = new Point2D(\n begin.getX() + translation.x,\n begin.getY() + translation.y\n );\n const end = line.getEnd();\n const newEnd = new Point2D(\n end.getX() + translation.x,\n end.getY() + translation.y\n );\n annotation.mathShape = newBegin;\n annotation.referencePoints = [newEnd];\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {Point2D} The mathematical shape.\n */\n #calculateMathShape(points) {\n return points[0];\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.arrow;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Line} The konva shape.\n */\n #createShape(annotation, style) {\n const point = annotation.mathShape;\n const endPoint = annotation.referencePoints[0];\n const line = new Line(point, endPoint);\n\n // konva line\n const kshape = new Konva.Line({\n points: [\n point.getX(),\n point.getY(),\n endPoint.getX(),\n endPoint.getY()\n ],\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape'\n });\n\n // larger hitfunc\n const tickLen = 20;\n const linePerp0 = getPerpendicularLine(\n line, point, tickLen, style.getZoomScale());\n const linePerp1 = getPerpendicularLine(\n line, endPoint, tickLen, style.getZoomScale());\n kshape.hitFunc(function (context) {\n context.beginPath();\n context.moveTo(linePerp0.getBegin().getX(), linePerp0.getBegin().getY());\n context.lineTo(linePerp0.getEnd().getX(), linePerp0.getEnd().getY());\n context.lineTo(linePerp1.getEnd().getX(), linePerp1.getEnd().getY());\n context.lineTo(linePerp1.getBegin().getX(), linePerp1.getBegin().getY());\n context.closePath();\n context.fillStrokeShape(kshape);\n });\n\n return kshape;\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Line|undefined} The shape.\n */\n #getShape(group) {\n return getLineShape(group);\n }\n\n /**\n * Creates the konva shape extras.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Array} The konva shape extras.\n */\n #createShapeExtras(annotation, style) {\n const point = annotation.mathShape;\n const endPoint = annotation.referencePoints[0];\n const line = new Line(point, endPoint);\n\n const tickLen = 20;\n // perpendicular line at 2*tickLen\n const perpLine = getPerpendicularLineAtDistance(\n line, 2 * tickLen, tickLen, style.getZoomScale());\n\n // triangle\n const ktriangle = new Konva.Line({\n points: [\n line.getBegin().getX(),\n line.getBegin().getY(),\n perpLine.getBegin().getX(),\n perpLine.getBegin().getY(),\n perpLine.getEnd().getX(),\n perpLine.getEnd().getY(),\n ],\n fill: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n closed: true,\n name: 'shape-triangle'\n });\n\n return [ktriangle];\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const point = annotation.mathShape;\n return point;\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n #updateShape(annotation, anchor, style) {\n const point = annotation.mathShape;\n const endPoint = annotation.referencePoints[0];\n const line = new Line(point, endPoint);\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kline = this.#getShape(group);\n\n // reset position after possible shape drag\n kline.position({x: 0, y: 0});\n // update shape\n kline.points([\n point.getX(),\n point.getY(),\n endPoint.getX(),\n endPoint.getY(),\n ]);\n\n // associated triangle shape\n const ktriangle = group.getChildren(function (node) {\n return node.name() === 'shape-triangle';\n })[0];\n if (!(ktriangle instanceof Konva.Line)) {\n return;\n }\n // find anchors\n const begin = getAnchorShape(group, 0);\n const end = getAnchorShape(group, 1);\n\n // update 'self' (undo case)\n switch (anchor.id()) {\n case 'anchor0':\n begin.x(anchor.x());\n begin.y(anchor.y());\n break;\n case 'anchor1':\n end.x(anchor.x());\n end.y(anchor.y());\n break;\n default:\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n\n const tickLen = 20;\n\n // triangle\n const perpLine = getPerpendicularLineAtDistance(\n line, 2 * tickLen, tickLen, style.getZoomScale());\n ktriangle.position({x: 0, y: 0});\n ktriangle.points([\n line.getBegin().getX(),\n line.getBegin().getY(),\n perpLine.getBegin().getX(),\n perpLine.getBegin().getY(),\n perpLine.getEnd().getX(),\n perpLine.getEnd().getY(),\n ]);\n\n // larger hitfunc\n const linePerp0 = getPerpendicularLine(\n line, point, tickLen, style.getZoomScale());\n const linePerp1 = getPerpendicularLine(\n line, endPoint, tickLen, style.getZoomScale());\n kline.hitFunc(function (context) {\n context.beginPath();\n context.moveTo(linePerp0.getBegin().getX(), linePerp0.getBegin().getY());\n context.lineTo(linePerp0.getEnd().getX(), linePerp0.getEnd().getY());\n context.lineTo(linePerp1.getEnd().getX(), linePerp1.getEnd().getY());\n context.lineTo(linePerp1.getBegin().getX(), linePerp1.getBegin().getY());\n context.closePath();\n context.fillStrokeShape(kline);\n });\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} [_group] The associated group.\n * @returns {Konva.Group|undefined} The shadow konva group.\n */\n #getDebugShadow(_annotation, _group) {\n return;\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} _group The associated group.\n */\n #updateDebugShadow(_annotation, _group) {\n // does nothing\n }\n\n} // class ArrowFactory\n","import {Circle} from '../math/circle';\nimport {Point2D} from '../math/point';\nimport {logger} from '../utils/logger';\nimport {defaults} from '../app/defaults';\nimport {\n isNodeNameShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorShape\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Circle factory.\n */\nexport class CircleFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'circle';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof Circle;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number} The number of points.\n */\n getNPoints() {\n return 2;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 0;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create a circle shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(this.#createShape(annotation, style));\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(this.#labelFactory.create(annotation, style));\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n return group;\n }\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Circle} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const centerX = shape.x();\n const centerY = shape.y();\n const radius = shape.radius() * Math.sqrt(2) / 2;\n return [\n new Point2D(centerX - radius, centerY - radius),\n new Point2D(centerX + radius, centerY - radius),\n new Point2D(centerX - radius, centerY + radius),\n new Point2D(centerX + radius, centerY + radius),\n ];\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Circle} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const centerX = shape.x();\n const centerY = shape.y();\n const radius = shape.radius();\n return [\n new Point2D(centerX - radius, centerY),\n new Point2D(centerX + radius, centerY),\n new Point2D(centerX, centerY + radius),\n new Point2D(centerX, centerY - radius),\n ];\n }\n\n /**\n * Get anchors to update a circle shape.\n *\n * @param {Konva.Circle} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} anchor The active anchor.\n */\n constrainAnchorMove(anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // find special points\n const left = getAnchorShape(group, 0);\n const right = getAnchorShape(group, 1);\n const bottom = getAnchorShape(group, 2);\n const top = getAnchorShape(group, 3);\n\n // update 'self' (undo case) and special points\n switch (anchor.id()) {\n case 'anchor0':\n // block y\n left.y(right.y());\n break;\n case 'anchor1':\n // block y\n right.y(left.y());\n break;\n case 'anchor2':\n // block x\n bottom.x(top.x());\n break;\n case 'anchor3':\n // block x\n top.x(bottom.x());\n break;\n default :\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // math shape\n const circle = annotation.mathShape;\n const center = new Point2D(\n circle.getCenter().getX(),\n circle.getCenter().getY()\n );\n const anchorPoint = new Point2D(anchor.x(), anchor.y());\n const newRadius = center.getDistance(anchorPoint);\n annotation.mathShape = new Circle(center, newRadius);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const circle = annotation.mathShape;\n const center = circle.getCenter();\n const newCenter = new Point2D(\n center.getX() + translation.x,\n center.getY() + translation.y\n );\n annotation.mathShape = new Circle(newCenter, circle.getRadius());\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {Circle} The mathematical shape.\n */\n #calculateMathShape(points) {\n // calculate radius\n const a = Math.abs(points[0].getX() - points[1].getX());\n const b = Math.abs(points[0].getY() - points[1].getY());\n const radius = Math.round(Math.sqrt(a * a + b * b));\n // physical shape\n return new Circle(points[0], radius);\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.circle;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Circle} The konva shape.\n */\n #createShape(annotation, style) {\n const circle = annotation.mathShape;\n // konva circle\n return new Konva.Circle({\n x: circle.getCenter().getX(),\n y: circle.getCenter().getY(),\n radius: circle.getRadius(),\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape'\n });\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Circle|undefined} The shape.\n */\n #getShape(group) {\n const kshape = group.getChildren(isNodeNameShape)[0];\n if (!(kshape instanceof Konva.Circle)) {\n return;\n }\n return kshape;\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const circle = annotation.mathShape;\n const center = circle.getCenter();\n const radius = circle.getRadius();\n return new Point2D(\n center.getX() - radius,\n center.getY() + radius,\n );\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} _style The application style.\n */\n #updateShape(annotation, anchor, _style) {\n const circle = annotation.mathShape;\n const center = circle.getCenter();\n const radius = circle.getRadius();\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kcircle = this.#getShape(group);\n // update shape: just update the radius\n kcircle.radius(radius);\n\n // find anchors\n const left = getAnchorShape(group, 0);\n const right = getAnchorShape(group, 1);\n const bottom = getAnchorShape(group, 2);\n const top = getAnchorShape(group, 3);\n\n const swapX = right.x() < left.x() ? -1 : 1;\n const swapY = top.y() < bottom.y() ? 1 : -1;\n\n // update 'self' (undo case) and other anchors\n switch (anchor.id()) {\n case 'anchor0':\n // update self\n left.x(anchor.x());\n // update others\n right.x(center.getX() + swapX * radius);\n bottom.y(center.getY() + radius);\n top.y(center.getY() - radius);\n break;\n case 'anchor1':\n // update self\n right.x(anchor.x());\n // update others\n left.x(center.getX() - swapX * radius);\n bottom.y(center.getY() + radius);\n top.y(center.getY() - radius);\n break;\n case 'anchor2':\n // update self\n bottom.y(anchor.y());\n // update others\n left.x(center.getX() - radius);\n right.x(center.getX() + radius);\n top.y(center.getY() - swapY * radius);\n break;\n case 'anchor3':\n // update self\n top.y(anchor.y());\n // update others\n left.x(center.getX() - radius);\n right.x(center.getX() + radius);\n bottom.y(center.getY() + swapY * radius);\n break;\n default :\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} annotation The annotation to shadow.\n * @param {Konva.Group} [group] The associated group.\n * @returns {Konva.Group|undefined} The shadow konva group.\n */\n #getDebugShadow(annotation, group) {\n const circle = annotation.mathShape;\n\n // possible group offset\n let offsetX = 0;\n let offsetY = 0;\n if (typeof group !== 'undefined') {\n offsetX = group.x();\n offsetY = group.y();\n }\n const kshadow = new Konva.Group();\n kshadow.name('shadow');\n const regions = circle.getRound();\n for (let i = 0; i < regions.length; ++i) {\n const region = regions[i];\n const minX = region[0][0];\n const minY = region[0][1];\n const maxX = region[1][0];\n const pixelLine = new Konva.Rect({\n x: minX - offsetX,\n y: minY - offsetY,\n width: maxX - minX,\n height: 1,\n fill: 'grey',\n strokeWidth: 0,\n strokeScaleEnabled: false,\n opacity: 0.3,\n name: 'shadow-element'\n });\n kshadow.add(pixelLine);\n }\n return kshadow;\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} annotation The annotation to shadow.\n * @param {Konva.Group} group The associated group.\n */\n #updateDebugShadow(annotation, group) {\n const kshadow = group.getChildren(function (node) {\n return node.name() === 'shadow';\n })[0];\n if (typeof kshadow !== 'undefined') {\n // remove previous\n kshadow.destroy();\n // add new\n group.add(this.#getDebugShadow(annotation, group));\n }\n }\n\n} // class CircleFactory\n","import {Ellipse} from '../math/ellipse';\nimport {Point2D} from '../math/point';\nimport {logger} from '../utils/logger';\nimport {defaults} from '../app/defaults';\nimport {\n isNodeNameShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorShape\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Ellipse factory.\n */\nexport class EllipseFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'ellipse';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof Ellipse;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number} The number of points.\n */\n getNPoints() {\n return 2;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 0;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create an ellipse shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(this.#createShape(annotation, style));\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(this.#labelFactory.create(annotation, style));\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n return group;\n }\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Ellipse} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const centerX = shape.x();\n const centerY = shape.y();\n const radiusX = shape.radiusX() * Math.sqrt(2) / 2;\n const radiusY = shape.radiusY() * Math.sqrt(2) / 2;\n return [\n new Point2D(centerX - radiusX, centerY - radiusY),\n new Point2D(centerX + radiusX, centerY - radiusY),\n new Point2D(centerX - radiusX, centerY + radiusY),\n new Point2D(centerX + radiusX, centerY + radiusY),\n ];\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Ellipse} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const centerX = shape.x();\n const centerY = shape.y();\n const radius = shape.radius();\n return [\n new Point2D(centerX - radius.x, centerY),\n new Point2D(centerX + radius.x, centerY),\n new Point2D(centerX, centerY + radius.y),\n new Point2D(centerX, centerY - radius.y),\n ];\n }\n\n /**\n * Get anchors to update a ellipse shape.\n *\n * @param {Konva.Ellipse} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} anchor The active anchor.\n */\n constrainAnchorMove(anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // find special points\n const left = getAnchorShape(group, 0);\n const right = getAnchorShape(group, 1);\n const bottom = getAnchorShape(group, 2);\n const top = getAnchorShape(group, 3);\n\n // update 'self' (undo case) and special points\n switch (anchor.id()) {\n case 'anchor0':\n // block y\n left.y(right.y());\n break;\n case 'anchor1':\n // block y\n right.y(left.y());\n break;\n case 'anchor2':\n // block x\n bottom.x(top.x());\n break;\n case 'anchor3':\n // block x\n top.x(bottom.x());\n break;\n default :\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // math shape\n const ellipse = annotation.mathShape;\n const center = ellipse.getCenter();\n let radiusX = ellipse.getA();\n let radiusY = ellipse.getB();\n\n // update 'self' (undo case) and special points\n switch (anchor.id()) {\n case 'anchor0':\n radiusX = center.getX() - anchor.x();\n break;\n case 'anchor1':\n radiusX = anchor.x() - center.getX();\n break;\n case 'anchor2':\n radiusY = anchor.y() - center.getY();\n break;\n case 'anchor3':\n radiusY = center.getY() - anchor.y();\n break;\n default :\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n\n annotation.mathShape = new Ellipse(\n center, Math.abs(radiusX), Math.abs(radiusY));\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const ellipse = annotation.mathShape;\n const center = ellipse.getCenter();\n const newCenter = new Point2D(\n center.getX() + translation.x,\n center.getY() + translation.y\n );\n annotation.mathShape = new Ellipse(\n newCenter, ellipse.getA(), ellipse.getB());\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {Ellipse} The mathematical shape.\n */\n #calculateMathShape(points) {\n // calculate radius\n const a = Math.abs(points[0].getX() - points[1].getX());\n const b = Math.abs(points[0].getY() - points[1].getY());\n // physical shape\n return new Ellipse(points[0], a, b);\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.ellipse;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Ellipse} The konva shape.\n */\n #createShape(annotation, style) {\n const ellipse = annotation.mathShape;\n const center = ellipse.getCenter();\n const radius = {\n x: ellipse.getA(),\n y: ellipse.getB()\n };\n // konva circle\n return new Konva.Ellipse({\n x: center.getX(),\n y: center.getY(),\n radius: radius,\n radiusX: radius.x,\n radiusY: radius.y,\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape'\n });\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Ellipse|undefined} The shape.\n */\n #getShape(group) {\n const kshape = group.getChildren(isNodeNameShape)[0];\n if (!(kshape instanceof Konva.Ellipse)) {\n return;\n }\n return kshape;\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const ellipse = annotation.mathShape;\n const center = ellipse.getCenter();\n return new Point2D(\n center.getX() - ellipse.getA(),\n center.getY() + ellipse.getB()\n );\n }\n\n /**\n * Update shape on anchor move.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} _style The application style.\n */\n #updateShape(annotation, anchor, _style) {\n const ellipse = annotation.mathShape;\n const center = ellipse.getCenter();\n const radiusX = ellipse.getA();\n const radiusY = ellipse.getB();\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kellipse = this.#getShape(group);\n // update shape: just update radius\n kellipse.radius({\n x: radiusX,\n y: radiusY\n });\n\n // find anchors\n const left = getAnchorShape(group, 0);\n const right = getAnchorShape(group, 1);\n const bottom = getAnchorShape(group, 2);\n const top = getAnchorShape(group, 3);\n\n const swapX = right.x() < left.x() ? -1 : 1;\n const swapY = top.y() < bottom.y() ? 1 : -1;\n\n // update 'self' (undo case) and other anchors\n switch (anchor.id()) {\n case 'anchor0':\n // update self\n left.x(anchor.x());\n // update others\n right.x(center.getX() + swapX * radiusX);\n bottom.y(center.getY() + radiusY);\n top.y(center.getY() - radiusY);\n break;\n case 'anchor1':\n // update self\n right.x(anchor.x());\n // update others\n left.x(center.getX() - swapX * radiusX);\n bottom.y(center.getY() + radiusY);\n top.y(center.getY() - radiusY);\n break;\n case 'anchor2':\n // update self\n bottom.y(anchor.y());\n // update others\n left.x(center.getX() - radiusX);\n right.x(center.getX() + radiusX);\n top.y(center.getY() - swapY * radiusY);\n break;\n case 'anchor3':\n // update self\n top.y(anchor.y());\n // update others\n left.x(center.getX() - radiusX);\n right.x(center.getX() + radiusX);\n bottom.y(center.getY() + swapY * radiusY);\n break;\n default :\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} annotation The annotation to shadow.\n * @param {Konva.Group} [group] The associated group.\n * @returns {Konva.Group|undefined} The shadow konva group.\n */\n #getDebugShadow(annotation, group) {\n const ellipse = annotation.mathShape;\n\n // possible group offset\n let offsetX = 0;\n let offsetY = 0;\n if (typeof group !== 'undefined') {\n offsetX = group.x();\n offsetY = group.y();\n }\n const kshadow = new Konva.Group();\n kshadow.name('shadow');\n const regions = ellipse.getRound();\n for (let i = 0; i < regions.length; ++i) {\n const region = regions[i];\n const minX = region[0][0];\n const minY = region[0][1];\n const maxX = region[1][0];\n const pixelLine = new Konva.Rect({\n x: minX - offsetX,\n y: minY - offsetY,\n width: maxX - minX,\n height: 1,\n fill: 'grey',\n strokeWidth: 0,\n strokeScaleEnabled: false,\n opacity: 0.3,\n name: 'shadow-element'\n });\n kshadow.add(pixelLine);\n }\n return kshadow;\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} annotation The annotation to shadow.\n * @param {Konva.Group} group The associated group.\n */\n #updateDebugShadow(annotation, group) {\n const kshadow = group.getChildren(function (node) {\n return node.name() === 'shadow';\n })[0];\n if (typeof kshadow !== 'undefined') {\n // remove previous\n kshadow.destroy();\n // add new\n group.add(this.#getDebugShadow(annotation, group));\n }\n }\n\n} // class EllipseFactory\n","import {Line, getAngle} from '../math/line';\nimport {Protractor} from '../math/protractor';\nimport {Point2D} from '../math/point';\nimport {defaults} from '../app/defaults';\nimport {\n getLineShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorShape\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Protractor factory.\n */\nexport class ProtractorFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'protractor';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof Protractor;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number} The number of points.\n */\n getNPoints() {\n return 3;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 500;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create a line shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n const protractor = annotation.mathShape;\n\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(this.#createShape(annotation, style));\n\n if (protractor.getLength() === this.getNPoints()) {\n // extras\n const extras = this.#createShapeExtras(annotation, style);\n for (const extra of extras) {\n group.add(extra);\n }\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(this.#labelFactory.create(annotation, style));\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n }\n return group;\n }\n\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n return [\n new Point2D(points[2] + sx, points[3] + sy)\n ];\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n return [\n new Point2D(points[0] + sx, points[1] + sy),\n new Point2D(points[2] + sx, points[3] + sy),\n new Point2D(points[4] + sx, points[5] + sy)\n ];\n }\n\n /**\n * Get anchors to update a line shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} _anchor The active anchor.\n */\n constrainAnchorMove(_anchor) {\n // no constraints\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kline = this.#getShape(group);\n // find special points\n const begin = getAnchorShape(group, 0);\n const mid = getAnchorShape(group, 1);\n const end = getAnchorShape(group, 2);\n\n // math shape\n // compensate for possible shape drag\n const pointBegin = new Point2D(\n begin.x() - kline.x(),\n begin.y() - kline.y()\n );\n const pointMid = new Point2D(\n mid.x() - kline.x(),\n mid.y() - kline.y()\n );\n const pointEnd = new Point2D(\n end.x() - kline.x(),\n end.y() - kline.y()\n );\n annotation.mathShape = new Protractor([pointBegin, pointMid, pointEnd]);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const protractor = annotation.mathShape;\n const newPointList = [];\n for (let i = 0; i < 3; ++i) {\n newPointList.push(new Point2D(\n protractor.getPoint(i).getX() + translation.x,\n protractor.getPoint(i).getY() + translation.y\n ));\n }\n annotation.mathShape = new Protractor(newPointList);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {Protractor} The mathematical shape.\n */\n #calculateMathShape(points) {\n return new Protractor(points);\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.protractor;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Line} The konva shape.\n */\n #createShape(annotation, style) {\n const protractor = annotation.mathShape;\n const points = [];\n for (let i = 0; i < protractor.getLength(); ++i) {\n points.push(protractor.getPoint(i).getX());\n points.push(protractor.getPoint(i).getY());\n }\n\n // konva line\n const kshape = new Konva.Line({\n points: points,\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape'\n });\n\n if (protractor.getLength() === this.getNPoints()) {\n // larger hitfunc\n kshape.hitFunc(function (context) {\n context.beginPath();\n context.moveTo(\n protractor.getPoint(0).getX(), protractor.getPoint(0).getY());\n context.lineTo(\n protractor.getPoint(1).getX(), protractor.getPoint(1).getY());\n context.lineTo(\n protractor.getPoint(2).getX(), protractor.getPoint(2).getY());\n context.closePath();\n context.fillStrokeShape(kshape);\n });\n }\n\n return kshape;\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Line|undefined} The shape.\n */\n #getShape(group) {\n return getLineShape(group);\n }\n\n /**\n * Creates the konva shape extras.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Array} The konva shape extras.\n */\n #createShapeExtras(annotation, style) {\n const protractor = annotation.mathShape;\n const line0 = new Line(\n protractor.getPoint(0), protractor.getPoint(1));\n const line1 = new Line(\n protractor.getPoint(1), protractor.getPoint(2));\n\n let angle = getAngle(line0, line1);\n let inclination = line0.getInclination();\n if (angle > 180) {\n angle = 360 - angle;\n inclination += angle;\n }\n\n const radius = Math.min(line0.getLength(), line1.getLength()) * 33 / 100;\n const karc = new Konva.Arc({\n innerRadius: radius,\n outerRadius: radius,\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n angle: angle,\n rotation: -inclination,\n x: protractor.getPoint(1).getX(),\n y: protractor.getPoint(1).getY(),\n name: 'shape-arc'\n });\n\n return [karc];\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const protractor = annotation.mathShape;\n const line0 = new Line(\n protractor.getPoint(0), protractor.getPoint(1));\n const line1 = new Line(\n protractor.getPoint(1), protractor.getPoint(2));\n\n const midX =\n (line0.getMidpoint().getX() + line1.getMidpoint().getX()) / 2;\n const midY =\n (line0.getMidpoint().getY() + line1.getMidpoint().getY()) / 2;\n\n return new Point2D(\n midX,\n midY\n );\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} _style The application style.\n */\n #updateShape(annotation, anchor, _style) {\n const protractor = annotation.mathShape;\n const line0 = new Line(\n protractor.getPoint(0), protractor.getPoint(1));\n const line1 = new Line(\n protractor.getPoint(1), protractor.getPoint(2));\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kline = this.#getShape(group);\n\n // reset position after possible shape drag\n kline.position({x: 0, y: 0});\n // update shape\n kline.points([\n protractor.getPoint(0).getX(),\n protractor.getPoint(0).getY(),\n protractor.getPoint(1).getX(),\n protractor.getPoint(1).getY(),\n protractor.getPoint(2).getX(),\n protractor.getPoint(2).getY()\n ]);\n\n // associated arc\n const karc = group.getChildren(function (node) {\n return node.name() === 'shape-arc';\n })[0];\n if (!(karc instanceof Konva.Arc)) {\n return;\n }\n\n // find special points\n const begin = getAnchorShape(group, 0);\n const mid = getAnchorShape(group, 1);\n const end = getAnchorShape(group, 2);\n\n // update special points\n switch (anchor.id()) {\n case 'anchor0':\n begin.x(anchor.x());\n begin.y(anchor.y());\n break;\n case 'anchor1':\n mid.x(anchor.x());\n mid.y(anchor.y());\n break;\n case 'anchor2':\n end.x(anchor.x());\n end.y(anchor.y());\n break;\n }\n\n // angle\n let angle = getAngle(line0, line1);\n let inclination = line0.getInclination();\n if (angle > 180) {\n angle = 360 - angle;\n inclination += angle;\n }\n\n // arc\n const radius = Math.min(line0.getLength(), line1.getLength()) * 33 / 100;\n karc.innerRadius(radius);\n karc.outerRadius(radius);\n karc.angle(angle);\n karc.rotation(-inclination);\n const arcPos = {x: mid.x(), y: mid.y()};\n karc.position(arcPos);\n\n // larger hitfunc\n kline.hitFunc(function (context) {\n context.beginPath();\n context.moveTo(\n protractor.getPoint(0).getX(), protractor.getPoint(0).getY());\n context.lineTo(\n protractor.getPoint(1).getX(), protractor.getPoint(1).getY());\n context.lineTo(\n protractor.getPoint(2).getX(), protractor.getPoint(2).getY());\n context.closePath();\n context.fillStrokeShape(kline);\n });\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} [_group] The associated group.\n * @returns {Konva.Group|undefined} The shadow konva group.\n */\n #getDebugShadow(_annotation, _group) {\n return;\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} _group The associated group.\n */\n #updateDebugShadow(_annotation, _group) {\n // does nothing\n }\n\n} // class ProtractorFactory\n","import {Rectangle} from '../math/rectangle';\nimport {Point2D} from '../math/point';\nimport {logger} from '../utils/logger';\nimport {defaults} from '../app/defaults';\nimport {\n isNodeNameShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorShape\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Rectangle factory.\n */\nexport class RectangleFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'rectangle';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof Rectangle;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number} The number of points.\n */\n getNPoints() {\n return 2;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 0;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create a rectangle shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(shape);\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(label);\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n return group;\n }\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Rect} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const sx = shape.x();\n const sy = shape.y();\n const width = shape.width();\n const height = shape.height();\n return [\n new Point2D(sx + width / 2, sy),\n new Point2D(sx, sy + height / 2),\n new Point2D(sx + width / 2, sy + height),\n new Point2D(sx + width, sy + height / 2),\n ];\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Rect} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const sx = shape.x();\n const sy = shape.y();\n const width = shape.width();\n const height = shape.height();\n return [\n new Point2D(sx, sy),\n new Point2D(sx + width, sy),\n new Point2D(sx + width, sy + height),\n new Point2D(sx, sy + height),\n ];\n }\n\n /**\n * Get anchors to update a rectangle shape.\n *\n * @param {Konva.Rect} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} _anchor The active anchor.\n */\n constrainAnchorMove(_anchor) {\n // no constraints\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // find anchors\n const topLeft = getAnchorShape(group, 0);\n const bottomRight = getAnchorShape(group, 2);\n\n const pointTopLeft = new Point2D(\n topLeft.x(),\n topLeft.y()\n );\n const pointBottomRight = new Point2D(\n bottomRight.x(),\n bottomRight.y()\n );\n // new rect\n annotation.mathShape = new Rectangle(pointTopLeft, pointBottomRight);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const rectangle = annotation.mathShape;\n const begin = rectangle.getBegin();\n const newBegin = new Point2D(\n begin.getX() + translation.x,\n begin.getY() + translation.y\n );\n const end = rectangle.getEnd();\n const newEnd = new Point2D(\n end.getX() + translation.x,\n end.getY() + translation.y\n );\n annotation.mathShape = new Rectangle(newBegin, newEnd);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label content.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {Rectangle} The mathematical shape.\n */\n #calculateMathShape(points) {\n return new Rectangle(points[0], points[1]);\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.rectangle;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Rect} The konva shape.\n */\n #createShape(annotation, style) {\n const rectangle = annotation.mathShape;\n // konva rect\n return new Konva.Rect({\n x: rectangle.getBegin().getX(),\n y: rectangle.getBegin().getY(),\n width: rectangle.getWidth(),\n height: rectangle.getHeight(),\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape'\n });\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Rect|undefined} The shape.\n */\n #getShape(group) {\n const kshape = group.getChildren(isNodeNameShape)[0];\n if (!(kshape instanceof Konva.Rect)) {\n return;\n }\n return kshape;\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const rectangle = annotation.mathShape;\n return new Point2D(\n rectangle.getBegin().getX(),\n rectangle.getEnd().getY(),\n );\n }\n\n /**\n * Update shape on anchor move.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} _style The application style.\n */\n #updateShape(annotation, anchor, _style) {\n const rectangle = annotation.mathShape;\n const begin = rectangle.getBegin();\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const krect = this.#getShape(group);\n // update shape\n krect.position({\n x: begin.getX(),\n y: begin.getY()\n });\n krect.size({\n width: rectangle.getWidth(),\n height: rectangle.getHeight()\n });\n\n // find anchors\n const topLeft = getAnchorShape(group, 0);\n const topRight = getAnchorShape(group, 1);\n const bottomRight = getAnchorShape(group, 2);\n const bottomLeft = getAnchorShape(group, 3);\n\n // update 'self' (undo case) and other anchors\n switch (anchor.id()) {\n case 'anchor0':\n // update self\n topLeft.x(anchor.x());\n topLeft.y(anchor.y());\n // update others\n topRight.y(anchor.y());\n bottomLeft.x(anchor.x());\n break;\n case 'anchor1':\n // update self\n topRight.x(anchor.x());\n topRight.y(anchor.y());\n // update others\n topLeft.y(anchor.y());\n bottomRight.x(anchor.x());\n break;\n case 'anchor2':\n // update self\n bottomRight.x(anchor.x());\n bottomRight.y(anchor.y());\n // update others\n bottomLeft.y(anchor.y());\n topRight.x(anchor.x());\n break;\n case 'anchor3':\n // update self\n bottomLeft.x(anchor.x());\n bottomLeft.y(anchor.y());\n // update others\n bottomRight.y(anchor.y());\n topLeft.x(anchor.x());\n break;\n default :\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} annotation The anootation to shadow.\n * @param {Konva.Group} [_group] The associated group.\n * @returns {Konva.Rect} The shadow konva rect.\n */\n #getDebugShadow(annotation, _group) {\n const rectangle = annotation.mathShape;\n const round = rectangle.getRound();\n const rWidth = round.max.getX() - round.min.getX();\n const rHeight = round.max.getY() - round.min.getY();\n return new Konva.Rect({\n x: round.min.getX(),\n y: round.min.getY(),\n width: rWidth,\n height: rHeight,\n fill: 'grey',\n strokeWidth: 0,\n strokeScaleEnabled: false,\n opacity: 0.3,\n name: 'shadow'\n });\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} annotation The annotation to shadow.\n * @param {Konva.Group} group The associated group.\n */\n #updateDebugShadow(annotation, group) {\n const kshadow = group.getChildren(function (node) {\n return node.name() === 'shadow';\n })[0];\n if (typeof kshadow !== 'undefined') {\n // remove previous\n kshadow.destroy();\n // add new\n group.add(this.#getDebugShadow(annotation, group));\n }\n }\n\n} // class RectangleFactory\n","import {ROI} from '../math/roi';\nimport {Point2D} from '../math/point';\nimport {defaults} from '../app/defaults';\nimport {\n getLineShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorIndex\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * ROI factory.\n */\nexport class RoiFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'roi';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof ROI;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number|undefined} The number of points.\n */\n getNPoints() {\n // undefined to end with double click\n return undefined;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 100;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create a roi shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(this.#createShape(annotation, style));\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(this.#labelFactory.create(annotation, style));\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n return group;\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n const positions = [];\n for (let i = 0; i < points.length; i = i + 2) {\n positions.push(new Point2D(\n points[i] + sx,\n points[i + 1] + sy\n ));\n }\n return positions;\n }\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n const positions = [];\n for (let i = 0; i < points.length; i += 2) {\n const nextIndex = (i + 2) % points.length;\n const midX = (points[i] + points[nextIndex]) / 2 + sx;\n const midY = (points[i + 1] + points[nextIndex + 1]) / 2 + sy;\n positions.push(new Point2D(midX, midY));\n }\n return positions;\n }\n\n /**\n * Get anchors to update a roi shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} _anchor The active anchor.\n */\n constrainAnchorMove(_anchor) {\n // no constraints\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kroi = this.#getShape(group);\n\n // update the roi point and compensate for possible drag\n // (the anchor id is the index of the point in the main list)\n const roi = annotation.mathShape;\n const points = roi.getPoints().slice();\n const newPoint = new Point2D(\n anchor.x() - kroi.x(),\n anchor.y() - kroi.y()\n );\n const index = getAnchorIndex(anchor.id());\n points[index] = newPoint;\n\n // new math shape\n annotation.mathShape = new ROI(points);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const roi = annotation.mathShape;\n const newPoints = [];\n for (let i = 0; i < roi.getLength(); ++i) {\n newPoints.push(new Point2D(\n roi.getPoint(i).getX() + translation.x,\n roi.getPoint(i).getY() + translation.y\n ));\n }\n annotation.mathShape = new ROI(newPoints);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {ROI} The mathematical shape.\n */\n #calculateMathShape(points) {\n return new ROI(points);\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.roi;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Line} The konva shape.\n */\n #createShape(annotation, style) {\n const roi = annotation.mathShape;\n // konva line\n const arr = [];\n for (let i = 0; i < roi.getLength(); ++i) {\n arr.push(roi.getPoint(i).getX());\n arr.push(roi.getPoint(i).getY());\n }\n return new Konva.Line({\n points: arr,\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape',\n closed: true\n });\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Line|undefined} The shape.\n */\n #getShape(group) {\n return getLineShape(group);\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const roi = annotation.mathShape;\n return new Point2D(\n roi.getPoint(0).getX(),\n roi.getPoint(0).getY()\n );\n }\n\n /**\n * Update shape on anchor move.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} _style The application style.\n */\n #updateShape(annotation, anchor, _style) {\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kroi = this.#getShape(group);\n // update the roi point and compensate for possible drag\n // (the anchor id is the index of the point in the main list)\n const points = kroi.points();\n const index = getAnchorIndex(anchor.id()) * 2;\n points[index] = anchor.x() - kroi.x();\n points[index + 1] = anchor.y() - kroi.y();\n kroi.points(points);\n\n // update self\n const point = group.getChildren(function (node) {\n return node.id() === anchor.id();\n })[0];\n\n point.x(anchor.x());\n point.y(anchor.y());\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} _annotation The anootation to shadow.\n * @param {Konva.Group} [_group] The associated group.\n * @returns {Konva.Line} The shadow konva line.\n */\n #getDebugShadow(_annotation, _group) {\n // does nothing\n return undefined;\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} _group The associated group.\n */\n #updateDebugShadow(_annotation, _group) {\n // does nothing\n }\n\n} // class RoiFactory\n","import {Line, getPerpendicularLine} from '../math/line';\nimport {Point2D} from '../math/point';\nimport {logger} from '../utils/logger';\nimport {defaults} from '../app/defaults';\nimport {\n getLineShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorShape\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Ruler factory.\n */\nexport class RulerFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'ruler';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof Line;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number} The number of points.\n */\n getNPoints() {\n return 2;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 0;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create a line shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(this.#createShape(annotation, style));\n // extras\n const extras = this.#createShapeExtras(annotation, style);\n for (const extra of extras) {\n group.add(extra);\n }\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(this.#labelFactory.create(annotation, style));\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n return group;\n }\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n const centerX = (points[0] + points[2]) / 2 + sx;\n const centerY = (points[1] + points[3]) / 2 + sy;\n return [new Point2D(centerX, centerY)];\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n return [\n new Point2D(points[0] + sx, points[1] + sy),\n new Point2D(points[2] + sx, points[3] + sy)\n ];\n }\n\n /**\n * Get anchors to update a line shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} _anchor The active anchor.\n */\n constrainAnchorMove(_anchor) {\n // no constraints\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kline = this.#getShape(group);\n // find anchors\n const begin = getAnchorShape(group, 0);\n const end = getAnchorShape(group, 1);\n\n // math shape\n // compensate for possible shape drag\n const pointBegin = new Point2D(\n begin.x() - kline.x(),\n begin.y() - kline.y()\n );\n const pointEnd = new Point2D(\n end.x() - kline.x(),\n end.y() - kline.y()\n );\n annotation.mathShape = new Line(pointBegin, pointEnd);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const line = annotation.mathShape;\n const begin = line.getBegin();\n const newBegin = new Point2D(\n begin.getX() + translation.x,\n begin.getY() + translation.y\n );\n const end = line.getEnd();\n const newEnd = new Point2D(\n end.getX() + translation.x,\n end.getY() + translation.y\n );\n annotation.mathShape = new Line(newBegin, newEnd);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {Line} The mathematical shape.\n */\n #calculateMathShape(points) {\n return new Line(points[0], points[1]);\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.ruler;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Line} The konva shape.\n */\n #createShape(annotation, style) {\n const line = annotation.mathShape;\n\n // konva line\n const kshape = new Konva.Line({\n points: [\n line.getBegin().getX(),\n line.getBegin().getY(),\n line.getEnd().getX(),\n line.getEnd().getY()\n ],\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape'\n });\n\n // larger hitfunc\n const tickLen = 20;\n const linePerp0 = getPerpendicularLine(\n line, line.getBegin(), tickLen, style.getZoomScale());\n const linePerp1 = getPerpendicularLine(\n line, line.getEnd(), tickLen, style.getZoomScale());\n kshape.hitFunc(function (context) {\n context.beginPath();\n context.moveTo(linePerp0.getBegin().getX(), linePerp0.getBegin().getY());\n context.lineTo(linePerp0.getEnd().getX(), linePerp0.getEnd().getY());\n context.lineTo(linePerp1.getEnd().getX(), linePerp1.getEnd().getY());\n context.lineTo(linePerp1.getBegin().getX(), linePerp1.getBegin().getY());\n context.closePath();\n context.fillStrokeShape(kshape);\n });\n\n return kshape;\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Line|undefined} The shape.\n */\n #getShape(group) {\n return getLineShape(group);\n }\n\n /**\n * Creates the konva shape extras.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Array} The konva shape extras.\n */\n #createShapeExtras(annotation, style) {\n const line = annotation.mathShape;\n\n const tickLen = 20;\n\n // tick begin\n const linePerp0 = getPerpendicularLine(\n line, line.getBegin(), tickLen, style.getZoomScale());\n const ktick0 = new Konva.Line({\n points: [\n linePerp0.getBegin().getX(),\n linePerp0.getBegin().getY(),\n linePerp0.getEnd().getX(),\n linePerp0.getEnd().getY()\n ],\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape-tick0'\n });\n\n // tick end\n const linePerp1 = getPerpendicularLine(\n line, line.getEnd(), tickLen, style.getZoomScale());\n const ktick1 = new Konva.Line({\n points: [\n linePerp1.getBegin().getX(),\n linePerp1.getBegin().getY(),\n linePerp1.getEnd().getX(),\n linePerp1.getEnd().getY()\n ],\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape-tick1'\n });\n\n return [ktick0, ktick1];\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const line = annotation.mathShape;\n const begin = line.getBegin();\n const end = line.getEnd();\n // lowest point\n let res = begin;\n if (begin.getY() < end.getY()) {\n res = end;\n }\n return res;\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n #updateShape(annotation, anchor, style) {\n const line = annotation.mathShape;\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kline = this.#getShape(group);\n\n // reset position after possible shape drag\n kline.position({x: 0, y: 0});\n // update shape\n kline.points([\n line.getBegin().getX(),\n line.getBegin().getY(),\n line.getEnd().getX(),\n line.getEnd().getY(),\n ]);\n\n // associated tick0\n const ktick0 = group.getChildren(function (node) {\n return node.name() === 'shape-tick0';\n })[0];\n if (!(ktick0 instanceof Konva.Line)) {\n return;\n }\n // associated tick1\n const ktick1 = group.getChildren(function (node) {\n return node.name() === 'shape-tick1';\n })[0];\n if (!(ktick1 instanceof Konva.Line)) {\n return;\n }\n // find anchors\n const begin = getAnchorShape(group, 0);\n const end = getAnchorShape(group, 1);\n\n // update 'self' (undo case)\n switch (anchor.id()) {\n case 'anchor0':\n begin.x(anchor.x());\n begin.y(anchor.y());\n break;\n case 'anchor1':\n end.x(anchor.x());\n end.y(anchor.y());\n break;\n default:\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n\n // tick\n const tickLen = 20;\n const linePerp0 = getPerpendicularLine(\n line, line.getBegin(), tickLen, style.getZoomScale());\n ktick0.position({x: 0, y: 0});\n ktick0.points([linePerp0.getBegin().getX(),\n linePerp0.getBegin().getY(),\n linePerp0.getEnd().getX(),\n linePerp0.getEnd().getY()]);\n const linePerp1 = getPerpendicularLine(\n line, line.getEnd(), tickLen, style.getZoomScale());\n ktick1.position({x: 0, y: 0});\n ktick1.points([linePerp1.getBegin().getX(),\n linePerp1.getBegin().getY(),\n linePerp1.getEnd().getX(),\n linePerp1.getEnd().getY()]);\n\n // larger hitfunc\n kline.hitFunc(function (context) {\n context.beginPath();\n context.moveTo(linePerp0.getBegin().getX(), linePerp0.getBegin().getY());\n context.lineTo(linePerp0.getEnd().getX(), linePerp0.getEnd().getY());\n context.lineTo(linePerp1.getEnd().getX(), linePerp1.getEnd().getY());\n context.lineTo(linePerp1.getBegin().getX(), linePerp1.getBegin().getY());\n context.closePath();\n context.fillStrokeShape(kline);\n });\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} [_group] The associated group.\n * @returns {Konva.Group|undefined} The shadow konva group.\n */\n #getDebugShadow(_annotation, _group) {\n return;\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} _group The associated group.\n */\n #updateDebugShadow(_annotation, _group) {\n // does nothing\n }\n\n} // class RulerFactory\n","import {logger} from '../utils/logger';\nimport {getFlags, replaceFlags} from '../utils/string';\nimport {Point} from '../math/point';\nimport {getOrientationName} from '../math/orientation';\nimport {defaultToolOptions, toolOptions} from '../tools/index';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D, Point3D} from '../math/point';\nimport {ViewController} from '../app/viewController';\nimport {PlaneHelper} from './planeHelper';\n/* eslint-enable no-unused-vars */\n\n/**\n * Image annotation.\n */\nexport class Annotation {\n /**\n * The ID.\n *\n * @type {string}\n */\n id;\n\n /**\n * The reference image SOP UID.\n *\n * @type {string}\n */\n referenceSopUID;\n\n /**\n * The mathematical shape.\n *\n * @type {object}\n */\n mathShape;\n\n /**\n * Additional points used to define the annotation.\n *\n * @type {Point2D[]|undefined}\n */\n referencePoints;\n\n /**\n * The color: for example 'green', '#00ff00' or 'rgb(0,255,0)'.\n *\n * @type {string|undefined}\n */\n colour;\n\n /**\n * Annotation quantification.\n *\n * @type {object|undefined}\n */\n quantification;\n\n /**\n * Text expression. Can contain variables surrounded with '{}' that will\n * be extracted from the quantification object.\n *\n * @type {string|undefined}\n */\n textExpr;\n\n /**\n * Label position. If undefined, the default shape\n * label position will be used.\n *\n * @type {Point2D|undefined}\n */\n labelPosition;\n\n /**\n * The plane origin, the 3D position of index [0, 0, k].\n *\n * @type {Point3D|undefined}\n */\n planeOrigin;\n\n /**\n * A couple of points that help define the annotation plane.\n *\n * @type {Point3D[]|undefined}\n */\n planePoints;\n\n /**\n * Associated view controller: needed for quantification and label.\n *\n * @type {ViewController|undefined}\n */\n #viewController;\n\n /**\n * Get the orientation name for this annotation.\n *\n * @returns {string|undefined} The orientation name,\n * undefined if same as reference data.\n */\n getOrientationName() {\n let res;\n if (typeof this.planePoints !== 'undefined') {\n const cosines = this.planePoints[1].getValues().concat(\n this.planePoints[2].getValues()\n );\n res = getOrientationName(cosines);\n }\n return res;\n }\n\n /**\n * Initialise the annotation.\n *\n * @param {ViewController} viewController The associated view controller.\n */\n init(viewController) {\n if (typeof this.referenceSopUID !== 'undefined') {\n logger.debug('Cannot initialise annotation twice');\n return;\n }\n\n this.#viewController = viewController;\n // set UID\n this.referenceSopUID = viewController.getCurrentImageUid();\n // set plane origin (not saved with file)\n this.planeOrigin =\n viewController.getOriginForImageUid(this.referenceSopUID);\n // set plane points if not aquisition orientation\n // (planePoints are saved with file if present)\n if (!viewController.isAquisitionOrientation()) {\n this.planePoints = viewController.getPlanePoints(\n viewController.getCurrentPosition()\n );\n }\n }\n\n /**\n * Check if an input view is compatible with the annotation.\n *\n * @param {PlaneHelper} planeHelper The input view to check.\n * @returns {boolean} True if compatible view.\n */\n isCompatibleView(planeHelper) {\n let res = false;\n\n // TODO: add check for referenceSopUID\n\n if (typeof this.planePoints === 'undefined') {\n // non oriented view\n if (planeHelper.isAquisitionOrientation()) {\n res = true;\n }\n } else {\n // oriented view: compare cosines (independent of slice index)\n const cosines = planeHelper.getCosines();\n const cosine1 = new Point3D(cosines[0], cosines[1], cosines[2]);\n const cosine2 = new Point3D(cosines[3], cosines[4], cosines[5]);\n\n if (cosine1.equals(this.planePoints[1]) &&\n cosine2.equals(this.planePoints[2])) {\n res = true;\n }\n }\n return res;\n }\n\n /**\n * Set the associated view controller if it is compatible.\n *\n * @param {ViewController} viewController The view controller.\n */\n setViewController(viewController) {\n // check uid\n if (!viewController.includesImageUid(this.referenceSopUID)) {\n return;\n }\n // check if same view\n if (!this.isCompatibleView(viewController.getPlaneHelper())) {\n return;\n }\n this.#viewController = viewController;\n\n // set plane origin (not saved with file)\n this.planeOrigin =\n viewController.getOriginForImageUid(this.referenceSopUID);\n }\n\n /**\n * Get the centroid of the math shape.\n *\n * @returns {Point|undefined} The 3D centroid point.\n */\n getCentroid() {\n let res;\n if (typeof this.#viewController !== 'undefined' &&\n typeof this.mathShape.getCentroid !== 'undefined') {\n // find the slice index of the annotation origin\n let origin = this.planeOrigin;\n if (typeof this.planePoints !== 'undefined') {\n origin = this.planePoints[0];\n }\n const originPoint =\n new Point([origin.getX(), origin.getY(), origin.getZ()]);\n const originIndex =\n this.#viewController.getIndexFromPosition(originPoint);\n const scrollIndex = this.#viewController.getScrollIndex();\n const k = originIndex.getValues()[scrollIndex];\n\n // shape center converted to 3D\n const planePoint = this.mathShape.getCentroid();\n res = this.#viewController.getPositionFromPlanePoint(planePoint, k);\n }\n return res;\n }\n\n /**\n * Set the annotation text expression.\n *\n * @param {Object.} labelText The list of label\n * texts indexed by modality.\n */\n setTextExpr(labelText) {\n if (typeof this.#viewController !== 'undefined') {\n const modality = this.#viewController.getModality();\n\n if (typeof labelText[modality] !== 'undefined') {\n this.textExpr = labelText[modality];\n } else {\n this.textExpr = labelText['*'];\n }\n } else {\n logger.warn('Cannot set text expr without a view controller');\n }\n }\n\n /**\n * Get the annotation label text by applying the\n * text expression on the current quantification.\n *\n * @returns {string} The resulting text.\n */\n getText() {\n return replaceFlags(this.textExpr, this.quantification);\n }\n\n /**\n * Update the annotation quantification.\n */\n updateQuantification() {\n if (typeof this.#viewController !== 'undefined' &&\n typeof this.mathShape.quantify !== 'undefined') {\n this.quantification = this.mathShape.quantify(\n this.#viewController,\n getFlags(this.textExpr));\n }\n }\n\n /**\n * Get the math shape associated draw factory.\n *\n * @returns {object} The factory.\n */\n getFactory() {\n let fac;\n // check in user provided factories\n if (typeof toolOptions.draw !== 'undefined') {\n for (const factoryName in toolOptions.draw) {\n const factory = toolOptions.draw[factoryName];\n if (factory.supports(this.mathShape)) {\n fac = new factory();\n break;\n }\n }\n }\n // check in default factories\n if (typeof fac === 'undefined') {\n for (const factoryName in defaultToolOptions.draw) {\n const factory = defaultToolOptions.draw[factoryName];\n if (factory.supports(this.mathShape)) {\n fac = new factory();\n break;\n }\n }\n }\n if (typeof fac === 'undefined') {\n logger.warn('No shape factory found for math shape');\n }\n return fac;\n }\n}\n","import {logger} from '../utils/logger';\nimport {Point2D} from '../math/point';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * List of interaction event names.\n */\nexport const InteractionEventNames = [\n 'mousedown',\n 'mousemove',\n 'mouseup',\n 'mouseout',\n 'wheel',\n 'dblclick',\n 'touchstart',\n 'touchmove',\n 'touchend'\n];\n\n/**\n * Overridalbe custom UI object for client defined UI.\n */\nexport const customUI = {\n /**\n * Open a dialogue to edit roi data. Defaults to window.prompt.\n *\n * @param {Annotation} annotation The roi data.\n * @param {Function} callback The callback to launch on dialogue exit.\n */\n openRoiDialog(annotation, callback) {\n const textExpr = prompt('Label', annotation.textExpr);\n if (textExpr !== null) {\n annotation.textExpr = textExpr;\n callback(annotation);\n }\n }\n};\n\n/**\n * Get the positions (without the parent offset) of a list of touch events.\n *\n * @param {Array} touches The list of touch events.\n * @returns {Point2D[]} The list of positions of the touch events.\n */\nfunction getTouchesPositions(touches) {\n // get the touch offset from all its parents\n let offsetLeft = 0;\n let offsetTop = 0;\n if (touches.length !== 0 &&\n typeof touches[0].target !== 'undefined') {\n let offsetParent = touches[0].target.offsetParent;\n while (offsetParent) {\n if (!isNaN(offsetParent.offsetLeft)) {\n offsetLeft += offsetParent.offsetLeft;\n }\n if (!isNaN(offsetParent.offsetTop)) {\n offsetTop += offsetParent.offsetTop;\n }\n offsetParent = offsetParent.offsetParent;\n }\n } else {\n logger.debug('No touch target offset parent.');\n }\n // set its position\n const positions = [];\n for (let i = 0; i < touches.length; ++i) {\n positions.push(new Point2D(\n touches[i].pageX - offsetLeft,\n touches[i].pageY - offsetTop\n ));\n }\n return positions;\n}\n\n/**\n * Get the offsets of an input touch event.\n *\n * @param {object} event The event to get the offset from.\n * @returns {Point2D[]} The array of points.\n */\nexport function getTouchPoints(event) {\n let positions = [];\n if (typeof event.targetTouches !== 'undefined' &&\n event.targetTouches.length !== 0) {\n // see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/targetTouches\n positions = getTouchesPositions(event.targetTouches);\n } else if (typeof event.changedTouches !== 'undefined' &&\n event.changedTouches.length !== 0) {\n // see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/changedTouches\n positions = getTouchesPositions(event.changedTouches);\n }\n return positions;\n}\n\n/**\n * Get the offset of an input mouse event.\n *\n * @param {object} event The event to get the offset from.\n * @returns {Point2D} The 2D point.\n */\nexport function getMousePoint(event) {\n // offsetX/Y: the offset in the X coordinate of the mouse pointer\n // between that event and the padding edge of the target node\n // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/offsetX\n // https://caniuse.com/mdn-api_mouseevent_offsetx\n return new Point2D(\n event.offsetX,\n event.offsetY\n );\n}\n\n/**\n * Test if a canvas with the input size can be created.\n *\n * Ref:\n * - {@link https://github.com/ivmartel/dwv/issues/902},\n * - {@link https://github.com/jhildenbiddle/canvas-size/blob/v1.2.4/src/canvas-test.js}.\n *\n * @param {number} width The canvas width.\n * @param {number} height The canvas height.\n * @returns {boolean} True is the canvas can be created.\n */\nexport function canCreateCanvas(width, height) {\n // test canvas with input size\n const testCvs = document.createElement('canvas');\n testCvs.width = width;\n testCvs.height = height;\n // crop canvas to speed up test\n const cropCvs = document.createElement('canvas');\n cropCvs.width = 1;\n cropCvs.height = 1;\n // contexts\n const testCtx = testCvs.getContext('2d');\n const cropCtx = cropCvs.getContext('2d');\n // set data\n if (testCtx) {\n testCtx.fillRect(width - 1, height - 1, 1, 1);\n // Render the test pixel in the bottom-right corner of the\n // test canvas in the top-left of the 1x1 crop canvas. This\n // dramatically reducing the time for getImageData to complete.\n cropCtx.drawImage(testCvs, width - 1, height - 1, 1, 1, 0, 0, 1, 1);\n }\n // Verify image data (alpha component, Pass = 255, Fail = 0)\n return cropCtx && cropCtx.getImageData(0, 0, 1, 1).data[3] !== 0;\n}\n","import {Index} from '../math/index';\nimport {ListenerHandler} from '../utils/listen';\nimport {viewEventNames} from '../image/view';\nimport {ViewController} from '../app/viewController';\nimport {Point2D} from '../math/point';\nimport {\n canCreateCanvas,\n InteractionEventNames\n} from './generic';\nimport {getScaledOffset} from './layerGroup';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Vector3D} from '../math/vector';\nimport {Point, Point3D} from '../math/point';\nimport {Scalar2D, Scalar3D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * View layer.\n */\nexport class ViewLayer {\n\n /**\n * Container div.\n *\n * @type {HTMLElement}\n */\n #containerDiv;\n\n /**\n * The view controller.\n *\n * @type {ViewController}\n */\n #viewController = null;\n\n /**\n * The main display canvas.\n *\n * @type {object}\n */\n #canvas = null;\n\n /**\n * The offscreen canvas: used to store the raw, unscaled pixel data.\n *\n * @type {object}\n */\n #offscreenCanvas = null;\n\n /**\n * The associated CanvasRenderingContext2D.\n *\n * @type {object}\n */\n #context = null;\n\n /**\n * Flag to know if the current position is valid.\n *\n * @type {boolean}\n */\n #isValidPosition = true;\n\n /**\n * The image data array.\n *\n * @type {ImageData}\n */\n #imageData = null;\n\n /**\n * The layer base size as {x,y}.\n *\n * @type {Scalar2D}\n */\n #baseSize;\n\n /**\n * The layer base spacing as {x,y}.\n *\n * @type {Scalar2D}\n */\n #baseSpacing;\n\n /**\n * The layer opacity.\n *\n * @type {number}\n */\n #opacity = 1;\n\n /**\n * The layer scale.\n *\n * @type {Scalar2D}\n */\n #scale = {x: 1, y: 1};\n\n /**\n * The layer fit scale.\n *\n * @type {Scalar2D}\n */\n #fitScale = {x: 1, y: 1};\n\n /**\n * The layer flip scale.\n *\n * @type {Scalar3D}\n */\n #flipScale = {x: 1, y: 1, z: 1};\n\n /**\n * The layer offset.\n *\n * @type {Scalar2D}\n */\n #offset = {x: 0, y: 0};\n\n /**\n * The base layer offset.\n *\n * @type {Scalar2D}\n */\n #baseOffset = {x: 0, y: 0};\n\n /**\n * The view offset.\n *\n * @type {Scalar2D}\n */\n #viewOffset = {x: 0, y: 0};\n\n /**\n * The zoom offset.\n *\n * @type {Scalar2D}\n */\n #zoomOffset = {x: 0, y: 0};\n\n /**\n * The flip offset.\n *\n * @type {Scalar2D}\n */\n #flipOffset = {x: 0, y: 0};\n\n /**\n * Data update flag.\n *\n * @type {boolean}\n */\n #needsDataUpdate = null;\n\n /**\n * The associated data id.\n *\n * @type {string}\n */\n #dataId;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Image smoothing flag.\n *\n * See: {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingEnabled}.\n *\n * @type {boolean}\n */\n #imageSmoothing = false;\n\n /**\n * Layer group origin.\n *\n * @type {Point3D}\n */\n #layerGroupOrigin;\n\n /**\n * Layer group first origin.\n *\n * @type {Point3D}\n */\n #layerGroupOrigin0;\n\n /**\n * @param {HTMLElement} containerDiv The layer div, its id will be used\n * as this layer id.\n */\n constructor(containerDiv) {\n this.#containerDiv = containerDiv;\n // specific css class name\n this.#containerDiv.className += ' viewLayer';\n }\n\n /**\n * Get the associated data id.\n *\n * @returns {string} The data id.\n */\n getDataId() {\n return this.#dataId;\n }\n\n /**\n * Get the layer scale.\n *\n * @returns {Scalar2D} The scale as {x,y}.\n */\n getScale() {\n return this.#scale;\n }\n\n /**\n * Get the layer zoom offset without the fit scale.\n *\n * @returns {Scalar2D} The offset as {x,y}.\n */\n getAbsoluteZoomOffset() {\n return {\n x: this.#zoomOffset.x * this.#fitScale.x,\n y: this.#zoomOffset.y * this.#fitScale.y\n };\n }\n\n /**\n * Set the imageSmoothing flag value.\n *\n * @param {boolean} flag True to enable smoothing.\n */\n setImageSmoothing(flag) {\n this.#imageSmoothing = flag;\n }\n\n /**\n * Set the associated view.\n *\n * @param {object} view The view.\n * @param {string} dataId The associated data id.\n */\n setView(view, dataId) {\n this.#dataId = dataId;\n // local listeners\n view.addEventListener('wlchange', this.#onWLChange);\n view.addEventListener('colourmapchange', this.#onColourMapChange);\n view.addEventListener('positionchange', this.#onPositionChange);\n view.addEventListener('alphafuncchange', this.#onAlphaFuncChange);\n // view events\n for (let j = 0; j < viewEventNames.length; ++j) {\n view.addEventListener(viewEventNames[j], this.#fireEvent);\n }\n // create view controller\n this.#viewController = new ViewController(view);\n // bind layer and image\n this.bindImage();\n }\n\n /**\n * Get the view controller.\n *\n * @returns {ViewController} The controller.\n */\n getViewController() {\n return this.#viewController;\n }\n\n /**\n * Get the canvas image data.\n *\n * @returns {object} The image data.\n */\n getImageData() {\n return this.#imageData;\n }\n\n /**\n * Handle an image set event.\n *\n * @param {object} event The event.\n * @function\n */\n onimageset = (event) => {\n // event.value = [index, image]\n if (this.#dataId === event.dataid) {\n this.#viewController.setImage(event.value[0]);\n this.#setBaseSize(this.#viewController.getImageSize().get2D());\n this.#needsDataUpdate = true;\n }\n };\n\n /**\n * Bind this layer to the view image.\n */\n bindImage() {\n if (this.#viewController) {\n this.#viewController.bindImageAndLayer(this);\n }\n }\n\n /**\n * Unbind this layer to the view image.\n */\n unbindImage() {\n if (this.#viewController) {\n this.#viewController.unbindImageAndLayer(this);\n }\n }\n\n /**\n * Handle an image content change event.\n *\n * @param {object} event The event.\n * @function\n */\n onimagecontentchange = (event) => {\n // event.value = [index]\n if (this.#dataId === event.dataid) {\n this.#isValidPosition = this.#viewController.isPositionInBounds();\n // flag update and draw\n this.#needsDataUpdate = true;\n this.draw();\n }\n };\n\n /**\n * Handle an image change event.\n *\n * @param {object} event The event.\n * @function\n */\n onimagegeometrychange = (event) => {\n // event.value = [index]\n if (this.#dataId === event.dataid) {\n const vcSize = this.#viewController.getImageSize().get2D();\n if (this.#baseSize.x !== vcSize.x ||\n this.#baseSize.y !== vcSize.y) {\n // size changed, recalculate base offset\n // in case origin changed\n if (typeof this.#layerGroupOrigin !== 'undefined' &&\n typeof this.#layerGroupOrigin0 !== 'undefined') {\n const origin0 = this.#viewController.getOrigin();\n const scrollOffset = this.#layerGroupOrigin0.minus(origin0);\n const origin = this.#viewController.getOrigin(\n this.#viewController.getCurrentPosition()\n );\n const planeOffset = this.#layerGroupOrigin.minus(origin);\n this.setBaseOffset(scrollOffset, planeOffset);\n }\n // update base size\n this.#setBaseSize(vcSize);\n // flag update and draw\n this.#needsDataUpdate = true;\n this.draw();\n }\n }\n };\n\n // common layer methods [start] ---------------\n\n /**\n * Get the id of the layer.\n *\n * @returns {string} The string id.\n */\n getId() {\n return this.#containerDiv.id;\n }\n\n /**\n * Remove the HTML element from the DOM.\n */\n removeFromDOM() {\n this.#containerDiv.remove();\n }\n\n /**\n * Get the layer base size (without scale).\n *\n * @returns {Scalar2D} The size as {x,y}.\n */\n getBaseSize() {\n return this.#baseSize;\n }\n\n /**\n * Get the image world (mm) 2D size.\n *\n * @returns {Scalar2D} The 2D size as {x,y}.\n */\n getImageWorldSize() {\n return this.#viewController.getImageWorldSize();\n }\n\n /**\n * Get the layer opacity.\n *\n * @returns {number} The opacity ([0:1] range).\n */\n getOpacity() {\n return this.#opacity;\n }\n\n /**\n * Set the layer opacity.\n *\n * @param {number} alpha The opacity ([0:1] range).\n */\n setOpacity(alpha) {\n if (alpha === this.#opacity) {\n return;\n }\n\n this.#opacity = Math.min(Math.max(alpha, 0), 1);\n\n /**\n * Opacity change event.\n *\n * @event App#opacitychange\n * @type {object}\n * @property {string} type The event type.\n */\n const event = {\n type: 'opacitychange',\n value: [this.#opacity]\n };\n this.#fireEvent(event);\n }\n\n /**\n * Add a flip offset along the layer X axis.\n */\n addFlipOffsetX() {\n this.#flipOffset.x += this.#canvas.width / this.#scale.x;\n this.#offset.x += this.#flipOffset.x;\n }\n\n /**\n * Add a flip offset along the layer Y axis.\n */\n addFlipOffsetY() {\n this.#flipOffset.y += this.#canvas.height / this.#scale.y;\n this.#offset.y += this.#flipOffset.y;\n }\n\n /**\n * Flip the scale along the layer X axis.\n */\n flipScaleX() {\n this.#flipScale.x *= -1;\n }\n\n /**\n * Flip the scale along the layer Y axis.\n */\n flipScaleY() {\n this.#flipScale.y *= -1;\n }\n\n /**\n * Flip the scale along the layer Z axis.\n */\n flipScaleZ() {\n this.#flipScale.z *= -1;\n }\n\n /**\n * Set the layer scale.\n *\n * @param {Scalar3D} newScale The scale as {x,y,z}.\n * @param {Point3D} [center] The scale center.\n */\n setScale(newScale, center) {\n const helper = this.#viewController.getPlaneHelper();\n const orientedNewScale = helper.getTargetOrientedPositiveXYZ({\n x: newScale.x * this.#flipScale.x,\n y: newScale.y * this.#flipScale.y,\n z: newScale.z * this.#flipScale.z,\n });\n const finalNewScale = {\n x: this.#fitScale.x * orientedNewScale.x,\n y: this.#fitScale.y * orientedNewScale.y\n };\n\n if (Math.abs(newScale.x) === 1 &&\n Math.abs(newScale.y) === 1 &&\n Math.abs(newScale.z) === 1) {\n // reset zoom offset for scale=1\n const resetOffset = {\n x: this.#offset.x - this.#zoomOffset.x,\n y: this.#offset.y - this.#zoomOffset.y\n };\n // store new offset\n this.#zoomOffset = {x: 0, y: 0};\n this.#offset = resetOffset;\n } else {\n if (typeof center !== 'undefined') {\n let worldCenter = helper.getPlaneOffsetFromOffset3D({\n x: center.getX(),\n y: center.getY(),\n z: center.getZ()\n });\n // center was obtained with viewLayer.displayToMainPlanePos\n // compensated for baseOffset\n // TODO: justify...\n worldCenter = {\n x: worldCenter.x + this.#baseOffset.x,\n y: worldCenter.y + this.#baseOffset.y\n };\n\n const newOffset = getScaledOffset(\n this.#offset, this.#scale, finalNewScale, worldCenter);\n\n const newZoomOffset = {\n x: this.#zoomOffset.x + newOffset.x - this.#offset.x,\n y: this.#zoomOffset.y + newOffset.y - this.#offset.y\n };\n // store new offset\n this.#zoomOffset = newZoomOffset;\n this.#offset = newOffset;\n }\n }\n\n // store new scale\n this.#scale = finalNewScale;\n }\n\n /**\n * Initialise the layer scale.\n *\n * @param {Scalar3D} newScale The scale as {x,y,z}.\n * @param {Scalar2D} absoluteZoomOffset The zoom offset as {x,y}\n * without the fit scale (as provided by getAbsoluteZoomOffset).\n */\n initScale(newScale, absoluteZoomOffset) {\n const helper = this.#viewController.getPlaneHelper();\n const orientedNewScale = helper.getTargetOrientedPositiveXYZ({\n x: newScale.x * this.#flipScale.x,\n y: newScale.y * this.#flipScale.y,\n z: newScale.z * this.#flipScale.z,\n });\n const finalNewScale = {\n x: this.#fitScale.x * orientedNewScale.x,\n y: this.#fitScale.y * orientedNewScale.y\n };\n this.#scale = finalNewScale;\n\n this.#zoomOffset = {\n x: absoluteZoomOffset.x / this.#fitScale.x,\n y: absoluteZoomOffset.y / this.#fitScale.y\n };\n this.#offset = {\n x: this.#offset.x + this.#zoomOffset.x,\n y: this.#offset.y + this.#zoomOffset.y\n };\n }\n\n /**\n * Set the base layer offset. Updates the layer offset.\n *\n * @param {Vector3D} scrollOffset The scroll offset vector.\n * @param {Vector3D} planeOffset The plane offset vector.\n * @param {Point3D} [layerGroupOrigin] The layer group origin.\n * @param {Point3D} [layerGroupOrigin0] The layer group first origin.\n * @returns {boolean} True if the offset was updated.\n */\n setBaseOffset(\n scrollOffset, planeOffset,\n layerGroupOrigin, layerGroupOrigin0) {\n const helper = this.#viewController.getPlaneHelper();\n const scrollIndex = helper.getNativeScrollIndex();\n const newOffset = helper.getPlaneOffsetFromOffset3D({\n x: scrollIndex === 0 ? scrollOffset.getX() : planeOffset.getX(),\n y: scrollIndex === 1 ? scrollOffset.getY() : planeOffset.getY(),\n z: scrollIndex === 2 ? scrollOffset.getZ() : planeOffset.getZ(),\n });\n const needsUpdate = this.#baseOffset.x !== newOffset.x ||\n this.#baseOffset.y !== newOffset.y;\n // store layer group origins\n if (typeof layerGroupOrigin !== 'undefined' &&\n typeof layerGroupOrigin0 !== 'undefined') {\n this.#layerGroupOrigin = layerGroupOrigin;\n this.#layerGroupOrigin0 = layerGroupOrigin0;\n }\n // reset offset if needed\n if (needsUpdate) {\n this.#offset = {\n x: this.#offset.x - this.#baseOffset.x + newOffset.x,\n y: this.#offset.y - this.#baseOffset.y + newOffset.y\n };\n this.#baseOffset = newOffset;\n }\n return needsUpdate;\n }\n\n /**\n * Set the layer offset.\n *\n * @param {Scalar3D} newOffset The offset as {x,y,z}.\n */\n setOffset(newOffset) {\n const helper = this.#viewController.getPlaneHelper();\n const planeNewOffset = helper.getPlaneOffsetFromOffset3D(newOffset);\n this.#offset = {\n x: planeNewOffset.x +\n this.#viewOffset.x +\n this.#baseOffset.x +\n this.#zoomOffset.x +\n this.#flipOffset.x,\n y: planeNewOffset.y +\n this.#viewOffset.y +\n this.#baseOffset.y +\n this.#zoomOffset.y +\n this.#flipOffset.y\n };\n }\n\n /**\n * Transform a display position to a 2D index.\n *\n * @param {Point2D} point2D The input point.\n * @returns {Index} The equivalent 2D index.\n */\n displayToPlaneIndex(point2D) {\n const planePos = this.displayToPlanePos(point2D);\n return new Index([\n Math.floor(planePos.getX()),\n Math.floor(planePos.getY())\n ]);\n }\n\n /**\n * Remove scale from a display position.\n *\n * @param {Point2D} point2D The input point.\n * @returns {Point2D} The de-scaled point.\n */\n displayToPlaneScale(point2D) {\n return new Point2D(\n point2D.getX() / this.#scale.x,\n point2D.getY() / this.#scale.y\n );\n }\n\n /**\n * Get a plane position from a display position.\n *\n * @param {Point2D} point2D The input point.\n * @returns {Point2D} The plane position.\n */\n displayToPlanePos(point2D) {\n const deScaled = this.displayToPlaneScale(point2D);\n return new Point2D(\n deScaled.getX() + this.#offset.x,\n deScaled.getY() + this.#offset.y\n );\n }\n\n /**\n * Get a display position from a plane position.\n *\n * @param {Point2D} point2D The input point.\n * @returns {Point2D} The display position, can be individually\n * undefined if out of bounds.\n */\n planePosToDisplay(point2D) {\n let posX =\n (point2D.getX() - this.#offset.x + this.#baseOffset.x) * this.#scale.x;\n let posY =\n (point2D.getY() - this.#offset.y + this.#baseOffset.y) * this.#scale.y;\n // check if in bounds\n if (posX < 0 || posX >= this.#canvas.width) {\n posX = undefined;\n }\n if (posY < 0 || posY >= this.#canvas.height) {\n posY = undefined;\n }\n return new Point2D(posX, posY);\n }\n\n /**\n * Get a main plane position from a display position.\n *\n * @param {Point2D} point2D The input point.\n * @returns {Point2D} The main plane position.\n */\n displayToMainPlanePos(point2D) {\n const planePos = this.displayToPlanePos(point2D);\n return new Point2D(\n planePos.getX() - this.#baseOffset.x,\n planePos.getY() - this.#baseOffset.y\n );\n }\n\n /**\n * Display the layer.\n *\n * @param {boolean} flag Whether to display the layer or not.\n */\n display(flag) {\n this.#containerDiv.style.display = flag ? '' : 'none';\n }\n\n /**\n * Check if the layer is visible.\n *\n * @returns {boolean} True if the layer is visible.\n */\n isVisible() {\n return this.#containerDiv.style.display === '';\n }\n\n /**\n * Draw the content (imageData) of the layer.\n * The imageData variable needs to be set.\n *\n * @fires App#renderstart\n * @fires App#renderend\n */\n draw() {\n // skip for non valid position\n if (!this.#isValidPosition) {\n return;\n }\n\n /**\n * Render start event.\n *\n * @event App#renderstart\n * @type {object}\n * @property {string} type The event type.\n */\n let event = {\n type: 'renderstart',\n layerid: this.getId(),\n dataid: this.getDataId()\n };\n this.#fireEvent(event);\n\n // update data if needed\n if (this.#needsDataUpdate) {\n this.#updateImageData();\n }\n\n // context opacity\n this.#context.globalAlpha = this.#opacity;\n\n // clear context\n this.clear();\n\n // draw the cached canvas on the context\n // transform takes as input a, b, c, d, e, f to create\n // the transform matrix (column-major order):\n // [ a c e ]\n // [ b d f ]\n // [ 0 0 1 ]\n this.#context.setTransform(\n this.#scale.x,\n 0,\n 0,\n this.#scale.y,\n -1 * this.#offset.x * this.#scale.x,\n -1 * this.#offset.y * this.#scale.y\n );\n\n // disable smoothing (set just before draw, could be reset by resize)\n this.#context.imageSmoothingEnabled = this.#imageSmoothing;\n // draw image\n this.#context.drawImage(this.#offscreenCanvas, 0, 0);\n\n /**\n * Render end event.\n *\n * @event App#renderend\n * @type {object}\n * @property {string} type The event type.\n */\n event = {\n type: 'renderend',\n layerid: this.getId(),\n dataid: this.getDataId()\n };\n this.#fireEvent(event);\n }\n\n /**\n * Initialise the layer: set the canvas and context.\n *\n * @param {Scalar2D} size The image size as {x,y}.\n * @param {Scalar2D} spacing The image spacing as {x,y}.\n * @param {number} alpha The initial data opacity.\n */\n initialise(size, spacing, alpha) {\n // set locals\n this.#baseSpacing = spacing;\n this.#opacity = Math.min(Math.max(alpha, 0), 1);\n\n // create canvas\n // (canvas size is set in fitToContainer)\n this.#canvas = document.createElement('canvas');\n this.#containerDiv.appendChild(this.#canvas);\n\n // check that the getContext method exists\n if (!this.#canvas.getContext) {\n alert('Error: no canvas.getContext method.');\n return;\n }\n // get the 2D context\n this.#context = this.#canvas.getContext('2d');\n if (!this.#context) {\n alert('Error: failed to get the 2D context.');\n return;\n }\n\n // off screen canvas\n this.#offscreenCanvas = document.createElement('canvas');\n\n // set base size: needs an existing context and off screen canvas\n this.#setBaseSize(size);\n\n // update data on first draw\n this.#needsDataUpdate = true;\n }\n\n /**\n * Set the base size of the layer.\n *\n * @param {Scalar2D} size The size as {x,y}.\n */\n #setBaseSize(size) {\n // check canvas creation\n if (!canCreateCanvas(size.x, size.y)) {\n throw new Error('Cannot create canvas with size ' +\n size.x + ', ' + size.y);\n }\n\n // set local\n this.#baseSize = size;\n\n // off screen canvas\n this.#offscreenCanvas.width = this.#baseSize.x;\n this.#offscreenCanvas.height = this.#baseSize.y;\n // original empty image data array\n this.#context.clearRect(0, 0, this.#baseSize.x, this.#baseSize.y);\n this.#imageData = this.#context.createImageData(\n this.#baseSize.x, this.#baseSize.y);\n }\n\n /**\n * Fit the layer to its parent container.\n *\n * @param {Scalar2D} containerSize The fit size as {x,y}.\n * @param {number} divToWorldSizeRatio The div to world size ratio.\n * @param {Scalar2D} fitOffset The fit offset as {x,y}.\n */\n fitToContainer(containerSize, divToWorldSizeRatio, fitOffset) {\n let needsDraw = false;\n\n // set canvas size if different from previous\n if (this.#canvas.width !== containerSize.x ||\n this.#canvas.height !== containerSize.y) {\n if (!canCreateCanvas(containerSize.x, containerSize.y)) {\n throw new Error('Cannot resize canvas ' +\n containerSize.x + ', ' + containerSize.y);\n }\n // canvas size change triggers canvas reset\n this.#canvas.width = containerSize.x;\n this.#canvas.height = containerSize.y;\n // update draw flag\n needsDraw = true;\n }\n\n // fit scale\n const divToImageSizeRatio = {\n x: divToWorldSizeRatio * this.#baseSpacing.x,\n y: divToWorldSizeRatio * this.#baseSpacing.y\n };\n // #scale = inputScale * fitScale * flipScale\n // flipScale does not change here, we can omit it\n // newScale = (#scale / fitScale) * newFitScale\n const newScale = {\n x: this.#scale.x * divToImageSizeRatio.x / this.#fitScale.x,\n y: this.#scale.y * divToImageSizeRatio.y / this.#fitScale.y\n };\n\n // set scales if different from previous\n if (this.#scale.x !== newScale.x ||\n this.#scale.y !== newScale.y) {\n this.#fitScale = divToImageSizeRatio;\n this.#scale = newScale;\n // update draw flag\n needsDraw = true;\n }\n\n // view offset\n const newViewOffset = {\n x: fitOffset.x / divToImageSizeRatio.x,\n y: fitOffset.y / divToImageSizeRatio.y\n };\n // flip offset\n const scaledImageSize = {\n x: containerSize.x / divToImageSizeRatio.x,\n y: containerSize.y / divToImageSizeRatio.y\n };\n const newFlipOffset = {\n x: this.#flipOffset.x !== 0 ? scaledImageSize.x : 0,\n y: this.#flipOffset.y !== 0 ? scaledImageSize.y : 0,\n };\n\n // set offsets if different from previous\n if (this.#viewOffset.x !== newViewOffset.x ||\n this.#viewOffset.y !== newViewOffset.y ||\n this.#flipOffset.x !== newFlipOffset.x ||\n this.#flipOffset.y !== newFlipOffset.y) {\n // update global offset\n this.#offset = {\n x: this.#offset.x +\n newViewOffset.x - this.#viewOffset.x +\n newFlipOffset.x - this.#flipOffset.x,\n y: this.#offset.y +\n newViewOffset.y - this.#viewOffset.y +\n newFlipOffset.y - this.#flipOffset.y,\n };\n // update private local offsets\n this.#flipOffset = newFlipOffset;\n this.#viewOffset = newViewOffset;\n // update draw flag\n needsDraw = true;\n }\n\n // draw if needed\n if (needsDraw) {\n this.draw();\n }\n }\n\n /**\n * Enable and listen to container interaction events.\n */\n bindInteraction() {\n // allow pointer events\n this.#containerDiv.style.pointerEvents = 'auto';\n // interaction events\n const names = InteractionEventNames;\n for (let i = 0; i < names.length; ++i) {\n const eventName = names[i];\n const passive = eventName !== 'wheel';\n this.#containerDiv.addEventListener(\n eventName, this.#fireEvent, {passive: passive});\n }\n }\n\n /**\n * Disable and stop listening to container interaction events.\n */\n unbindInteraction() {\n // disable pointer events\n this.#containerDiv.style.pointerEvents = 'none';\n // interaction events\n const names = InteractionEventNames;\n for (let i = 0; i < names.length; ++i) {\n this.#containerDiv.removeEventListener(names[i], this.#fireEvent);\n }\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n event.srclayerid = this.getId();\n event.dataid = this.#dataId;\n this.#listenerHandler.fireEvent(event);\n };\n\n // common layer methods [end] ---------------\n\n /**\n * Update the canvas image data.\n */\n #updateImageData() {\n // generate image data\n this.#viewController.generateImageData(this.#imageData);\n // pass the data to the off screen canvas\n this.#offscreenCanvas.getContext('2d').putImageData(this.#imageData, 0, 0);\n // update data flag\n this.#needsDataUpdate = false;\n }\n\n /**\n * Handle window/level change.\n *\n * @param {object} event The event fired when changing the window/level.\n */\n #onWLChange = (event) => {\n // generate and draw if no skip flag\n const skip = typeof event.skipGenerate !== 'undefined' &&\n event.skipGenerate === true;\n if (!skip) {\n this.#needsDataUpdate = true;\n this.draw();\n }\n };\n\n /**\n * Handle colour map change.\n *\n * @param {object} event The event fired when changing the colour map.\n */\n #onColourMapChange = (event) => {\n const skip = typeof event.skipGenerate !== 'undefined' &&\n event.skipGenerate === true;\n if (!skip) {\n this.#needsDataUpdate = true;\n this.draw();\n }\n };\n\n /**\n * Handle position change.\n *\n * @param {object} event The event fired when changing the position.\n */\n #onPositionChange = (event) => {\n const skip = typeof event.skipGenerate !== 'undefined' &&\n event.skipGenerate === true;\n if (!skip) {\n let valid = true;\n if (typeof event.valid !== 'undefined') {\n valid = event.valid;\n }\n // clear for non valid events\n if (!valid) {\n // clear only once\n if (this.#isValidPosition) {\n this.#isValidPosition = false;\n this.clear();\n }\n } else {\n // 3D dimensions\n const dims3D = [0, 1, 2];\n // remove scroll index\n const indexScrollIndex =\n dims3D.indexOf(this.#viewController.getScrollIndex());\n dims3D.splice(indexScrollIndex, 1);\n // remove non scroll index from diff dims\n const diffDims = event.diffDims.filter(function (item) {\n return dims3D.indexOf(item) === -1;\n });\n // update if we have something left\n if (diffDims.length !== 0 || !this.#isValidPosition) {\n // reset valid flag\n this.#isValidPosition = true;\n // reset update flag\n this.#needsDataUpdate = true;\n this.draw();\n }\n }\n }\n };\n\n /**\n * Handle alpha function change.\n *\n * @param {object} event The event fired when changing the function.\n */\n #onAlphaFuncChange = (event) => {\n const skip = typeof event.skipGenerate !== 'undefined' &&\n event.skipGenerate === true;\n if (!skip) {\n this.#needsDataUpdate = true;\n this.draw();\n }\n };\n\n /**\n * Set the current position.\n *\n * @param {Point} position The new position.\n * @param {Index} _index The new index.\n * @returns {boolean} True if the position was updated.\n */\n setCurrentPosition(position, _index) {\n return this.#viewController.setCurrentPosition(position);\n }\n\n /**\n * Clear the context.\n */\n clear() {\n // clear the context: reset the transform first\n // store the current transformation matrix\n this.#context.save();\n // use the identity matrix while clearing the canvas\n this.#context.setTransform(1, 0, 0, 1, 0, 0);\n this.#context.clearRect(0, 0, this.#canvas.width, this.#canvas.height);\n // restore the transform\n this.#context.restore();\n }\n\n} // ViewLayer class\n","import {Index} from '../math/index';\nimport {Point} from '../math/point';\nimport {Vector3D} from '../math/vector';\nimport {viewEventNames} from '../image/view';\nimport {ListenerHandler} from '../utils/listen';\nimport {logger} from '../utils/logger';\nimport {precisionRound} from '../utils/string';\nimport {ViewLayer} from './viewLayer';\nimport {DrawLayer} from './drawLayer';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Matrix33} from '../math/matrix';\nimport {Point2D, Point3D} from '../math/point';\nimport {Scalar2D, Scalar3D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get the layer div id.\n *\n * @param {string} groupDivId The layer group div id.\n * @param {number} layerIndex The layer index.\n * @returns {string} A string id.\n */\nexport function getLayerDivId(groupDivId, layerIndex) {\n return groupDivId + '-layer-' + layerIndex;\n}\n\n/**\n * Get the layer details from a div id.\n *\n * @param {string} idString The layer div id.\n * @returns {object} The layer details as {groupDivId, layerIndex, layerId}.\n */\nexport function getLayerDetailsFromLayerDivId(idString) {\n const split = idString.split('-layer-');\n if (split.length !== 2) {\n logger.warn('Not the expected layer div id format...');\n }\n return {\n groupDivId: split[0],\n layerIndex: split[1],\n layerId: idString,\n };\n}\n\n/**\n * Get the layer details from a mouse event.\n *\n * @param {object} event The event to get the layer div id from. Expecting\n * an event origininating from a canvas inside a layer HTML div\n * with the 'layer' class and id generated with `getLayerDivId`.\n * @returns {object} The layer details as {groupDivId, layerIndex, layerId}.\n */\nexport function getLayerDetailsFromEvent(event) {\n let res = null;\n // get the closest element from the event target and with the 'layer' class\n const layerDiv = event.target.closest('.layer');\n if (layerDiv && typeof layerDiv.id !== 'undefined') {\n res = getLayerDetailsFromLayerDivId(layerDiv.id);\n }\n return res;\n}\n\n/**\n * Get a scaled offset to adapt to new scale and such as the input center\n * stays at the same position.\n *\n * @param {Scalar2D} offset The previous offset as {x,y}.\n * @param {Scalar2D} scale The previous scale as {x,y}.\n * @param {Scalar2D} newScale The new scale as {x,y}.\n * @param {Scalar2D} center The scale center as {x,y}.\n * @returns {Scalar2D} The scaled offset as {x,y}.\n */\nexport function getScaledOffset(offset, scale, newScale, center) {\n // worldPoint = indexPoint / scale + offset\n //=> indexPoint = (worldPoint - offset ) * scale\n\n // plane center should stay the same:\n // indexCenter / newScale + newOffset =\n // indexCenter / oldScale + oldOffset\n //=> newOffset = indexCenter / oldScale + oldOffset -\n // indexCenter / newScale\n //=> newOffset = worldCenter - indexCenter / newScale\n const indexCenter = {\n x: (center.x - offset.x) * scale.x,\n y: (center.y - offset.y) * scale.y\n };\n return {\n x: center.x - (indexCenter.x / newScale.x),\n y: center.y - (indexCenter.y / newScale.y)\n };\n}\n\n/**\n * Layer group.\n *\n * - Display position: {x,y},\n * - Plane position: Index (access: get(i)),\n * - (world) Position: Point3D (access: getX, getY, getZ).\n *\n * Display -> World:\n * - planePos = viewLayer.displayToPlanePos(displayPos)\n * -> compensate for layer scale and offset,\n * - pos = viewController.getPositionFromPlanePoint(planePos).\n *\n * World -> Display:\n * - planePos = viewController.getOffset3DFromPlaneOffset(pos)\n * no need yet for a planePos to displayPos...\n */\nexport class LayerGroup {\n\n /**\n * The container div.\n *\n * @type {HTMLElement}\n */\n #containerDiv;\n\n // jsdoc does not like\n // @type {(ViewLayer|DrawLayer)[]}\n\n /**\n * List of layers.\n *\n * @type {Array}\n */\n #layers = [];\n\n /**\n * The layer scale as {x,y,z}.\n *\n * @type {Scalar3D}\n */\n #scale = {x: 1, y: 1, z: 1};\n\n /**\n * The base scale as {x,y,z}: all posterior scale will be on top of this one.\n *\n * @type {Scalar3D}\n */\n #baseScale = {x: 1, y: 1, z: 1};\n\n /**\n * The layer offset as {x,y,z}.\n *\n * @type {Scalar3D}\n */\n #offset = {x: 0, y: 0, z: 0};\n\n /**\n * Active view layer index.\n *\n * @type {number}\n */\n #activeViewLayerIndex = undefined;\n\n /**\n * Active draw layer index.\n *\n * @type {number}\n */\n #activeDrawLayerIndex = undefined;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Flag to activate crosshair or not.\n *\n * @type {boolean}\n */\n #showCrosshair = false;\n\n /**\n * Crosshair HTML elements.\n *\n * @type {HTMLElement[]}\n */\n #crosshairHtmlElements = [];\n\n /**\n * Tooltip HTML element.\n *\n * @type {HTMLElement}\n */\n #tooltipHtmlElement;\n\n /**\n * The current position used for the crosshair.\n *\n * @type {Point}\n */\n #currentPosition;\n\n /**\n * Image smoothing flag.\n *\n * @type {boolean}\n */\n #imageSmoothing = false;\n\n /**\n * @param {HTMLElement} containerDiv The associated HTML div.\n */\n constructor(containerDiv) {\n this.#containerDiv = containerDiv;\n }\n\n /**\n * Get the showCrosshair flag.\n *\n * @returns {boolean} True to display the crosshair.\n */\n getShowCrosshair() {\n return this.#showCrosshair;\n }\n\n /**\n * Set the showCrosshair flag.\n *\n * @param {boolean} flag True to display the crosshair.\n */\n setShowCrosshair(flag) {\n this.#showCrosshair = flag;\n if (flag) {\n // listen to offset and zoom change\n this.addEventListener('offsetchange', this.#updateCrosshairOnChange);\n this.addEventListener('zoomchange', this.#updateCrosshairOnChange);\n // show crosshair div\n this.#showCrosshairDiv();\n } else {\n // listen to offset and zoom change\n this.removeEventListener('offsetchange', this.#updateCrosshairOnChange);\n this.removeEventListener('zoomchange', this.#updateCrosshairOnChange);\n // remove crosshair div\n this.#removeCrosshairDiv();\n }\n }\n\n /**\n * Set the imageSmoothing flag value.\n *\n * @param {boolean} flag True to enable smoothing.\n */\n setImageSmoothing(flag) {\n this.#imageSmoothing = flag;\n // set for existing layers\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer) {\n layer.setImageSmoothing(flag);\n }\n }\n }\n\n /**\n * Update crosshair on offset or zoom change.\n *\n * @param {object} _event The change event.\n */\n #updateCrosshairOnChange = (_event) => {\n this.#showCrosshairDiv();\n };\n\n /**\n * Get the Id of the container div.\n *\n * @returns {string} The id of the div.\n */\n getDivId() {\n return this.#containerDiv.id;\n }\n\n /**\n * Get the layer scale.\n *\n * @returns {Scalar3D} The scale as {x,y,z}.\n */\n getScale() {\n return this.#scale;\n }\n\n /**\n * Get the base scale.\n *\n * @returns {Scalar3D} The scale as {x,y,z}.\n */\n getBaseScale() {\n return this.#baseScale;\n }\n\n\n /**\n * Get the added scale: the scale added to the base scale.\n *\n * @returns {Scalar3D} The scale as {x,y,z}.\n */\n getAddedScale() {\n return {\n x: this.#scale.x / this.#baseScale.x,\n y: this.#scale.y / this.#baseScale.y,\n z: this.#scale.z / this.#baseScale.z\n };\n }\n\n /**\n * Get the layer offset.\n *\n * @returns {Scalar3D} The offset as {x,y,z}.\n */\n getOffset() {\n return this.#offset;\n }\n\n /**\n * Get the number of layers handled by this class.\n *\n * @returns {number} The number of layers.\n */\n getNumberOfLayers() {\n let count = 0;\n this.#layers.forEach(item => {\n if (typeof item !== 'undefined') {\n count++;\n }\n });\n return count;\n }\n\n /**\n * Check if this layerGroup contains a layer with the input id.\n *\n * @param {string} id The layer id to look for.\n * @returns {boolean} True if this group contains\n * a layer with the input id.\n */\n includes(id) {\n if (typeof id === 'undefined') {\n return false;\n }\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined' &&\n layer.getId() === id) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get a list of view layers according to an input callback function.\n *\n * @param {Function} [callbackFn] A function that takes\n * a ViewLayer as input and returns a boolean. If undefined,\n * returns all view layers.\n * @returns {ViewLayer[]} The layers that\n * satisfy the callbackFn.\n */\n getViewLayers(callbackFn) {\n if (typeof callbackFn === 'undefined') {\n callbackFn = function () {\n return true;\n };\n }\n const res = [];\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer &&\n callbackFn(layer)) {\n res.push(layer);\n }\n }\n return res;\n }\n\n /**\n * Test if one of the view layers satisfies an input callbackFn.\n *\n * @param {Function} callbackFn A function that takes\n * a ViewLayer as input and returns a boolean.\n * @returns {boolean} True if one of the ViewLayers\n * satisfies the callbackFn.\n */\n someViewLayer(callbackFn) {\n let hasOne = false;\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer &&\n callbackFn(layer)) {\n hasOne = true;\n break;\n }\n }\n return hasOne;\n }\n\n /**\n * Get a list of draw layers according to an input callback function.\n *\n * @param {Function} [callbackFn] A function that takes\n * a DrawLayer as input and returns a boolean. If undefined,\n * returns all draw layers.\n * @returns {DrawLayer[]} The layers that\n * satisfy the callbackFn.\n */\n getDrawLayers(callbackFn) {\n if (typeof callbackFn === 'undefined') {\n callbackFn = function () {\n return true;\n };\n }\n const res = [];\n for (const layer of this.#layers) {\n if (layer instanceof DrawLayer &&\n callbackFn(layer)) {\n res.push(layer);\n }\n }\n return res;\n }\n\n /**\n * Get the number of view layers handled by this class.\n *\n * @returns {number} The number of layers.\n */\n getNumberOfViewLayers() {\n let count = 0;\n this.#layers.forEach(item => {\n if (typeof item !== 'undefined' &&\n item instanceof ViewLayer) {\n count++;\n }\n });\n return count;\n }\n\n /**\n * Get the active image layer.\n *\n * @returns {ViewLayer|undefined} The layer.\n */\n getActiveViewLayer() {\n let layer;\n if (typeof this.#activeViewLayerIndex !== 'undefined') {\n const tmpLayer = this.#layers[this.#activeViewLayerIndex];\n if (tmpLayer instanceof ViewLayer) {\n layer = tmpLayer;\n }\n }\n return layer;\n }\n\n /**\n * Get the base view layer.\n *\n * @returns {ViewLayer|undefined} The layer.\n */\n getBaseViewLayer() {\n // use first layer as base for calculating position and\n // line sizes\n let baseLayer;\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer) {\n baseLayer = layer;\n break;\n }\n }\n if (typeof baseLayer === 'undefined') {\n logger.warn('No layer found');\n return;\n }\n return baseLayer;\n }\n\n /**\n * Get the view layers associated to a data id.\n *\n * @param {string} dataId The data id.\n * @returns {ViewLayer[]} The layers.\n */\n getViewLayersByDataId(dataId) {\n const callbackFn = function (layer) {\n return layer.getDataId() === dataId;\n };\n return this.getViewLayers(callbackFn);\n }\n\n /**\n * Search view layers for equal imae meta data.\n *\n * @param {object} meta The meta data to find.\n * @returns {ViewLayer[]} The list of view layers that contain matched data.\n */\n searchViewLayers(meta) {\n const res = [];\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer) {\n if (layer.getViewController().equalImageMeta(meta)) {\n res.push(layer);\n }\n }\n }\n return res;\n }\n\n /**\n * Get the view layers data indices.\n *\n * @returns {string[]} The list of indices.\n */\n getViewDataIndices() {\n const res = [];\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer) {\n res.push(layer.getDataId());\n }\n }\n return res;\n }\n\n /**\n * Get the active draw layer.\n *\n * @returns {DrawLayer|undefined} The layer.\n */\n getActiveDrawLayer() {\n let layer;\n if (typeof this.#activeDrawLayerIndex !== 'undefined') {\n const tmpLayer = this.#layers[this.#activeDrawLayerIndex];\n if (tmpLayer instanceof DrawLayer) {\n layer = tmpLayer;\n }\n }\n return layer;\n }\n\n /**\n * Get the draw layers associated to a data id.\n *\n * @param {string} dataId The data id.\n * @returns {DrawLayer[]} The layers.\n */\n getDrawLayersByDataId(dataId) {\n const callbackFn = function (layer) {\n return layer.getDataId() === dataId;\n };\n return this.getDrawLayers(callbackFn);\n }\n\n /**\n * Set the active view layer.\n *\n * @param {number} index The index of the layer to set as active.\n */\n setActiveViewLayer(index) {\n if (this.#layers[index] instanceof ViewLayer) {\n this.#activeViewLayerIndex = index;\n /**\n * Active layer change event.\n *\n * @event LayerGroup#activelayerchange\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} value The changed value.\n */\n this.#fireEvent({\n type: 'activelayerchange',\n value: [this.#layers[index]]\n });\n } else {\n logger.warn('No view layer to set as active with index: ' +\n index);\n }\n }\n\n /**\n * Set the active view layer with a data id.\n *\n * @param {string} dataId The data id.\n */\n setActiveViewLayerByDataId(dataId) {\n let index;\n for (let i = 0; i < this.#layers.length; ++i) {\n if (this.#layers[i] instanceof ViewLayer &&\n this.#layers[i].getDataId() === dataId) {\n // stop at first one\n index = i;\n break;\n }\n }\n if (typeof index !== 'undefined') {\n this.setActiveViewLayer(index);\n } else {\n logger.warn('No view layer to set as active with dataId: ' +\n dataId);\n }\n }\n\n /**\n * Set the active draw layer.\n *\n * @param {number|undefined} index The index of the layer to set as active\n * or undefined to not set any.\n */\n setActiveDrawLayer(index) {\n this.#activeDrawLayerIndex = index;\n this.#fireEvent({\n type: 'activelayerchange',\n value: [this.#layers[index]]\n });\n }\n\n /**\n * Set the active draw layer with a data id.\n *\n * @param {string} dataId The data id.\n */\n setActiveDrawLayerByDataId(dataId) {\n let index;\n for (let i = 0; i < this.#layers.length; ++i) {\n if (this.#layers[i] instanceof DrawLayer &&\n this.#layers[i].getDataId() === dataId) {\n // stop at first one\n index = i;\n break;\n }\n }\n if (typeof index !== 'undefined') {\n this.setActiveDrawLayer(index);\n } else {\n logger.warn('No draw layer to set as active with dataId: ' +\n dataId);\n }\n }\n\n /**\n * Add a view layer.\n *\n * The new layer will be marked as the active view layer.\n *\n * @returns {ViewLayer} The created layer.\n */\n addViewLayer() {\n // layer index\n const viewLayerIndex = this.#layers.length;\n // create div\n const div = this.#getNextLayerDiv();\n // prepend to container\n this.#containerDiv.append(div);\n // view layer\n const layer = new ViewLayer(div);\n layer.setImageSmoothing(this.#imageSmoothing);\n // add layer\n this.#layers.push(layer);\n // mark it as active\n this.setActiveViewLayer(viewLayerIndex);\n // bind view layer events\n this.#bindViewLayer(layer);\n // return\n return layer;\n }\n\n /**\n * Add a draw layer.\n *\n * The new layer will be marked as the active draw layer.\n *\n * @returns {DrawLayer} The created layer.\n */\n addDrawLayer() {\n // store active index\n this.#activeDrawLayerIndex = this.#layers.length;\n // create div\n const div = this.#getNextLayerDiv();\n // prepend to container\n this.#containerDiv.append(div);\n // draw layer\n const layer = new DrawLayer(div);\n // add layer\n this.#layers.push(layer);\n // bind draw layer events\n this.#bindDrawLayer(layer);\n // return\n return layer;\n }\n\n /**\n * Bind view layer events to this.\n *\n * @param {ViewLayer} viewLayer The view layer to bind.\n */\n #bindViewLayer(viewLayer) {\n // listen to position change to update other group layers\n viewLayer.addEventListener(\n 'positionchange', this.updateLayersToPositionChange);\n // propagate view viewLayer-layer events\n for (const eventName of viewEventNames) {\n viewLayer.addEventListener(eventName, this.#fireEvent);\n }\n // propagate viewLayer events\n viewLayer.addEventListener('renderstart', this.#fireEvent);\n viewLayer.addEventListener('renderend', this.#fireEvent);\n }\n\n /**\n * Un-bind a view layer events to this.\n *\n * @param {ViewLayer} viewLayer The view layer to unbind.\n */\n #unbindViewLayer(viewLayer) {\n // stop listening to position change to update other group layers\n viewLayer.removeEventListener(\n 'positionchange', this.updateLayersToPositionChange);\n // stop propagating view viewLayer-layer events\n for (const eventName of viewEventNames) {\n viewLayer.removeEventListener(eventName, this.#fireEvent);\n }\n // stop propagating viewLayer events\n viewLayer.removeEventListener('renderstart', this.#fireEvent);\n viewLayer.removeEventListener('renderend', this.#fireEvent);\n\n // stop view layer - image binding\n // (binding is done in layer.setView)\n viewLayer.unbindImage();\n }\n\n /**\n * Bind draw layer events to this.\n *\n * @param {DrawLayer} drawLayer The draw layer to bind.\n */\n #bindDrawLayer(drawLayer) {\n // listen to position change to update other group layers\n drawLayer.addEventListener(\n 'positionchange', this.updateLayersToPositionChange);\n drawLayer.addEventListener(\n 'positionchange', this.#fireEvent);\n // propagate drawLayer events\n drawLayer.addEventListener('drawcreate', this.#fireEvent);\n drawLayer.addEventListener('drawdelete', this.#fireEvent);\n }\n\n /**\n * Un-bind a draw layer events to this.\n *\n * @param {DrawLayer} drawLayer The draw layer to unbind.\n */\n #unbindDrawLayer(drawLayer) {\n // stop listening to position change to update other group layers\n drawLayer.removeEventListener(\n 'positionchange', this.updateLayersToPositionChange);\n drawLayer.removeEventListener(\n 'positionchange', this.#fireEvent);\n // propagate drawLayer events\n drawLayer.removeEventListener('drawcreate', this.#fireEvent);\n drawLayer.removeEventListener('drawdelete', this.#fireEvent);\n }\n\n /**\n * Get the next layer DOM div.\n *\n * @returns {HTMLDivElement} A DOM div.\n */\n #getNextLayerDiv() {\n const div = document.createElement('div');\n div.id = getLayerDivId(this.getDivId(), this.#layers.length);\n div.className = 'layer';\n div.style.pointerEvents = 'none';\n return div;\n }\n\n /**\n * Empty the layer list.\n */\n empty() {\n this.#layers = [];\n // reset active indices\n this.#activeViewLayerIndex = undefined;\n this.#activeDrawLayerIndex = undefined;\n // remove possible crosshair\n this.#removeCrosshairDiv();\n // clean container div\n const previous = this.#containerDiv.getElementsByClassName('layer');\n if (previous) {\n while (previous.length > 0) {\n previous[0].remove();\n }\n }\n }\n\n /**\n * Remove all layers for a specific data.\n *\n * @param {string} dataId The data to remove its layers.\n */\n removeLayersByDataId(dataId) {\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined' &&\n layer.getDataId() === dataId) {\n this.removeLayer(layer);\n }\n }\n }\n\n /**\n * Remove a layer from this layer group.\n * Warning: if current active layer, the index will\n * be set to `undefined`. Call one of the setActive\n * methods to define the active index.\n *\n * @param {ViewLayer | DrawLayer} layer The layer to remove.\n */\n removeLayer(layer) {\n // find layer\n const index = this.#layers.findIndex((item) => item === layer);\n if (index === -1) {\n throw new Error('Cannot find layer to remove');\n }\n // unbind and update active index\n if (layer instanceof ViewLayer) {\n this.#unbindViewLayer(layer);\n if (this.#activeViewLayerIndex === index) {\n this.#activeViewLayerIndex = undefined;\n }\n } else {\n this.#unbindDrawLayer(layer);\n if (this.#activeDrawLayerIndex === index) {\n this.#activeDrawLayerIndex = undefined;\n }\n }\n // reset in storage\n this.#layers[index] = undefined;\n // update html\n layer.removeFromDOM();\n }\n\n /**\n * Show a crosshair at a given position.\n *\n * @param {Point} [position] The position where to show the crosshair,\n * defaults to current position.\n */\n #showCrosshairDiv(position) {\n if (typeof position === 'undefined') {\n position = this.#currentPosition;\n }\n\n // remove previous\n this.#removeCrosshairDiv();\n\n // use first layer as base for calculating position and\n // line sizes\n let baseLayer;\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer) {\n baseLayer = layer;\n break;\n }\n }\n if (typeof baseLayer === 'undefined') {\n logger.warn('No layer to show crosshair');\n return;\n }\n\n const vc = baseLayer.getViewController();\n const planePos = vc.getPlanePositionFromPosition(position);\n const displayPos = baseLayer.planePosToDisplay(planePos);\n\n // horizontal line\n if (typeof displayPos.getY() !== 'undefined') {\n const lineH = document.createElement('hr');\n lineH.id = this.getDivId() + '-scroll-crosshair-horizontal';\n lineH.className = 'horizontal';\n lineH.style.width = this.#containerDiv.offsetWidth + 'px';\n lineH.style.left = '0px';\n lineH.style.top = displayPos.getY() + 'px';\n // add to local array\n this.#crosshairHtmlElements.push(lineH);\n // add to html\n this.#containerDiv.appendChild(lineH);\n }\n\n // vertical line\n if (typeof displayPos.getX() !== 'undefined') {\n const lineV = document.createElement('hr');\n lineV.id = this.getDivId() + '-scroll-crosshair-vertical';\n lineV.className = 'vertical';\n lineV.style.width = this.#containerDiv.offsetHeight + 'px';\n lineV.style.left = (displayPos.getX()) + 'px';\n lineV.style.top = '0px';\n // add to local array\n this.#crosshairHtmlElements.push(lineV);\n // add to html\n this.#containerDiv.appendChild(lineV);\n }\n }\n\n /**\n * Remove crosshair divs.\n */\n #removeCrosshairDiv() {\n for (const element of this.#crosshairHtmlElements) {\n element.remove();\n }\n this.#crosshairHtmlElements = [];\n }\n\n /**\n * Displays a tooltip in a temporary `span`.\n * Works with css to hide/show the span only on mouse hover.\n *\n * @param {Point2D} point The update point.\n */\n showTooltip(point) {\n // remove previous div\n this.removeTooltipDiv();\n\n const viewLayer = this.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n const planePos = viewLayer.displayToPlanePos(point);\n const position = viewController.getPositionFromPlanePoint(planePos);\n const value = viewController.getRescaledImageValue(position);\n\n // create\n if (typeof value !== 'undefined') {\n const span = document.createElement('span');\n span.id = 'scroll-tooltip';\n // tooltip position\n span.style.left = (point.getX() + 10) + 'px';\n span.style.top = (point.getY() + 10) + 'px';\n let text = precisionRound(value, 3).toString();\n if (typeof viewController.getPixelUnit() !== 'undefined') {\n text += ' ' + viewController.getPixelUnit();\n }\n span.appendChild(document.createTextNode(text));\n // add to local var\n this.#tooltipHtmlElement = span;\n // add to html\n this.#containerDiv.appendChild(span);\n }\n }\n\n /**\n * Remove the tooltip html div.\n */\n removeTooltipDiv() {\n if (typeof this.#tooltipHtmlElement !== 'undefined') {\n this.#tooltipHtmlElement.remove();\n this.#tooltipHtmlElement = undefined;\n }\n }\n\n /**\n * Can the input position be set on one of the view layers.\n *\n * @param {Point} position The input position.\n * @returns {boolean} True if one view layer accepts the input position.\n */\n isPositionInBounds(position) {\n return this.someViewLayer(function (layer) {\n return layer.getViewController().isPositionInBounds(position);\n });\n }\n\n /**\n * Can one of the view layers be scrolled.\n *\n * @returns {boolean} True if one view layer can be scrolled.\n */\n canScroll() {\n return this.someViewLayer(function (layer) {\n return layer.getViewController().canScroll();\n });\n }\n\n /**\n * Does one of the view layer have more than one slice in the\n * given dimension.\n *\n * @param {number} dim The input dimension.\n * @returns {boolean} True if one view layer has more than one slice.\n */\n moreThanOne(dim) {\n return this.someViewLayer(function (layer) {\n return layer.getViewController().moreThanOne(dim);\n });\n }\n\n /**\n * Update layers (but not the active view layer) to a position change.\n *\n * @param {object} event The position change event.\n * @function\n */\n updateLayersToPositionChange = (event) => {\n // pause positionchange listeners\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.removeEventListener(\n 'positionchange', this.updateLayersToPositionChange);\n layer.removeEventListener('positionchange', this.#fireEvent);\n }\n }\n\n const index = new Index(event.value[0]);\n const position = new Point(event.value[1]);\n\n // store current position\n this.#currentPosition = position;\n\n if (this.#showCrosshair) {\n this.#showCrosshairDiv(position);\n }\n\n // origin of the first view layer\n const viewLayerOffsets = {};\n let baseViewLayerOrigin0;\n let baseViewLayerOrigin;\n // update position for all layers except the source one\n for (const layer of this.#layers) {\n if (typeof layer === 'undefined') {\n continue;\n }\n let hasSetOffset = false;\n\n // view layer case: define and set offsets\n if (layer instanceof ViewLayer) {\n const vc = layer.getViewController();\n // origin0 should always be there\n const origin0 = vc.getOrigin();\n // depending on position, origin could be undefined\n const origin = vc.getOrigin(position);\n\n let scrollOffset;\n let planeOffset;\n\n if (typeof baseViewLayerOrigin === 'undefined') {\n // first view layer, store origins\n baseViewLayerOrigin0 = origin0;\n baseViewLayerOrigin = origin;\n // no offset\n scrollOffset = new Vector3D(0, 0, 0);\n planeOffset = new Vector3D(0, 0, 0);\n } else {\n if (vc.isPositionInBounds(position) &&\n typeof origin !== 'undefined') {\n // TODO: compensate for possible different orientation between views\n const scrollDiff = baseViewLayerOrigin0.minus(origin0);\n scrollOffset = new Vector3D(\n scrollDiff.getX(), scrollDiff.getY(), scrollDiff.getZ());\n const planeDiff = baseViewLayerOrigin.minus(origin);\n planeOffset = new Vector3D(\n planeDiff.getX(), planeDiff.getY(), planeDiff.getZ());\n }\n }\n\n // set and store offsets\n if (typeof scrollOffset !== 'undefined' &&\n typeof planeOffset !== 'undefined') {\n hasSetOffset =\n layer.setBaseOffset(\n scrollOffset, planeOffset,\n baseViewLayerOrigin, baseViewLayerOrigin0\n );\n // store\n viewLayerOffsets[layer.getId()] = {\n scroll: scrollOffset,\n plane: planeOffset\n };\n }\n }\n\n // draw layer case: use associated view layer offsets\n if (layer instanceof DrawLayer) {\n const refOffsets = viewLayerOffsets[layer.getReferenceLayerId()];\n if (typeof refOffsets !== 'undefined') {\n hasSetOffset =\n layer.setBaseOffset(refOffsets.scroll, refOffsets.plane);\n }\n }\n\n // update position (triggers redraw)\n let hasSetPos = false;\n if (layer.getId() !== event.srclayerid) {\n hasSetPos = layer.setCurrentPosition(position, index);\n }\n\n // force redraw if needed\n if (!hasSetPos && hasSetOffset) {\n layer.draw();\n }\n }\n\n // re-start positionchange listeners\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.addEventListener(\n 'positionchange', this.updateLayersToPositionChange);\n layer.addEventListener('positionchange', this.#fireEvent);\n }\n }\n };\n\n /**\n * Calculate the div to world size ratio needed to fit\n * the largest data.\n *\n * @returns {number|undefined} The ratio.\n */\n getDivToWorldSizeRatio() {\n // check container\n if (this.#containerDiv.offsetWidth === 0 &&\n this.#containerDiv.offsetHeight === 0) {\n throw new Error('Cannot fit to zero sized container.');\n }\n // get max world size\n const maxWorldSize = this.getMaxWorldSize();\n if (typeof maxWorldSize === 'undefined') {\n return undefined;\n }\n // if the container has a width but no height,\n // resize it to follow the same ratio to completely\n // fill the div with the image\n if (this.#containerDiv.offsetHeight === 0) {\n const ratioX = this.#containerDiv.offsetWidth / maxWorldSize.x;\n const height = maxWorldSize.y * ratioX;\n this.#containerDiv.style.height = height + 'px';\n }\n // return best fit\n return Math.min(\n this.#containerDiv.offsetWidth / maxWorldSize.x,\n this.#containerDiv.offsetHeight / maxWorldSize.y\n );\n }\n\n /**\n * Fit to container: set the layers div to world size ratio.\n *\n * @param {number} divToWorldSizeRatio The ratio.\n */\n fitToContainer(divToWorldSizeRatio) {\n // get maximum world size\n const maxWorldSize = this.getMaxWorldSize();\n // exit if none\n if (typeof maxWorldSize === 'undefined') {\n return;\n }\n\n const containerSize = {\n x: this.#containerDiv.offsetWidth,\n y: this.#containerDiv.offsetHeight\n };\n // offset to keep data centered\n const fitOffset = {\n x: -0.5 *\n (containerSize.x - Math.floor(maxWorldSize.x * divToWorldSizeRatio)),\n y: -0.5 *\n (containerSize.y - Math.floor(maxWorldSize.y * divToWorldSizeRatio))\n };\n\n // apply to layers\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.fitToContainer(containerSize, divToWorldSizeRatio, fitOffset);\n }\n }\n\n // update crosshair\n if (this.#showCrosshair) {\n this.#showCrosshairDiv();\n }\n }\n\n /**\n * Get the largest data world (mm) size.\n *\n * @returns {Scalar2D|undefined} The largest size as {x,y}.\n */\n getMaxWorldSize() {\n let maxSize = {x: 0, y: 0};\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer) {\n const size = layer.getImageWorldSize();\n if (size.x > maxSize.x) {\n maxSize.x = size.x;\n }\n if (size.y > maxSize.y) {\n maxSize.y = size.y;\n }\n }\n }\n if (maxSize.x === 0 && maxSize.y === 0) {\n maxSize = undefined;\n }\n return maxSize;\n }\n\n /**\n * Flip all layers along the Z axis without offset compensation.\n */\n flipScaleZ() {\n this.#baseScale.z *= -1;\n this.setScale(this.#baseScale);\n }\n\n /**\n * Add scale to the layers. Scale cannot go lower than 0.1.\n *\n * @param {number} scaleStep The scale to add.\n * @param {Point3D} center The scale center Point3D.\n */\n addScale(scaleStep, center) {\n const newScale = {\n x: this.#scale.x * (1 + scaleStep),\n y: this.#scale.y * (1 + scaleStep),\n z: this.#scale.z * (1 + scaleStep)\n };\n this.setScale(newScale, center);\n }\n\n /**\n * Set the layers' scale.\n *\n * @param {Scalar3D} newScale The scale to apply as {x,y,z}.\n * @param {Point3D} [center] The scale center Point3D.\n * @fires LayerGroup#zoomchange\n */\n setScale(newScale, center) {\n this.#scale = newScale;\n // apply to layers\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.setScale(this.#scale, center);\n }\n }\n\n // event value\n const value = [\n newScale.x,\n newScale.y,\n newScale.z\n ];\n if (typeof center !== 'undefined') {\n value.push(center.getX());\n value.push(center.getY());\n value.push(center.getZ());\n }\n\n /**\n * Zoom change event.\n *\n * @event LayerGroup#zoomchange\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} value The changed value.\n */\n this.#fireEvent({\n type: 'zoomchange',\n value: value\n });\n }\n\n /**\n * Add translation to the layers.\n *\n * @param {Scalar3D} translation The translation as {x,y,z}.\n */\n addTranslation(translation) {\n this.setOffset({\n x: this.#offset.x - translation.x,\n y: this.#offset.y - translation.y,\n z: this.#offset.z - translation.z\n });\n }\n\n /**\n * Set the layers' offset.\n *\n * @param {Scalar3D} newOffset The offset as {x,y,z}.\n * @fires LayerGroup#offsetchange\n */\n setOffset(newOffset) {\n // store\n this.#offset = newOffset;\n // apply to layers\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.setOffset(this.#offset);\n }\n }\n\n /**\n * Offset change event.\n *\n * @event LayerGroup#offsetchange\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} value The changed value.\n */\n this.#fireEvent({\n type: 'offsetchange',\n value: [\n this.#offset.x,\n this.#offset.y,\n this.#offset.z\n ]\n });\n }\n\n /**\n * Reset the stage to its initial scale and no offset.\n */\n reset() {\n this.setScale(this.#baseScale);\n this.setOffset({x: 0, y: 0, z: 0});\n }\n\n /**\n * Draw the layer.\n */\n draw() {\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.draw();\n }\n }\n }\n\n /**\n * Display the layer.\n *\n * @param {boolean} flag Whether to display the layer or not.\n */\n display(flag) {\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.display(flag);\n }\n }\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n} // LayerGroup class\n","import {Point, Point3D} from '../math/point';\nimport {WindowLevel} from '../image/windowLevel';\nimport {LayerGroup} from './layerGroup';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {ViewLayer} from '../gui/viewLayer';\nimport {DrawLayer} from '../gui/drawLayer';\n/* eslint-enable no-unused-vars */\n\n/**\n * Window/level binder.\n */\nexport class WindowLevelBinder {\n getEventType = function () {\n return 'wlchange';\n };\n getCallback = function (layerGroup) {\n return function (event) {\n const viewLayers = layerGroup.getViewLayersByDataId(event.dataid);\n if (viewLayers.length !== 0) {\n const vc = viewLayers[0].getViewController();\n if (event.value.length === 2) {\n const wl = new WindowLevel(event.value[0], event.value[1]);\n vc.setWindowLevel(wl);\n }\n if (event.value.length === 3) {\n vc.setWindowLevelPreset(event.value[2]);\n }\n }\n };\n };\n}\n\n/**\n * Colour map binder.\n */\nexport class ColourMapBinder {\n getEventType = function () {\n return 'colourmapchange';\n };\n getCallback = function (layerGroup) {\n return function (event) {\n const viewLayers = layerGroup.getViewLayersByDataId(event.dataid);\n if (viewLayers.length !== 0) {\n const vc = viewLayers[0].getViewController();\n vc.setColourMap(event.value[0]);\n }\n };\n };\n}\n\n/**\n * Position binder.\n */\nexport class PositionBinder {\n getEventType = function () {\n return 'positionchange';\n };\n getCallback = function (layerGroup) {\n return function (event) {\n const pointValues = event.value[1];\n const vc = layerGroup.getActiveViewLayer().getViewController();\n // handle different number of dimensions\n const currentPos = vc.getCurrentPosition();\n const currentDims = currentPos.length();\n const inputDims = pointValues.length;\n if (inputDims !== currentDims) {\n if (inputDims === currentDims - 1) {\n // add missing dim, for ex: input 3D -> current 4D\n pointValues.push(currentPos.get(currentDims - 1));\n } else if (inputDims === currentDims + 1) {\n // remove extra dim, for ex: input 4D -> current 3D\n pointValues.pop();\n }\n }\n vc.setCurrentPosition(new Point(pointValues));\n };\n };\n}\n\n/**\n * Zoom binder.\n */\nexport class ZoomBinder {\n getEventType = function () {\n return 'zoomchange';\n };\n getCallback = function (layerGroup) {\n return function (event) {\n const scale = {\n x: event.value[0],\n y: event.value[1],\n z: event.value[2]\n };\n let center;\n if (event.value.length === 6) {\n center = new Point3D(\n event.value[3],\n event.value[4],\n event.value[5]\n );\n }\n layerGroup.setScale(scale, center);\n layerGroup.draw();\n };\n };\n}\n\n/**\n * Offset binder.\n */\nexport class OffsetBinder {\n getEventType = function () {\n return 'offsetchange';\n };\n getCallback = function (layerGroup) {\n return function (event) {\n layerGroup.setOffset({\n x: event.value[0],\n y: event.value[1],\n z: event.value[2]\n });\n layerGroup.draw();\n };\n };\n}\n\n/**\n * Opacity binder. Only propagates to view layers of the same data.\n */\nexport class OpacityBinder {\n getEventType = function () {\n return 'opacitychange';\n };\n getCallback = function (layerGroup) {\n return function (event) {\n // exit if no data id\n if (typeof event.dataid === 'undefined') {\n return;\n }\n // propagate to first view layer if it is not base layer\n const viewLayers = layerGroup.getViewLayersByDataId(event.dataid);\n const baseLayer = layerGroup.getBaseViewLayer();\n if (viewLayers.length !== 0 && baseLayer !== viewLayers[0]) {\n viewLayers[0].setOpacity(event.value);\n viewLayers[0].draw();\n }\n };\n };\n}\n\n/**\n * List of binders.\n */\nexport const binderList = {\n WindowLevelBinder,\n PositionBinder,\n ZoomBinder,\n OffsetBinder,\n OpacityBinder,\n ColourMapBinder\n};\n\n/**\n * Stage: controls a list of layer groups and their\n * synchronisation.\n */\nexport class Stage {\n\n /**\n * Associated layer groups.\n *\n * @type {LayerGroup[]}\n */\n #layerGroups = [];\n\n /**\n * Active layer group index.\n *\n * @type {number|undefined}\n */\n #activeLayerGroupIndex;\n\n /**\n * Image smoothing flag.\n *\n * @type {boolean}\n */\n #imageSmoothing = false;\n\n // layer group binders\n #binders = [];\n // binder callbacks\n #callbackStore = null;\n\n /**\n * Get the layer group at the given index.\n *\n * @param {number} index The index.\n * @returns {LayerGroup|undefined} The layer group.\n */\n getLayerGroup(index) {\n return this.#layerGroups[index];\n }\n\n /**\n * Get the number of layer groups that form the stage.\n *\n * @returns {number} The number of layer groups.\n */\n getNumberOfLayerGroups() {\n return this.#layerGroups.length;\n }\n\n /**\n * Get the active layer group.\n *\n * @returns {LayerGroup|undefined} The layer group.\n */\n getActiveLayerGroup() {\n return this.getLayerGroup(this.#activeLayerGroupIndex);\n }\n\n /**\n * Set the active layer group.\n *\n * @param {number} index The layer group index.\n */\n setActiveLayerGroup(index) {\n if (typeof this.getLayerGroup(index) !== 'undefined') {\n this.#activeLayerGroupIndex = index;\n } else {\n logger.warn('No layer group to set as active with index: ' +\n index);\n }\n }\n\n /**\n * Get the view layers associated to a data id.\n *\n * @param {string} dataId The data id.\n * @returns {ViewLayer[]} The layers.\n */\n getViewLayersByDataId(dataId) {\n let res = [];\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n res = res.concat(this.#layerGroups[i].getViewLayersByDataId(dataId));\n }\n return res;\n }\n\n /**\n * Get a list of view layers according to an input callback function.\n *\n * @param {Function} [callbackFn] A function that takes\n * a ViewLayer as input and returns a boolean. If undefined,\n * returns all view layers.\n * @returns {ViewLayer[]} The layers that\n * satisfy the callbackFn.\n */\n getViewLayers(callbackFn) {\n let res = [];\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n res = res.concat(this.#layerGroups[i].getViewLayers(callbackFn));\n }\n return res;\n }\n\n /**\n * Get the draw layers associated to a data id.\n *\n * @param {string} dataId The data id.\n * @returns {DrawLayer[]} The layers.\n */\n getDrawLayersByDataId(dataId) {\n let res = [];\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n res = res.concat(this.#layerGroups[i].getDrawLayersByDataId(dataId));\n }\n return res;\n }\n\n /**\n * Get a list of draw layers according to an input callback function.\n *\n * @param {Function} [callbackFn] A function that takes\n * a DrawLayer as input and returns a boolean. If undefined,\n * returns all draw layers.\n * @returns {DrawLayer[]} The layers that\n * satisfy the callbackFn.\n */\n getDrawLayers(callbackFn) {\n let res = [];\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n res = res.concat(this.#layerGroups[i].getDrawLayers(callbackFn));\n }\n return res;\n }\n\n /**\n * Add a layer group to the list.\n *\n * The new layer group will be marked as the active layer group.\n *\n * @param {object} htmlElement The HTML element of the layer group.\n * @returns {LayerGroup} The newly created layer group.\n */\n addLayerGroup(htmlElement) {\n this.#activeLayerGroupIndex = this.#layerGroups.length;\n const layerGroup = new LayerGroup(htmlElement);\n layerGroup.setImageSmoothing(this.#imageSmoothing);\n // add to storage\n const isBound = this.#callbackStore && this.#callbackStore.length !== 0;\n if (isBound) {\n this.unbindLayerGroups();\n }\n this.#layerGroups.push(layerGroup);\n if (isBound) {\n this.bindLayerGroups();\n }\n // return created group\n return layerGroup;\n }\n\n /**\n * Get a layer group from an HTML element id.\n *\n * @param {string} id The element id to find.\n * @returns {LayerGroup} The layer group.\n */\n getLayerGroupByDivId(id) {\n return this.#layerGroups.find(function (item) {\n return item.getDivId() === id;\n });\n }\n\n /**\n * Set the layer groups binders.\n *\n * @param {Array} list The list of binder objects.\n */\n setBinders(list) {\n if (typeof list === 'undefined' || list === null) {\n throw new Error('Cannot set null or undefined binders');\n }\n if (this.#binders.length !== 0) {\n this.unbindLayerGroups();\n }\n this.#binders = list.slice();\n this.bindLayerGroups();\n }\n\n /**\n * Empty the layer group list.\n */\n empty() {\n this.unbindLayerGroups();\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n this.#layerGroups[i].empty();\n }\n this.#layerGroups = [];\n this.#activeLayerGroupIndex = undefined;\n }\n\n /**\n * Remove all layers for a specific data.\n *\n * @param {string} dataId The data to remove its layers.\n */\n removeLayersByDataId(dataId) {\n for (const layerGroup of this.#layerGroups) {\n layerGroup.removeLayersByDataId(dataId);\n }\n }\n\n /**\n * Remove a layer group from this stage.\n *\n * @param {LayerGroup} layerGroup The layer group to remove.\n */\n removeLayerGroup(layerGroup) {\n // find layer\n const index = this.#layerGroups.findIndex((item) => item === layerGroup);\n if (index === -1) {\n throw new Error('Cannot find layerGroup to remove');\n }\n // unbind\n this.unbindLayerGroups();\n // empty layer group\n layerGroup.empty();\n // remove from storage\n this.#layerGroups.splice(index, 1);\n // update active index\n if (this.#activeLayerGroupIndex === index) {\n this.#activeLayerGroupIndex = undefined;\n }\n // bind\n this.bindLayerGroups();\n }\n\n /**\n * Reset the stage: calls reset on all layer groups.\n */\n reset() {\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n this.#layerGroups[i].reset();\n }\n }\n\n /**\n * Draw the stage: calls draw on all layer groups.\n */\n draw() {\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n this.#layerGroups[i].draw();\n }\n }\n\n /**\n * Fit to container: synchronise the div to world size ratio\n * of the group layers.\n */\n fitToContainer() {\n // find the minimum ratio\n let minRatio;\n const hasRatio = [];\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n const ratio = this.#layerGroups[i].getDivToWorldSizeRatio();\n if (typeof ratio !== 'undefined') {\n hasRatio.push(i);\n if (typeof minRatio === 'undefined' || ratio < minRatio) {\n minRatio = ratio;\n }\n }\n }\n // exit if no ratio\n if (typeof minRatio === 'undefined') {\n return;\n }\n // apply min ratio to layers\n for (let j = 0; j < this.#layerGroups.length; ++j) {\n if (hasRatio.includes(j)) {\n this.#layerGroups[j].fitToContainer(minRatio);\n }\n }\n }\n\n /**\n * Bind the layer groups of the stage.\n */\n bindLayerGroups() {\n if (this.#layerGroups.length === 0 ||\n this.#layerGroups.length === 1 ||\n this.#binders.length === 0) {\n return;\n }\n // create callback store\n this.#callbackStore = new Array(this.#layerGroups.length);\n // add listeners\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n for (let j = 0; j < this.#binders.length; ++j) {\n this.#addEventListeners(i, this.#binders[j]);\n }\n }\n }\n\n /**\n * Unbind the layer groups of the stage.\n */\n unbindLayerGroups() {\n if (this.#layerGroups.length === 0 ||\n this.#layerGroups.length === 1 ||\n this.#binders.length === 0 ||\n !this.#callbackStore) {\n return;\n }\n // remove listeners\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n for (let j = 0; j < this.#binders.length; ++j) {\n this.#removeEventListeners(i, this.#binders[j]);\n }\n }\n // clear callback store\n this.#callbackStore = null;\n }\n\n /**\n * Set the imageSmoothing flag value.\n *\n * @param {boolean} flag True to enable smoothing.\n */\n setImageSmoothing(flag) {\n this.#imageSmoothing = flag;\n // set for existing layer groups\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n this.#layerGroups[i].setImageSmoothing(flag);\n }\n }\n\n /**\n * Get the binder callback function for a given layer group index.\n * The function is created if not yet stored.\n *\n * @param {object} binder The layer binder.\n * @param {number} index The index of the associated layer group.\n * @returns {Function} The binder function.\n */\n #getBinderCallback(binder, index) {\n if (typeof this.#callbackStore[index] === 'undefined') {\n this.#callbackStore[index] = [];\n }\n const store = this.#callbackStore[index];\n let binderObj = store.find(function (elem) {\n return elem.binder === binder;\n });\n if (typeof binderObj === 'undefined') {\n // create new callback object\n binderObj = {\n binder: binder,\n callback: (event) => {\n // stop listeners\n this.#removeEventListeners(index, binder);\n // apply binder\n binder.getCallback(this.#layerGroups[index])(event);\n // re-start listeners\n this.#addEventListeners(index, binder);\n }\n };\n this.#callbackStore[index].push(binderObj);\n }\n return binderObj.callback;\n }\n\n /**\n * Add event listeners for a given layer group index and binder.\n *\n * @param {number} index The index of the associated layer group.\n * @param {object} binder The layer binder.\n */\n #addEventListeners(index, binder) {\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n if (i !== index) {\n this.#layerGroups[index].addEventListener(\n binder.getEventType(),\n this.#getBinderCallback(binder, i)\n );\n }\n }\n }\n\n /**\n * Remove event listeners for a given layer group index and binder.\n *\n * @param {number} index The index of the associated layer group.\n * @param {object} binder The layer binder.\n */\n #removeEventListeners(index, binder) {\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n if (i !== index) {\n this.#layerGroups[index].removeEventListener(\n binder.getEventType(),\n this.#getBinderCallback(binder, i)\n );\n }\n }\n }\n\n} // class Stage\n","import {Index} from '../math/index';\nimport {colourNameToHex} from '../utils/colour';\nimport {WindowLevel} from '../image/windowLevel';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * State class.\n * Saves: data url/path, display info.\n *\n * History:\n * - v0.5 (dwv 0.30.0, 12/2021):\n * - store position as array,\n * - new draw position group key.\n * - v0.4 (dwv 0.29.0, 06/2021):\n * - move drawing details into meta property,\n * - remove scale center and translation, add offset.\n * - v0.3 (dwv v0.23.0, 03/2018):\n * - new drawing structure, drawings are now the full layer object and\n * using toObject to avoid saving a string representation,\n * - new details structure: simple array of objects referenced by draw ids.\n * - v0.2 (dwv v0.17.0, 12/2016):\n * - adds draw details: array [nslices][nframes] of detail objects.\n * - v0.1 (dwv v0.15.0, 07/2016):\n * - adds version,\n * - drawings: array [nslices][nframes] with all groups.\n * - initial release (dwv v0.10.0, 05/2015), no version number:\n * - content: window-center, window-width, position, scale,\n * scaleCenter, translation, drawings,\n * - drawings: array [nslices] with all groups.\n */\nexport class State {\n /**\n * The state data id.\n *\n * @type {string}\n */\n #dataId;\n\n /**\n * @param {string} dataId The associated data id.\n */\n constructor(dataId) {\n this.#dataId = dataId;\n }\n\n /**\n * Load an application state from JSON.\n *\n * @param {string} json The state as a JSON string.\n * @returns {object} The state object.\n */\n fromJSON(json) {\n const data = JSON.parse(json);\n let res = null;\n if (data.version === '0.1') {\n res = this.#readV01(data);\n } else if (data.version === '0.2') {\n res = this.#readV02(data);\n } else if (data.version === '0.3') {\n res = this.#readV03(data);\n } else if (data.version === '0.4') {\n res = this.#readV04(data);\n } else if (data.version === '0.5') {\n res = this.#readV05(data);\n } else {\n throw new Error('Unknown state file format version: \\'' +\n data.version + '\\'.');\n }\n return res;\n }\n\n /**\n * Load an application state from JSON.\n *\n * @param {App} app The app to apply the state to.\n * @param {object} data The state data.\n */\n apply(app, data) {\n const layerGroup = app.getActiveLayerGroup();\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n // display\n const wl = new WindowLevel(data['window-center'], data['window-width']);\n viewController.setWindowLevel(wl);\n // position is index...\n viewController.setCurrentIndex(new Index(data.position));\n // apply saved scale on top of current base one\n const baseScale = app.getActiveLayerGroup().getBaseScale();\n let scale = null;\n let offset = null;\n if (typeof data.scaleCenter !== 'undefined') {\n scale = {\n x: data.scale * baseScale.x,\n y: data.scale * baseScale.y,\n z: 1\n };\n // ---- transform translation (now) ----\n // Tx = -offset.x * scale.x\n // => offset.x = -Tx / scale.x\n // ---- transform translation (before) ----\n // origin.x = centerX - (centerX - origin.x) * (newZoomX / zoom.x);\n // (zoom.x -> initial zoom = base scale, origin.x = 0)\n // Tx = origin.x + (trans.x * zoom.x)\n const originX = data.scaleCenter.x - data.scaleCenter.x * data.scale;\n const originY = data.scaleCenter.y - data.scaleCenter.y * data.scale;\n const oldTx = originX + data.translation.x * scale.x;\n const oldTy = originY + data.translation.y * scale.y;\n offset = {\n x: -oldTx / scale.x,\n y: -oldTy / scale.y,\n z: 0\n };\n } else {\n scale = {\n x: data.scale.x * baseScale.x,\n y: data.scale.y * baseScale.y,\n z: baseScale.z\n };\n offset = {\n x: data.offset.x,\n y: data.offset.y,\n z: 0\n };\n }\n app.getActiveLayerGroup().setScale(scale);\n app.getActiveLayerGroup().setOffset(offset);\n // drawings (will draw the draw layer)\n app.setDrawings(data.drawings, data.drawingsDetails, this.#dataId);\n }\n\n /**\n * Read an application state from an Object in v0.1 format.\n *\n * @param {object} data The Object representation of the state.\n * @returns {object} The state object.\n */\n #readV01(data) {\n // v0.1 -> v0.2\n const v02DAndD = v01Tov02DrawingsAndDetails(data.drawings);\n // v0.2 -> v0.3, v0.4\n data.drawings = v02Tov03Drawings(v02DAndD.drawings).toObject();\n data.drawingsDetails = v03Tov04DrawingsDetails(\n v02DAndD.drawingsDetails);\n // v0.4 -> v0.5\n data = v04Tov05Data(data);\n data.drawings = v04Tov05Drawings(data.drawings);\n return data;\n }\n\n /**\n * Read an application state from an Object in v0.2 format.\n *\n * @param {object} data The Object representation of the state.\n * @returns {object} The state object.\n */\n #readV02(data) {\n // v0.2 -> v0.3, v0.4\n data.drawings = v02Tov03Drawings(data.drawings).toObject();\n data.drawingsDetails = v03Tov04DrawingsDetails(\n v02Tov03DrawingsDetails(data.drawingsDetails));\n // v0.4 -> v0.5\n data = v04Tov05Data(data);\n data.drawings = v04Tov05Drawings(data.drawings);\n return data;\n }\n\n /**\n * Read an application state from an Object in v0.3 format.\n *\n * @param {object} data The Object representation of the state.\n * @returns {object} The state object.\n */\n #readV03(data) {\n // v0.3 -> v0.4\n data.drawingsDetails = v03Tov04DrawingsDetails(data.drawingsDetails);\n // v0.4 -> v0.5\n data = v04Tov05Data(data);\n data.drawings = v04Tov05Drawings(data.drawings);\n return data;\n }\n\n /**\n * Read an application state from an Object in v0.4 format.\n *\n * @param {object} data The Object representation of the state.\n * @returns {object} The state object.\n */\n #readV04(data) {\n // v0.4 -> v0.5\n data = v04Tov05Data(data);\n data.drawings = v04Tov05Drawings(data.drawings);\n return data;\n }\n /**\n * Read an application state from an Object in v0.5 format.\n *\n * @param {object} data The Object representation of the state.\n * @returns {object} The state object.\n */\n #readV05(data) {\n return data;\n }\n\n} // State class\n\n/**\n * Convert drawings from v0.2 to v0.3:\n * - v0.2: one layer per slice/frame,\n * - v0.3: one layer, one group per slice. `setDrawing` expects the full stage.\n *\n * @param {Array} drawings An array of drawings.\n * @returns {object} The layer with the converted drawings.\n */\nfunction v02Tov03Drawings(drawings) {\n // Auxiliar variables\n let group, groupShapes, parentGroup;\n // Avoid errors when dropping multiple states\n //drawLayer.getChildren().each(function(node){\n // node.visible(false);\n //});\n\n /**\n * Get the draw group id for a given position.\n *\n * @param {Index} currentPosition The current position.\n * @returns {string} The group id.\n */\n function getDrawPositionGroupId(currentPosition) {\n const sliceNumber = currentPosition.get(2);\n const frameNumber = currentPosition.length() === 4\n ? currentPosition.get(3) : 0;\n return 'slice-' + sliceNumber + '_frame-' + frameNumber;\n }\n\n const drawLayer = new Konva.Layer({\n listening: false,\n visible: true\n });\n\n // Get the positions-groups data\n const groupDrawings = typeof drawings === 'string'\n ? JSON.parse(drawings) : drawings;\n // Iterate over each position-groups\n for (let k = 0, lenk = groupDrawings.length; k < lenk; ++k) {\n // Iterate over each frame\n for (let f = 0, lenf = groupDrawings[k].length; f < lenf; ++f) {\n groupShapes = groupDrawings[k][f];\n if (groupShapes.length !== 0) {\n // Create position-group set as visible and append it to drawLayer\n parentGroup = new Konva.Group({\n id: getDrawPositionGroupId(new Index([1, 1, k, f])),\n name: 'position-group',\n visible: false\n });\n\n // Iterate over shapes-group\n for (let g = 0, leng = groupShapes.length; g < leng; ++g) {\n // create the konva group\n group = Konva.Node.create(groupShapes[g]);\n // enforce draggable: only the shape was draggable in v0.2,\n // now the whole group is.\n group.draggable(true);\n group.getChildren().forEach(function (gnode) {\n gnode.draggable(false);\n });\n // add to position group\n parentGroup.add(group);\n }\n // add to layer\n drawLayer.add(parentGroup);\n }\n }\n }\n\n return drawLayer;\n}\n\n/**\n * Convert drawings from v0.1 to v0.2:\n * - v0.1: text on its own,\n * - v0.2: text as part of label.\n *\n * @param {Array} inputDrawings An array of drawings.\n * @returns {object} The converted drawings.\n */\nfunction v01Tov02DrawingsAndDetails(inputDrawings) {\n const newDrawings = [];\n const drawingsDetails = {};\n\n let drawGroups;\n let drawGroup;\n // loop over each slice\n for (let k = 0, lenk = inputDrawings.length; k < lenk; ++k) {\n // loop over each frame\n newDrawings[k] = [];\n for (let f = 0, lenf = inputDrawings[k].length; f < lenf; ++f) {\n // draw group\n drawGroups = inputDrawings[k][f];\n const newFrameDrawings = [];\n // Iterate over shapes-group\n for (let g = 0, leng = drawGroups.length; g < leng; ++g) {\n // create konva group from input\n drawGroup = Konva.Node.create(drawGroups[g]);\n // force visible (not set in state)\n drawGroup.visible(true);\n // label position\n let pos = {x: 0, y: 0};\n // update shape colour\n const kshape = drawGroup.getChildren(function (node) {\n return node.name() === 'shape';\n })[0];\n kshape.stroke(colourNameToHex(kshape.stroke()));\n // special line case\n if (drawGroup.name() === 'line-group') {\n // update name\n drawGroup.name('ruler-group');\n // add ticks\n const ktick0 = new Konva.Line({\n points: [kshape.points()[0],\n kshape.points()[1],\n kshape.points()[0],\n kshape.points()[1]],\n name: 'shape-tick0'\n });\n drawGroup.add(ktick0);\n const ktick1 = new Konva.Line({\n points: [kshape.points()[2],\n kshape.points()[3],\n kshape.points()[2],\n kshape.points()[3]],\n name: 'shape-tick1'\n });\n drawGroup.add(ktick1);\n }\n // special protractor case: update arc name\n const karcs = drawGroup.getChildren(function (node) {\n return node.name() === 'arc';\n });\n if (karcs.length === 1) {\n karcs[0].name('shape-arc');\n }\n // get its text\n const ktexts = drawGroup.getChildren(function (node) {\n return node.name() === 'text';\n });\n // update text: move it into a label\n let ktext = new Konva.Text({\n name: 'text',\n text: ''\n });\n if (ktexts.length === 1) {\n pos.x = ktexts[0].x();\n pos.y = ktexts[0].y();\n // remove it from the group\n ktexts[0].remove();\n // use it\n ktext = ktexts[0];\n } else {\n // use shape position if no text\n if (kshape.points().length !== 0) {\n pos = {x: kshape.points()[0],\n y: kshape.points()[1]};\n }\n }\n // create new label with text and tag\n const klabel = new Konva.Label({\n x: pos.x,\n y: pos.y,\n name: 'label'\n });\n klabel.add(ktext);\n klabel.add(new Konva.Tag());\n // add label to group\n drawGroup.add(klabel);\n // add group to list\n newFrameDrawings.push(JSON.stringify(drawGroup.toObject()));\n\n // create details (v0.3 format)\n let textExpr = ktext.text();\n const txtLen = textExpr.length;\n let quant = null;\n // adapt to text with flag\n if (drawGroup.name() === 'ruler-group') {\n quant = {\n length: {\n value: parseFloat(textExpr.substring(0, txtLen - 2)),\n unit: textExpr.substring(-2)\n }\n };\n textExpr = '{length}';\n } else if (drawGroup.name() === 'ellipse-group' ||\n drawGroup.name() === 'rectangle-group') {\n quant = {\n surface: {\n value: parseFloat(textExpr.substring(0, txtLen - 3)),\n unit: textExpr.substring(-3)\n }\n };\n textExpr = '{surface}';\n } else if (drawGroup.name() === 'protractor-group' ||\n drawGroup.name() === 'rectangle-group') {\n quant = {\n angle: {\n value: parseFloat(textExpr.substring(0, txtLen - 1)),\n unit: textExpr.substring(-1)\n }\n };\n textExpr = '{angle}';\n }\n // set details\n drawingsDetails[drawGroup.id()] = {\n textExpr: textExpr,\n longText: '',\n quant: quant\n };\n\n }\n newDrawings[k].push(newFrameDrawings);\n }\n }\n\n return {drawings: newDrawings, drawingsDetails: drawingsDetails};\n}\n\n/**\n * Convert drawing details from v0.2 to v0.3:\n * - v0.2: array [nslices][nframes] with all,\n * - v0.3: simple array of objects referenced by draw ids.\n *\n * @param {Array} details An array of drawing details.\n * @returns {object} The converted drawings.\n */\nfunction v02Tov03DrawingsDetails(details) {\n const res = {};\n // Get the positions-groups data\n const groupDetails = typeof details === 'string'\n ? JSON.parse(details) : details;\n // Iterate over each position-groups\n for (let k = 0, lenk = groupDetails.length; k < lenk; ++k) {\n // Iterate over each frame\n for (let f = 0, lenf = groupDetails[k].length; f < lenf; ++f) {\n // Iterate over shapes-group\n for (let g = 0, leng = groupDetails[k][f].length; g < leng; ++g) {\n const group = groupDetails[k][f][g];\n res[group.id] = {\n textExpr: group.textExpr,\n longText: group.longText,\n quant: group.quant\n };\n }\n }\n }\n return res;\n}\n\n/**\n * Convert drawing details from v0.3 to v0.4:\n * - v0.3: properties at group root,\n * - v0.4: properties in group meta object.\n *\n * @param {Array} details An array of drawing details.\n * @returns {object} The converted drawings.\n */\nfunction v03Tov04DrawingsDetails(details) {\n const res = {};\n const keys = Object.keys(details);\n // Iterate over each position-groups\n for (let k = 0, lenk = keys.length; k < lenk; ++k) {\n const detail = details[keys[k]];\n res[keys[k]] = {\n meta: {\n textExpr: detail.textExpr,\n longText: detail.longText,\n quantification: detail.quant\n }\n };\n }\n return res;\n}\n\n/**\n * Convert drawing from v0.4 to v0.5:\n * - v0.4: position as object,\n * - v0.5: position as array.\n *\n * @param {object} data An array of drawing.\n * @returns {object} The converted drawings.\n */\nfunction v04Tov05Data(data) {\n const pos = data.position;\n data.position = [pos.i, pos.j, pos.k];\n return data;\n}\n\n/**\n * Convert drawing from v0.4 to v0.5:\n * - v0.4: draw id as 'slice-0_frame-1',\n * - v0.5: draw id as '#2-0_#3-1'.\n *\n * @param {object} inputDrawings An array of drawing.\n * @returns {object} The converted drawings.\n */\nfunction v04Tov05Drawings(inputDrawings) {\n // Iterate over each position-groups\n const posGroups = inputDrawings.children;\n for (let k = 0, lenk = posGroups.length; k < lenk; ++k) {\n const posGroup = posGroups[k];\n const id = posGroup.attrs.id;\n const ids = id.split('_');\n const sliceNumber = parseInt(ids[0].substring(6), 10); // 'slice-0'\n const frameNumber = parseInt(ids[1].substring(6), 10); // 'frame-0'\n let newId = '#2-';\n if (sliceNumber === 0 && frameNumber !== 0) {\n newId += frameNumber;\n } else {\n newId += sliceNumber;\n }\n posGroup.attrs.id = newId;\n }\n return inputDrawings;\n}\n","import {logger} from './logger';\nimport {splitKeyValueString} from './string';\n\n/**\n * Get an full object URL from a string uri.\n *\n * @param {string} uri A string representing the url.\n * @returns {URL} A URL object.\n */\nexport function getUrlFromUri(uri) {\n // add base to allow for relative urls\n // (base is not used for absolute urls)\n let base;\n if (window.location.origin !== 'null') {\n base = window.location.origin;\n }\n return new URL(uri, base);\n}\n\n/**\n * Split an input URI:\n * 'root?key0=val00&key0=val01&key1=val10' returns\n * { base : root, query : [ key0 : [val00, val01], key1 : val1 ] }\n * Returns an empty object if the input string is not correct (null, empty...)\n * or if it is not a query string (no question mark).\n *\n * @param {string} uri The string to split.\n * @returns {object} The split string.\n */\nexport function splitUri(uri) {\n // result\n const result = {};\n // check if query string\n let sepIndex = null;\n if (uri && (sepIndex = uri.indexOf('?')) !== -1) {\n // base: before the '?'\n result.base = uri.substring(0, sepIndex);\n // query : after the '?' and until possible '#'\n let hashIndex = uri.indexOf('#');\n if (hashIndex === -1) {\n hashIndex = uri.length;\n }\n const query = uri.substring(sepIndex + 1, hashIndex);\n // split key/value pairs of the query\n result.query = splitKeyValueString(query);\n }\n // return\n return result;\n}\n\n/**\n * Get the query part, split into an array, of an input URI.\n * The URI scheme is: `base?query#fragment`.\n *\n * @param {string} uri The input URI.\n * @returns {object} The query part, split into an array, of the input URI.\n */\nexport function getUriQuery(uri) {\n // split\n const parts = splitUri(uri);\n // check not empty\n if (Object.keys(parts).length === 0) {\n return null;\n }\n // return query\n return parts.query;\n}\n\n/**\n * Generic URI query decoder.\n * Supports manifest:\n * `[dwv root]?input=encodeURIComponent('[manifest file]')&type=manifest`.\n * Or encoded URI with base and key value/pairs:\n * `[dwv root]?input=encodeURIComponent([root]?key0=value0&key1=value1)`.\n *\n * @param {object} query The query part to the input URI.\n * @param {Function} callback The function to call with the decoded file urls.\n * @param {object} options Optional url request options.\n */\nexport function decodeQuery(query, callback, options) {\n // manifest\n if (query.type && query.type === 'manifest') {\n decodeManifestQuery(query, callback);\n } else {\n // default case: encoded URI with base and key/value pairs\n callback(\n decodeKeyValueUri(query.input, query.dwvReplaceMode),\n options);\n }\n}\n\n/**\n * Decode a Key/Value pair URI. If a key is repeated, the result\n * be an array of base + each key.\n *\n * @param {string} uri The URI to decode.\n * @param {string} replaceMode The key replace mode. Can be:\n * - key (default): keep the key\n * - other than key: do not use the key\n * 'file' is a special case where the '?' of the query is not kept.\n * @returns {string[]} The list of input file urls.\n */\nexport function decodeKeyValueUri(uri, replaceMode) {\n const result = [];\n\n // repeat key replace mode (default to keep key)\n let repeatKeyReplaceMode = 'key';\n if (replaceMode) {\n repeatKeyReplaceMode = replaceMode;\n }\n\n // decode input URI\n const queryUri = decodeURIComponent(uri);\n // get key/value pairs from input URI\n const inputQueryPairs = splitUri(queryUri);\n if (Object.keys(inputQueryPairs).length === 0) {\n result.push(queryUri);\n } else {\n const keys = Object.keys(inputQueryPairs.query);\n // find repeat key\n let repeatKey = null;\n for (let i = 0; i < keys.length; ++i) {\n if (inputQueryPairs.query[keys[i]] instanceof Array) {\n repeatKey = keys[i];\n break;\n }\n }\n\n if (!repeatKey) {\n result.push(queryUri);\n } else {\n const repeatList = inputQueryPairs.query[repeatKey];\n // build base uri\n let baseUrl = inputQueryPairs.base;\n // add '?' when:\n // - base is not empty\n // - the repeatKey is not 'file'\n // root/path/to/?file=0.jpg&file=1.jpg\n if (baseUrl !== '' && repeatKey !== 'file') {\n baseUrl += '?';\n }\n let gotOneArg = false;\n for (let j = 0; j < keys.length; ++j) {\n if (keys[j] !== repeatKey) {\n if (gotOneArg) {\n baseUrl += '&';\n }\n baseUrl += keys[j] + '=' + inputQueryPairs.query[keys[j]];\n gotOneArg = true;\n }\n }\n // append built urls to result\n let url;\n for (let k = 0; k < repeatList.length; ++k) {\n url = baseUrl;\n if (gotOneArg) {\n url += '&';\n }\n if (repeatKeyReplaceMode === 'key') {\n url += repeatKey + '=';\n }\n // other than 'key' mode: do nothing\n url += repeatList[k];\n result.push(url);\n }\n }\n }\n // return\n return result;\n}\n\n/**\n * Decode a manifest query.\n *\n * @external XMLHttpRequest\n * @param {object} query The manifest query: {input, nslices},\n * with input the input URI and nslices the number of slices.\n * @param {Function} callback The function to call with the decoded urls.\n */\nfunction decodeManifestQuery(query, callback) {\n let uri = '';\n if (query.input[0] === '/') {\n uri = window.location.protocol + '//' + window.location.host;\n }\n // TODO: needs to be decoded (decodeURIComponent?\n uri += query.input;\n\n /**\n * Handle error.\n *\n * @param {object} event The error event.\n */\n function onError(event) {\n logger.warn('RequestError while receiving manifest: ' +\n event.target.status);\n }\n\n /**\n * Handle load.\n *\n * @param {object} event The load event.\n */\n function onLoad(event) {\n callback(decodeManifest(event.target.responseXML, query.nslices));\n }\n\n const request = new XMLHttpRequest();\n request.open('GET', decodeURIComponent(uri), true);\n request.responseType = 'document';\n request.onload = onLoad;\n request.onerror = onError;\n request.send(null);\n}\n\n/**\n * Decode an XML manifest.\n *\n * @param {object} manifest The manifest to decode.\n * @param {number} nslices The number of slices to load.\n * @returns {string[]} The decoded manifest.\n */\nexport function decodeManifest(manifest, nslices) {\n const result = [];\n // wado url\n const wadoElement = manifest.getElementsByTagName('wado_query');\n const wadoURL = wadoElement[0].getAttribute('wadoURL');\n const rootURL = wadoURL + '?requestType=WADO&contentType=application/dicom&';\n // patient list\n const patientList = manifest.getElementsByTagName('Patient');\n if (patientList.length > 1) {\n logger.warn('More than one patient, loading first one.');\n }\n // study list\n const studyList = patientList[0].getElementsByTagName('Study');\n if (studyList.length > 1) {\n logger.warn('More than one study, loading first one.');\n }\n const studyUID = studyList[0].getAttribute('StudyInstanceUID');\n // series list\n const seriesList = studyList[0].getElementsByTagName('Series');\n if (seriesList.length > 1) {\n logger.warn('More than one series, loading first one.');\n }\n const seriesUID = seriesList[0].getAttribute('SeriesInstanceUID');\n // instance list\n const instanceList = seriesList[0].getElementsByTagName('Instance');\n // loop on instances and push links\n let max = instanceList.length;\n if (nslices < max) {\n max = nslices;\n }\n for (let i = 0; i < max; ++i) {\n const sopInstanceUID = instanceList[i].getAttribute('SOPInstanceUID');\n const link = rootURL +\n '&studyUID=' + studyUID +\n '&seriesUID=' + seriesUID +\n '&objectUID=' + sopInstanceUID;\n result.push(link);\n }\n // return\n return result;\n}\n","import {ListenerHandler} from './listen';\n\n/**\n * UndoStack class.\n */\nexport class UndoStack {\n /**\n * Array of commands.\n *\n * @type {Array}\n */\n #stack = [];\n\n /**\n * Current command index.\n *\n * @type {number}\n */\n #curCmdIndex = 0;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Get the stack size.\n *\n * @returns {number} The size of the stack.\n */\n getStackSize() {\n return this.#stack.length;\n }\n\n /**\n * Get the current stack index.\n *\n * @returns {number} The stack index.\n */\n getCurrentStackIndex() {\n return this.#curCmdIndex;\n }\n\n /**\n * Add a command to the stack.\n *\n * @param {object} cmd The command to add.\n * @fires UndoStack#undoadd\n */\n add(cmd) {\n // clear commands after current index\n this.#stack = this.#stack.slice(0, this.#curCmdIndex);\n // store command\n this.#stack.push(cmd);\n // increment index\n ++this.#curCmdIndex;\n /**\n * Command add to undo stack event.\n *\n * @event UndoStack#undoadd\n * @type {object}\n * @property {string} type The event type.\n * @property {string} command The name of the command added to the\n * undo stack.\n */\n this.#fireEvent({\n type: 'undoadd',\n command: cmd.getName()\n });\n }\n\n /**\n * Remove a command to the stack.\n *\n * @param {string} name The name of the command to remove.\n * @returns {boolean} True if the command was found and removed.\n * @fires UndoStack#undoremove\n */\n remove(name) {\n let res = false;\n const hasInputName = function (element) {\n return element.getName() === name;\n };\n const index = this.#stack.findIndex(hasInputName);\n if (index !== -1) {\n // remove command\n this.#stack.splice(index, 1);\n // decrement index\n --this.#curCmdIndex;\n // result\n res = true;\n /**\n * Command remove from undo stack event.\n *\n * @event UndoStack#undoremove\n * @type {object}\n * @property {string} type The event type.\n * @property {string} command The name of the command added to the\n * undo stack.\n */\n this.#fireEvent({\n type: 'undoremove',\n command: name\n });\n }\n return res;\n }\n\n /**\n * Undo the last command.\n *\n * @fires UndoStack#undo\n */\n undo() {\n // a bit inefficient...\n if (this.#curCmdIndex > 0) {\n // decrement command index\n --this.#curCmdIndex;\n // undo last command\n this.#stack[this.#curCmdIndex].undo();\n /**\n * Command undo event.\n *\n * @event UndoStack#undo\n * @type {object}\n * @property {string} type The event type.\n * @property {string} command The name of the undone command.\n */\n this.#fireEvent({\n type: 'undo',\n command: this.#stack[this.#curCmdIndex].getName()\n });\n }\n }\n\n /**\n * Redo the last command.\n *\n * @fires UndoStack#redo\n */\n redo() {\n if (this.#curCmdIndex < this.#stack.length) {\n // run last command\n this.#stack[this.#curCmdIndex].execute();\n /**\n * Command redo event.\n *\n * @event UndoStack#redo\n * @type {object}\n * @property {string} type The event type.\n * @property {string} command The name of the redone command.\n */\n this.#fireEvent({\n type: 'redo',\n command: this.#stack[this.#curCmdIndex].getName()\n });\n // increment command index\n ++this.#curCmdIndex;\n }\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n} // UndoStack class\n","import {InteractionEventNames} from '../gui/generic';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {LayerGroup} from '../gui/layerGroup';\nimport {ViewLayer} from '../gui/viewLayer';\nimport {DrawLayer} from '../gui/drawLayer';\n/* eslint-enable no-unused-vars */\n\n/**\n * Toolbox controller.\n */\nexport class ToolboxController {\n\n /**\n * List of tools to control.\n *\n * @type {object}\n */\n #toolList;\n\n /**\n * Selected tool.\n *\n * @type {object}\n */\n #selectedTool = null;\n\n /**\n * Callback store to allow attach/detach.\n *\n * @type {Array}\n */\n #callbackStore = [];\n\n /**\n * Current layers bound to tool.\n *\n * @type {object}\n */\n #boundLayers = {};\n\n /**\n * @param {object} toolList The list of tool objects.\n */\n constructor(toolList) {\n this.#toolList = toolList;\n }\n\n /**\n * Initialise.\n */\n init() {\n for (const key in this.#toolList) {\n this.#toolList[key].init();\n }\n // enable shortcuts\n this.enableShortcuts(true);\n }\n\n /**\n * Enable or disable shortcuts. The 'init' methods enables shortcuts\n * by default. Call this method after init to disable shortcuts.\n *\n * @param {boolean} flag True to enable shortcuts.\n */\n enableShortcuts(flag) {\n if (flag) {\n window.addEventListener('keydown',\n this.#getCallback('window', 'keydown'), true);\n } else {\n window.removeEventListener('keydown',\n this.#getCallback('window', 'keydown'), true);\n }\n }\n\n /**\n * Get the tool list.\n *\n * @returns {Array} The list of tool objects.\n */\n getToolList() {\n return this.#toolList;\n }\n\n /**\n * Check if a tool is in the tool list.\n *\n * @param {string} name The name to check.\n * @returns {boolean} The tool list element for the given name.\n */\n hasTool(name) {\n return typeof this.getToolList()[name] !== 'undefined';\n }\n\n /**\n * Get the selected tool.\n *\n * @returns {object} The selected tool.\n */\n getSelectedTool() {\n return this.#selectedTool;\n }\n\n /**\n * Get the selected tool event handler.\n *\n * @param {string} eventType The event type, for example\n * mousedown, touchstart...\n * @returns {Function} The event handler.\n */\n getSelectedToolEventHandler(eventType) {\n return this.getSelectedTool()[eventType];\n }\n\n /**\n * Set the selected tool.\n *\n * @param {string} name The name of the tool.\n */\n setSelectedTool(name) {\n // check if we have it\n if (!this.hasTool(name)) {\n throw new Error('Unknown tool: \\'' + name + '\\'');\n }\n // de-activate previous\n if (this.#selectedTool) {\n this.#selectedTool.activate(false);\n }\n // set internal var\n this.#selectedTool = this.#toolList[name];\n // activate new tool\n this.#selectedTool.activate(true);\n }\n\n /**\n * Set the selected tool live features.\n *\n * @param {object} list The list of features.\n */\n setToolFeatures(list) {\n if (this.getSelectedTool()) {\n this.getSelectedTool().setFeatures(list);\n }\n }\n\n /**\n * Listen to layer interaction events.\n *\n * @param {LayerGroup} layerGroup The associated layer group.\n * @param {ViewLayer|DrawLayer} layer The layer to listen to.\n */\n bindLayerGroup(layerGroup, layer) {\n const divId = layerGroup.getDivId();\n // listen to active layer changes\n layerGroup.addEventListener(\n 'activelayerchange', this.#getActiveLayerChangeHandler(divId));\n // bind the layer\n this.#internalBindLayerGroup(divId, layer);\n }\n\n /**\n * Bind a layer group to this controller.\n *\n * @param {string} layerGroupDivId The layer group div id.\n * @param {ViewLayer|DrawLayer} layer The layer.\n */\n #internalBindLayerGroup(layerGroupDivId, layer) {\n // remove from local list if preset\n if (typeof this.#boundLayers[layerGroupDivId] !== 'undefined') {\n this.#unbindLayer(this.#boundLayers[layerGroupDivId]);\n }\n // replace layer in local list\n this.#boundLayers[layerGroupDivId] = layer;\n // bind layer\n this.#bindLayer(layer);\n }\n\n /**\n * Get an active layer change handler.\n *\n * @param {string} divId The associated layer group div id.\n * @returns {Function} The event handler.\n */\n #getActiveLayerChangeHandler(divId) {\n return (event) => {\n const layer = event.value[0];\n if (typeof layer !== 'undefined') {\n this.#internalBindLayerGroup(divId, layer);\n }\n };\n }\n\n /**\n * Add canvas mouse and touch listeners to a layer.\n *\n * @param {ViewLayer|DrawLayer} layer The layer to start listening to.\n */\n #bindLayer(layer) {\n layer.bindInteraction();\n // interaction events\n const names = InteractionEventNames;\n for (let i = 0; i < names.length; ++i) {\n layer.addEventListener(names[i],\n this.#getCallback(layer.getId(), names[i]));\n }\n }\n\n /**\n * Remove canvas mouse and touch listeners to a layer.\n *\n * @param {ViewLayer|DrawLayer} layer The layer to stop listening to.\n */\n #unbindLayer(layer) {\n layer.unbindInteraction();\n // interaction events\n const names = InteractionEventNames;\n for (let i = 0; i < names.length; ++i) {\n layer.removeEventListener(names[i],\n this.#getCallback(layer.getId(), names[i]));\n }\n }\n\n /**\n * Mou(se) and (T)ouch event handler. This function just determines\n * the mouse/touch position relative to the canvas element.\n * It then passes it to the current tool.\n *\n * @param {string} layerId The layer id.\n * @param {string} eventType The event type.\n * @returns {object} A callback for the provided layer and event.\n */\n #getCallback(layerId, eventType) {\n if (typeof this.#callbackStore[layerId] === 'undefined') {\n this.#callbackStore[layerId] = [];\n }\n\n if (typeof this.#callbackStore[layerId][eventType] === 'undefined') {\n const applySelectedTool = (event) => {\n // make sure we have a tool\n if (this.#selectedTool) {\n const func = this.#selectedTool[event.type];\n if (func) {\n func(event);\n }\n }\n };\n // store callback\n this.#callbackStore[layerId][eventType] = applySelectedTool;\n }\n\n return this.#callbackStore[layerId][eventType];\n }\n\n} // class ToolboxController\n","/**\n * Multiple progresses handler.\n * Stores a multi dimensional list of progresses to allow to\n * calculate a global progress.\n *\n */\nexport class MultiProgressHandler {\n\n /**\n * List of progresses.\n * First dimension is a list of item for which the progress is recorded,\n * for example file names.\n * Second dimension is a list of possible progresses, for example\n * the progress of the download and the progress of the decoding.\n *\n * @type {Array}\n */\n #progresses = [];\n\n /**\n * Number of dimensions.\n *\n * @type {number}\n */\n #numberOfDimensions = 2;\n\n /**\n * Progress callback.\n *\n * @type {Function}\n */\n #callback;\n\n /**\n * @param {Function} callback The function to pass the global progress to.\n */\n constructor(callback) {\n this.#callback = callback;\n }\n\n /**\n * Set the number of dimensions.\n *\n * @param {number} num The number.\n */\n setNumberOfDimensions(num) {\n this.#numberOfDimensions = num;\n }\n\n /**\n * Set the number of data to load.\n *\n * @param {number} n The number of data to load.\n */\n setNToLoad(n) {\n for (let i = 0; i < n; ++i) {\n this.#progresses[i] = [];\n for (let j = 0; j < this.#numberOfDimensions; ++j) {\n this.#progresses[i][j] = 0;\n }\n }\n }\n\n /**\n * Handle a load progress.\n * Call the member callback with a global event.\n *\n * @param {object} event The progress event.\n */\n onprogress = (event) => {\n // check event\n if (!event.lengthComputable) {\n return;\n }\n if (typeof event.subindex === 'undefined') {\n return;\n }\n if (typeof event.index === 'undefined') {\n return;\n }\n // calculate percent\n const percent = (event.loaded * 100) / event.total;\n // set percent for index\n this.#progresses[event.index][event.subindex] = percent;\n\n // item progress\n let item = null;\n if (typeof event.item !== 'undefined') {\n item = event.item;\n } else {\n item = {\n loaded: this.#getItemProgress(event.index),\n total: 100,\n source: event.source\n };\n }\n\n // call callback with a global event\n this.#callback({\n lengthComputable: true,\n loaded: this.#getGlobalPercent(),\n total: 100,\n item: item\n });\n };\n\n /**\n * Get the item load percent.\n *\n * @param {number} index The index of the item.\n * @returns {number} The load percentage.\n */\n #getItemProgress(index) {\n let sum = 0;\n for (let j = 0; j < this.#numberOfDimensions; ++j) {\n sum += this.#progresses[index][j];\n }\n return sum / this.#numberOfDimensions;\n }\n\n /**\n * Get the global load percent including the provided one.\n *\n * @returns {number} The accumulated percentage.\n */\n #getGlobalPercent() {\n let sum = 0;\n const lenprog = this.#progresses.length;\n for (let i = 0; i < lenprog; ++i) {\n sum += this.#getItemProgress(i);\n }\n return Math.round(sum / lenprog);\n }\n\n\n /**\n * @callback eventFn\n * @param {object} event The event.\n */\n\n /**\n * Create a mono progress event handler.\n *\n * @param {number} index The index of the data.\n * @param {number} subindex The sub-index of the data.\n * @returns {eventFn} A progress handler function.\n */\n getMonoProgressHandler(index, subindex) {\n return (event) => {\n event.index = index;\n event.subindex = subindex;\n this.onprogress(event);\n };\n }\n\n /**\n * Create a mono progress event handler with an undefined index.\n * Warning: The caller handles the progress index.\n *\n * @param {number} subindex The sub-index of the data.\n * @returns {eventFn} A progress handler function.\n */\n getUndefinedMonoProgressHandler(subindex) {\n return (event) => {\n event.subindex = subindex;\n this.onprogress(event);\n };\n }\n}\n","import {endsWith, getRootPath} from '../utils/string';\nimport {MultiProgressHandler} from '../utils/progress';\nimport {getFileListFromDicomDir} from '../dicom/dicomElementsWrapper';\nimport {loaderList} from './loaderList';\n\n// url content types\nexport const urlContentTypes = {\n Text: 0,\n ArrayBuffer: 1\n};\n\n/**\n * Urls loader.\n */\nexport class UrlsLoader {\n\n /**\n * Input data.\n *\n * @type {string[]}\n */\n #inputData = null;\n\n /**\n * Array of launched requests.\n *\n * @type {XMLHttpRequest[]}\n */\n #requests = [];\n\n /**\n * Data loader.\n *\n * @type {object}\n */\n #runningLoader = null;\n\n /**\n * Number of loaded data.\n *\n * @type {number}\n */\n #nLoad = 0;\n\n /**\n * Number of load end events.\n *\n * @type {number}\n */\n #nLoadend = 0;\n\n /**\n * Flag to know if the load is aborting.\n *\n * @type {boolean}\n */\n #aborting;\n\n /**\n * The default character set (optional).\n *\n * @type {string}\n */\n #defaultCharacterSet;\n\n /**\n * Get the default character set.\n *\n * @returns {string} The default character set.\n */\n getDefaultCharacterSet() {\n return this.#defaultCharacterSet;\n }\n\n /**\n * Set the default character set.\n *\n * @param {string} characterSet The character set.\n */\n setDefaultCharacterSet(characterSet) {\n this.#defaultCharacterSet = characterSet;\n }\n\n /**\n * Store the current input.\n *\n * @param {string[]} data The input data.\n */\n #storeInputData(data) {\n this.#inputData = data;\n // reset counters\n this.#nLoad = 0;\n this.#nLoadend = 0;\n // reset flag\n this.#aborting = false;\n // clear storage\n this.#clearStoredRequests();\n this.#clearStoredLoader();\n }\n\n /**\n * Store a launched request.\n *\n * @param {XMLHttpRequest} request The launched request.\n */\n #storeRequest(request) {\n this.#requests.push(request);\n }\n\n /**\n * Clear the stored requests.\n *\n */\n #clearStoredRequests() {\n this.#requests = [];\n }\n\n /**\n * Store the launched loader.\n *\n * @param {object} loader The launched loader.\n */\n #storeLoader(loader) {\n this.#runningLoader = loader;\n }\n\n /**\n * Clear the stored loader.\n *\n */\n #clearStoredLoader() {\n this.#runningLoader = null;\n }\n\n /**\n * Increment the number of loaded data\n * and call onload if loaded all data.\n *\n * @param {object} _event The load data event.\n */\n #addLoad = (_event) => {\n this.#nLoad++;\n // call onload when all is loaded\n // (not using the input event since it is\n // an individual load)\n if (this.#nLoad === this.#inputData.length) {\n this.onload({\n source: this.#inputData\n });\n }\n };\n\n /**\n * Increment the counter of load end events\n * and run callbacks when all done, erroneus or not.\n *\n * @param {object} _event The load end event.\n */\n #addLoadend = (_event) => {\n this.#nLoadend++;\n // call onloadend when all is run\n // (not using the input event since it is\n // an individual load end)\n if (this.#nLoadend === this.#inputData.length) {\n this.onloadend({\n source: this.#inputData\n });\n }\n };\n\n /**\n * @callback eventFn\n * @param {object} event The event.\n */\n\n /**\n * Augment a callback event with a srouce.\n *\n * @param {object} callback The callback to augment its event.\n * @param {object} source The source to add to the event.\n * @returns {eventFn} The augmented callback.\n */\n #augmentCallbackEvent(callback, source) {\n return (event) => {\n event.source = source;\n callback(event);\n };\n }\n\n /**\n * Load a list of URLs or a DICOMDIR.\n *\n * @param {string[]} data The list of urls to load.\n * @param {object} [options] Load options.\n */\n load(data, options) {\n // send start event\n this.onloadstart({\n source: data\n });\n\n // check if DICOMDIR case\n if (data.length === 1 &&\n (endsWith(data[0], 'DICOMDIR') ||\n endsWith(data[0], '.dcmdir'))) {\n this.#loadDicomDir(data[0], options);\n } else {\n this.#loadUrls(data, options);\n }\n }\n\n /**\n * Get a load handler for a data element.\n *\n * @param {object} loader The associated loader.\n * @param {string} dataElement The data element.\n * @param {number} i The index of the element.\n * @returns {eventFn} A load handler.\n */\n #getLoadHandler(loader, dataElement, i) {\n return (event) => {\n // check response status\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Response_codes\n // status 200: \"OK\"; status 0: \"debug\"\n const status = event.target.status;\n if (status !== 200 && status !== 0) {\n this.onerror({\n source: dataElement,\n error: 'GET ' + event.target.responseURL +\n ' ' + event.target.status +\n ' (' + event.target.statusText + ')',\n target: event.target\n });\n this.#addLoadend();\n } else {\n loader.load(event.target.response, dataElement, i);\n }\n };\n }\n\n /**\n * Load a list of urls.\n *\n * @param {string[]} data The list of urls to load.\n * @param {object} [options] The options object, can contain:\n * - requestHeaders: an array of {name, value} to use as request headers,\n * - withCredentials: boolean xhr.withCredentials flag to pass\n * to the request,\n * - batchSize: the size of the request url batch.\n */\n #loadUrls(data, options) {\n // check input\n if (typeof data === 'undefined' || data.length === 0) {\n return;\n }\n this.#storeInputData(data);\n\n // create prgress handler\n const mproghandler = new MultiProgressHandler(this.onprogress);\n mproghandler.setNToLoad(data.length);\n\n // create loaders\n const loaders = [];\n for (let m = 0; m < loaderList.length; ++m) {\n loaders.push(new loaderList[m]());\n }\n\n // find an appropriate loader\n let dataElement = data[0];\n let loader = null;\n let foundLoader = false;\n for (let l = 0; l < loaders.length; ++l) {\n loader = loaders[l];\n if (loader.canLoadUrl(dataElement, options)) {\n foundLoader = true;\n // load options\n loader.setOptions({\n numberOfFiles: data.length,\n defaultCharacterSet: this.getDefaultCharacterSet()\n });\n // set loader callbacks\n // loader.onloadstart: nothing to do\n loader.onprogress = mproghandler.getUndefinedMonoProgressHandler(1);\n loader.onloaditem = this.onloaditem;\n loader.onload = this.#addLoad;\n loader.onloadend = this.#addLoadend;\n loader.onerror = this.onerror;\n loader.onabort = this.onabort;\n\n // store loader\n this.#storeLoader(loader);\n // exit\n break;\n }\n }\n if (!foundLoader) {\n throw new Error('No loader found for url: ' + dataElement);\n }\n\n // store last run request index\n let lastRunRequestIndex = 0;\n const requestOnLoadEnd = () => {\n // launch next in queue\n if (lastRunRequestIndex < this.#requests.length - 1 && !this.#aborting) {\n ++lastRunRequestIndex;\n this.#requests[lastRunRequestIndex].send(null);\n }\n };\n\n // loop on I/O elements\n for (let i = 0; i < data.length; ++i) {\n dataElement = data[i];\n\n // check loader\n if (!loader.canLoadUrl(dataElement, options)) {\n throw new Error('Input url of different type: ' + dataElement);\n }\n /**\n * The http request.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest}.\n *\n * @external XMLHttpRequest\n */\n const request = new XMLHttpRequest();\n request.open('GET', dataElement, true);\n\n // request options\n if (typeof options !== 'undefined') {\n // optional request headers\n if (typeof options.requestHeaders !== 'undefined') {\n const requestHeaders = options.requestHeaders;\n for (let j = 0; j < requestHeaders.length; ++j) {\n if (typeof requestHeaders[j].name !== 'undefined' &&\n typeof requestHeaders[j].value !== 'undefined') {\n request.setRequestHeader(\n requestHeaders[j].name, requestHeaders[j].value);\n }\n }\n }\n // optional withCredentials\n // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials\n if (typeof options.withCredentials !== 'undefined') {\n request.withCredentials = options.withCredentials;\n }\n }\n\n // set request callbacks\n // request.onloadstart: nothing to do\n request.onprogress = this.#augmentCallbackEvent(\n mproghandler.getMonoProgressHandler(i, 0), dataElement);\n request.onload = this.#getLoadHandler(loader, dataElement, i);\n request.onloadend = requestOnLoadEnd;\n const errorCallback =\n this.#augmentCallbackEvent(this.onerror, dataElement);\n request.onerror = (event) => {\n this.#addLoadend();\n errorCallback(event);\n };\n const abortCallback =\n this.#augmentCallbackEvent(this.onabort, dataElement);\n request.onabort = (event) => {\n this.#addLoadend();\n abortCallback(event);\n };\n // response type (default is 'text')\n if (loader.loadUrlAs() === urlContentTypes.ArrayBuffer) {\n request.responseType = 'arraybuffer';\n }\n\n // store request\n this.#storeRequest(request);\n }\n\n // launch requests in batch\n let batchSize = this.#requests.length;\n if (typeof options !== 'undefined') {\n // optional request batch size\n if (typeof options.batchSize !== 'undefined' && batchSize !== 0) {\n batchSize = Math.min(options.batchSize, this.#requests.length);\n }\n }\n for (let r = 0; r < batchSize; ++r) {\n if (!this.#aborting) {\n lastRunRequestIndex = r;\n this.#requests[lastRunRequestIndex].send(null);\n }\n }\n }\n\n /**\n * Load a DICOMDIR.\n *\n * @param {string} dicomDirUrl The DICOMDIR url.\n * @param {object} [options] Load options.\n */\n #loadDicomDir(dicomDirUrl, options) {\n // read DICOMDIR\n const request = new XMLHttpRequest();\n request.open('GET', dicomDirUrl, true);\n request.responseType = 'arraybuffer';\n // request.onloadstart: nothing to do\n /**\n * @param {object} event The load event.\n */\n request.onload = (event) => {\n // check status\n const status = event.target.status;\n if (status !== 200 && status !== 0) {\n this.onerror({\n source: dicomDirUrl,\n error: 'GET ' + event.target.responseURL +\n ' ' + event.target.status +\n ' (' + event.target.statusText + ')',\n target: event.target\n });\n this.onloadend({});\n } else {\n // get the file list\n const list = getFileListFromDicomDir(event.target.response);\n // use the first list\n const urls = list[0][0];\n // append root url\n const rootUrl = getRootPath(dicomDirUrl);\n const fullUrls = [];\n for (let i = 0; i < urls.length; ++i) {\n fullUrls.push(rootUrl + '/' + urls[i]);\n }\n // load urls\n this.#loadUrls(fullUrls, options);\n }\n };\n request.onerror = (event) => {\n this.#augmentCallbackEvent(this.onerror, dicomDirUrl)(event);\n this.onloadend({});\n };\n request.onabort = (event) => {\n this.#augmentCallbackEvent(this.onabort, dicomDirUrl)(event);\n this.onloadend({});\n };\n // request.onloadend: nothing to do\n // send request\n request.send(null);\n }\n\n /**\n * Abort a load.\n */\n abort() {\n this.#aborting = true;\n // abort non finished requests\n for (let i = 0; i < this.#requests.length; ++i) {\n // 0: UNSENT, 1: OPENED, 2: HEADERS_RECEIVED (send()), 3: LOADING, 4: DONE\n if (this.#requests[i].readyState !== 4) {\n this.#requests[i].abort();\n }\n }\n // abort loader\n if (this.#runningLoader && this.#runningLoader.isLoading()) {\n this.#runningLoader.abort();\n }\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle a load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class UrlsLoader\n","/**\n * Thread Pool.\n *\n * Highly inspired from {@link http://www.smartjava.org/content/html5-easily-parallelize-jobs-using-web-workers-and-threadpool}.\n */\nexport class ThreadPool {\n\n /**\n * @param {number} poolSize The size of the pool.\n */\n constructor(poolSize) {\n this.poolSize = poolSize;\n // task queue\n this.taskQueue = [];\n // lsit of available threads\n this.freeThreads = [];\n // create 'poolSize' number of worker threads\n for (let i = 0; i < poolSize; ++i) {\n this.freeThreads.push(new WorkerThread(this));\n }\n // list of running threads (unsed in abort)\n this.runningThreads = [];\n }\n\n /**\n * Add a worker task to the queue.\n * Will be run when a thread is made available.\n *\n * @param {object} workerTask The task to add to the queue.\n */\n addWorkerTask(workerTask) {\n // send work start if first task\n if (this.freeThreads.length === this.poolSize) {\n this.onworkstart({type: 'work-start'});\n }\n // launch task or queue\n if (this.freeThreads.length > 0) {\n // get the first free worker thread\n const workerThread = this.freeThreads.shift();\n // add the thread to the runnning list\n this.runningThreads.push(workerThread);\n // run the input task\n workerThread.run(workerTask);\n } else {\n // no free thread, add task to queue\n this.taskQueue.push(workerTask);\n }\n }\n\n /**\n * Abort all threads.\n */\n abort() {\n // stop all threads\n this.#stop();\n // callback\n this.onabort({type: 'work-abort'});\n this.onworkend({type: 'work-end'});\n }\n\n /**\n * Handle a task end.\n *\n * @param {object} workerThread The thread to free.\n */\n onTaskEnd(workerThread) {\n // launch next task in queue or finish\n if (this.taskQueue.length > 0) {\n // get waiting task\n const workerTask = this.taskQueue.shift();\n // use input thread to run the waiting task\n workerThread.run(workerTask);\n } else {\n // stop the worker\n workerThread.stop();\n // no task to run, add to free list\n this.freeThreads.push(workerThread);\n // remove from running list\n for (let i = 0; i < this.runningThreads.length; ++i) {\n if (this.runningThreads[i].getId() === workerThread.getId()) {\n this.runningThreads.splice(i, 1);\n }\n }\n // the work is done when the queue is back to its initial size\n if (this.freeThreads.length === this.poolSize) {\n this.onwork({type: 'work'});\n this.onworkend({type: 'work-end'});\n }\n }\n }\n\n /**\n * Handle an error message from a worker.\n *\n * @param {object} event The error event.\n */\n handleWorkerError = (event) => {\n // stop all threads\n this.#stop();\n // callback\n this.onerror({error: event});\n this.onworkend({type: 'work-end'});\n };\n\n // private ----------------------------------------------------------------\n\n /**\n * Stop the pool: stop all running threads.\n *\n */\n #stop() {\n // clear tasks\n this.taskQueue = [];\n // cancel running workers\n for (let i = 0; i < this.runningThreads.length; ++i) {\n this.runningThreads[i].stop();\n }\n this.runningThreads = [];\n }\n\n\n /**\n * Handle a work start event.\n * Default does nothing.\n *\n * @param {object} _event The work start event.\n */\n onworkstart(_event) {}\n\n /**\n * Handle a work item event.\n * Default does nothing.\n *\n * @param {object} _event The work item event fired\n * when a work item ended successfully.\n */\n onworkitem(_event) {}\n\n /**\n * Handle a work event.\n * Default does nothing.\n *\n * @param {object} _event The work event fired\n * when a work ended successfully.\n */\n onwork(_event) {}\n\n /**\n * Handle a work end event.\n * Default does nothing.\n *\n * @param {object} _event The work end event fired\n * when a work has completed, successfully or not.\n */\n onworkend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // ThreadPool\n\n/**\n * Worker background task.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/API/Worker}.\n *\n * @external Worker\n */\n\n/**\n * Worker thread.\n */\nclass WorkerThread {\n\n /**\n * @param {object} parentPool The parent pool.\n */\n constructor(parentPool) {\n this.parentPool = parentPool;\n // thread ID\n this.id = Math.random().toString(36).substring(2, 15);\n // running task\n this.runningTask = null;\n // worker used to run task\n this.worker;\n }\n\n /**\n * Get the thread ID.\n *\n * @returns {string} The thread ID (alphanumeric).\n */\n getId() {\n return this.id;\n }\n\n /**\n * Run a worker task.\n *\n * @param {object} workerTask The task to run.\n */\n run(workerTask) {\n // store task\n this.runningTask = workerTask;\n // create a new web worker if not done yet\n if (typeof this.worker === 'undefined') {\n this.worker = new Worker(this.runningTask.script);\n // set callbacks\n this.worker.onmessage = this.onmessage;\n this.worker.onerror = this.onerror;\n }\n // launch the worker\n this.worker.postMessage(this.runningTask.startMessage);\n }\n\n /**\n * Finish a task and tell the parent.\n */\n stop() {\n // stop the worker\n if (typeof this.worker !== 'undefined') {\n this.worker.terminate();\n // force create at next run\n this.worker = undefined;\n }\n }\n\n /**\n * Message event handler.\n * For now assume we only get a single callback from a worker\n * which also indicates the end of this worker.\n *\n * @param {object} event The message event.\n */\n onmessage = (event) => {\n // augment event\n event.itemNumber = this.runningTask.info.itemNumber;\n event.numberOfItems = this.runningTask.info.numberOfItems;\n event.index = this.runningTask.info.index;\n // send event\n this.parentPool.onworkitem(event);\n // tell the parent pool the task is done\n this.parentPool.onTaskEnd(this);\n };\n\n /**\n * Error event handler.\n *\n * @param {object} event The error event.\n */\n onerror = (event) => {\n // augment event\n event.itemNumber = this.runningTask.info.itemNumber;\n event.numberOfItems = this.runningTask.info.numberOfItems;\n event.index = this.runningTask.info.index;\n // pass to parent\n this.parentPool.handleWorkerError(event);\n // stop the worker and free the thread\n this.stop();\n };\n} // class WorkerThread\n\n/**\n * Worker task.\n */\nexport class WorkerTask {\n /**\n * @param {string} script The worker script.\n * @param {object} message The data to pass to the worker.\n * @param {object} info Information object about the input data.\n */\n constructor(script, message, info) {\n // worker script\n this.script = script;\n // worker start message\n this.startMessage = message;\n // information about the work data\n this.info = info;\n }\n}\n","import {ThreadPool, WorkerTask} from '../utils/thread';\n\n/**\n * The JPEG baseline decoder.\n *\n * Ref: {@link https://github.com/mozilla/pdf.js/blob/master/src/core/jpg.js}.\n *\n * @external JpegImage\n */\n/* global JpegImage */\n// @ts-ignore\nconst hasJpegBaselineDecoder = (typeof JpegImage !== 'undefined');\n\n/**\n * The JPEG decoder namespace.\n *\n * Ref: {@link https://github.com/rii-mango/JPEGLosslessDecoderJS}.\n *\n * @external jpeg\n */\n/* global jpeg */\nconst hasJpegLosslessDecoder =\n // @ts-ignore\n (typeof jpeg !== 'undefined') && (typeof jpeg.lossless !== 'undefined');\n\n/**\n * The JPEG 2000 decoder.\n *\n * Ref: {@link https://github.com/jpambrun/jpx-medical/blob/master/jpx.js}.\n *\n * @external JpxImage\n */\n/* global JpxImage */\n// @ts-ignore\nconst hasJpeg2000Decoder = (typeof JpxImage !== 'undefined');\n\n/* global dwvdecoder */\n\n/**\n * Decoder scripts to be passed to web workers for image decoding.\n */\nexport const decoderScripts = {\n jpeg2000: '',\n 'jpeg-lossless': '',\n 'jpeg-baseline': '',\n rle: ''\n};\n\n/**\n * Asynchronous pixel buffer decoder.\n */\nclass AsynchPixelBufferDecoder {\n\n /**\n * The associated worker script.\n *\n * @type {string}\n */\n #script;\n\n /**\n * Associated thread pool.\n *\n * @type {ThreadPool}\n */\n #pool = new ThreadPool(10);\n\n /**\n * Flag to know if callbacks are set.\n *\n * @type {boolean}\n */\n #areCallbacksSet = false;\n\n /**\n * @param {string} script The path to the decoder script to be used\n * by the web worker.\n * @param {number} _numberOfData The anticipated number of data to decode.\n */\n constructor(script, _numberOfData) {\n this.#script = script;\n }\n\n /**\n * Decode a pixel buffer.\n *\n * @param {Array} pixelBuffer The pixel buffer.\n * @param {object} pixelMeta The input meta data.\n * @param {object} info Information object about the input data.\n */\n decode(pixelBuffer, pixelMeta, info) {\n if (!this.#areCallbacksSet) {\n this.#areCallbacksSet = true;\n // set event handlers\n this.#pool.onworkstart = this.ondecodestart;\n this.#pool.onworkitem = this.ondecodeditem;\n this.#pool.onwork = this.ondecoded;\n this.#pool.onworkend = this.ondecodeend;\n this.#pool.onerror = this.onerror;\n this.#pool.onabort = this.onabort;\n }\n // create worker task\n const workerTask = new WorkerTask(\n this.#script,\n {\n buffer: pixelBuffer,\n meta: pixelMeta\n },\n info\n );\n // add it the queue and run it\n this.#pool.addWorkerTask(workerTask);\n }\n\n /**\n * Abort decoding.\n */\n abort() {\n // abort the thread pool, will trigger pool.onabort\n this.#pool.abort();\n }\n\n /**\n * Handle a decode start event.\n * Default does nothing.\n *\n * @param {object} _event The decode start event.\n */\n ondecodestart(_event) {}\n\n /**\n * Handle a decode item event.\n * Default does nothing.\n *\n * @param {object} _event The decode item event fired\n * when a decode item ended successfully.\n */\n ondecodeditem(_event) {}\n\n /**\n * Handle a decode event.\n * Default does nothing.\n *\n * @param {object} _event The decode event fired\n * when a file has been decoded successfully.\n */\n ondecoded(_event) {}\n\n /**\n * Handle a decode end event.\n * Default does nothing.\n *\n * @param {object} _event The decode end event fired\n * when a file decoding has completed, successfully or not.\n */\n ondecodeend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class AsynchPixelBufferDecoder\n\n/**\n * Synchronous pixel buffer decoder.\n */\nclass SynchPixelBufferDecoder {\n\n /**\n * Name of the compression algorithm.\n *\n * @type {string}\n */\n #algoName;\n\n /**\n * Number of data.\n *\n * @type {number}\n */\n #numberOfData;\n\n /**\n * @param {string} algoName The decompression algorithm name.\n * @param {number} numberOfData The anticipated number of data to decode.\n */\n constructor(algoName, numberOfData) {\n this.#algoName = algoName;\n this.#numberOfData = numberOfData;\n }\n\n // decode count\n #decodeCount = 0;\n\n /**\n * Decode a pixel buffer.\n *\n * @param {Array} pixelBuffer The pixel buffer.\n * @param {object} pixelMeta The input meta data.\n * @param {object} info Information object about the input data.\n * @external jpeg\n * @external JpegImage\n * @external JpxImage\n */\n decode(pixelBuffer, pixelMeta, info) {\n ++this.#decodeCount;\n\n let decoder = null;\n let decodedBuffer = null;\n if (this.#algoName === 'jpeg-lossless') {\n if (!hasJpegLosslessDecoder) {\n throw new Error('No JPEG Lossless decoder provided');\n }\n // bytes per element\n const bpe = pixelMeta.bitsAllocated / 8;\n const buf = new Uint8Array(pixelBuffer);\n // @ts-ignore\n decoder = new jpeg.lossless.Decoder();\n const decoded = decoder.decode(buf.buffer, 0, buf.buffer.byteLength, bpe);\n if (pixelMeta.bitsAllocated === 8) {\n if (pixelMeta.isSigned) {\n decodedBuffer = new Int8Array(decoded.buffer);\n } else {\n decodedBuffer = new Uint8Array(decoded.buffer);\n }\n } else if (pixelMeta.bitsAllocated === 16) {\n if (pixelMeta.isSigned) {\n decodedBuffer = new Int16Array(decoded.buffer);\n } else {\n decodedBuffer = new Uint16Array(decoded.buffer);\n }\n }\n } else if (this.#algoName === 'jpeg-baseline') {\n if (!hasJpegBaselineDecoder) {\n throw new Error('No JPEG Baseline decoder provided');\n }\n // @ts-ignore\n decoder = new JpegImage();\n decoder.parse(pixelBuffer);\n decodedBuffer = decoder.getData(decoder.width, decoder.height);\n } else if (this.#algoName === 'jpeg2000') {\n if (!hasJpeg2000Decoder) {\n throw new Error('No JPEG 2000 decoder provided');\n }\n // decompress pixel buffer into Int16 image\n // @ts-ignore\n decoder = new JpxImage();\n decoder.parse(pixelBuffer);\n // set the pixel buffer\n decodedBuffer = decoder.tiles[0].items;\n } else if (this.#algoName === 'rle') {\n // decode DICOM buffer\n // @ts-ignore\n decoder = new dwvdecoder.RleDecoder();\n // set the pixel buffer\n decodedBuffer = decoder.decode(\n pixelBuffer,\n pixelMeta.bitsAllocated,\n pixelMeta.isSigned,\n pixelMeta.sliceSize,\n pixelMeta.samplesPerPixel,\n pixelMeta.planarConfiguration);\n }\n // send decode events\n this.ondecodeditem({\n data: [decodedBuffer],\n index: info.index,\n numberOfItems: info.numberOfItems,\n itemNumber: info.itemNumber\n });\n // decode end?\n if (this.#decodeCount === this.#numberOfData) {\n this.ondecoded({});\n this.ondecodeend({});\n }\n }\n\n /**\n * Abort decoding.\n */\n abort() {\n // nothing to do in the synchronous case.\n // callback\n this.onabort({});\n this.ondecodeend({});\n }\n\n /**\n * Handle a decode start event.\n * Default does nothing.\n *\n * @param {object} _event The decode start event.\n */\n ondecodestart(_event) {}\n\n /**\n * Handle a decode item event.\n * Default does nothing.\n *\n * @param {object} _event The decode item event fired\n * when a decode item ended successfully.\n */\n ondecodeditem(_event) {}\n\n /**\n * Handle a decode event.\n * Default does nothing.\n *\n * @param {object} _event The decode event fired\n * when a file has been decoded successfully.\n */\n ondecoded(_event) {}\n\n /**\n * Handle a decode end event.\n * Default does nothing.\n *\n * @param {object} _event The decode end event fired\n * when a file decoding has completed, successfully or not.\n */\n ondecodeend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class SynchPixelBufferDecoder\n\n/**\n * Decode a pixel buffer.\n *\n * If the 'decoderScripts' variable does not contain the desired,\n * algorythm the decoder will switch to the synchronous mode.\n */\nexport class PixelBufferDecoder {\n\n /**\n * Flag to know if callbacks are set.\n *\n * @type {boolean}\n */\n #areCallbacksSet = false;\n\n /**\n * Pixel decoder.\n * Defined only once.\n *\n * @type {object}\n */\n #pixelDecoder = null;\n\n /**\n * @param {string} algoName The decompression algorithm name.\n * @param {number} numberOfData The anticipated number of data to decode.\n */\n constructor(algoName, numberOfData) {\n // initialise the asynch decoder (if possible)\n if (typeof decoderScripts !== 'undefined' &&\n typeof decoderScripts[algoName] !== 'undefined') {\n this.#pixelDecoder = new AsynchPixelBufferDecoder(\n decoderScripts[algoName], numberOfData);\n } else {\n this.#pixelDecoder = new SynchPixelBufferDecoder(\n algoName, numberOfData);\n }\n }\n\n /**\n * Get data from an input buffer using a DICOM parser.\n *\n * @param {Array} pixelBuffer The input data buffer.\n * @param {object} pixelMeta The input meta data.\n * @param {object} info Information object about the input data.\n */\n decode(pixelBuffer, pixelMeta, info) {\n if (!this.#areCallbacksSet) {\n this.#areCallbacksSet = true;\n // set callbacks\n this.#pixelDecoder.ondecodestart = this.ondecodestart;\n this.#pixelDecoder.ondecodeditem = this.ondecodeditem;\n this.#pixelDecoder.ondecoded = this.ondecoded;\n this.#pixelDecoder.ondecodeend = this.ondecodeend;\n this.#pixelDecoder.onerror = this.onerror;\n this.#pixelDecoder.onabort = this.onabort;\n }\n // decode and call the callback\n this.#pixelDecoder.decode(pixelBuffer, pixelMeta, info);\n }\n\n /**\n * Abort decoding.\n */\n abort() {\n // decoder classes should define an abort\n this.#pixelDecoder.abort();\n }\n\n /**\n * Handle a decode start event.\n * Default does nothing.\n *\n * @param {object} _event The decode start event.\n */\n ondecodestart(_event) {}\n\n /**\n * Handle a decode item event.\n * Default does nothing.\n *\n * @param {object} _event The decode item event fired\n * when a decode item ended successfully.\n */\n ondecodeditem(_event) {}\n\n /**\n * Handle a decode event.\n * Default does nothing.\n *\n * @param {object} _event The decode event fired\n * when a file has been decoded successfully.\n */\n ondecoded(_event) {}\n\n /**\n * Handle a decode end event.\n * Default does nothing.\n *\n * @param {object} _event The decode end event fired\n * when a file decoding has completed, successfully or not.\n */\n ondecodeend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class PixelBufferDecoder\n","import {\n getCode,\n getDicomCodeItem\n} from './dicomCode';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\nimport {DicomCode} from './dicomCode';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n NumericValue: '0040A30A',\n FloatingPointValue: '0040A161',\n RationalNumeratorValue: '0040A162',\n RationalDenominatorValue: '0040A163',\n MeasurementUnitsCodeSequence: '004008EA'\n};\n\n/**\n * DICOM measured value: property of a numeric measurement.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.html#table_C.18.1-1}.\n */\nexport class MeasuredValue {\n /**\n * @type {number}\n */\n numericValue;\n\n /**\n * @type {number}\n */\n floatingPointValue;\n\n /**\n * @type {number}\n */\n rationalNumeratorValue;\n\n /**\n * @type {number}\n */\n rationalDenominatorValue;\n\n /**\n * @type {DicomCode}\n */\n measurementUnitsCode;\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The object as string.\n */\n toString() {\n return this.numericValue + ' ' +\n this.measurementUnitsCode.toString();\n };\n\n};\n\n/**\n * Get a measured value object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {MeasuredValue} A measured value object.\n */\nexport function getMeasuredValue(dataElements) {\n const value = new MeasuredValue();\n\n if (typeof dataElements[TagKeys.NumericValue] !== 'undefined') {\n value.numericValue = dataElements[TagKeys.NumericValue].value[0];\n }\n if (typeof dataElements[TagKeys.FloatingPointValue] !== 'undefined') {\n value.floatingPointValue =\n dataElements[TagKeys.FloatingPointValue].value[0];\n }\n if (typeof dataElements[TagKeys.RationalNumeratorValue] !== 'undefined') {\n value.rationalNumeratorValue =\n dataElements[TagKeys.RationalNumeratorValue].value[0];\n }\n if (typeof dataElements[TagKeys.RationalDenominatorValue] !== 'undefined') {\n value.rationalDenominatorValue =\n dataElements[TagKeys.RationalDenominatorValue].value[0];\n }\n if (typeof dataElements[TagKeys.MeasurementUnitsCodeSequence] !==\n 'undefined') {\n value.measurementUnitsCode = getCode(\n dataElements[TagKeys.MeasurementUnitsCodeSequence].value[0]);\n }\n\n return value;\n};\n\n/**\n * Get a simple dicom element item from a measured value object.\n *\n * @param {MeasuredValue} value The measured value object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomMeasuredValueItem(value) {\n // dicom item (tags are in group/element order)\n const item = {};\n\n if (typeof value.measurementUnitsCode !== 'undefined') {\n item.MeasurementUnitsCodeSequence = {\n value: [getDicomCodeItem(value.measurementUnitsCode)]\n };\n }\n if (typeof value.floatingPointValue !== 'undefined') {\n item.FloatingPointValue = value.floatingPointValue;\n }\n if (typeof value.rationalNumeratorValue !== 'undefined') {\n item.RationalNumeratorValue = value.rationalNumeratorValue;\n }\n if (typeof value.rationalDenominatorValue !== 'undefined') {\n item.RationalDenominatorValue = value.rationalDenominatorValue;\n }\n if (typeof value.numericValue !== 'undefined') {\n item.NumericValue = value.numericValue;\n }\n\n // return\n return item;\n}\n","import {\n getCode,\n getDicomCodeItem\n} from './dicomCode';\nimport {\n getMeasuredValue,\n getDicomMeasuredValueItem\n} from './dicomMeasuredValue';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\nimport {MeasuredValue} from './dicomMeasuredValue';\nimport {DicomCode} from './dicomCode';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n MeasuredValueSequence: '0040A300',\n NumericValueQualifierCodeSequence: '0040A301'\n};\n\n/**\n * DICOM numeric measurement: item of a SR content sequence.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.html#table_C.18.1-1}.\n */\nexport class NumericMeasurement {\n /**\n * @type {MeasuredValue}\n */\n measuredValue;\n\n /**\n * @type {DicomCode}\n */\n numericValueQualifierCode;\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The object as string.\n */\n toString() {\n let res = this.measuredValue.toString();\n if (typeof this.numericValueQualifierCode !== 'undefined') {\n res += ' ' + this.numericValueQualifierCode.toString();\n }\n return res;\n }\n};\n\n/**\n * Get a measurement object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {NumericMeasurement} A measurement object.\n */\nexport function getNumericMeasurement(dataElements) {\n const measurement = new NumericMeasurement();\n\n if (typeof dataElements[TagKeys.MeasuredValueSequence] !== 'undefined') {\n measurement.measuredValue = getMeasuredValue(\n dataElements[TagKeys.MeasuredValueSequence].value[0]);\n }\n if (typeof dataElements[TagKeys.NumericValueQualifierCodeSequence] !==\n 'undefined') {\n measurement.numericValueQualifierCode = getCode(\n dataElements[TagKeys.NumericValueQualifierCodeSequence].value[0]);\n }\n\n return measurement;\n};\n\n/**\n * Get a simple dicom element item from a measurement object.\n *\n * @param {NumericMeasurement} measurement The measurement object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomNumericMeasurementItem(measurement) {\n // dicom item (tags are in group/element order)\n const item = {};\n\n if (typeof measurement.measuredValue !== 'undefined') {\n item.MeasuredValueSequence = {\n value: [getDicomMeasuredValueItem(measurement.measuredValue)]\n };\n }\n if (typeof measurement.numericValueQualifierCode !== 'undefined') {\n item.NumericValueQualifierCodeSequence = {\n value: [getDicomCodeItem(measurement.numericValueQualifierCode)]\n };\n }\n\n // return\n return item;\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n ReferencedSOPClassUID: '00081150',\n ReferencedSOPInstanceUID: '00081155'\n};\n\n/**\n * DICOM sop instance reference.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_10.8.html#table_10-11}.\n */\nexport class SopInstanceReference {\n /**\n * @type {string}\n */\n referencedSOPClassUID;\n\n /**\n * @type {string}\n */\n referencedSOPInstanceUID;\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The object as string.\n */\n toString() {\n return this.referencedSOPInstanceUID + ' (class: ' +\n this.referencedSOPClassUID + ')';\n };\n};\n\n/**\n * Get a SOP reference object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {SopInstanceReference} A SOP reference object.\n */\nexport function getSopInstanceReference(dataElements) {\n const ref = new SopInstanceReference();\n\n if (typeof dataElements[TagKeys.ReferencedSOPClassUID] !== 'undefined') {\n ref.referencedSOPClassUID =\n dataElements[TagKeys.ReferencedSOPClassUID].value[0];\n }\n if (typeof dataElements[TagKeys.ReferencedSOPInstanceUID] !== 'undefined') {\n ref.referencedSOPInstanceUID =\n dataElements[TagKeys.ReferencedSOPInstanceUID].value[0];\n }\n\n return ref;\n};\n\n/**\n * Get a simple dicom element item from a SOP reference object.\n *\n * @param {SopInstanceReference} ref The SOP reference object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomSopInstanceReferenceItem(ref) {\n // dicom item (tags are in group/element order)\n const item = {};\n\n if (typeof ref.referencedSOPClassUID !== 'undefined') {\n item.ReferencedSOPClassUID = ref.referencedSOPClassUID;\n }\n if (typeof ref.referencedSOPInstanceUID !== 'undefined') {\n item.ReferencedSOPInstanceUID = ref.referencedSOPInstanceUID;\n }\n\n // return\n return item;\n}\n","import {\n getSopInstanceReference,\n getDicomSopInstanceReferenceItem\n} from './dicomSopInstanceReference';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n ReferencedFrameNumber: '00081160',\n ReferencedSOPSequence: '00081199',\n ReferencedSegmentNumber: '0062000B'\n};\n\n/**\n * DICOM image reference: item of a SR content sequence.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.4.html#table_C.18.4-1}.\n */\nexport class ImageReference {\n /**\n * @type {object}\n */\n referencedSOPSequence;\n\n /**\n * @type {object}\n */\n referencedFrameNumber;\n\n /**\n * @type {string}\n */\n referencedSegmentNumber;\n\n /**\n * @type {string}\n */\n fiducialUID;\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The object as string.\n */\n toString() {\n return this.referencedSOPSequence.toString();\n };\n};\n\n/**\n * Get a reference object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {ImageReference} A reference object.\n */\nexport function getImageReference(dataElements) {\n const ref = new ImageReference();\n\n if (typeof dataElements[TagKeys.ReferencedFrameNumber] !== 'undefined') {\n ref.referencedFrameNumber =\n dataElements[TagKeys.ReferencedFrameNumber].value[0];\n }\n if (typeof dataElements[TagKeys.ReferencedSOPSequence] !== 'undefined') {\n ref.referencedSOPSequence = getSopInstanceReference(\n dataElements[TagKeys.ReferencedSOPSequence].value[0]);\n }\n if (typeof dataElements[TagKeys.ReferencedSegmentNumber] !== 'undefined') {\n ref.referencedSegmentNumber =\n dataElements[TagKeys.ReferencedSegmentNumber].value[0];\n }\n\n return ref;\n};\n\n/**\n * Get a simple dicom element item from a reference object.\n *\n * @param {ImageReference} ref The reference object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomImageReferenceItem(ref) {\n // dicom item (tags are in group/element order)\n const item = {};\n\n if (typeof ref.referencedFrameNumber !== 'undefined') {\n item.ReferencedFrameNumber = ref.referencedFrameNumber;\n }\n if (typeof ref.referencedSOPSequence !== 'undefined') {\n item.ReferencedSOPSequence = {\n value: [getDicomSopInstanceReferenceItem(ref.referencedSOPSequence)]\n };\n }\n if (typeof ref.referencedSegmentNumber !== 'undefined') {\n item.ReferencedSegmentNumber =\n ref.referencedSegmentNumber;\n }\n\n // return\n return item;\n}\n","import {Point2D} from '../math/point';\nimport {Line, areOrthogonal} from '../math/line';\nimport {Protractor} from '../math/protractor';\nimport {ROI} from '../math/roi';\nimport {Circle} from '../math/circle';\nimport {Ellipse} from '../math/ellipse';\nimport {Rectangle} from '../math/rectangle';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n PixelOriginInterpretation: '00480301',\n GraphicData: '00700022',\n GraphicType: '00700023',\n FiducialUID: '0070031A'\n};\n\n/**\n * DICOM graphic types.\n */\nexport const GraphicTypes = {\n point: 'POINT',\n multipoint: 'MULTIPOINT',\n polyline: 'POLYLINE',\n circle: 'CIRCLE',\n ellipse: 'ELLIPSE'\n};\n\n/**\n * DICOM spatial coordinate (SCOORD): item of a SR content sequence.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.6.html#table_C.18.6-1}.\n */\nexport class SpatialCoordinate {\n /**\n * @type {string[]}\n */\n graphicData;\n\n /**\n * @type {string}\n */\n graphicType;\n\n /**\n * @type {string}\n */\n pixelOriginInterpretation;\n\n /**\n * @type {string}\n */\n fiducialUID;\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The object as string.\n */\n toString() {\n return this.graphicType +\n ' {' + this.graphicData + '}';\n };\n};\n\n/**\n * Get a scoord object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {SpatialCoordinate} A scoord object.\n */\nexport function getSpatialCoordinate(dataElements) {\n const scoord = new SpatialCoordinate();\n\n if (typeof dataElements[TagKeys.GraphicData] !== 'undefined') {\n scoord.graphicData = dataElements[TagKeys.GraphicData].value;\n }\n if (typeof dataElements[TagKeys.GraphicType] !== 'undefined') {\n scoord.graphicType = dataElements[TagKeys.GraphicType].value[0];\n }\n if (typeof dataElements[TagKeys.PixelOriginInterpretation] !== 'undefined') {\n scoord.pixelOriginInterpretation =\n dataElements[TagKeys.PixelOriginInterpretation].value[0];\n }\n if (typeof dataElements[TagKeys.FiducialUID] !== 'undefined') {\n scoord.fiducialUID = dataElements[TagKeys.FiducialUID].value[0];\n }\n return scoord;\n};\n\n/**\n * Get a simple dicom element item from a scoord object.\n *\n * @param {SpatialCoordinate} scoord The scoord object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomSpatialCoordinateItem(scoord) {\n // dicom item (tags are in group/element order)\n const item = {};\n\n if (typeof scoord.pixelOriginInterpretation !== 'undefined') {\n item.PixelOriginInterpretation = scoord.pixelOriginInterpretation;\n }\n if (typeof scoord.graphicData !== 'undefined') {\n item.GraphicData = scoord.graphicData;\n }\n if (typeof scoord.graphicType !== 'undefined') {\n item.GraphicType = scoord.graphicType;\n }\n if (typeof scoord.fiducialUID !== 'undefined') {\n item.FiducialUID = scoord.fiducialUID;\n }\n\n // return\n return item;\n}\n\n/**\n * Get a DICOM spatial coordinate (SCOORD) from a mathematical shape.\n *\n * @param {Point2D|Line|Protractor|ROI|Circle|Ellipse|Rectangle} shape\n * The math shape.\n * @returns {SpatialCoordinate} The DICOM scoord.\n */\nexport function getScoordFromShape(shape) {\n const scoord = new SpatialCoordinate();\n\n if (shape instanceof Point2D) {\n scoord.graphicData = [\n shape.getX().toString(),\n shape.getY().toString(),\n ];\n scoord.graphicType = GraphicTypes.point;\n } else if (shape instanceof Line) {\n scoord.graphicData = [\n shape.getBegin().getX().toString(),\n shape.getBegin().getY().toString(),\n shape.getEnd().getX().toString(),\n shape.getEnd().getY().toString(),\n ];\n scoord.graphicType = GraphicTypes.polyline;\n } else if (shape instanceof Protractor) {\n scoord.graphicData = [];\n for (let i = 0; i < 3; ++i) {\n scoord.graphicData.push(shape.getPoint(i).getX().toString());\n scoord.graphicData.push(shape.getPoint(i).getY().toString());\n }\n scoord.graphicType = GraphicTypes.polyline;\n } else if (shape instanceof ROI) {\n scoord.graphicData = [];\n for (let i = 0; i < shape.getLength(); ++i) {\n scoord.graphicData.push(shape.getPoint(i).getX().toString());\n scoord.graphicData.push(shape.getPoint(i).getY().toString());\n }\n // repeat first point to close shape\n const firstPoint = shape.getPoint(0);\n scoord.graphicData.push(firstPoint.getX().toString());\n scoord.graphicData.push(firstPoint.getY().toString());\n\n scoord.graphicType = GraphicTypes.polyline;\n } else if (shape instanceof Circle) {\n const center = shape.getCenter();\n const pointPerimeter = new Point2D(\n center.getX() + shape.getRadius(), center.getY()\n );\n scoord.graphicData = [\n center.getX().toString(),\n center.getY().toString(),\n pointPerimeter.getX().toString(),\n pointPerimeter.getY().toString(),\n ];\n scoord.graphicType = GraphicTypes.circle;\n } else if (shape instanceof Ellipse) {\n const center = shape.getCenter();\n const radiusX = shape.getA();\n const radiusY = shape.getB();\n scoord.graphicData = [\n (center.getX() - radiusX).toString(),\n center.getY().toString(),\n (center.getX() + radiusX).toString(),\n center.getY().toString(),\n center.getX().toString(),\n (center.getY() - radiusY).toString(),\n center.getX().toString(),\n (center.getY() + radiusY).toString()\n ];\n scoord.graphicType = GraphicTypes.ellipse;\n } else if (shape instanceof Rectangle) {\n const begin = shape.getBegin();\n const end = shape.getEnd();\n // begin as first and last point to close shape\n scoord.graphicData = [\n begin.getX().toString(),\n begin.getY().toString(),\n begin.getX().toString(),\n end.getY().toString(),\n end.getX().toString(),\n end.getY().toString(),\n end.getX().toString(),\n begin.getY().toString(),\n begin.getX().toString(),\n begin.getY().toString()\n ];\n scoord.graphicType = GraphicTypes.polyline;\n }\n\n return scoord;\n};\n\n/**\n * Get a mathematical shape from a DICOM spatial coordinate (SCOORD).\n *\n * @param {SpatialCoordinate} scoord The DICOM scoord.\n * @returns {Point2D|Line|Protractor|ROI|Circle|Ellipse|Rectangle}\n * The math shape.\n */\nexport function getShapeFromScoord(scoord) {\n // extract points\n const dataLength = scoord.graphicData.length;\n if (dataLength % 2 !== 0) {\n throw new Error('Expecting even number of coordinates in scroord data');\n }\n const points = [];\n for (let i = 0; i < dataLength; i += 2) {\n points.push(new Point2D(\n parseFloat(scoord.graphicData[i]),\n parseFloat(scoord.graphicData[i + 1])\n ));\n }\n let isClosed = false;\n const numberOfPoints = points.length;\n if (numberOfPoints > 2) {\n const firstPoint = points[0];\n const lastPoint = points[numberOfPoints - 1];\n isClosed = firstPoint.equals(lastPoint);\n }\n\n // create math shape\n let shape;\n if (scoord.graphicType === GraphicTypes.point) {\n if (points.length !== 1) {\n throw new Error('Expecting 1 point for point');\n }\n shape = points[0];\n } else if (scoord.graphicType === GraphicTypes.circle) {\n if (points.length !== 2) {\n throw new Error('Expecting 2 points for circles');\n }\n const center = points[0];\n const pointPerimeter = points[1];\n const radius = pointPerimeter.getDistance(center);\n shape = new Circle(center, radius);\n } else if (scoord.graphicType === GraphicTypes.ellipse) {\n if (points.length !== 4) {\n throw new Error('Expecting 4 points for ellipses');\n }\n // TODO: make more generic\n const radiusX = points[0].getDistance(points[1]) / 2;\n const radiusY = points[2].getDistance(points[3]) / 2;\n const center = new Point2D(\n points[0].getX() + radiusX,\n points[0].getY()\n );\n shape = new Ellipse(center, radiusX, radiusY);\n } else if (scoord.graphicType === GraphicTypes.polyline) {\n if (!isClosed) {\n if (points.length === 2) {\n shape = new Line(points[0], points[1]);\n } else if (points.length === 3) {\n shape = new Protractor([points[0], points[1], points[2]]);\n }\n } else {\n if (points.length === 5) {\n const line0 = new Line(points[0], points[1]);\n const line1 = new Line(points[1], points[2]);\n const line2 = new Line(points[2], points[3]);\n const line3 = new Line(points[3], points[4]);\n if (areOrthogonal(line0, line1) &&\n areOrthogonal(line1, line2) &&\n areOrthogonal(line2, line3)) {\n shape = new Rectangle(points[0], points[2]);\n } else {\n // remove last=first point for closed shape\n shape = new ROI(points.slice(0, -1));\n }\n } else {\n // remove last=first point for closed shape\n shape = new ROI(points.slice(0, -1));\n }\n }\n }\n\n return shape;\n};","// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n GraphicData: '00700022',\n GraphicType: '00700023',\n ReferencedFrameofReferenceUID: '30060024',\n FiducialUID: '0070031A'\n};\n\n/**\n * DICOM spatial coordinate 3D (SCOORD3D): item of a SR content sequence.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.9.html#table_C.18.9-1}.\n */\nexport class SpatialCoordinate3D {\n /**\n * @type {string[]}\n */\n graphicData;\n\n /**\n * @type {string}\n */\n graphicType;\n\n /**\n * @type {string}\n */\n referencedFrameofReferenceUID;\n\n /**\n * @type {string}\n */\n fiducialUID;\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The object as string.\n */\n toString() {\n return this.graphicType +\n '{' + this.graphicData + '}';\n };\n};\n\n/**\n * Get a scoord3d object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {SpatialCoordinate3D} A scoord3d object.\n */\nexport function getSpatialCoordinate3D(dataElements) {\n const scoord = new SpatialCoordinate3D();\n\n if (typeof dataElements[TagKeys.GraphicData] !== 'undefined') {\n scoord.graphicData = dataElements[TagKeys.GraphicData].value;\n }\n if (typeof dataElements[TagKeys.GraphicType] !== 'undefined') {\n scoord.graphicType = dataElements[TagKeys.GraphicType].value[0];\n }\n if (typeof dataElements[TagKeys.ReferencedFrameofReferenceUID] !==\n 'undefined') {\n scoord.referencedFrameofReferenceUID =\n dataElements[TagKeys.ReferencedFrameofReferenceUID].value[0];\n }\n if (typeof dataElements[TagKeys.FiducialUID] !== 'undefined') {\n scoord.fiducialUID = dataElements[TagKeys.FiducialUID].value[0];\n }\n return scoord;\n};\n\n/**\n * Get a simple dicom element item from a scoord3d object.\n *\n * @param {SpatialCoordinate3D} scoord The scoord3d object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomSpatialCoordinate3DItem(scoord) {\n // dicom item (tags are in group/element order)\n const item = {};\n\n if (typeof scoord.graphicData !== 'undefined') {\n item.GraphicData = scoord.graphicData;\n }\n if (typeof scoord.graphicType !== 'undefined') {\n item.GraphicType = scoord.graphicType;\n }\n if (typeof scoord.referencedFrameofReferenceUID !== 'undefined') {\n item.ReferencedFrameofReferenceUID =\n scoord.referencedFrameofReferenceUID;\n }\n if (typeof scoord.fiducialUID !== 'undefined') {\n item.FiducialUID = scoord.fiducialUID;\n }\n\n // return\n return item;\n}","import {\n NumericMeasurement,\n getNumericMeasurement,\n getDicomNumericMeasurementItem\n} from './dicomNumericMeasurement';\nimport {\n getCode,\n getDicomCodeItem,\n getConceptNameCode,\n getMeasurementUnitsCode\n} from './dicomCode';\nimport {\n getImageReference,\n getDicomImageReferenceItem\n} from './dicomImageReference';\nimport {\n getSopInstanceReference,\n getDicomSopInstanceReferenceItem\n} from './dicomSopInstanceReference';\nimport {\n getSpatialCoordinate,\n getDicomSpatialCoordinateItem\n} from './dicomSpatialCoordinate';\nimport {\n getSpatialCoordinate3D,\n getDicomSpatialCoordinate3DItem\n} from './dicomSpatialCoordinate3D';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\nimport {DicomCode} from './dicomCode';\nimport {MeasuredValue} from './dicomMeasuredValue';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n ReferencedSOPSequence: '00081199',\n RelationshipType: '0040A010',\n ValueType: '0040A040',\n ConceptNameCodeSequence: '0040A043',\n ConceptCodeSequence: '0040A168',\n ContentSequence: '0040A730',\n DateTime: '0040A120',\n Date: '0040A121',\n Time: '0040A122',\n UID: '0040A124',\n PersonName: '0040A123',\n TextValue: '0040A160',\n ContinuityOfContent: '0040A050'\n};\n\n/**\n * DICOM relationship types.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.17.3.2.4.html#sect_C.17.3.2.4}.\n */\nexport const RelationshipTypes = {\n contains: 'CONTAINS',\n hasProperties: 'HAS PROPERTIES',\n hasObsContext: 'HAS OBS CONTEXT',\n hasAcqContext: 'HAS ACQ CONTEXT',\n inferredFrom: 'INFERRED FROM',\n selectedFrom: 'SELECTED FROM',\n hasConceptMod: 'HAS CONCEPT MOD'\n};\n\n/**\n * DICOM value types.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.17.3.2.html#sect_C.17.3.2.1}.\n */\nexport const ValueTypes = {\n text: 'TEXT',\n num: 'NUM',\n code: 'CODE',\n date: 'DATE',\n time: 'TIME',\n datetime: 'DATETIME',\n uidref: 'UIDREF',\n pname: 'PNAME',\n composite: 'COMPOSITE',\n image: 'IMAGE',\n waveform: 'WAVEFORM',\n scoord: 'SCOORD',\n scoord3d: 'SCOORD3D',\n tcoord: 'TCOORD',\n container: 'CONTAINER',\n table: 'TABLE',\n};\n\n/**\n * DICOM value type to associated tag name.\n */\nexport const ValueTypeValueTagName = {\n TEXT: 'TextValue',\n DATE: 'Date',\n TIME: 'Time',\n DATETIME: 'DateTime',\n UIDREF: 'UID',\n PNAME: 'PersonName',\n CONTAINER: 'ContinuityOfContent',\n};\n\n/**\n * DICOM SR content: item of a SR content sequence.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.17.3.html}.\n */\nexport class DicomSRContent {\n /**\n * Value type.\n *\n * @type {string}\n */\n valueType;\n /**\n * Concept name code.\n *\n * @type {DicomCode|undefined}\n */\n conceptNameCode;\n /**\n * Relationship Type.\n *\n * @type {string}\n */\n relationshipType;\n\n /**\n * Content sequence (0040,A730).\n *\n * @type {DicomSRContent[]|undefined}\n */\n contentSequence;\n\n /**\n * Value.\n *\n * @type {object}\n */\n value;\n\n /**\n * @param {string} valueType The content item value type.\n */\n constructor(valueType) {\n this.valueType = valueType;\n }\n\n /**\n * Get a string representation of this object.\n *\n * @param {string} [prefix] An optional prefix for recursive content.\n * @returns {string} The object as string.\n */\n toString(prefix) {\n if (typeof prefix === 'undefined') {\n prefix = '';\n }\n\n let res = '';\n\n if (typeof this.relationshipType !== 'undefined') {\n res += '(' + this.relationshipType + ') ';\n }\n\n res += this.valueType + ': ';\n\n if (typeof this.conceptNameCode !== 'undefined') {\n res += this.conceptNameCode.toString();\n }\n\n res += ' = ' + this.value.toString();\n\n if (typeof this.contentSequence !== 'undefined') {\n for (const item of this.contentSequence) {\n res += '\\n' + prefix + '- ' + item.toString(prefix + ' ');\n }\n }\n\n return res;\n }\n}\n\n/**\n * Check if two content item objects are equal.\n *\n * @param {DicomCode} item1 The first content item.\n * @param {DicomCode} item2 The second content item.\n * @returns {boolean} True if both content items are equal.\n */\nexport function isEqualContentItem(item1, item2) {\n return Object.keys(item1).length === Object.keys(item2).length &&\n Object.keys(item1).every(key =>\n Object.prototype.hasOwnProperty.call(item2, key) &&\n item1[key] === item2[key]\n );\n}\n\n/**\n * Get a content item object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {DicomSRContent} A content item object.\n */\nexport function getSRContent(dataElements) {\n // valueType -> ValueType (type1)\n let valueType = '';\n if (typeof dataElements[TagKeys.ValueType] !== 'undefined') {\n valueType = dataElements[TagKeys.ValueType].value[0];\n }\n\n const content = new DicomSRContent(valueType);\n\n // relationshipType -> RelationType (type1)\n if (typeof dataElements[TagKeys.RelationshipType] !== 'undefined') {\n content.relationshipType =\n dataElements[TagKeys.RelationshipType].value[0];\n }\n\n if (typeof dataElements[TagKeys.ConceptNameCodeSequence] !== 'undefined') {\n content.conceptNameCode =\n getCode(dataElements[TagKeys.ConceptNameCodeSequence].value[0]);\n }\n\n // set value acording to valueType\n // (date and time are stored as string)\n if (valueType === ValueTypes.code) {\n content.value = getCode(\n dataElements[TagKeys.ConceptCodeSequence].value[0]);\n } else if (valueType === ValueTypes.num) {\n content.value = getNumericMeasurement(dataElements);\n } else if (valueType === ValueTypes.image) {\n content.value = getImageReference(dataElements);\n } else if (valueType === ValueTypes.composite) {\n content.value = getSopInstanceReference(\n dataElements[TagKeys.ReferencedSOPSequence].value[0]\n );\n } else if (valueType === ValueTypes.scoord) {\n content.value = getSpatialCoordinate(dataElements);\n } else if (valueType === ValueTypes.scoord3d) {\n content.value = getSpatialCoordinate3D(dataElements);\n } else {\n const valueTagName = ValueTypeValueTagName[valueType];\n if (typeof valueTagName !== 'undefined') {\n content.value = dataElements[TagKeys[valueTagName]].value[0];\n } else {\n console.warn('Unsupported input ValueType: ' + valueType);\n }\n }\n\n const contentSqEl = dataElements[TagKeys.ContentSequence];\n if (typeof contentSqEl !== 'undefined') {\n content.contentSequence = [];\n for (const item of dataElements[TagKeys.ContentSequence].value) {\n content.contentSequence.push(getSRContent(item));\n }\n }\n\n return content;\n}\n\n/**\n * Get a simple dicom element item from a content item object.\n *\n * @param {DicomSRContent} content The content item object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomSRContentItem(content) {\n // dicom item (tags are in ~group/element order)\n let contentItem = {};\n\n if (typeof content.relationshipType !== 'undefined') {\n contentItem.RelationshipType = content.relationshipType;\n }\n if (typeof content.valueType !== 'undefined') {\n contentItem.ValueType = content.valueType;\n }\n if (typeof content.conceptNameCode !== 'undefined') {\n contentItem.ConceptNameCodeSequence = {\n value: [getDicomCodeItem(content.conceptNameCode)]\n };\n }\n\n // set appropriate value tag (data and time are stored as string)\n if (content.valueType === 'CODE') {\n contentItem.ConceptCodeSequence = {\n value: [getDicomCodeItem(content.value)]\n };\n } else if (content.valueType === ValueTypes.num) {\n contentItem = {\n ...contentItem,\n ...getDicomNumericMeasurementItem(content.value)\n };\n } else if (content.valueType === ValueTypes.image) {\n contentItem = {\n ...contentItem,\n ...getDicomImageReferenceItem(content.value)\n };\n } else if (content.valueType === ValueTypes.composite) {\n contentItem = {\n ...contentItem,\n ...getDicomSopInstanceReferenceItem(content.value)\n };\n } else if (content.valueType === ValueTypes.scoord) {\n contentItem = {\n ...contentItem,\n ...getDicomSpatialCoordinateItem(content.value)\n };\n } else if (content.valueType === ValueTypes.scoord3d) {\n contentItem = {\n ...contentItem,\n ...getDicomSpatialCoordinate3DItem(content.value)\n };\n } else {\n const valueTagName = ValueTypeValueTagName[content.valueType];\n if (typeof valueTagName !== 'undefined') {\n contentItem[valueTagName] = content.value;\n } else {\n console.warn('Unsupported output ValueType: ' + content.valueType);\n }\n }\n\n if (typeof content.contentSequence !== 'undefined') {\n contentItem.ContentSequence = {\n value: []\n };\n for (const item of content.contentSequence) {\n contentItem.ContentSequence.value.push(getDicomSRContentItem(item));\n }\n }\n\n return contentItem;\n}\n\n/**\n * Get a DicomSRContent from a value.\n *\n * @param {string} name The value name.\n * @param {object} value The value.\n * @param {string} unit The values' unit.\n * @returns {DicomSRContent|undefined} The SR content.\n */\nexport function getSRContentFromValue(name, value, unit) {\n const conceptNameCode = getConceptNameCode(name);\n\n if (typeof conceptNameCode === 'undefined') {\n return undefined;\n }\n\n const content = new DicomSRContent(ValueTypes.num);\n content.relationshipType = RelationshipTypes.contains;\n content.conceptNameCode = conceptNameCode;\n\n const measure = new MeasuredValue();\n measure.numericValue = value;\n measure.measurementUnitsCode = getMeasurementUnitsCode(unit);\n const numMeasure = new NumericMeasurement();\n numMeasure.measuredValue = measure;\n\n content.value = numMeasure;\n\n return content;\n}","import {\n dateToDateObj,\n getDicomDate,\n dateToTimeObj,\n getDicomTime,\n} from '../dicom/dicomDate';\nimport {\n ValueTypes,\n RelationshipTypes,\n getSRContent,\n getDicomSRContentItem,\n DicomSRContent,\n getSRContentFromValue\n} from '../dicom/dicomSRContent';\nimport {\n isEqualCode,\n getPathCode,\n getMeasurementGroupCode,\n getImageRegionCode,\n getReferenceGeometryCode,\n getSourceImageCode,\n getTrackingIdentifierCode,\n getShortLabelCode,\n getReferencePointsCode,\n getColourCode,\n getQuantificationName,\n getQuantificationUnit\n} from '../dicom/dicomCode';\nimport {getElementsFromJSONTags} from '../dicom/dicomWriter';\nimport {ImageReference} from '../dicom/dicomImageReference';\nimport {SopInstanceReference} from '../dicom/dicomSopInstanceReference';\nimport {\n GraphicTypes,\n getScoordFromShape,\n getShapeFromScoord,\n SpatialCoordinate\n} from '../dicom/dicomSpatialCoordinate';\nimport {SpatialCoordinate3D} from '../dicom/dicomSpatialCoordinate3D';\nimport {guid} from '../math/stats';\nimport {logger} from '../utils/logger';\nimport {Annotation} from './annotation';\nimport {AnnotationGroup} from './annotationGroup';\nimport {Line} from '../math/line';\nimport {Point2D, Point3D} from '../math/point';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * Merge two tag lists.\n *\n * @param {object} tags1 Base list, will be modified.\n * @param {object} tags2 List to merge.\n */\nfunction mergeTags(tags1, tags2) {\n const keys2 = Object.keys(tags2);\n for (const tagName2 of keys2) {\n if (tags1[tagName2] !== undefined) {\n logger.trace('Overwritting tag: ' + tagName2);\n }\n tags1[tagName2] = tags2[tagName2];\n }\n}\n\n/**\n * {@link AnnotationGroup} factory.\n */\nexport class AnnotationGroupFactory {\n\n /**\n * Possible warning created by checkElements.\n *\n * @type {string|undefined}\n */\n #warning;\n\n /**\n * Get a warning string if elements are not as expected.\n * Created by checkElements.\n *\n * @returns {string|undefined} The warning.\n */\n getWarning() {\n return this.#warning;\n }\n\n /**\n * Check dicom elements. Throws an error if not suitable.\n *\n * @param {Object} dataElements The DICOM data elements.\n * @returns {string|undefined} A possible warning.\n */\n checkElements(dataElements) {\n // reset\n this.#warning = undefined;\n\n const srContent = getSRContent(dataElements);\n if (typeof srContent.conceptNameCode !== 'undefined') {\n if (srContent.conceptNameCode.value !== getMeasurementGroupCode().value) {\n this.#warning = 'Not a measurement group';\n }\n } else {\n this.#warning = 'No root concept name code';\n }\n\n return this.#warning;\n }\n\n /**\n * Convert a DICOM SR content of type SCOORD into an annotation.\n *\n * @param {DicomSRContent} item The input SCOORD.\n * @returns {Annotation} The annotation.\n */\n #scoordToAnnotation(item) {\n const annotation = new Annotation();\n annotation.mathShape = getShapeFromScoord(item.value);\n // default\n annotation.id = guid();\n annotation.textExpr = '';\n\n for (const subItem of item.contentSequence) {\n // reference image UID\n if (subItem.valueType === ValueTypes.image &&\n subItem.relationshipType === RelationshipTypes.selectedFrom &&\n isEqualCode(subItem.conceptNameCode, getSourceImageCode())) {\n annotation.referenceSopUID =\n subItem.value.referencedSOPSequence.referencedSOPInstanceUID;\n }\n // annotation id\n if (subItem.valueType === ValueTypes.uidref &&\n subItem.relationshipType === RelationshipTypes.hasProperties &&\n isEqualCode(subItem.conceptNameCode, getTrackingIdentifierCode())) {\n annotation.id = subItem.value;\n }\n // text expr\n if (subItem.valueType === ValueTypes.text &&\n subItem.relationshipType === RelationshipTypes.hasProperties &&\n isEqualCode(subItem.conceptNameCode, getShortLabelCode())) {\n annotation.textExpr = subItem.value;\n if (typeof subItem.contentSequence !== 'undefined') {\n for (const subsubItem of subItem.contentSequence) {\n if (subsubItem.valueType === ValueTypes.scoord &&\n subsubItem.relationshipType === RelationshipTypes.hasProperties &&\n isEqualCode(\n subsubItem.conceptNameCode, getReferencePointsCode())) {\n annotation.labelPosition = new Point2D(\n subsubItem.value.graphicData[0],\n subsubItem.value.graphicData[1]\n );\n }\n }\n }\n }\n // color\n if (subItem.valueType === ValueTypes.text &&\n subItem.relationshipType === RelationshipTypes.hasProperties &&\n isEqualCode(subItem.conceptNameCode, getColourCode())) {\n annotation.colour = subItem.value;\n }\n // reference points\n if (subItem.valueType === ValueTypes.scoord &&\n subItem.relationshipType === RelationshipTypes.hasProperties &&\n isEqualCode(subItem.conceptNameCode, getReferencePointsCode()) &&\n subItem.value.graphicType === GraphicTypes.multipoint) {\n const points = [];\n for (let i = 0; i < subItem.value.graphicData.length; i += 2) {\n points.push(new Point2D(\n subItem.value.graphicData[i],\n subItem.value.graphicData[i + 1]\n ));\n }\n annotation.referencePoints = points;\n }\n // plane points\n if (subItem.valueType === ValueTypes.scoord3d &&\n subItem.relationshipType === RelationshipTypes.hasProperties &&\n isEqualCode(\n subItem.conceptNameCode, getReferenceGeometryCode()) &&\n subItem.value.graphicType === GraphicTypes.multipoint) {\n const data = subItem.value.graphicData;\n const points = [];\n const nPoints = Math.floor(data.length / 3);\n for (let i = 0; i < nPoints; ++i) {\n const j = i * 3;\n points.push(new Point3D(data[j], data[j + 1], data[j + 2]));\n }\n annotation.planePoints = points;\n }\n // quantification\n if (subItem.valueType === ValueTypes.num &&\n subItem.relationshipType === RelationshipTypes.contains) {\n const quantifName =\n getQuantificationName(subItem.conceptNameCode);\n if (typeof quantifName === 'undefined') {\n continue;\n }\n const measuredValue = subItem.value.measuredValue;\n const quantifUnit = getQuantificationUnit(\n measuredValue.measurementUnitsCode);\n if (typeof annotation.quantification === 'undefined') {\n annotation.quantification = {};\n }\n annotation.quantification[quantifName] = {\n value: measuredValue.numericValue,\n unit: quantifUnit\n };\n }\n }\n return annotation;\n }\n\n /**\n * Get an {@link Annotation} object from the read DICOM file.\n *\n * @param {Object} dataElements The DICOM tags.\n * @returns {AnnotationGroup} A new annotation group.\n */\n create(dataElements) {\n const annotations = [];\n const srContent = getSRContent(dataElements);\n for (const item of srContent.contentSequence) {\n if (item.valueType === ValueTypes.scoord) {\n annotations.push(this.#scoordToAnnotation(item));\n }\n }\n const annotationGroup = new AnnotationGroup(annotations);\n\n const safeGet = function (key) {\n let res;\n const element = dataElements[key];\n if (typeof element !== 'undefined') {\n res = element.value[0];\n }\n return res;\n };\n\n // StudyInstanceUID\n annotationGroup.setMetaValue('StudyInstanceUID', safeGet('0020000D'));\n // Modality\n annotationGroup.setMetaValue('Modality', safeGet('00080060'));\n // patient info\n annotationGroup.setMetaValue('PatientName', safeGet('00100010'));\n annotationGroup.setMetaValue('PatientID', safeGet('00100020'));\n annotationGroup.setMetaValue('PatientBirthDate', safeGet('00100030'));\n annotationGroup.setMetaValue('PatientSex', safeGet('00100040'));\n\n // ReferencedSeriesSequence\n const element = dataElements['00081115'];\n if (typeof element !== 'undefined') {\n const seriesElement = element.value[0]['0020000E'];\n if (typeof seriesElement !== 'undefined') {\n annotationGroup.setMetaValue(\n 'ReferencedSeriesSequence', {\n value: [{\n SeriesInstanceUID: seriesElement.value[0]\n }]\n }\n );\n }\n }\n\n return annotationGroup;\n }\n\n /**\n * Convert an annotation into a DICOM SCOORD.\n *\n * @param {Annotation} annotation The input annotation.\n * @returns {DicomSRContent} An SR content of type SCOORD.\n */\n #annotationToScoord(annotation) {\n const srScoord = new DicomSRContent(ValueTypes.scoord);\n srScoord.relationshipType = RelationshipTypes.contains;\n if (annotation.mathShape instanceof Line) {\n srScoord.conceptNameCode = getPathCode();\n } else {\n srScoord.conceptNameCode = getImageRegionCode();\n }\n srScoord.value = getScoordFromShape(annotation.mathShape);\n\n const itemContentSequence = [];\n\n // reference image UID\n const srImage = new DicomSRContent(ValueTypes.image);\n srImage.relationshipType = RelationshipTypes.selectedFrom;\n srImage.conceptNameCode = getSourceImageCode();\n const sopRef = new SopInstanceReference();\n sopRef.referencedSOPClassUID = '';\n sopRef.referencedSOPInstanceUID = annotation.referenceSopUID;\n const imageRef = new ImageReference();\n imageRef.referencedSOPSequence = sopRef;\n srImage.value = imageRef;\n itemContentSequence.push(srImage);\n\n // annotation id\n const srUid = new DicomSRContent(ValueTypes.uidref);\n srUid.relationshipType = RelationshipTypes.hasProperties;\n srUid.conceptNameCode = getTrackingIdentifierCode();\n srUid.value = annotation.id;\n itemContentSequence.push(srUid);\n\n // text expr\n const shortLabel = new DicomSRContent(ValueTypes.text);\n shortLabel.relationshipType = RelationshipTypes.hasProperties;\n shortLabel.conceptNameCode = getShortLabelCode();\n shortLabel.value = annotation.textExpr;\n // label position\n if (typeof annotation.labelPosition !== 'undefined') {\n const labelPosition = new DicomSRContent(ValueTypes.scoord);\n labelPosition.relationshipType = RelationshipTypes.hasProperties;\n labelPosition.conceptNameCode = getReferencePointsCode();\n const labelPosScoord = new SpatialCoordinate();\n labelPosScoord.graphicType = GraphicTypes.point;\n const graphicData = [\n annotation.labelPosition.getX().toString(),\n annotation.labelPosition.getY().toString()\n ];\n labelPosScoord.graphicData = graphicData;\n labelPosition.value = labelPosScoord;\n\n // add position to label sequence\n shortLabel.contentSequence = [labelPosition];\n }\n itemContentSequence.push(shortLabel);\n\n // colour\n const colour = new DicomSRContent(ValueTypes.text);\n colour.relationshipType = RelationshipTypes.hasProperties;\n colour.conceptNameCode = getColourCode();\n colour.value = annotation.colour;\n itemContentSequence.push(colour);\n\n // reference points\n if (typeof annotation.referencePoints !== 'undefined') {\n const referencePoints = new DicomSRContent(ValueTypes.scoord);\n referencePoints.relationshipType = RelationshipTypes.hasProperties;\n referencePoints.conceptNameCode = getReferencePointsCode();\n const refPointsScoord = new SpatialCoordinate();\n refPointsScoord.graphicType = GraphicTypes.multipoint;\n const graphicData = [];\n for (const point of annotation.referencePoints) {\n graphicData.push(point.getX().toString());\n graphicData.push(point.getY().toString());\n }\n refPointsScoord.graphicData = graphicData;\n\n referencePoints.value = refPointsScoord;\n itemContentSequence.push(referencePoints);\n }\n\n // plane points\n if (typeof annotation.planePoints !== 'undefined') {\n const planePoints = new DicomSRContent(ValueTypes.scoord3d);\n planePoints.relationshipType = RelationshipTypes.hasProperties;\n planePoints.conceptNameCode = getReferenceGeometryCode();\n const pointsScoord = new SpatialCoordinate3D();\n pointsScoord.graphicType = GraphicTypes.multipoint;\n const graphicData = [];\n for (const planePoint of annotation.planePoints) {\n graphicData.push(planePoint.getX().toString());\n graphicData.push(planePoint.getY().toString());\n graphicData.push(planePoint.getZ().toString());\n }\n pointsScoord.graphicData = graphicData;\n\n planePoints.value = pointsScoord;\n itemContentSequence.push(planePoints);\n }\n\n // quantification\n if (typeof annotation.quantification !== 'undefined') {\n for (const key in annotation.quantification) {\n const quatifContent = getSRContentFromValue(\n key,\n annotation.quantification[key].value,\n annotation.quantification[key].unit\n );\n if (typeof quatifContent !== 'undefined') {\n itemContentSequence.push(quatifContent);\n }\n }\n }\n\n srScoord.contentSequence = itemContentSequence;\n return srScoord;\n }\n\n /**\n * Convert an annotation group into a DICOM SR object.\n *\n * @param {AnnotationGroup} annotationGroup The annotation group.\n * @param {Object} [extraTags] Optional list of extra tags.\n * @returns {Object} A list of dicom elements.\n */\n toDicom(annotationGroup, extraTags) {\n let tags = annotationGroup.getMeta();\n\n // transfer syntax: ExplicitVRLittleEndian\n tags.TransferSyntaxUID = '1.2.840.10008.1.2.1';\n // class: Basic Text SR Storage\n tags.SOPClassUID = '1.2.840.10008.5.1.4.1.1.88.11';\n tags.MediaStorageSOPClassUID = '1.2.840.10008.5.1.4.1.1.88.11';\n tags.CompletionFlag = 'PARTIAL';\n tags.VerificationFlag = 'UNVERIFIED';\n\n const now = new Date();\n tags.ContentDate = getDicomDate(dateToDateObj(now));\n tags.ContentTime = getDicomTime(dateToTimeObj(now));\n\n const contentSequence = [];\n for (const annotation of annotationGroup.getList()) {\n contentSequence.push(this.#annotationToScoord(annotation));\n }\n\n // main\n if (contentSequence.length !== 0) {\n const srContent = new DicomSRContent(ValueTypes.container);\n srContent.conceptNameCode = getMeasurementGroupCode();\n srContent.contentSequence = contentSequence;\n\n tags = {\n ...tags,\n ...getDicomSRContentItem(srContent)\n };\n }\n\n // merge extra tags if provided\n if (typeof extraTags !== 'undefined') {\n mergeTags(tags, extraTags);\n }\n\n return getElementsFromJSONTags(tags);\n }\n\n}","import {ListenerHandler} from '../utils/listen';\nimport {mergeObjects} from '../utils/operator';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from '../image/image';\nimport {AnnotationGroup} from '../image/annotationGroup';\n/* eslint-enable no-unused-vars */\n\n/**\n * DICOM data: meta and possible image.\n */\nexport class DicomData {\n /**\n * DICOM meta data.\n *\n * @type {object}\n */\n meta;\n\n /**\n * Image extracted from meta data.\n *\n * @type {Image|undefined}\n */\n image;\n /**\n * Annotattion group extracted from meta data.\n *\n * @type {AnnotationGroup|undefined}\n */\n annotationGroup;\n\n /**\n * @param {object} meta The DICOM meta data.\n */\n constructor(meta) {\n this.meta = meta;\n }\n}\n\n/*\n * DicomData controller.\n */\nexport class DataController {\n\n /**\n * List of DICOM data.\n *\n * @type {Object}\n */\n #dataList = {};\n\n /**\n * Distinct data loaded counter.\n *\n * @type {number}\n */\n #dataIdCounter = -1;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Get the next data id.\n *\n * @returns {string} The data id.\n */\n getNextDataId() {\n ++this.#dataIdCounter;\n return this.#dataIdCounter.toString();\n }\n\n /**\n * Get the list of ids in the data storage.\n *\n * @returns {string[]} The list of data ids.\n */\n getDataIds() {\n return Object.keys(this.#dataList);\n }\n\n /**\n * Reset the class: empty the data storage.\n */\n reset() {\n this.#dataList = {};\n }\n\n /**\n * Get a data at a given index.\n *\n * @param {string} dataId The data id.\n * @returns {DicomData|undefined} The DICOM data.\n */\n get(dataId) {\n return this.#dataList[dataId];\n }\n\n /**\n * Get the list of dataIds that contain the input UIDs.\n *\n * @param {string[]} uids A list of UIDs.\n * @returns {string[]} The list of dataIds that contain the UIDs.\n */\n getDataIdsFromSopUids(uids) {\n const res = [];\n // check input\n if (typeof uids === 'undefined' ||\n uids.length === 0) {\n return res;\n }\n const keys = Object.keys(this.#dataList);\n for (const key of keys) {\n if (typeof this.#dataList[key].image !== 'undefined' &&\n this.#dataList[key].image.containsImageUids(uids)) {\n res.push(key);\n }\n }\n return res;\n }\n\n /**\n * Set the image at a given index.\n *\n * @param {string} dataId The data id.\n * @param {Image} image The image to set.\n */\n setImage(dataId, image) {\n this.#dataList[dataId].image = image;\n /**\n * Data image set event.\n *\n * @event DataController#dataimageset\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} value The event value, first element is the image.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'dataimageset',\n value: [image],\n dataid: dataId\n });\n // listen to image change\n image.addEventListener('imagecontentchange', this.#getFireEvent(dataId));\n image.addEventListener('imagegeometrychange', this.#getFireEvent(dataId));\n }\n\n /**\n * Add a new data.\n *\n * @param {string} dataId The data id.\n * @param {DicomData} data The data.\n */\n add(dataId, data) {\n if (typeof this.#dataList[dataId] !== 'undefined') {\n throw new Error('Data id already used in storage: ' + dataId);\n }\n // store the new image\n this.#dataList[dataId] = data;\n /**\n * Data add event.\n *\n * @event DataController#dataadd\n * @type {object}\n * @property {string} type The event type.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'dataadd',\n dataid: dataId\n });\n // listen to image change\n if (typeof data.image !== 'undefined') {\n data.image.addEventListener(\n 'imagecontentchange', this.#getFireEvent(dataId));\n data.image.addEventListener(\n 'imagegeometrychange', this.#getFireEvent(dataId));\n }\n if (typeof data.annotationGroup !== 'undefined') {\n data.annotationGroup.addEventListener(\n 'annotationadd', this.#getFireEvent(dataId));\n data.annotationGroup.addEventListener(\n 'annotationupdate', this.#getFireEvent(dataId));\n data.annotationGroup.addEventListener(\n 'annotationremove', this.#getFireEvent(dataId));\n }\n }\n\n /**\n * Remove a data from the list.\n *\n * @param {string} dataId The data id.\n */\n remove(dataId) {\n if (typeof this.#dataList[dataId] !== 'undefined') {\n // stop listeners\n const image = this.#dataList[dataId].image;\n if (typeof image !== 'undefined') {\n image.removeEventListener(\n 'imagecontentchange', this.#getFireEvent(dataId));\n image.removeEventListener(\n 'imagegeometrychange', this.#getFireEvent(dataId));\n }\n const annotationGroup = this.#dataList[dataId].annotationGroup;\n if (typeof annotationGroup !== 'undefined') {\n annotationGroup.removeEventListener(\n 'annotationadd', this.#getFireEvent(dataId));\n annotationGroup.removeEventListener(\n 'annotationupdate', this.#getFireEvent(dataId));\n annotationGroup.removeEventListener(\n 'annotationremove', this.#getFireEvent(dataId));\n }\n // remove data from list\n delete this.#dataList[dataId];\n /**\n * Data remove event.\n *\n * @event DataController#dataremove\n * @type {object}\n * @property {string} type The event type.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'dataremove',\n dataid: dataId\n });\n }\n }\n\n /**\n * Update the current data.\n *\n * @param {string} dataId The data id.\n * @param {DicomData} data The data.\n */\n update(dataId, data) {\n if (typeof this.#dataList[dataId] === 'undefined') {\n throw new Error('Cannot find data to update: ' + dataId);\n }\n const dataToUpdate = this.#dataList[dataId];\n\n // add slice to current image\n if (typeof dataToUpdate.image !== 'undefined' &&\n typeof data.image !== 'undefined'\n ) {\n dataToUpdate.image.appendSlice(data.image);\n }\n\n // update meta data\n // TODO add time support\n let idKey = '';\n if (typeof data.meta['00020010'] !== 'undefined') {\n // dicom case, use 'InstanceNumber'\n idKey = '00200013';\n } else {\n idKey = 'imageUid';\n }\n dataToUpdate.meta = mergeObjects(\n dataToUpdate.meta,\n data.meta,\n idKey,\n 'value');\n\n /**\n * Data udpate event.\n *\n * @event DataController#dataupdate\n * @type {object}\n * @property {string} type The event type.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'dataupdate',\n dataid: dataId\n });\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n /**\n * Get a fireEvent function that adds the input data id\n * to the event value.\n *\n * @param {string} dataId The data id.\n * @returns {Function} A fireEvent function.\n */\n #getFireEvent(dataId) {\n return (event) => {\n event.dataid = dataId;\n this.#fireEvent(event);\n };\n }\n\n} // DataController class\n","import {arrayEquals} from './array';\n\n/**\n * Merge two similar objects.\n *\n * Objects need to be in the form of:\n * \n * {\n * idKey: {valueKey: [0]},\n * key0: {valueKey: [\"abc\"]},\n * key1: {valueKey: [33]}\n * }\n * .\n *\n * Merged objects will be in the form of:\n * \n * {\n * idKey: {valueKey: [0,1,2], merged: true},\n * key0: {valueKey: {\n * 0: [\"abc\"],\n * 1: [\"def\"],\n * 2: [\"ghi\"]\n * }},\n * key1: {valueKey: {\n * 0: [33],\n * 1: [44],\n * 2: [55]\n * }}\n * }\n * .\n *\n * @param {object} obj1 The first object, can be the result of a previous merge.\n * @param {object} obj2 The second object.\n * @param {string} idKey The key to use as index for duplicate values.\n * @param {string} valueKey The key to use to access object values.\n * @returns {object} The merged object.\n */\nexport function mergeObjects(obj1, obj2, idKey, valueKey) {\n const res = {};\n // check id key\n if (!idKey) {\n throw new Error('Cannot merge object with an undefined id key: ' + idKey);\n } else {\n if (!Object.prototype.hasOwnProperty.call(obj1, idKey)) {\n throw new Error('Id key not found in first object while merging: ' +\n idKey + ', obj: ' + obj1);\n }\n if (!Object.prototype.hasOwnProperty.call(obj2, idKey)) {\n throw new Error('Id key not found in second object while merging: ' +\n idKey + ', obj: ' + obj2);\n }\n }\n // check value key\n if (!valueKey) {\n throw new Error('Cannot merge object with an undefined value key: ' +\n valueKey);\n }\n\n // check if merged object\n let mergedObj1 = false;\n if (Object.prototype.hasOwnProperty.call(obj1[idKey], 'merged') &&\n obj1[idKey].merged) {\n mergedObj1 = true;\n }\n // handle the id part\n if (!Object.prototype.hasOwnProperty.call(obj1[idKey], valueKey)) {\n throw new Error('Id value not found in first object while merging: ' +\n idKey + ', valueKey: ' + valueKey + ', ojb: ' + obj1);\n }\n if (!Object.prototype.hasOwnProperty.call(obj2[idKey], valueKey)) {\n throw new Error('Id value not found in second object while merging: ' +\n idKey + ', valueKey: ' + valueKey + ', ojb: ' + obj2);\n }\n let id1 = obj1[idKey][valueKey];\n const id2 = obj2[idKey][valueKey][0];\n // update id key\n res[idKey] = obj1[idKey];\n if (mergedObj1) {\n // check if array does not include id2\n for (let k = 0; k < id1.length; ++k) {\n if (id1[k] === id2) {\n throw new Error('The first object already contains id2: ' +\n id2 + ', id1: ' + id1);\n }\n }\n res[idKey][valueKey].push(id2);\n } else {\n id1 = id1[0];\n if (id1 === id2) {\n throw new Error('Cannot merge object with same ids: ' +\n id1 + ', id2: ' + id2);\n }\n // update merge object\n res[idKey][valueKey].push(id2);\n res[idKey].merged = true;\n }\n\n // get keys\n const keys1 = Object.keys(obj1);\n // keys2 without duplicates of keys1\n const keys2 = Object.keys(obj2).filter(function (item) {\n return keys1.indexOf(item) < 0;\n });\n const keys = keys1.concat(keys2);\n\n // loop through keys\n for (let i = 0; i < keys.length; ++i) {\n const key = keys[i];\n if (key !== idKey) {\n // first\n let value1;\n let subValue1;\n if (Object.prototype.hasOwnProperty.call(obj1, key)) {\n value1 = obj1[key];\n if (Object.prototype.hasOwnProperty.call(value1, valueKey)) {\n subValue1 = value1[valueKey];\n }\n }\n // second\n let value2;\n let subValue2;\n if (Object.prototype.hasOwnProperty.call(obj2, key)) {\n value2 = obj2[key];\n if (Object.prototype.hasOwnProperty.call(value2, valueKey)) {\n subValue2 = value2[valueKey];\n }\n }\n // result value\n let value;\n // use existing to copy properties\n if (typeof value1 !== 'undefined') {\n value = value1;\n } else if (typeof value2 !== 'undefined') {\n value = value2;\n }\n // create merge object if different values\n if (!arrayEquals(subValue1, subValue2)) {\n // add to merged object or create new\n if (mergedObj1) {\n if (Array.isArray(subValue1)) {\n // merged object with repeated value\n // copy it with the index list\n value[valueKey] = {};\n for (let j = 0; j < id1.length; ++j) {\n value[valueKey][id1[j]] = subValue1;\n }\n } else {\n value[valueKey] = subValue1;\n }\n // undefined subValue1\n if (typeof value[valueKey] === 'undefined') {\n value[valueKey] = {};\n }\n // add obj2 value\n value[valueKey][id2] = subValue2;\n } else {\n // create merge object\n const newValue = {};\n newValue[id1] = subValue1;\n newValue[id2] = subValue2;\n value[valueKey] = newValue;\n }\n }\n // store value in result object\n res[key] = value;\n }\n }\n return res;\n}\n","import {logger} from '../utils/logger';\nimport {\n DicomParser,\n getSyntaxDecompressionName\n} from '../dicom/dicomParser';\nimport {ImageFactory} from './imageFactory';\nimport {MaskFactory} from './maskFactory';\nimport {PixelBufferDecoder} from './decoder';\nimport {AnnotationGroupFactory} from './annotationGroupFactory';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from '../dicom/dataElement';\nimport {DicomData} from '../app/dataController';\n/* eslint-enable no-unused-vars */\n\n/**\n * Create a View from a DICOM buffer.\n */\nexport class DicomBufferToView {\n\n /**\n * Converter options.\n *\n * @type {object}\n */\n #options;\n\n /**\n * Set the converter options.\n *\n * @param {object} opt The input options.\n */\n setOptions(opt) {\n this.#options = opt;\n }\n\n /**\n * Pixel buffer decoder.\n * Define only once to allow optional asynchronous mode.\n *\n * @type {object}\n */\n #pixelDecoder = null;\n\n // local tmp storage\n #dicomParserStore = [];\n #finalBufferStore = [];\n #decompressedSizes = [];\n #factories = [];\n\n /**\n * Get the factory associated to input DICOM elements.\n *\n * @param {Object} elements The DICOM elements.\n * @returns {ImageFactory|MaskFactory|AnnotationGroupFactory|undefined}\n * The associated factory.\n */\n #getFactory(elements) {\n let factory;\n const modalityElement = elements['00080060'];\n if (typeof modalityElement !== 'undefined') {\n const modality = modalityElement.value[0];\n if (modality === 'SEG') {\n // mask factory for DICOM SEG\n factory = new MaskFactory();\n } else if (modality === 'SR') {\n // annotation factory for DICOM SR\n factory = new AnnotationGroupFactory();\n }\n }\n // image factory for pixel data\n if (typeof factory === 'undefined') {\n const pixelElement = elements['7FE00010'];\n if (typeof pixelElement !== 'undefined') {\n factory = new ImageFactory();\n }\n }\n return factory;\n }\n\n /**\n * Generate the data object.\n *\n * @param {number} index The data index.\n * @param {string} origin The data origin.\n */\n #generateData(index, origin) {\n const dataElements = this.#dicomParserStore[index].getDicomElements();\n const factory = this.#factories[index];\n // exit if no factory\n if (typeof factory === 'undefined') {\n return;\n }\n // create data\n try {\n const data = new DicomData(dataElements);\n if (factory instanceof AnnotationGroupFactory) {\n data.annotationGroup = factory.create(dataElements);\n } else {\n data.image = factory.create(\n dataElements,\n this.#finalBufferStore[index],\n this.#options.numberOfFiles);\n }\n // call onloaditem\n this.onloaditem({\n data: data,\n source: origin,\n warn: factory.getWarning()\n });\n } catch (error) {\n this.onerror({\n error: error,\n source: origin\n });\n this.onloadend({\n source: origin\n });\n }\n }\n\n /**\n * Generate the image object from an uncompressed buffer.\n *\n * @param {number} index The data index.\n * @param {string} origin The data origin.\n */\n #generateImageUncompressed(index, origin) {\n // send progress\n this.onprogress({\n lengthComputable: true,\n loaded: 100,\n total: 100,\n index: index,\n source: origin\n });\n // generate image\n this.#generateData(index, origin);\n // send load events\n this.onload({\n source: origin\n });\n this.onloadend({\n source: origin\n });\n }\n\n /**\n * Generate the image object from an compressed buffer.\n *\n * @param {number} index The data index.\n * @param {Array} pixelBuffer The dicom parser.\n * @param {string} algoName The compression algorithm name.\n */\n #generateImageCompressed(index, pixelBuffer, algoName) {\n const dicomParser = this.#dicomParserStore[index];\n\n // gather pixel buffer meta data\n const bitsAllocated =\n dicomParser.getDicomElements()['00280100'].value[0];\n const pixelRepresentation =\n dicomParser.getDicomElements()['00280103'].value[0];\n const pixelMeta = {\n bitsAllocated: bitsAllocated,\n isSigned: (pixelRepresentation === 1)\n };\n const columnsElement = dicomParser.getDicomElements()['00280011'];\n const rowsElement = dicomParser.getDicomElements()['00280010'];\n if (typeof columnsElement !== 'undefined' &&\n typeof rowsElement !== 'undefined') {\n pixelMeta.sliceSize = columnsElement.value[0] * rowsElement.value[0];\n }\n const samplesPerPixelElement =\n dicomParser.getDicomElements()['00280002'];\n if (typeof samplesPerPixelElement !== 'undefined') {\n pixelMeta.samplesPerPixel = samplesPerPixelElement.value[0];\n }\n const planarConfigurationElement =\n dicomParser.getDicomElements()['00280006'];\n if (typeof planarConfigurationElement !== 'undefined') {\n pixelMeta.planarConfiguration = planarConfigurationElement.value[0];\n }\n\n const numberOfItems = pixelBuffer.length;\n\n // setup the decoder (one decoder per all converts)\n if (this.#pixelDecoder === null) {\n this.#pixelDecoder = new PixelBufferDecoder(\n algoName, numberOfItems);\n // callbacks\n // pixelDecoder.ondecodestart: nothing to do\n this.#pixelDecoder.ondecodeditem = (event) => {\n this.#onDecodedItem(event);\n // send onload and onloadend when all items have been decoded\n if (event.itemNumber + 1 === event.numberOfItems) {\n this.onload(event);\n this.onloadend(event);\n }\n };\n // pixelDecoder.ondecoded: nothing to do\n // pixelDecoder.ondecodeend: nothing to do\n this.#pixelDecoder.onerror = this.onerror;\n this.#pixelDecoder.onabort = this.onabort;\n }\n\n // launch decode\n for (let i = 0; i < numberOfItems; ++i) {\n this.#pixelDecoder.decode(pixelBuffer[i], pixelMeta,\n {\n itemNumber: i,\n numberOfItems: numberOfItems,\n index: index\n }\n );\n }\n }\n\n /**\n * Handle a decoded item event.\n *\n * @param {object} event The decoded item event.\n */\n #onDecodedItem(event) {\n // send progress\n this.onprogress({\n lengthComputable: true,\n loaded: event.itemNumber + 1,\n total: event.numberOfItems,\n index: event.index,\n source: origin\n });\n\n const dataIndex = event.index;\n\n // store decoded data\n const decodedData = event.data[0];\n if (event.numberOfItems !== 1) {\n // allocate buffer if not done yet\n if (typeof this.#decompressedSizes[dataIndex] === 'undefined') {\n this.#decompressedSizes[dataIndex] = decodedData.length;\n const fullSize = event.numberOfItems *\n this.#decompressedSizes[dataIndex];\n try {\n this.#finalBufferStore[dataIndex] =\n new decodedData.constructor(fullSize);\n } catch (error) {\n if (error instanceof RangeError) {\n const powerOf2 = Math.floor(Math.log(fullSize) / Math.log(2));\n logger.error('Cannot allocate ' +\n decodedData.constructor.name +\n ' of size: ' +\n fullSize + ' (>2^' + powerOf2 + ') for decompressed data.');\n }\n // abort\n this.#pixelDecoder.abort();\n // send events\n this.onerror({\n error: error,\n source: origin\n });\n this.onloadend({\n source: origin\n });\n // exit\n return;\n }\n }\n // hoping for all items to have the same size...\n if (decodedData.length !== this.#decompressedSizes[dataIndex]) {\n logger.warn('Unsupported varying decompressed data size: ' +\n decodedData.length + ' != ' + this.#decompressedSizes[dataIndex]);\n }\n // set buffer item data\n this.#finalBufferStore[dataIndex].set(\n decodedData, this.#decompressedSizes[dataIndex] * event.itemNumber);\n } else {\n this.#finalBufferStore[dataIndex] = decodedData;\n }\n\n // create image for the first item\n if (event.itemNumber === 0) {\n this.#generateData(dataIndex, origin);\n }\n }\n\n /**\n * Handle non image data.\n *\n * @param {number} index The data index.\n * @param {string} origin The data origin.\n */\n #handleNonImageData(index, origin) {\n this.#generateData(index, origin);\n // send load events\n this.onload({\n source: origin\n });\n this.onloadend({\n source: origin\n });\n }\n\n /**\n * Handle image data.\n *\n * @param {number} index The data index.\n * @param {string} origin The data origin.\n */\n #handleImageData(index, origin) {\n const dicomParser = this.#dicomParserStore[index];\n\n const pixelBuffer = dicomParser.getDicomElements()['7FE00010'].value;\n // help GC: discard pixel buffer from elements\n dicomParser.getDicomElements()['7FE00010'].value = [];\n this.#finalBufferStore[index] = pixelBuffer[0];\n\n // transfer syntax (always there)\n const syntax = dicomParser.getDicomElements()['00020010'].value[0];\n const algoName = getSyntaxDecompressionName(syntax);\n const needDecompression = typeof algoName !== 'undefined';\n\n if (needDecompression) {\n // generate image\n this.#generateImageCompressed(\n index,\n pixelBuffer,\n algoName);\n } else {\n this.#generateImageUncompressed(index, origin);\n }\n }\n\n /**\n * Get data from an input buffer using a DICOM parser.\n *\n * @param {ArrayBuffer} buffer The input data buffer.\n * @param {string} origin The data origin.\n * @param {number} dataIndex The data index.\n */\n convert(buffer, origin, dataIndex) {\n // start event\n this.onloadstart({\n source: origin,\n index: dataIndex\n });\n\n // DICOM parser\n const dicomParser = new DicomParser();\n\n if (typeof this.#options.defaultCharacterSet !== 'undefined') {\n dicomParser.setDefaultCharacterSet(this.#options.defaultCharacterSet);\n }\n // parse the buffer\n let factory;\n try {\n dicomParser.parse(buffer);\n // check elements\n factory = this.#getFactory(dicomParser.getDicomElements());\n if (typeof factory !== 'undefined') {\n factory.checkElements(dicomParser.getDicomElements());\n }\n } catch (error) {\n this.onerror({\n error: error,\n source: origin\n });\n this.onloadend({\n source: origin\n });\n return;\n }\n\n // store\n this.#dicomParserStore[dataIndex] = dicomParser;\n this.#factories[dataIndex] = factory;\n\n // handle parsed data\n if (factory instanceof AnnotationGroupFactory) {\n this.#handleNonImageData(dataIndex, origin);\n } else {\n this.#handleImageData(dataIndex, origin);\n }\n }\n\n /**\n * Abort a conversion.\n */\n abort() {\n // abort decoding, will trigger pixelDecoder.onabort\n if (this.#pixelDecoder) {\n this.#pixelDecoder.abort();\n }\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n /**\n * Handle a load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class DicomBufferToView\n","import {MultiProgressHandler} from '../utils/progress';\nimport {loaderList} from './loaderList';\n\n/**\n * Memory loader.\n */\nexport class MemoryLoader {\n\n /**\n * Input data.\n *\n * @type {Array}\n */\n #inputData = null;\n\n /**\n * Data loader.\n *\n * @type {object}\n */\n #runningLoader = null;\n\n /**\n * Number of loaded data.\n *\n * @type {number}\n */\n #nLoad = 0;\n\n /**\n * Number of load end events.\n *\n * @type {number}\n */\n #nLoadend = 0;\n\n /**\n * The default character set (optional).\n *\n * @type {string}\n */\n #defaultCharacterSet;\n\n /**\n * Get the default character set.\n *\n * @returns {string} The default character set.\n */\n getDefaultCharacterSet() {\n return this.#defaultCharacterSet;\n }\n\n /**\n * Set the default character set.\n *\n * @param {string} characterSet The character set.\n */\n setDefaultCharacterSet(characterSet) {\n this.#defaultCharacterSet = characterSet;\n }\n\n /**\n * Store the current input.\n *\n * @param {object} data The input data.\n */\n #storeInputData(data) {\n this.#inputData = data;\n // reset counters\n this.#nLoad = 0;\n this.#nLoadend = 0;\n // clear storage\n this.#clearStoredLoader();\n }\n\n /**\n * Store the launched loader.\n *\n * @param {object} loader The launched loader.\n */\n #storeLoader(loader) {\n this.#runningLoader = loader;\n }\n\n /**\n * Clear the stored loader.\n *\n */\n #clearStoredLoader() {\n this.#runningLoader = null;\n }\n\n /**\n * Increment the number of loaded data\n * and call onload if loaded all data.\n *\n * @param {object} _event The load data event.\n */\n #addLoad = (_event) => {\n this.#nLoad++;\n // call onload when all is loaded\n // (not using the input event since it is not the\n // general load)\n if (this.#nLoad === this.#inputData.length) {\n this.onload({\n source: this.#inputData\n });\n }\n };\n\n /**\n * Increment the counter of load end events\n * and run callbacks when all done, erroneus or not.\n *\n * @param {object} _event The load end event.\n */\n #addLoadend = (_event) => {\n this.#nLoadend++;\n // call onloadend when all is run\n // (not using the input event since it is not the\n // general load end)\n if (this.#nLoadend === this.#inputData.length) {\n this.onloadend({\n source: this.#inputData\n });\n }\n };\n\n /**\n * Load a list of buffers.\n *\n * @param {Array} data The list of buffers to load.\n */\n load(data) {\n // check input\n if (typeof data === 'undefined' || data.length === 0) {\n return;\n }\n this.#storeInputData(data);\n\n // send start event\n this.onloadstart({\n source: data\n });\n\n // create prgress handler\n const mproghandler = new MultiProgressHandler(this.onprogress);\n mproghandler.setNToLoad(data.length);\n mproghandler.setNumberOfDimensions(1);\n\n // create loaders\n const loaders = [];\n for (let m = 0; m < loaderList.length; ++m) {\n loaders.push(new loaderList[m]());\n }\n\n // find an appropriate loader\n let dataElement = data[0];\n let loader = null;\n let foundLoader = false;\n for (let l = 0; l < loaders.length; ++l) {\n loader = loaders[l];\n if (loader.canLoadMemory(dataElement)) {\n foundLoader = true;\n // load options\n loader.setOptions({\n numberOfFiles: data.length,\n defaultCharacterSet: this.getDefaultCharacterSet()\n });\n // set loader callbacks\n // loader.onloadstart: nothing to do\n loader.onprogress = mproghandler.getUndefinedMonoProgressHandler(0);\n loader.onloaditem = this.onloaditem;\n loader.onload = this.#addLoad;\n loader.onloadend = this.#addLoadend;\n loader.onerror = this.onerror;\n loader.onabort = this.onabort;\n\n // store loader\n this.#storeLoader(loader);\n // exit\n break;\n }\n }\n if (!foundLoader) {\n throw new Error('No loader found for data: ' + dataElement.filename);\n }\n\n // loop on I/O elements\n for (let i = 0; i < data.length; ++i) {\n dataElement = data[i];\n // check loader\n if (!loader.canLoadMemory(dataElement)) {\n throw new Error('Input data of different type: ' +\n dataElement.filename);\n }\n // read\n loader.load(dataElement.data, dataElement.filename, i);\n }\n }\n\n /**\n * Abort a load.\n */\n abort() {\n // abort loader\n if (this.#runningLoader && this.#runningLoader.isLoading()) {\n this.#runningLoader.abort();\n }\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle a load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class MemoryLoader\n","import {Size} from '../image/size';\nimport {Spacing} from '../image/spacing';\nimport {Geometry} from '../image/geometry';\nimport {Image} from '../image/image';\nimport {Point3D} from '../math/point';\n\n/**\n * Create a simple array buffer from an ImageData buffer.\n *\n * @param {object} imageData The ImageData taken from a context.\n * @returns {Uint8Array} The image buffer.\n */\nfunction imageDataToBuffer(imageData) {\n // remove alpha\n // TODO support passing the full image data\n const dataLen = imageData.data.length;\n const buffer = new Uint8Array((dataLen / 4) * 3);\n let j = 0;\n for (let i = 0; i < dataLen; i += 4) {\n buffer[j] = imageData.data[i];\n buffer[j + 1] = imageData.data[i + 1];\n buffer[j + 2] = imageData.data[i + 2];\n j += 3;\n }\n return buffer;\n}\n\n/**\n * Get an image from an input context imageData.\n *\n * @param {number} width The width of the coresponding image.\n * @param {number} height The height of the coresponding image.\n * @param {number} sliceIndex The slice index of the imageData.\n * @param {object} imageBuffer The image buffer.\n * @param {number} numberOfFrames The final number of frames.\n * @param {string} imageUid The image UID.\n * @returns {object} The corresponding view.\n */\nfunction getDefaultImage(\n width, height, sliceIndex,\n imageBuffer, numberOfFrames,\n imageUid) {\n // image size\n const imageSize = new Size([width, height, 1]);\n // default spacing\n // TODO: misleading...\n const imageSpacing = new Spacing([1, 1, 1]);\n // default origin\n const origin = new Point3D(0, 0, sliceIndex);\n // create image\n const geometry = new Geometry(origin, imageSize, imageSpacing);\n const image = new Image(geometry, imageBuffer, [imageUid]);\n image.setPhotometricInterpretation('RGB');\n // meta information\n const meta = {};\n meta.BitsStored = 8;\n if (typeof numberOfFrames !== 'undefined') {\n meta.numberOfFiles = numberOfFrames;\n }\n image.setMeta(meta);\n // return\n return image;\n}\n\n/**\n * Get data from an input image using a canvas.\n *\n * @param {HTMLImageElement} domImage The DOM Image,\n * an HTMLImageElement with extra info.\n * @param {string|File} origin The data origin.\n * @param {number} index The data index.\n * @returns {object} A load data event.\n */\nexport function getViewFromDOMImage(domImage, origin, index) {\n // image size\n const width = domImage.width;\n const height = domImage.height;\n\n // draw the image in the canvas in order to get its data\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n ctx.drawImage(domImage, 0, 0);\n // get the image data\n const imageData = ctx.getImageData(0, 0, width, height);\n\n // image properties\n const info = {};\n if (typeof origin === 'string') {\n info['origin'] = {value: origin};\n } else {\n info['fileName'] = {value: origin.name};\n info['fileType'] = {value: origin.type};\n info['fileLastModifiedDate'] = {value: origin.lastModified};\n }\n info['imageWidth'] = {value: width};\n info['imageHeight'] = {value: height};\n\n const sliceIndex = index ? index : 0;\n info['imageUid'] = {value: sliceIndex};\n\n // create view\n const imageBuffer = imageDataToBuffer(imageData);\n const image = getDefaultImage(\n width, height, sliceIndex, imageBuffer, 1, sliceIndex.toString());\n\n // return\n return {\n data: {\n image: image,\n info: info\n },\n source: origin\n };\n}\n\n/**\n * Get data from an input image using a canvas.\n *\n * @param {object} video The DOM Video, an HTMLVideoElement with extra info.\n * @param {Function} onloaditem On load callback.\n * @param {object} onload The function to call once the data is loaded.\n * @param {object} onprogress The function to call to report progress.\n * @param {object} onloadend The function to call to report load end.\n * @param {string|File} origin The data origin.\n * @param {number} dataIndex The data index.\n */\nexport function getViewFromDOMVideo(\n video, onloaditem, onload, onprogress, onloadend,\n origin, dataIndex) {\n // video size\n const width = video.videoWidth;\n const height = video.videoHeight;\n\n // default frame rate...\n const frameRate = 30;\n // number of frames\n const numberOfFrames = Math.ceil(video.duration * frameRate);\n\n // video properties\n const info = {};\n if (typeof origin === 'string') {\n info['origin'] = {value: origin};\n } else {\n info['fileName'] = {value: origin.name};\n info['fileType'] = {value: origin.type};\n info['fileLastModifiedDate'] = {value: origin.lastModified};\n }\n info['imageWidth'] = {value: width};\n info['imageHeight'] = {value: height};\n info['numberOfFrames'] = {value: numberOfFrames};\n info['imageUid'] = {value: 0};\n\n // draw the image in the canvas in order to get its data\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n\n // using seeked to loop through all video frames\n video.addEventListener('seeked', onseeked, false);\n\n // current frame index\n let frameIndex = 0;\n // video image\n let image = null;\n\n /**\n * Draw the context and store it as a frame.\n */\n function storeFrame() {\n // send progress\n onprogress({\n lengthComputable: true,\n loaded: frameIndex,\n total: numberOfFrames,\n index: dataIndex,\n source: origin\n });\n // draw image\n ctx.drawImage(video, 0, 0);\n // context to image buffer\n const imgBuffer = imageDataToBuffer(\n ctx.getImageData(0, 0, width, height));\n if (frameIndex === 0) {\n // create view\n image = getDefaultImage(\n width, height, 1, imgBuffer, numberOfFrames, dataIndex.toString());\n // call callback\n onloaditem({\n data: {\n image: image,\n info: info\n },\n source: origin\n });\n } else {\n image.appendFrameBuffer(imgBuffer, frameIndex);\n }\n // increment index\n ++frameIndex;\n }\n\n let nextTime = 0;\n\n /**\n * Handle seeked event.\n *\n * @param {object} event The seeked event.\n */\n function onseeked(event) {\n // store\n storeFrame();\n // set the next time\n // (not using currentTime, it seems to get offseted)\n nextTime += 1 / frameRate;\n if (nextTime <= event.target.duration) {\n this.currentTime = nextTime;\n } else {\n onload({\n source: origin\n });\n onloadend({\n source: origin\n });\n // stop listening\n video.removeEventListener('seeked', onseeked);\n }\n }\n\n // trigger the first seek\n video.currentTime = nextTime;\n}\n","import {DicomDataLoader} from './dicomDataLoader';\nimport {JSONTextLoader} from './jsonTextLoader';\nimport {MultipartLoader} from './multipartLoader';\nimport {RawImageLoader} from './rawImageLoader';\nimport {RawVideoLoader} from './rawVideoLoader';\nimport {ZipLoader} from './zipLoader';\n\nexport const loaderList = [\n DicomDataLoader,\n JSONTextLoader,\n MultipartLoader,\n RawImageLoader,\n RawVideoLoader,\n ZipLoader\n];\n","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\nimport {DicomBufferToView} from '../image/dicomBufferToView';\n\n/**\n * DICOM data loader.\n */\nexport class DicomDataLoader {\n\n /**\n * Loader options.\n *\n * @type {object}\n */\n #options = {};\n\n /**\n * Loading flag.\n *\n * @type {boolean}\n */\n #isLoading = false;\n\n /**\n * Set the loader options.\n *\n * @param {object} opt The input options.\n */\n setOptions(opt) {\n this.#options = opt;\n }\n\n /**\n * Is the load ongoing?\n *\n * @returns {boolean} True if loading.\n */\n isLoading() {\n return this.#isLoading;\n }\n\n /**\n * DICOM buffer to View (asynchronous).\n *\n */\n #db2v = new DicomBufferToView();\n\n /**\n * Load data.\n *\n * @param {object} buffer The DICOM buffer.\n * @param {string} origin The data origin.\n * @param {number} index The data index.\n */\n load(buffer, origin, index) {\n // setup db2v ony once\n if (!this.#isLoading) {\n // pass options\n this.#db2v.setOptions(this.#options);\n // connect handlers\n this.#db2v.onloadstart = this.onloadstart;\n this.#db2v.onprogress = this.onprogress;\n this.#db2v.onloaditem = this.onloaditem;\n this.#db2v.onload = this.onload;\n this.#db2v.onloadend = (event) => {\n // reset loading flag\n this.#isLoading = false;\n // call listeners\n this.onloadend(event);\n };\n this.#db2v.onerror = (event) => {\n event.source = origin;\n this.onerror(event);\n };\n this.#db2v.onabort = this.onabort;\n }\n\n // set loading flag\n this.#isLoading = true;\n // convert\n this.#db2v.convert(buffer, origin, index);\n }\n\n /**\n * Abort load.\n */\n abort() {\n // reset loading flag\n this.#isLoading = false;\n // abort conversion, will trigger db2v.onabort\n this.#db2v.abort();\n }\n\n /**\n * Check if the loader can load the provided file.\n * True if one of the folowing conditions is true:\n * - the file has a 'dcm' extension,\n * - the file has no extension.\n *\n * @param {File} file The file to check.\n * @returns {boolean} True if the file can be loaded.\n */\n canLoadFile(file) {\n const ext = getFileExtension(file.name);\n const hasNoExt = (ext === null);\n const hasDcmExt = (ext === 'dcm');\n return hasNoExt || hasDcmExt;\n }\n\n /**\n * Check if the loader can load the provided url.\n * True if one of the folowing conditions is true:\n * - the `options.forceLoader` is 'dicom',\n * - the `options.requestHeaders` contains a 'Accept: application/dicom',\n * - the url has a 'contentType' and it is 'application/dicom'\n * (as in wado urls),\n * - the url has no 'contentType' and no extension or the extension is 'dcm'.\n *\n * @param {string} url The url to check.\n * @param {object} [options] Optional url request options.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadUrl(url, options) {\n // check options\n if (typeof options !== 'undefined') {\n // check options.forceLoader\n if (typeof options.forceLoader !== 'undefined' &&\n options.forceLoader === 'dicom') {\n return true;\n }\n // check options.requestHeaders for 'Accept'\n if (typeof options.requestHeaders !== 'undefined') {\n const isNameAccept = function (element) {\n return element.name === 'Accept';\n };\n const acceptHeader = options.requestHeaders.find(isNameAccept);\n if (typeof acceptHeader !== 'undefined') {\n // starts with 'application/dicom' and no '+'\n const acceptValue = 'application/dicom';\n return startsWith(acceptHeader.value, acceptValue) &&\n acceptHeader.value[acceptValue.length] !== '+';\n }\n }\n }\n\n const urlObjext = getUrlFromUri(url);\n // extension\n const ext = getFileExtension(urlObjext.pathname);\n const hasNoExt = (ext === null);\n const hasDcmExt = (ext === 'dcm');\n // content type (for wado url)\n const contentType = urlObjext.searchParams.get('contentType');\n const hasContentType = contentType !== null &&\n typeof contentType !== 'undefined';\n const hasDicomContentType = (contentType === 'application/dicom');\n\n return hasContentType ? hasDicomContentType : (hasNoExt || hasDcmExt);\n }\n\n /**\n * Check if the loader can load the provided memory object.\n *\n * @param {object} mem The memory object.\n * @returns {boolean} True if the object can be loaded.\n */\n canLoadMemory(mem) {\n const contentType = mem['Content-Type'];\n if (typeof contentType !== 'undefined' &&\n contentType.startsWith('application/dicom')) {\n return true;\n }\n if (typeof mem.filename !== 'undefined') {\n const tmpFile = new File(['from memory'], mem.filename);\n return this.canLoadFile(tmpFile);\n }\n return false;\n }\n\n /**\n * Get the file content type needed by the loader.\n *\n * @returns {number} One of the 'fileContentTypes'.\n */\n loadFileAs() {\n return fileContentTypes.ArrayBuffer;\n }\n\n /**\n * Get the url content type needed by the loader.\n *\n * @returns {number} One of the 'urlContentTypes'.\n */\n loadUrlAs() {\n return urlContentTypes.ArrayBuffer;\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a progress event.\n * Default does nothing.\n *\n * @param {object} _event The load progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle an load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class DicomDataLoader\n","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\n\n/**\n * JSON text loader.\n */\nexport class JSONTextLoader {\n\n /**\n * Loading flag.\n *\n * @type {boolean}\n */\n #isLoading = false;\n\n /**\n * Set the loader options.\n *\n * @param {object} _opt The input options.\n */\n setOptions(_opt) {\n // does nothing\n }\n\n /**\n * Is the load ongoing?\n *\n * @returns {boolean} True if loading.\n */\n isLoading() {\n return this.#isLoading;\n }\n\n /**\n * Load data.\n *\n * @param {object} text The input text.\n * @param {string} origin The data origin.\n * @param {number} index The data index.\n */\n load(text, origin, index) {\n // set loading flag\n this.#isLoading = true;\n this.onloadstart({\n source: origin\n });\n\n try {\n this.onprogress({\n lengthComputable: true,\n loaded: 100,\n total: 100,\n index: index,\n source: origin\n });\n const data = {\n data: text,\n source: origin\n };\n // only expecting one item\n this.onloaditem(data);\n this.onload(data);\n } catch (error) {\n this.onerror({\n error: error,\n source: origin\n });\n } finally {\n // reset loading flag\n this.#isLoading = false;\n this.onloadend({\n source: origin\n });\n }\n }\n\n /**\n * Abort load: pass to listeners.\n */\n abort() {\n // reset loading flag\n this.#isLoading = false;\n // call listeners\n this.onabort({});\n this.onloadend({});\n }\n\n /**\n * Check if the loader can load the provided file.\n * True if the file has a 'json' extension.\n *\n * @param {File} file The file to check.\n * @returns {boolean} True if the file can be loaded.\n */\n canLoadFile(file) {\n const ext = getFileExtension(file.name);\n return (ext === 'json');\n }\n\n /**\n * Check if the loader can load the provided url.\n * True if one of the folowing conditions is true:\n * - the `options.forceLoader` is 'json',\n * - the `options.requestHeaders` contains a 'Accept: application/json' or\n * 'Accept: application/dicom+json',\n * - the url has a 'json' extension.\n *\n * @param {string} url The url to check.\n * @param {object} [options] Optional url request options.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadUrl(url, options) {\n // check options\n if (typeof options !== 'undefined') {\n // check options.forceLoader\n if (typeof options.forceLoader !== 'undefined' &&\n options.forceLoader === 'json') {\n return true;\n }\n // check options.requestHeaders for 'Accept'\n if (typeof options.requestHeaders !== 'undefined') {\n const isNameAccept = function (element) {\n return element.name === 'Accept';\n };\n const acceptHeader = options.requestHeaders.find(isNameAccept);\n if (typeof acceptHeader !== 'undefined') {\n // starts with 'application/json' or 'application/dicom+json\n return startsWith(acceptHeader.value, 'application/json') ||\n startsWith(acceptHeader.value, 'application/dicom+json');\n }\n }\n }\n\n const urlObjext = getUrlFromUri(url);\n const ext = getFileExtension(urlObjext.pathname);\n return (ext === 'json');\n }\n\n /**\n * Check if the loader can load the provided memory object.\n *\n * @param {object} mem The memory object.\n * @returns {boolean} True if the object can be loaded.\n */\n canLoadMemory(mem) {\n const contentType = mem['Content-Type'];\n if (typeof contentType !== 'undefined' &&\n contentType.startsWith('application/json')) {\n return true;\n }\n if (typeof mem.filename !== 'undefined') {\n const tmpFile = new File(['from memory'], mem.filename);\n return this.canLoadFile(tmpFile);\n }\n return false;\n }\n\n /**\n * Get the file content type needed by the loader.\n *\n * @returns {number} One of the 'fileContentTypes'.\n */\n loadFileAs() {\n return fileContentTypes.Text;\n }\n\n /**\n * Get the url content type needed by the loader.\n *\n * @returns {number} One of the 'urlContentTypes'.\n */\n loadUrlAs() {\n return urlContentTypes.Text;\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a progress event.\n * Default does nothing.\n *\n * @param {object} _event The load progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle an load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class JSONTextLoader\n","import {startsWith} from '../utils/string';\nimport {parseMultipart} from '../utils/array';\nimport {MemoryLoader} from './memoryLoader';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\n\n/**\n * Multipart data loader.\n */\nexport class MultipartLoader {\n\n /**\n * Loading flag.\n *\n * @type {boolean}\n */\n #isLoading = false;\n\n /**\n * Set the loader options.\n *\n * @param {object} _opt The input options.\n */\n setOptions(_opt) {\n // does nothing\n }\n\n /**\n * Is the load ongoing?\n *\n * @returns {boolean} True if loading.\n */\n isLoading() {\n return this.#isLoading;\n }\n\n /**\n * Load data.\n *\n * @param {object} buffer The DICOM buffer.\n * @param {string} origin The data origin.\n * @param {number} index The data index.\n */\n load(buffer, origin, index) {\n // send start event\n this.onloadstart({\n source: origin\n });\n // set loading flag\n this.#isLoading = true;\n\n const memoryIO = new MemoryLoader();\n // memoryIO.onloadstart: nothing to do\n memoryIO.onprogress = (progress) => {\n // add 50% to take into account the un-Multipartping\n progress.loaded = 50 + progress.loaded / 2;\n // set data index\n progress.index = index;\n this.onprogress(progress);\n };\n memoryIO.onloaditem = this.onloaditem;\n memoryIO.onload = this.onload;\n memoryIO.onloadend = (event) => {\n // reset loading flag\n this.#isLoading = false;\n // call listeners\n this.onloadend(event);\n };\n memoryIO.onerror = this.onerror;\n memoryIO.onabort = this.onabort;\n // launch\n memoryIO.load(parseMultipart(buffer));\n }\n\n /**\n * Abort load: pass to listeners.\n */\n abort() {\n // reset loading flag\n this.#isLoading = false;\n // call listeners\n this.onabort({});\n this.onloadend({});\n }\n\n /**\n * Check if the loader can load the provided file.\n * Always returns false.\n *\n * @param {File} _file The file to check.\n * @returns {boolean} True if the file can be loaded.\n */\n canLoadFile(_file) {\n return false;\n }\n\n /**\n * Check if the loader can load the provided url.\n * True if one of the folowing conditions is true:\n * - the `options.forceLoader` is 'multipart',\n * - the `options.requestHeaders` contains a 'Accept: multipart/related'.\n *\n * @param {string} url The url to check.\n * @param {object} [options] Optional url request options.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadUrl(url, options) {\n // check options\n if (typeof options !== 'undefined') {\n // check options.forceLoader\n if (typeof options.forceLoader !== 'undefined' &&\n options.forceLoader === 'multipart') {\n return true;\n }\n // check options.requestHeaders for 'Accept'\n if (typeof options.requestHeaders !== 'undefined') {\n const isNameAccept = function (element) {\n return element.name === 'Accept';\n };\n const acceptHeader = options.requestHeaders.find(isNameAccept);\n if (typeof acceptHeader !== 'undefined') {\n // starts with 'multipart/related'\n return startsWith(acceptHeader.value, 'multipart/related');\n }\n }\n }\n\n return false;\n }\n\n /**\n * Check if the loader can load the provided memory object.\n *\n * @param {object} _mem The memory object.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadMemory(_mem) {\n return false;\n }\n\n /**\n * Get the file content type needed by the loader.\n *\n * @returns {number} One of the 'fileContentTypes'.\n */\n loadFileAs() {\n return fileContentTypes.ArrayBuffer;\n }\n\n /**\n * Get the url content type needed by the loader.\n *\n * @returns {number} One of the 'urlContentTypes'.\n */\n loadUrlAs() {\n return urlContentTypes.ArrayBuffer;\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle an load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class MultipartLoader\n","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {getViewFromDOMImage} from '../image/domReader';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\n\n/**\n * Raw image loader.\n */\nexport class RawImageLoader {\n\n /**\n * If abort is triggered, all image.onload callbacks have to be cancelled.\n *\n * @type {boolean}\n */\n #aborted = false;\n\n /**\n * Set the loader options.\n *\n * @param {object} _opt The input options.\n */\n setOptions(_opt) {\n // does nothing\n }\n\n /**\n * Is the load ongoing? TODO...\n *\n * @returns {boolean} True if loading.\n */\n isLoading() {\n return true;\n }\n\n /**\n * Create a Data URI from an HTTP request response.\n *\n * @param {ArrayBuffer} response The HTTP request response.\n * @param {string} dataType The data type.\n * @returns {string} The data URI.\n */\n #createDataUri(response, dataType) {\n // image type\n let imageType = dataType;\n if (!imageType || imageType === 'jpg') {\n imageType = 'jpeg';\n }\n // create uri\n const file = new Blob([response], {type: 'image/' + imageType});\n return window.URL.createObjectURL(file);\n }\n\n /**\n * Load data.\n *\n * @param {ArrayBuffer|string} buffer The read data.\n * @param {string|File} origin The data origin.\n * @param {number} index The data index.\n */\n load(buffer, origin, index) {\n this.#aborted = false;\n // create a DOM image\n const image = new Image();\n // triggered by ctx.drawImage\n image.onload = (/*event*/) => {\n try {\n if (!this.#aborted) {\n this.onprogress({\n lengthComputable: true,\n loaded: 100,\n total: 100,\n index: index,\n source: origin\n });\n const data = getViewFromDOMImage(image, origin, index);\n // only expecting one item\n this.onloaditem(data);\n this.onload(data);\n }\n } catch (error) {\n this.onerror({\n error: error,\n source: origin\n });\n } finally {\n this.onloadend({\n source: origin\n });\n }\n };\n // storing values to pass them on\n if (typeof buffer === 'string') {\n // file case\n image.src = buffer;\n } else if (typeof origin === 'string') {\n // url case\n const ext = origin.split('.').pop().toLowerCase();\n image.src = this.#createDataUri(buffer, ext);\n }\n }\n\n /**\n * Abort load.\n */\n abort() {\n this.#aborted = true;\n this.onabort({});\n this.onloadend({});\n }\n\n /**\n * Check if the loader can load the provided file.\n * True for files with type 'image.*'.\n *\n * @param {File} file The file to check.\n * @returns {boolean} True if the file can be loaded.\n */\n canLoadFile(file) {\n return (typeof file.type !== 'undefined' &&\n file.type.match('image.*') !== null);\n }\n\n /**\n * Check if the loader can load the provided url.\n * True if one of the folowing conditions is true:\n * - the `options.forceLoader` is 'rawimage',\n * - the `options.requestHeaders` contains an item\n * starting with 'Accept: image/'.\n * - the url has a 'contentType' and it is 'image/jpeg', 'image/png'\n * or 'image/gif' (as in wado urls),\n * - the url has no 'contentType' and the extension is 'jpeg', 'jpg',\n * 'png' or 'gif'.\n *\n * @param {string} url The url to check.\n * @param {object} [options] Optional url request options.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadUrl(url, options) {\n // check options\n if (typeof options !== 'undefined') {\n // check options.forceLoader\n if (typeof options.forceLoader !== 'undefined' &&\n options.forceLoader === 'rawimage') {\n return true;\n }\n // check options.requestHeaders for 'Accept'\n if (typeof options.requestHeaders !== 'undefined') {\n const isNameAccept = function (element) {\n return element.name === 'Accept';\n };\n const acceptHeader = options.requestHeaders.find(isNameAccept);\n if (typeof acceptHeader !== 'undefined') {\n // starts with 'image/'\n return startsWith(acceptHeader.value, 'image/');\n }\n }\n }\n\n const urlObjext = getUrlFromUri(url);\n // extension\n const ext = getFileExtension(urlObjext.pathname);\n const hasImageExt = (ext === 'jpeg') || (ext === 'jpg') ||\n (ext === 'png') || (ext === 'gif');\n // content type (for wado url)\n const contentType = urlObjext.searchParams.get('contentType');\n const hasContentType = contentType !== null &&\n typeof contentType !== 'undefined';\n const hasImageContentType = (contentType === 'image/jpeg') ||\n (contentType === 'image/png') ||\n (contentType === 'image/gif');\n\n return hasContentType ? hasImageContentType : hasImageExt;\n }\n\n /**\n * Check if the loader can load the provided memory object.\n *\n * @param {object} mem The memory object.\n * @returns {boolean} True if the object can be loaded.\n */\n canLoadMemory(mem) {\n if (typeof mem.filename !== 'undefined') {\n const tmpFile = new File(['from memory'], mem.filename);\n return this.canLoadFile(tmpFile);\n }\n return false;\n }\n\n /**\n * Get the file content type needed by the loader.\n *\n * @returns {number} One of the 'fileContentTypes'.\n */\n loadFileAs() {\n return fileContentTypes.DataURL;\n }\n\n /**\n * Get the url content type needed by the loader.\n *\n * @returns {number} One of the 'urlContentTypes'.\n */\n loadUrlAs() {\n return urlContentTypes.ArrayBuffer;\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle an load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class RawImageLoader","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {getViewFromDOMVideo} from '../image/domReader';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\n\n/**\n * Raw video loader.\n *\n * Url example (cors enabled):\n * {@link https://raw.githubusercontent.com/clappr/clappr/master/test/fixtures/SampleVideo_360x240_1mb.mp4}.\n */\nexport class RawVideoLoader {\n\n /**\n * Set the loader options.\n *\n * @param {object} _opt The input options.\n */\n setOptions(_opt) {\n // does nothing\n }\n\n /**\n * Is the load ongoing? TODO...\n *\n * @returns {boolean} True if loading.\n */\n isLoading() {\n return true;\n }\n\n /**\n * Create a Data URI from an HTTP request response.\n *\n * @param {object} response The HTTP request response.\n * @param {string} dataType The data type.\n * @returns {string} The data URI.\n */\n #createDataUri(response, dataType) {\n // image data as string\n const bytes = new Uint8Array(response);\n let videoDataStr = '';\n for (let i = 0; i < bytes.byteLength; ++i) {\n videoDataStr += String.fromCharCode(bytes[i]);\n }\n // create uri\n const uri = 'data:video/' + dataType +\n ';base64,' + window.btoa(videoDataStr);\n return uri;\n }\n\n /**\n * Internal Data URI load.\n *\n * @param {object} buffer The read data.\n * @param {string} origin The data origin.\n * @param {number} index The data index.\n */\n load(buffer, origin, index) {\n // create a DOM video\n const video = document.createElement('video');\n if (typeof origin === 'string') {\n // url case\n const ext = origin.split('.').pop().toLowerCase();\n video.src = this.#createDataUri(buffer, ext);\n } else {\n video.src = buffer;\n }\n // onload handler\n video.onloadedmetadata = (event) => {\n try {\n getViewFromDOMVideo(event.target,\n this.onloaditem, this.onload,\n this.onprogress, this.onloadend,\n origin, index);\n } catch (error) {\n this.onerror({\n error: error,\n source: origin\n });\n this.onloadend({\n source: origin\n });\n }\n };\n }\n\n /**\n * Abort load.\n */\n abort() {\n this.onabort({});\n this.onloadend({});\n }\n\n /**\n * Check if the loader can load the provided file.\n * True for files with type 'video.*'.\n *\n * @param {File} file The file to check.\n * @returns {boolean} True if the file can be loaded.\n */\n canLoadFile(file) {\n return (typeof file.type !== 'undefined' &&\n file.type.match('video.*') !== null);\n }\n\n /**\n * Check if the loader can load the provided url.\n * True if one of the folowing conditions is true:\n * - the `options.forceLoader` is 'rawvideo',\n * - the `options.requestHeaders` contains an item\n * starting with 'Accept: video/'.\n * - the url has a 'mp4', 'ogg' or 'webm' extension.\n *\n * @param {string} url The url to check.\n * @param {object} [options] Optional url request options.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadUrl(url, options) {\n // check options\n if (typeof options !== 'undefined') {\n // check options.forceLoader\n if (typeof options.forceLoader !== 'undefined' &&\n options.forceLoader === 'rawvideo') {\n return true;\n }\n // check options.requestHeaders for 'Accept'\n if (typeof options.requestHeaders !== 'undefined') {\n const isNameAccept = function (element) {\n return element.name === 'Accept';\n };\n const acceptHeader = options.requestHeaders.find(isNameAccept);\n if (typeof acceptHeader !== 'undefined') {\n // starts with 'video/'\n return startsWith(acceptHeader.value, 'video/');\n }\n }\n }\n\n const urlObjext = getUrlFromUri(url);\n const ext = getFileExtension(urlObjext.pathname);\n return (ext === 'mp4') ||\n (ext === 'ogg') ||\n (ext === 'webm');\n }\n\n /**\n * Check if the loader can load the provided memory object.\n *\n * @param {object} mem The memory object.\n * @returns {boolean} True if the object can be loaded.\n */\n canLoadMemory(mem) {\n if (typeof mem.filename !== 'undefined') {\n const tmpFile = new File(['from memory'], mem.filename);\n return this.canLoadFile(tmpFile);\n }\n return false;\n }\n\n /**\n * Get the file content type needed by the loader.\n *\n * @returns {number} One of the 'fileContentTypes'.\n */\n loadFileAs() {\n return fileContentTypes.DataURL;\n }\n\n /**\n * Get the url content type needed by the loader.\n *\n * @returns {number} One of the 'urlContentTypes'.\n */\n loadUrlAs() {\n return urlContentTypes.ArrayBuffer;\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle an load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class RawVideoLoader\n","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\nimport {MemoryLoader} from './memoryLoader';\n\n/**\n * The zip library.\n *\n * Ref: {@link https://github.com/Stuk/jszip}.\n *\n * @external JSZip\n */\nimport JSZip from 'jszip';\n\n/**\n * ZIP data loader.\n */\nexport class ZipLoader {\n\n /**\n * Loading flag.\n *\n * @type {boolean}\n */\n #isLoading = false;\n\n /**\n * Set the loader options.\n *\n * @param {object} _opt The input options.\n */\n setOptions(_opt) {\n // does nothing\n }\n\n /**\n * Is the load ongoing?\n *\n * @returns {boolean} True if loading.\n */\n isLoading() {\n return this.#isLoading;\n }\n\n #filename = '';\n #files = [];\n #zobjs = null;\n\n /**\n * JSZip.async callback.\n *\n * @param {ArrayBuffer} content Unzipped file image.\n * @param {object} origin The origin of the file.\n * @param {number} index The data index.\n */\n #zipAsyncCallback(content, origin, index) {\n this.#files.push({filename: this.#filename, data: content});\n\n // sent un-ziped progress with the data index\n // (max 50% to take into account the memory loading)\n const unzipPercent = this.#files.length * 100 / this.#zobjs.length;\n this.onprogress({\n lengthComputable: true,\n loaded: (unzipPercent / 2),\n total: 100,\n index: index,\n item: {\n loaded: unzipPercent,\n total: 100,\n source: origin\n }\n });\n\n // recursively call until we have all the files\n if (this.#files.length < this.#zobjs.length) {\n const num = this.#files.length;\n this.#filename = this.#zobjs[num].name;\n this.#zobjs[num].async('arrayBuffer').then((content) => {\n this.#zipAsyncCallback(content, origin, index);\n });\n } else {\n const memoryIO = new MemoryLoader();\n // memoryIO.onloadstart: nothing to do\n memoryIO.onprogress = (progress) => {\n // add 50% to take into account the un-zipping\n progress.loaded = 50 + progress.loaded / 2;\n // set data index\n progress.index = index;\n this.onprogress(progress);\n };\n memoryIO.onloaditem = this.onloaditem;\n memoryIO.onload = this.onload;\n memoryIO.onloadend = (event) => {\n // reset loading flag\n this.#isLoading = false;\n // call listeners\n this.onloadend(event);\n };\n memoryIO.onerror = this.onerror;\n memoryIO.onabort = this.onabort;\n // launch\n memoryIO.load(this.#files);\n }\n }\n\n /**\n * Load data.\n *\n * @param {object} buffer The DICOM buffer.\n * @param {string} origin The data origin.\n * @param {number} index The data index.\n */\n load(buffer, origin, index) {\n // send start event\n this.onloadstart({\n source: origin\n });\n // set loading flag\n this.#isLoading = true;\n\n JSZip.loadAsync(buffer).then((zip) => {\n this.#files = [];\n this.#zobjs = zip.file(/.*\\.dcm/);\n // recursively load zip files into the files array\n const num = this.#files.length;\n this.#filename = this.#zobjs[num].name;\n this.#zobjs[num].async('arrayBuffer').then((content) => {\n this.#zipAsyncCallback(content, origin, index);\n });\n });\n }\n\n /**\n * Abort load: pass to listeners.\n */\n abort() {\n // reset loading flag\n this.#isLoading = false;\n // call listeners\n this.onabort({});\n this.onloadend({});\n }\n\n /**\n * Check if the loader can load the provided file.\n * True if the file has a 'zip' extension.\n *\n * @param {File} file The file to check.\n * @returns {boolean} True if the file can be loaded.\n */\n canLoadFile(file) {\n const ext = getFileExtension(file.name);\n return (ext === 'zip');\n }\n\n /**\n * Check if the loader can load the provided url.\n * True if one of the folowing conditions is true:\n * - the `options.forceLoader` is 'zip',\n * - the `options.requestHeaders` contains an item\n * starting with 'Accept: application/zip'.\n * - the url has a 'zip' extension.\n *\n * @param {string} url The url to check.\n * @param {object} [options] Optional url request options.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadUrl(url, options) {\n // check options\n if (typeof options !== 'undefined') {\n // check options.forceLoader\n if (typeof options.forceLoader !== 'undefined' &&\n options.forceLoader === 'zip') {\n return true;\n }\n // check options.requestHeaders for 'Accept'\n if (typeof options.requestHeaders !== 'undefined') {\n const isNameAccept = function (element) {\n return element.name === 'Accept';\n };\n const acceptHeader = options.requestHeaders.find(isNameAccept);\n if (typeof acceptHeader !== 'undefined') {\n // starts with 'application/zip'\n return startsWith(acceptHeader.value, 'application/zip');\n }\n }\n }\n\n const urlObjext = getUrlFromUri(url);\n const ext = getFileExtension(urlObjext.pathname);\n return (ext === 'zip');\n }\n\n /**\n * Check if the loader can load the provided memory object.\n *\n * @param {object} mem The memory object.\n * @returns {boolean} True if the object can be loaded.\n */\n canLoadMemory(mem) {\n const contentType = mem['Content-Type'];\n if (typeof contentType !== 'undefined' &&\n contentType.startsWith('application/zip')) {\n return true;\n }\n if (typeof mem.filename !== 'undefined') {\n const tmpFile = new File(['from memory'], mem.filename);\n return this.canLoadFile(tmpFile);\n }\n return false;\n }\n\n /**\n * Get the file content type needed by the loader.\n *\n * @returns {number} One of the 'fileContentTypes'.\n */\n loadFileAs() {\n return fileContentTypes.ArrayBuffer;\n }\n\n /**\n * Get the url content type needed by the loader.\n *\n * @returns {number} One of the 'urlContentTypes'.\n */\n loadUrlAs() {\n return urlContentTypes.ArrayBuffer;\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle an load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class ZipLoader\n","import {MultiProgressHandler} from '../utils/progress';\nimport {loaderList} from './loaderList';\n\n// file content types\nexport const fileContentTypes = {\n Text: 0,\n ArrayBuffer: 1,\n DataURL: 2\n};\n\n/**\n * Files loader.\n */\nexport class FilesLoader {\n\n /**\n * Input data.\n *\n * @type {File[]}\n */\n #inputData = null;\n\n /**\n * Array of launched file readers.\n *\n * @type {FileReader[]}\n */\n #readers = [];\n\n /**\n * Data loader.\n *\n * @type {object}\n */\n #runningLoader = null;\n\n /**\n * Number of loaded data.\n *\n * @type {number}\n */\n #nLoad = 0;\n\n /**\n * Number of load end events.\n *\n * @type {number}\n */\n #nLoadend = 0;\n\n /**\n * The default character set (optional).\n *\n * @type {string}\n */\n #defaultCharacterSet;\n\n /**\n * Get the default character set.\n *\n * @returns {string} The default character set.\n */\n getDefaultCharacterSet() {\n return this.#defaultCharacterSet;\n }\n\n /**\n * Set the default character set.\n *\n * @param {string} characterSet The character set.\n */\n setDefaultCharacterSet(characterSet) {\n this.#defaultCharacterSet = characterSet;\n }\n\n /**\n * Store the current input.\n *\n * @param {File[]} data The input data.\n */\n #storeInputData(data) {\n this.#inputData = data;\n // reset counters\n this.#nLoad = 0;\n this.#nLoadend = 0;\n // clear storage\n this.#clearStoredReaders();\n this.#clearStoredLoader();\n }\n\n /**\n * Store a launched reader.\n *\n * @param {FileReader} reader The launched reader.\n */\n #storeReader(reader) {\n this.#readers.push(reader);\n }\n\n /**\n * Clear the stored readers.\n *\n */\n #clearStoredReaders() {\n this.#readers = [];\n }\n\n /**\n * Store the launched loader.\n *\n * @param {object} loader The launched loader.\n */\n #storeLoader(loader) {\n this.#runningLoader = loader;\n }\n\n /**\n * Clear the stored loader.\n *\n */\n #clearStoredLoader() {\n this.#runningLoader = null;\n }\n\n /**\n * Increment the number of loaded data\n * and call onload if loaded all data.\n *\n * @param {object} _event The load data event.\n */\n #addLoad = (_event) => {\n this.#nLoad++;\n // call onload when all is loaded\n // (not using the input event since it is\n // an individual load)\n if (this.#nLoad === this.#inputData.length) {\n this.onload({\n source: this.#inputData\n });\n }\n };\n\n /**\n * Increment the counter of load end events\n * and run callbacks when all done, erroneus or not.\n *\n * @param {object} _event The load end event.\n */\n #addLoadend = (_event) => {\n this.#nLoadend++;\n // call onloadend when all is run\n // (not using the input event since it is\n // an individual load end)\n if (this.#nLoadend === this.#inputData.length) {\n this.onloadend({\n source: this.#inputData\n });\n }\n };\n\n /**\n * @callback eventFn\n * @param {object} event The event.\n */\n\n /**\n * Augment a callback event with a srouce.\n *\n * @param {object} callback The callback to augment its event.\n * @param {object} source The source to add to the event.\n * @returns {eventFn} The augmented callback.\n */\n #augmentCallbackEvent(callback, source) {\n return (event) => {\n event.source = source;\n callback(event);\n };\n }\n\n /**\n * Get a load handler for a data element.\n *\n * @param {object} loader The associated loader.\n * @param {File} dataElement The data element.\n * @param {number} i The index of the element.\n * @returns {eventFn} A load handler.\n */\n #getLoadHandler(loader, dataElement, i) {\n return (event) => {\n loader.load(event.target.result, dataElement, i);\n };\n }\n\n\n /**\n * Load a list of files.\n *\n * @param {File[]} data The list of files to load.\n */\n load(data) {\n // check input\n if (typeof data === 'undefined' || data.length === 0) {\n return;\n }\n this.#storeInputData(data);\n\n // send start event\n this.onloadstart({\n source: data\n });\n\n // create prgress handler\n const mproghandler = new MultiProgressHandler(this.onprogress);\n mproghandler.setNToLoad(data.length);\n\n // create loaders\n const loaders = [];\n for (let m = 0; m < loaderList.length; ++m) {\n loaders.push(new loaderList[m]());\n }\n\n // find an appropriate loader\n let dataElement = data[0];\n let loader = null;\n let foundLoader = false;\n for (let l = 0; l < loaders.length; ++l) {\n loader = loaders[l];\n if (loader.canLoadFile(dataElement)) {\n foundLoader = true;\n // load options\n loader.setOptions({\n numberOfFiles: data.length,\n defaultCharacterSet: this.getDefaultCharacterSet()\n });\n // set loader callbacks\n // loader.onloadstart: nothing to do\n loader.onprogress = mproghandler.getUndefinedMonoProgressHandler(1);\n loader.onloaditem = this.onloaditem;\n loader.onload = this.#addLoad;\n loader.onloadend = this.#addLoadend;\n loader.onerror = this.onerror;\n loader.onabort = this.onabort;\n\n // store loader\n this.#storeLoader(loader);\n // exit\n break;\n }\n }\n if (!foundLoader) {\n throw new Error('No loader found for file: ' + dataElement.name);\n }\n\n // loop on I/O elements\n for (let i = 0; i < data.length; ++i) {\n dataElement = data[i];\n\n // check loader\n if (!loader.canLoadFile(dataElement)) {\n throw new Error('Input file of different type: ' + dataElement);\n }\n\n /**\n * The file reader.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader}.\n *\n * @external FileReader\n */\n const reader = new FileReader();\n // store reader\n this.#storeReader(reader);\n\n // set reader callbacks\n // reader.onloadstart: nothing to do\n reader.onprogress = this.#augmentCallbackEvent(\n mproghandler.getMonoProgressHandler(i, 0), dataElement);\n reader.onload = this.#getLoadHandler(loader, dataElement, i);\n // reader.onloadend: nothing to do\n const errorCallback =\n this.#augmentCallbackEvent(this.onerror, dataElement);\n reader.onerror = (event) => {\n this.#addLoadend();\n errorCallback(event);\n };\n const abortCallback =\n this.#augmentCallbackEvent(this.onabort, dataElement);\n reader.onabort = (event) => {\n this.#addLoadend();\n abortCallback(event);\n };\n // read\n if (loader.loadFileAs() === fileContentTypes.Text) {\n reader.readAsText(dataElement);\n } else if (loader.loadFileAs() === fileContentTypes.DataURL) {\n reader.readAsDataURL(dataElement);\n } else if (loader.loadFileAs() === fileContentTypes.ArrayBuffer) {\n reader.readAsArrayBuffer(dataElement);\n }\n }\n }\n\n /**\n * Abort a load.\n */\n abort() {\n // abort readers\n for (let i = 0; i < this.#readers.length; ++i) {\n // 0: EMPTY, 1: LOADING, 2: DONE\n if (this.#readers[i].readyState === 1) {\n this.#readers[i].abort();\n }\n }\n // abort loader\n if (this.#runningLoader && this.#runningLoader.isLoading()) {\n this.#runningLoader.abort();\n }\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle a load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class FilesLoader\n","import {FilesLoader} from '../io/filesLoader';\nimport {MemoryLoader} from '../io/memoryLoader';\nimport {UrlsLoader} from '../io/urlsLoader';\n\n/**\n * Load controller.\n */\nexport class LoadController {\n\n /**\n * The default character set.\n *\n * @type {string}\n */\n #defaultCharacterSet;\n\n /**\n * List of current loaders.\n *\n * @type {object}\n */\n #currentLoaders = {};\n\n /**\n * @param {string} defaultCharacterSet The default character set.\n */\n constructor(defaultCharacterSet) {\n this.#defaultCharacterSet = defaultCharacterSet;\n }\n\n /**\n * Load a list of files. Can be image files or a state file.\n *\n * @param {File[]} files The list of files to load.\n * @param {string} dataId The data Id.\n */\n loadFiles(files, dataId) {\n // has been checked for emptiness.\n const ext = files[0].name.split('.').pop().toLowerCase();\n if (ext === 'json') {\n this.#loadStateFile(files[0], dataId);\n } else {\n this.#loadImageFiles(files, dataId);\n }\n }\n\n /**\n * Load a list of URLs. Can be image files or a state file.\n *\n * @param {string[]} urls The list of urls to load.\n * @param {string} dataId The data Id.\n * @param {object} [options] The load options:\n * - requestHeaders: an array of {name, value} to use as request headers.\n * - withCredentials: credentials flag to pass to the request.\n */\n\n loadURLs(urls, dataId, options) {\n // has been checked for emptiness.\n const ext = urls[0].split('.').pop().toLowerCase();\n if (ext === 'json') {\n this.#loadStateUrl(urls[0], dataId, options);\n } else {\n this.#loadImageUrls(urls, dataId, options);\n }\n }\n\n /**\n * Load a list of ArrayBuffers.\n *\n * @param {Array} data The list of ArrayBuffers to load\n * in the form of [{name: '', filename: '', data: data}].\n * @param {string} dataId The data Id.\n */\n loadImageObject(data, dataId) {\n // create IO\n const memoryIO = new MemoryLoader();\n // load data\n this.#loadData(data, memoryIO, 'image', dataId);\n }\n\n /**\n * Get the currently loaded data ids.\n *\n * @returns {string[]} The data ids.\n */\n getLoadingDataIds() {\n return Object.keys(this.#currentLoaders);\n }\n\n /**\n * Abort an individual current loader.\n *\n * @param {string} dataId The data to stop loading.\n */\n abort(dataId) {\n if (typeof this.#currentLoaders[dataId] !== 'undefined') {\n this.#currentLoaders[dataId].loader.abort();\n delete this.#currentLoaders[dataId];\n }\n }\n\n // private ----------------------------------------------------------------\n\n /**\n * Load a list of image files.\n *\n * @param {File[]} files The list of image files to load.\n * @param {string} dataId The data Id.\n */\n #loadImageFiles(files, dataId) {\n // create IO\n const fileIO = new FilesLoader();\n fileIO.setDefaultCharacterSet(this.#defaultCharacterSet);\n // load data\n this.#loadData(files, fileIO, 'image', dataId);\n }\n\n /**\n * Load a list of image URLs.\n *\n * @param {string[]} urls The list of urls to load.\n * @param {string} [dataId] The data Id.\n * @param {object} [options] The load options:\n * - requestHeaders: an array of {name, value} to use as request headers.\n * - withCredentials: credentials flag to pass to the request.\n */\n #loadImageUrls(urls, dataId, options) {\n // create IO\n const urlIO = new UrlsLoader();\n urlIO.setDefaultCharacterSet(this.#defaultCharacterSet);\n // load data\n this.#loadData(urls, urlIO, 'image', dataId, options);\n }\n\n /**\n * Load a State file.\n *\n * @param {File} file The state file to load.\n * @param {string} dataId The data Id.\n */\n #loadStateFile(file, dataId) {\n // create IO\n const fileIO = new FilesLoader();\n // load data\n this.#loadData([file], fileIO, 'state', dataId);\n }\n\n\n /**\n * Load a State url.\n *\n * @param {string} url The state url to load.\n * @param {string} [dataId] The data Id.\n * @param {object} [options] The load options:\n * - requestHeaders: an array of {name, value} to use as request headers.\n * - withCredentials: credentials flag to pass to the request.\n */\n #loadStateUrl(url, dataId, options) {\n // create IO\n const urlIO = new UrlsLoader();\n // load data\n this.#loadData([url], urlIO, 'state', dataId, options);\n }\n\n /**\n * Load a list of data.\n *\n * @param {string[]|File[]|Array} data Array of data to load.\n * @param {object} loader The data loader.\n * @param {string} loadType The data load type: 'image' or 'state'.\n * @param {string} dataId The data id.\n * @param {object} [options] Options passed to the final loader.\n */\n #loadData(data, loader, loadType, dataId, options) {\n const eventInfo = {\n loadtype: loadType,\n dataid: dataId\n };\n\n // set callbacks\n loader.onloadstart = (event) => {\n // store loader to allow abort\n this.#currentLoaders[dataId] = {\n loader: loader,\n isFirstItem: true\n };\n // callback\n this.#augmentCallbackEvent(this.onloadstart, eventInfo)(event);\n };\n loader.onprogress = this.#augmentCallbackEvent(this.onprogress, eventInfo);\n loader.onloaditem = (event) => {\n const eventInfoItem = {\n loadtype: loadType,\n dataid: dataId\n };\n if (typeof this.#currentLoaders[dataId] !== 'undefined') {\n eventInfoItem.isfirstitem = this.#currentLoaders[dataId].isFirstItem;\n }\n // callback\n this.#augmentCallbackEvent(this.onloaditem, eventInfoItem)(event);\n // update loader\n if (typeof this.#currentLoaders[dataId] !== 'undefined' &&\n this.#currentLoaders[dataId].isFirstItem) {\n this.#currentLoaders[dataId].isFirstItem = false;\n }\n };\n loader.onload = this.#augmentCallbackEvent(this.onload, eventInfo);\n loader.onloadend = (event) => {\n // reset current loader\n delete this.#currentLoaders[dataId];\n // callback\n this.#augmentCallbackEvent(this.onloadend, eventInfo)(event);\n };\n loader.onerror = this.#augmentCallbackEvent(this.onerror, eventInfo);\n loader.onabort = this.#augmentCallbackEvent(this.onabort, eventInfo);\n // launch load\n try {\n loader.load(data, options);\n } catch (error) {\n this.onerror({\n error: error,\n dataid: dataId\n });\n this.onloadend({\n dataid: dataId\n });\n return;\n }\n }\n\n /**\n * Augment a callback event: adds loadtype to the event\n * passed to a callback.\n *\n * @param {object} callback The callback to update.\n * @param {object} info Info object to append to the event.\n * @returns {object} A function representing the modified callback.\n */\n #augmentCallbackEvent(callback, info) {\n return function (event) {\n const keys = Object.keys(info);\n for (let i = 0; i < keys.length; ++i) {\n const key = keys[i];\n event[key] = info[key];\n }\n callback(event);\n };\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when an item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class LoadController\n","import {ListenerHandler} from '../utils/listen';\nimport {getReverseOrientation} from '../dicom/dicomParser';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get a number toprecision function with the provided precision.\n *\n * @param {number} precision The precision to achieve.\n * @returns {Function} The to precision function.\n */\nfunction getNumberToPrecision(precision) {\n return function (num) {\n return Number(num).toPrecision(precision);\n };\n}\n\n/**\n * Create a default replace format from a given length.\n * For example: '{v0}, {v1}'.\n *\n * @param {number} length The length of the format.\n * @returns {string} A replace format.\n */\nfunction createDefaultReplaceFormat(length) {\n let res = '';\n for (let i = 0; i < length; ++i) {\n if (i !== 0) {\n res += ', ';\n }\n res += '{v' + i + '}';\n }\n return res;\n}\n\n/**\n * Replace flags in a input string. Flags are keywords surrounded with curly\n * braces in the form: '{v0}, {v1}'.\n *\n * @param {string} inputStr The input string.\n * @param {string[]} values An array of strings.\n * @example\n * var values = [\"a\", \"b\"];\n * var str = \"The length is: {v0}. The size is: {v1}\";\n * var res = replaceFlags(str, values);\n * // \"The length is: a. The size is: b\"\n * @returns {string} The result string.\n */\nfunction replaceFlags(inputStr, values) {\n let res = inputStr;\n for (let i = 0; i < values.length; ++i) {\n res = res.replace('{v' + i + '}', values[i]);\n }\n return res;\n}\n\n/**\n * DICOM Header overlay info.\n */\nexport class OverlayData {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Associated data id.\n *\n * @type {string}\n */\n #dataId;\n\n /**\n * Overlay config.\n *\n * @type {object}\n */\n #configs;\n\n /**\n * List of event used by the config.\n *\n * @type {string[]}\n */\n #eventNames = [];\n\n /**\n * Flag to know if listening to app.\n *\n * @type {boolean}\n */\n #isListening;\n\n /**\n * Overlay data.\n *\n * @type {Array}\n */\n #data = [];\n\n /**\n * Current data uid: set on pos change.\n *\n * @type {number}\n */\n #currentDataUid;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * @param {App} app The associated application.\n * @param {string} dataId The associated data id.\n * @param {object} configs The overlay config.\n */\n constructor(app, dataId, configs) {\n this.#app = app;\n this.#dataId = dataId;\n this.#configs = configs;\n\n // parse overlays to get the list of events to listen to\n const keys = Object.keys(this.#configs);\n for (let i = 0; i < keys.length; ++i) {\n const config = this.#configs[keys[i]];\n for (let j = 0; j < config.length; ++j) {\n const eventType = config[j].event;\n if (typeof eventType !== 'undefined') {\n if (!this.#eventNames.includes(eventType)) {\n this.#eventNames.push(eventType);\n }\n }\n }\n }\n // add app listeners\n this.addAppListeners();\n }\n\n /**\n * Reset the data.\n */\n reset() {\n this.#data = [];\n this.#currentDataUid = undefined;\n }\n\n /**\n * Handle a new loaded item event.\n *\n * @param {object} data The item meta data.\n */\n addItemMeta(data) {\n // create and store overlay data\n let dataUid;\n // check if dicom data (00020010: transfer syntax)\n if (typeof data['00020010'] !== 'undefined') {\n if (typeof data['00080018'] !== 'undefined') {\n // SOP instance UID\n dataUid = data['00080018'].value[0];\n } else {\n dataUid = data.length;\n }\n this.#data[dataUid] = createOverlayData(data, this.#configs);\n } else {\n // image file case\n const keys = Object.keys(data);\n for (let d = 0; d < keys.length; ++d) {\n const obj = data[keys[d]];\n if (keys[d] === 'imageUid') {\n dataUid = obj.value;\n break;\n }\n }\n this.#data[dataUid] = createOverlayDataForDom(data, this.#configs);\n }\n // store uid\n this.#currentDataUid = dataUid;\n }\n\n /**\n * Handle a changed slice event.\n *\n * @param {object} event The slicechange event.\n */\n #onSliceChange = (event) => {\n if (event.dataid !== this.#dataId) {\n return;\n }\n if (typeof event.data !== 'undefined' &&\n typeof event.data.imageUid !== 'undefined' &&\n this.#currentDataUid !== event.data.imageUid) {\n this.#currentDataUid = event.data.imageUid;\n this.#updateData(event);\n }\n };\n\n /**\n * Update the overlay data.\n *\n * @param {object} event An event defined by the overlay map and\n * registered in toggleListeners.\n */\n #updateData = (event) => {\n if (event.dataid !== this.#dataId) {\n return;\n }\n\n const sliceOverlayData = this.#data[this.#currentDataUid];\n if (typeof sliceOverlayData === 'undefined') {\n console.warn('No slice overlay data for: ' + this.#currentDataUid);\n return;\n }\n\n for (let n = 0; n < sliceOverlayData.length; ++n) {\n let text = undefined;\n if (typeof sliceOverlayData[n].tags !== 'undefined') {\n // update tags only on slice change\n if (event.type === 'positionchange') {\n text = sliceOverlayData[n].value;\n }\n } else {\n // update text if the value is an event type\n if (typeof sliceOverlayData[n].event !== 'undefined' &&\n sliceOverlayData[n].event === event.type) {\n const format = sliceOverlayData[n].format;\n let values = event.value;\n // optional number precision\n if (typeof sliceOverlayData[n].precision !== 'undefined') {\n let mapFunc = null;\n if (sliceOverlayData[n].precision === 'round') {\n mapFunc = Math.round;\n } else {\n mapFunc = getNumberToPrecision(sliceOverlayData[n].precision);\n }\n values = values.map(mapFunc);\n }\n text = replaceFlags(format, values);\n }\n }\n if (typeof text !== 'undefined') {\n sliceOverlayData[n].value = text;\n }\n }\n\n /**\n * Value change event.\n *\n * @event OverlayData#valuechange\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} data The value of the overlay data.\n */\n this.#fireEvent({\n type: 'valuechange',\n data: sliceOverlayData\n });\n };\n\n /**\n * Is this class listening to app events.\n *\n * @returns {boolean} True is listening to app events.\n */\n isListening() {\n return this.#isListening;\n }\n\n /**\n * Toggle info listeners.\n */\n addAppListeners() {\n // listen to update tags data\n this.#app.addEventListener('positionchange', this.#onSliceChange);\n // add event listeners\n for (let i = 0; i < this.#eventNames.length; ++i) {\n this.#app.addEventListener(this.#eventNames[i], this.#updateData);\n }\n // update flag\n this.#isListening = true;\n }\n\n /**\n * Toggle info listeners.\n */\n removeAppListeners() {\n // stop listening to update tags data\n this.#app.removeEventListener('positionchange', this.#onSliceChange);\n // remove event listeners\n for (let i = 0; i < this.#eventNames.length; ++i) {\n this.#app.removeEventListener(this.#eventNames[i], this.#updateData);\n }\n // update flag\n this.#isListening = false;\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {object} callback The method associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {object} callback The method associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent(event) {\n this.#listenerHandler.fireEvent(event);\n }\n\n} // class OverlayData\n\n/**\n * Create overlay data array for a DICOM image.\n *\n * @param {object} dicomElements DICOM elements of the image.\n * @param {object} configs The overlay data configs.\n * @returns {Array} Overlay data array.\n */\nfunction createOverlayData(dicomElements, configs) {\n const overlays = [];\n let modality;\n const modElement = dicomElements['00080060'];\n if (typeof modElement !== 'undefined') {\n modality = modElement.value[0];\n } else {\n return overlays;\n }\n const config = configs[modality] || configs['*'];\n if (!config) {\n return overlays;\n }\n\n for (let n = 0; n < config.length; ++n) {\n // deep copy\n const overlay = JSON.parse(JSON.stringify(config[n]));\n\n // add tag values\n const tags = overlay.tags;\n if (typeof tags !== 'undefined' && tags.length !== 0) {\n // get values\n const values = [];\n for (let i = 0; i < tags.length; ++i) {\n const elem = dicomElements[tags[i]];\n if (typeof elem !== 'undefined') {\n values.push(dicomElements[tags[i]].value);\n } else {\n values.push('');\n }\n }\n // format\n if (typeof overlay.format === 'undefined' || overlay.format === null) {\n overlay.format = createDefaultReplaceFormat(values.length);\n }\n overlay.value = replaceFlags(overlay.format, values).trim();\n }\n\n // store\n overlays.push(overlay);\n }\n\n // (0020,0020) Patient Orientation\n const poElement = dicomElements['00200020'];\n if (typeof poElement !== 'undefined' &&\n poElement.value.length === 2\n ) {\n const po0 = poElement.value[0];\n const po1 = poElement.value[1];\n overlays.push({\n pos: 'cr', value: po0, format: '{v0}'\n });\n overlays.push({\n pos: 'cl', value: getReverseOrientation(po0), format: '{v0}'\n });\n overlays.push({\n pos: 'bc', value: po1, format: '{v0}'\n });\n overlays.push({\n pos: 'tc', value: getReverseOrientation(po1), format: '{v0}'\n });\n }\n\n return overlays;\n}\n\n/**\n * Create overlay data array for a DOM image.\n *\n * @param {object} info Meta data.\n * @param {object} configs The overlay data configs.\n * @returns {Array} Overlay data array.\n */\nfunction createOverlayDataForDom(info, configs) {\n const overlays = [];\n const config = configs.DOM;\n if (!config) {\n return overlays;\n }\n\n const infoKeys = Object.keys(info);\n\n for (let n = 0; n < config.length; ++n) {\n // deep copy\n const overlay = JSON.parse(JSON.stringify(config[n]));\n\n // add tag values\n const tags = overlay.tags;\n if (typeof tags !== 'undefined' && tags.length !== 0) {\n // get values\n const values = [];\n for (let i = 0; i < tags.length; ++i) {\n for (let j = 0; j < infoKeys.length; ++j) {\n if (tags[i] === infoKeys[j]) {\n values.push(info[infoKeys[j]].value);\n }\n }\n }\n // format\n if (typeof overlay.format === 'undefined' || overlay.format === null) {\n overlay.format = createDefaultReplaceFormat(values.length);\n }\n overlay.value = replaceFlags(overlay.format, values).trim();\n }\n\n // store\n overlays.push(overlay);\n }\n\n return overlays;\n}\n","import {viewEventNames} from '../image/view';\nimport {ViewFactory} from '../image/viewFactory';\nimport {\n getMatrixFromName,\n getOrientationStringLPS,\n Orientation,\n getViewOrientation\n} from '../math/orientation';\nimport {Point3D} from '../math/point';\nimport {Stage} from '../gui/stage';\nimport {Style} from '../gui/style';\nimport {getLayerDetailsFromLayerDivId} from '../gui/layerGroup';\nimport {ListenerHandler} from '../utils/listen';\nimport {State} from '../io/state';\nimport {logger} from '../utils/logger';\nimport {getUriQuery, decodeQuery} from '../utils/uri';\nimport {UndoStack} from '../utils/undoStack';\nimport {ToolboxController} from './toolboxController';\nimport {LoadController} from './loadController';\nimport {DataController} from './dataController';\nimport {OverlayData} from '../gui/overlayData';\nimport {\n toolList,\n defaultToolList,\n toolOptions,\n defaultToolOptions\n} from '../tools';\nimport {binderList} from '../gui/stage';\nimport {WindowLevel} from '../image/windowLevel';\nimport {PlaneHelper} from '../image/planeHelper';\nimport {AnnotationGroup} from '../image/annotationGroup';\nimport {konvaToAnnotation} from '../gui/drawLayer';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {LayerGroup} from '../gui/layerGroup';\nimport {ViewLayer} from '../gui/viewLayer';\nimport {DrawLayer} from '../gui/drawLayer';\nimport {Image} from '../image/image';\nimport {Matrix33} from '../math/matrix';\nimport {DataElement} from '../dicom/dataElement';\nimport {Scalar3D} from '../math/scalar';\nimport {DicomData} from './dataController';\n/* eslint-enable no-unused-vars */\n\n/**\n * View configuration: mainly defines the ´divId´\n * of the associated HTML div.\n */\nexport class ViewConfig {\n /**\n * Associated HTML div id.\n *\n * @type {string}\n */\n divId;\n /**\n * Optional orientation of the data; 'axial', 'coronal' or 'sagittal'.\n * If undefined, will use the data aquisition plane.\n *\n * @type {string|undefined}\n */\n orientation;\n /**\n * Optional view colour map name.\n *\n * @type {string|undefined}\n */\n colourMap;\n /**\n * Optional layer opacity; in [0, 1] range.\n *\n * @type {number|undefined}\n */\n opacity;\n /**\n * Optional layer window level preset name.\n * If present, the preset name will be used and\n * the window centre and width ignored.\n *\n * @type {string|undefined}\n */\n wlPresetName;\n /**\n * Optional layer window center.\n *\n * @type {number|undefined}\n */\n windowCenter;\n /**\n * Optional layer window width.\n *\n * @type {number|undefined}\n */\n windowWidth;\n\n /**\n * @param {string} divId The associated HTML div id.\n */\n constructor(divId) {\n this.divId = divId;\n }\n}\n\n/**\n * Tool configuration.\n */\nexport class ToolConfig {\n /**\n * Optional tool options.\n * For Draw: list of shape names.\n * For Filter: list of filter names.\n *\n * @type {string[]|undefined}\n */\n options;\n\n /**\n * @param {string[]} [options] Optional tool options.\n */\n constructor(options) {\n this.options = options;\n }\n}\n\n/**\n * Application options.\n */\nexport class AppOptions {\n /**\n * DataId indexed object containing the data view configurations.\n *\n * @type {Object|undefined}\n */\n dataViewConfigs;\n /**\n * Tool name indexed object containing individual tool configurations.\n *\n * @type {Object|undefined}\n */\n tools;\n /**\n * Optional array of layerGroup binder names.\n *\n * @type {string[]|undefined}\n */\n binders;\n /**\n * Optional boolean flag to trigger the first data render\n * after the first loaded data or not. Defaults to true.\n *\n * @type {boolean|undefined}\n */\n viewOnFirstLoadItem;\n /**\n * Optional default chraracterset string used for DICOM parsing if\n * not passed in DICOM file.\n *\n * Valid values: {@link https://developer.mozilla.org/en-US/docs/Web/API/Encoding_API/Encodings}.\n *\n * @type {string|undefined}\n */\n defaultCharacterSet;\n /**\n * Optional overlay config.\n *\n * @type {object|undefined}\n */\n overlayConfig;\n /**\n * DOM root document.\n *\n * @type {DocumentFragment}\n */\n rootDocument;\n\n /**\n * @param {Object} [dataViewConfigs] Optional dataId\n * indexed object containing the data view configurations.\n */\n constructor(dataViewConfigs) {\n this.dataViewConfigs = dataViewConfigs;\n }\n}\n\n/**\n * List of ViewConfigs indexed by dataIds.\n *\n * @typedef {Object} DataViewConfigs\n */\n\n/**\n * Main application class.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * app.init(options);\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\nexport class App {\n\n /**\n * App options.\n *\n * @type {AppOptions}\n */\n #options = null;\n\n /**\n * Data controller.\n *\n * @type {DataController}\n */\n #dataController = null;\n\n /**\n * Toolbox controller.\n *\n * @type {ToolboxController}\n */\n #toolboxController = null;\n\n /**\n * Load controller.\n *\n * @type {LoadController}\n */\n #loadController = null;\n\n /**\n * Stage.\n *\n * @type {Stage}\n */\n #stage = null;\n\n /**\n * Undo stack.\n *\n * @type {UndoStack}\n */\n #undoStack = null;\n\n /**\n * Style.\n *\n * @type {Style}\n */\n #style = new Style();\n\n // overlay datas\n #overlayDatas = {};\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Get a DicomData.\n *\n * @param {string} dataId The data id.\n * @returns {DicomData|undefined} The data.\n */\n getData(dataId) {\n return this.#dataController.get(dataId);\n }\n\n /**\n * Get the image.\n *\n * @param {string} dataId The data id.\n * @returns {Image|undefined} The associated image.\n * @deprecated Since v0.34, please use the getData method.\n */\n getImage(dataId) {\n let res;\n if (typeof this.getData(dataId) !== 'undefined') {\n res = this.getData(dataId).image;\n }\n return res;\n }\n\n /**\n * Set the image at the given id.\n *\n * @param {string} dataId The data id.\n * @param {Image} img The associated image.\n */\n setImage(dataId, img) {\n this.#dataController.setImage(dataId, img);\n }\n\n /**\n * Add a new DicomData.\n *\n * @param {DicomData} data The new data.\n * @returns {string} The data id.\n */\n addData(data) {\n // get a new dataId\n const dataId = this.#dataController.getNextDataId();\n // add image to data controller\n this.#dataController.add(\n dataId,\n data\n );\n // optional render\n // if (this.#options.viewOnFirstLoadItem) {\n // this.render(dataId);\n // }\n // return\n return dataId;\n }\n\n /**\n * Get the meta data.\n *\n * @param {string} dataId The data id.\n * @returns {Object|undefined} The list of meta data.\n */\n getMetaData(dataId) {\n let res;\n if (typeof this.#dataController.get(dataId) !== 'undefined') {\n res = this.#dataController.get(dataId).meta;\n }\n return res;\n }\n\n /**\n * Get the list of ids in the data storage.\n *\n * @returns {string[]} The list of data ids.\n */\n getDataIds() {\n return this.#dataController.getDataIds();\n }\n\n /**\n * Get the list of dataIds that contain the input UIDs.\n *\n * @param {string[]} uids A list of UIDs.\n * @returns {string[]} The list of dataIds that contain the UIDs.\n */\n getDataIdsFromSopUids(uids) {\n return this.#dataController.getDataIdsFromSopUids(uids);\n }\n\n /**\n * Can the data (of the active view of the active layer) be scrolled?\n *\n * @returns {boolean} True if the data has a third dimension greater than one.\n * @deprecated Since v0.33, please use the ViewController\n * equivalent directly instead.\n */\n canScroll() {\n const viewLayer = this.#stage.getActiveLayerGroup().getActiveViewLayer();\n const controller = viewLayer.getViewController();\n return controller.canScroll();\n }\n\n /**\n * Can window and level be applied to the data\n * (of the active view of the active layer)?\n *\n * @returns {boolean} True if the data is monochrome.\n * @deprecated Since v0.33, please use the ViewController\n * equivalent directly instead.\n */\n canWindowLevel() {\n const viewLayer = this.#stage.getActiveLayerGroup().getActiveViewLayer();\n const controller = viewLayer.getViewController();\n return controller.canWindowLevel();\n }\n\n /**\n * Get the active layer group scale on top of the base scale.\n *\n * @returns {Scalar3D} The scale as {x,y,z}.\n */\n getAddedScale() {\n return this.#stage.getActiveLayerGroup().getAddedScale();\n }\n\n /**\n * Get the base scale of the active layer group.\n *\n * @returns {Scalar3D} The scale as {x,y,z}.\n */\n getBaseScale() {\n return this.#stage.getActiveLayerGroup().getBaseScale();\n }\n\n /**\n * Get the layer offset of the active layer group.\n *\n * @returns {Scalar3D} The offset as {x,y,z}.\n */\n getOffset() {\n return this.#stage.getActiveLayerGroup().getOffset();\n }\n\n /**\n * Get the toolbox controller.\n *\n * @returns {ToolboxController} The controller.\n */\n getToolboxController() {\n return this.#toolboxController;\n }\n\n /**\n * Get the active layer group.\n * The layer is available after the first loaded item.\n *\n * @returns {LayerGroup|undefined} The layer group.\n */\n getActiveLayerGroup() {\n return this.#stage.getActiveLayerGroup();\n }\n\n /**\n * Set the active layer group.\n *\n * @param {number} index The layer group index.\n */\n setActiveLayerGroup(index) {\n this.#stage.setActiveLayerGroup(index);\n }\n\n /**\n * Get the view layers associated to a data id.\n * The layer are available after the first loaded item.\n *\n * @param {string} dataId The data id.\n * @returns {ViewLayer[]} The layers.\n */\n getViewLayersByDataId(dataId) {\n return this.#stage.getViewLayersByDataId(dataId);\n }\n\n /**\n * Get a list of view layers according to an input callback function.\n *\n * @param {Function} [callbackFn] A function that takes\n * a ViewLayer as input and returns a boolean. If undefined,\n * returns all view layers.\n * @returns {ViewLayer[]} The layers that\n * satisfy the callbackFn.\n */\n getViewLayers(callbackFn) {\n return this.#stage.getViewLayers(callbackFn);\n }\n\n /**\n * Get the draw layers associated to a data id.\n * The layer are available after the first loaded item.\n *\n * @param {string} dataId The data id.\n * @returns {DrawLayer[]} The layers.\n */\n getDrawLayersByDataId(dataId) {\n return this.#stage.getDrawLayersByDataId(dataId);\n }\n\n /**\n * Get a list of draw layers according to an input callback function.\n *\n * @param {Function} [callbackFn] A function that takes\n * a DrawLayer as input and returns a boolean. If undefined,\n * returns all draw layers.\n * @returns {DrawLayer[]} The layers that\n * satisfy the callbackFn.\n */\n getDrawLayers(callbackFn) {\n return this.#stage.getDrawLayers(callbackFn);\n }\n\n /**\n * Get a layer group by div id.\n * The layer is available after the first loaded item.\n *\n * @param {string} divId The div id.\n * @returns {LayerGroup} The layer group.\n */\n getLayerGroupByDivId(divId) {\n return this.#stage.getLayerGroupByDivId(divId);\n }\n\n /**\n * Get the number of layer groups.\n *\n * @returns {number} The number of groups.\n */\n getNumberOfLayerGroups() {\n return this.#stage.getNumberOfLayerGroups();\n }\n\n /**\n * Get the app style.\n *\n * @returns {object} The app style.\n */\n getStyle() {\n return this.#style;\n }\n\n /**\n * Add a command to the undo stack.\n *\n * @param {object} cmd The command to add.\n * @fires UndoStack#undoadd\n * @function\n */\n addToUndoStack = (cmd) => {\n if (this.#undoStack !== null) {\n this.#undoStack.add(cmd);\n }\n };\n\n /**\n * Remove a command from the undo stack.\n *\n * @param {string} name The name of the command to remove.\n * @returns {boolean} True if the command was found and removed.\n * @fires UndoStack#undoremove\n * @function\n */\n removeFromUndoStack = (name) => {\n let res = false;\n if (this.#undoStack !== null) {\n res = this.#undoStack.remove(name);\n }\n return res;\n };\n\n /**\n * Initialise the application.\n *\n * @param {AppOptions} opt The application options.\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.viewOnFirstLoadItem = false;\n * app.init(options);\n * // render button\n * const button = document.createElement('button');\n * button.id = 'render';\n * button.disabled = true;\n * button.appendChild(document.createTextNode('render'));\n * document.body.appendChild(button);\n * app.addEventListener('load', function () {\n * const button = document.getElementById('render');\n * button.disabled = false;\n * button.onclick = function () {\n * // render data #0\n * app.render(0);\n * };\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\n init(opt) {\n // store\n this.#options = opt;\n // defaults\n if (typeof this.#options.viewOnFirstLoadItem === 'undefined') {\n this.#options.viewOnFirstLoadItem = true;\n }\n if (typeof this.#options.dataViewConfigs === 'undefined') {\n this.#options.dataViewConfigs = {};\n }\n if (typeof this.#options.rootDocument === 'undefined') {\n this.#options.rootDocument = document;\n }\n\n // undo stack\n this.#undoStack = new UndoStack();\n this.#undoStack.addEventListener('undoadd', this.#fireEvent);\n this.#undoStack.addEventListener('undo', this.#fireEvent);\n this.#undoStack.addEventListener('redo', this.#fireEvent);\n\n // tools\n if (typeof this.#options.tools !== 'undefined') {\n // setup the tool list\n const appToolList = {};\n const keys = Object.keys(this.#options.tools);\n for (let t = 0; t < keys.length; ++t) {\n const toolName = keys[t];\n // find the tool in the default tool list\n let toolClass = defaultToolList[toolName];\n // or use external one\n if (typeof toolClass === 'undefined') {\n toolClass = toolList[toolName];\n }\n if (typeof toolClass !== 'undefined') {\n // create tool instance\n appToolList[toolName] = new toolClass(this);\n // register listeners\n if (typeof appToolList[toolName].addEventListener !== 'undefined') {\n const names = appToolList[toolName].getEventNames();\n for (let j = 0; j < names.length; ++j) {\n appToolList[toolName].addEventListener(names[j], this.#fireEvent);\n }\n }\n // tool options\n const toolParams = this.#options.tools[toolName];\n if (typeof toolParams.options !== 'undefined' &&\n toolParams.options.length !== 0) {\n let type = 'raw';\n if (typeof appToolList[toolName].getOptionsType !== 'undefined') {\n type = appToolList[toolName].getOptionsType();\n }\n let appToolOptions;\n if (type === 'instance' || type === 'factory') {\n appToolOptions = {};\n for (let i = 0; i < toolParams.options.length; ++i) {\n const optionName = toolParams.options[i];\n let optionClassName = optionName;\n if (type === 'factory') {\n optionClassName += 'Factory';\n }\n const toolNamespace = toolName.charAt(0).toLowerCase() +\n toolName.slice(1);\n // find the option in the external tool list\n let tOptions = toolOptions[toolNamespace];\n let optionClass;\n if (typeof tOptions !== 'undefined') {\n optionClass = tOptions[optionClassName];\n }\n // or use the default one\n if (typeof optionClass === 'undefined') {\n tOptions = defaultToolOptions[toolNamespace];\n if (typeof tOptions !== 'undefined') {\n optionClass = tOptions[optionClassName];\n }\n }\n if (typeof optionClass !== 'undefined') {\n appToolOptions[optionName] = optionClass;\n } else {\n logger.warn('Could not find option class for: ' +\n optionName);\n }\n }\n } else {\n appToolOptions = toolParams.options;\n }\n appToolList[toolName].setOptions(appToolOptions);\n }\n } else {\n logger.warn('Could not initialise unknown tool: ' + toolName);\n }\n }\n // add tools to the controller\n this.#toolboxController = new ToolboxController(appToolList);\n }\n\n // create load controller\n this.#loadController =\n new LoadController(this.#options.defaultCharacterSet);\n this.#loadController.onloadstart = this.#onloadstart;\n this.#loadController.onprogress = this.#onloadprogress;\n this.#loadController.onloaditem = this.#onloaditem;\n this.#loadController.onload = this.#onload;\n this.#loadController.onloadend = this.#onloadend;\n this.#loadController.onerror = this.#onloaderror;\n this.#loadController.onabort = this.#onloadabort;\n\n // create data controller\n this.#dataController = new DataController();\n // propagate data events\n this.#dataController.addEventListener('dataadd', this.#fireEvent);\n this.#dataController.addEventListener('dataremove', this.#fireEvent);\n this.#dataController.addEventListener('dataimageset', this.#fireEvent);\n this.#dataController.addEventListener('dataupdate', this.#fireEvent);\n // propage individual data events\n this.#dataController.addEventListener(\n 'imagecontentchange', this.#fireEvent);\n this.#dataController.addEventListener(\n 'imagegeometrychange', this.#fireEvent);\n this.#dataController.addEventListener('annotationadd', this.#fireEvent);\n this.#dataController.addEventListener('annotationupdate', this.#fireEvent);\n this.#dataController.addEventListener('annotationremove', this.#fireEvent);\n this.#dataController.addEventListener(\n 'annotationgroupeditablechange', this.#fireEvent);\n // create stage\n this.#stage = new Stage();\n if (typeof this.#options.binders !== 'undefined') {\n this.#stage.setBinders(this.#options.binders);\n }\n }\n\n /**\n * Reset the application.\n */\n reset() {\n // clear objects\n this.#stage.empty();\n this.#overlayDatas = {};\n // reset undo/redo\n if (this.#undoStack) {\n this.#undoStack = new UndoStack();\n this.#undoStack.addEventListener('undoadd', this.#fireEvent);\n this.#undoStack.addEventListener('undo', this.#fireEvent);\n this.#undoStack.addEventListener('redo', this.#fireEvent);\n }\n }\n\n /**\n * Reset the layout of the application.\n */\n resetLayout() {\n this.#stage.reset();\n this.#stage.draw();\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n // load API [begin] -------------------------------------------------------\n\n /**\n * Load a list of files. Can be image files or a state file.\n *\n * @param {File[]} files The list of files to load.\n * @fires App#loadstart\n * @fires App#loadprogress\n * @fires App#loaditem\n * @fires App#loadend\n * @fires App#error\n * @fires App#abort\n * @function\n */\n loadFiles = (files) => {\n // Get new data id\n const dataId = this.#dataController.getNextDataId();\n if (files.length === 0) {\n logger.warn('Ignoring empty input file list.');\n return;\n }\n this.#loadController.loadFiles(files, dataId);\n };\n\n /**\n * Load a list of URLs. Can be image files or a state file.\n *\n * @param {string[]} urls The list of urls to load.\n * @param {object} [options] The options object, can contain:\n * - requestHeaders: an array of {name, value} to use as request headers,\n * - withCredentials: boolean xhr.withCredentials flag to pass to the request,\n * - batchSize: the size of the request url batch.\n * @fires App#loadstart\n * @fires App#loadprogress\n * @fires App#loaditem\n * @fires App#loadend\n * @fires App#error\n * @fires App#abort\n * @function\n */\n loadURLs = (urls, options) => {\n // Get new data id\n const dataId = this.#dataController.getNextDataId();\n if (urls.length === 0) {\n logger.warn('Ignoring empty input url list.');\n return;\n }\n this.#loadController.loadURLs(urls, dataId, options);\n };\n\n /**\n * Load from an input uri.\n *\n * @param {string} uri The input uri, for example: 'window.location.href'.\n * @param {object} [options] Optional url request options.\n * @function\n */\n loadFromUri = (uri, options) => {\n const query = getUriQuery(uri);\n\n // load end callback: loads the state.\n const onLoadEnd = (/*event*/) => {\n this.removeEventListener('loadend', onLoadEnd);\n this.loadURLs([query.state]);\n };\n\n // check query\n if (query && typeof query.input !== 'undefined') {\n // optional display state\n if (typeof query.state !== 'undefined') {\n // queue after main data load\n this.addEventListener('loadend', onLoadEnd);\n }\n // load base image\n decodeQuery(query, this.loadURLs, options);\n }\n // no else to allow for empty uris\n };\n\n /**\n * Load a list of ArrayBuffers.\n *\n * @param {Array} data The list of ArrayBuffers to load\n * in the form of [{name: \"\", filename: \"\", data: data}].\n * @fires App#loadstart\n * @fires App#loadprogress\n * @fires App#loaditem\n * @fires App#loadend\n * @fires App#error\n * @fires App#abort\n * @function\n */\n loadImageObject = (data) => {\n // Get new data id\n const dataId = this.#dataController.getNextDataId();\n this.#loadController.loadImageObject(data, dataId);\n };\n\n /**\n * Abort all the current loads.\n */\n abortAllLoads() {\n const ids = this.#loadController.getLoadingDataIds();\n for (const id of ids) {\n this.abortLoad(id);\n }\n }\n\n /**\n * Abort an individual data load.\n *\n * @param {string} dataId The data to stop loading.\n */\n abortLoad(dataId) {\n // abort load\n this.#loadController.abort(dataId);\n // remove data\n this.#dataController.remove(dataId);\n // clean up stage\n this.#stage.removeLayersByDataId(dataId);\n }\n\n // load API [end] ---------------------------------------------------------\n\n /**\n * Fit the display to the data of each layer group.\n * To be called once the image is loaded.\n */\n fitToContainer() {\n this.#stage.fitToContainer();\n }\n\n /**\n * Init the Window/Level display\n * (of the active layer of the active layer group).\n *\n * @deprecated Since v0.33, please set the opacity\n * of the desired view layer directly.\n */\n initWLDisplay() {\n const viewLayer = this.#stage.getActiveLayerGroup().getActiveViewLayer();\n const controller = viewLayer.getViewController();\n controller.initialise();\n }\n\n /**\n * Set the imageSmoothing flag value. Default is false.\n *\n * @param {boolean} flag True to enable smoothing.\n */\n setImageSmoothing(flag) {\n this.#stage.setImageSmoothing(flag);\n this.#stage.draw();\n }\n\n /**\n * Get the layer group configuration from a data id.\n *\n * @param {string} dataId The data id.\n * @param {boolean} [excludeStarConfig] Exclude the star config\n * (default to false).\n * @returns {ViewConfig[]} The list of associated configs.\n */\n getViewConfigs(dataId, excludeStarConfig) {\n // check options\n if (this.#options.dataViewConfigs === null ||\n typeof this.#options.dataViewConfigs === 'undefined') {\n throw new Error('No available data view configuration');\n }\n let configs = [];\n if (typeof this.#options.dataViewConfigs[dataId] !== 'undefined') {\n configs = this.#options.dataViewConfigs[dataId];\n } else if (!excludeStarConfig &&\n typeof this.#options.dataViewConfigs['*'] !== 'undefined') {\n configs = this.#options.dataViewConfigs['*'];\n }\n return configs;\n }\n\n /**\n * Get the layer group configuration for a data id and group\n * div id.\n *\n * @param {string} dataId The data id.\n * @param {string} groupDivId The layer group div id.\n * @param {boolean} [excludeStarConfig] Exclude the star config\n * (default to false).\n * @returns {ViewConfig|undefined} The associated config.\n */\n getViewConfig(dataId, groupDivId, excludeStarConfig) {\n const configs = this.getViewConfigs(dataId, excludeStarConfig);\n return configs.find(function (item) {\n return item.divId === groupDivId;\n });\n }\n\n /**\n * Get the data view config.\n * Carefull, returns a reference, do not modify without resetting.\n *\n * @returns {Object} The configuration list.\n */\n getDataViewConfigs() {\n return this.#options.dataViewConfigs;\n }\n\n /**\n * Set the data view configuration.\n * Resets the stage and recreates all the views.\n *\n * @param {Object} configs The configuration list.\n */\n setDataViewConfigs(configs) {\n // clean up\n this.#stage.empty();\n // set new\n this.#options.dataViewConfigs = configs;\n // create layer groups\n this.#createLayerGroups(configs);\n }\n\n /**\n * Add a data view config.\n *\n * @param {string} dataId The data id.\n * @param {ViewConfig} config The view configuration.\n */\n addDataViewConfig(dataId, config) {\n // add to list\n const configs = this.#options.dataViewConfigs;\n if (typeof configs[dataId] === 'undefined') {\n configs[dataId] = [];\n }\n const equalDivId = function (item) {\n return item.divId === config.divId;\n };\n const itemIndex = configs[dataId].findIndex(equalDivId);\n if (itemIndex === -1) {\n this.#options.dataViewConfigs[dataId].push(config);\n } else {\n throw new Error('Duplicate view config for data ' + dataId +\n ' and div ' + config.divId);\n }\n\n // add layer group if not done\n if (typeof this.#stage.getLayerGroupByDivId(config.divId) === 'undefined') {\n this.#createLayerGroup(config);\n }\n\n // render (will create layers)\n if (typeof this.#dataController.get(dataId) !== 'undefined') {\n this.render(dataId, [config]);\n }\n }\n\n /**\n * Remove a data view config.\n *\n * @param {string} dataId The data id.\n * @param {string} divId The div id.\n */\n removeDataViewConfig(dataId, divId) {\n // remove from list\n const configs = this.#options.dataViewConfigs;\n if (typeof configs[dataId] === 'undefined') {\n // no config for dataId\n return;\n }\n const equalDivId = function (item) {\n return item.divId === divId;\n };\n const itemIndex = configs[dataId].findIndex(equalDivId);\n if (itemIndex === -1) {\n // no config for divId\n return;\n }\n configs[dataId].splice(itemIndex, 1);\n if (configs[dataId].length === 0) {\n delete configs[dataId];\n }\n\n // data is loaded, remove view\n if (typeof this.#dataController.get(dataId) !== 'undefined') {\n const lg = this.#stage.getLayerGroupByDivId(divId);\n if (typeof lg !== 'undefined') {\n const vls = lg.getViewLayersByDataId(dataId);\n if (vls.length === 1) {\n lg.removeLayer(vls[0]);\n }\n const dls = lg.getDrawLayersByDataId(dataId);\n if (dls.length === 1) {\n lg.removeLayer(dls[0]);\n }\n if (vls.length === 0 && dls.length === 0) {\n throw new Error('Expected one layer, got none');\n }\n if (lg.getNumberOfLayers() === 0) {\n this.#stage.removeLayerGroup(lg);\n }\n }\n }\n }\n\n /**\n * Update an existing data view config.\n * Removes and re-creates the layer if found.\n *\n * @param {string} dataId The data id.\n * @param {string} divId The div id.\n * @param {ViewConfig} config The view configuration.\n */\n updateDataViewConfig(dataId, divId, config) {\n const configs = this.#options.dataViewConfigs;\n // check data id\n if (typeof configs[dataId] === 'undefined') {\n throw new Error('No config for dataId: ' + dataId);\n }\n // check div id\n const equalDivId = function (item) {\n return item.divId === divId;\n };\n const itemIndex = configs[dataId].findIndex(equalDivId);\n if (itemIndex === -1) {\n throw new Error('No config for dataId: ' +\n dataId + ' and divId: ' + divId);\n }\n // update config\n const configToUpdate = configs[dataId][itemIndex];\n for (const prop in config) {\n configToUpdate[prop] = config[prop];\n }\n\n // remove previous layers\n const lg = this.#stage.getLayerGroupByDivId(configToUpdate.divId);\n if (typeof lg !== 'undefined') {\n const vls = lg.getViewLayersByDataId(dataId);\n if (vls.length === 1) {\n lg.removeLayer(vls[0]);\n }\n const dls = lg.getDrawLayersByDataId(dataId);\n if (dls.length === 1) {\n lg.removeLayer(dls[0]);\n }\n if (vls.length === 0 && dls.length === 0) {\n throw new Error('Expected one layer, got none');\n }\n }\n\n // render (will create layer)\n if (typeof this.#dataController.get(dataId) !== 'undefined') {\n this.render(dataId, [configToUpdate]);\n }\n }\n\n /**\n * Create layer groups according to a data view config:\n * adds them to stage and binds them.\n *\n * @param {DataViewConfigs} dataViewConfigs The data view config.\n */\n #createLayerGroups(dataViewConfigs) {\n const dataKeys = Object.keys(dataViewConfigs);\n const divIds = [];\n for (let i = 0; i < dataKeys.length; ++i) {\n const viewConfigs = dataViewConfigs[dataKeys[i]];\n for (let j = 0; j < viewConfigs.length; ++j) {\n const viewConfig = viewConfigs[j];\n // view configs can contain the same divIds, avoid duplicating\n if (!divIds.includes(viewConfig.divId)) {\n this.#createLayerGroup(viewConfig);\n divIds.push(viewConfig.divId);\n }\n }\n }\n }\n\n /**\n * Create a layer group according to a view config:\n * adds it to stage and binds it.\n *\n * @param {ViewConfig} viewConfig The view config.\n */\n #createLayerGroup(viewConfig) {\n // create new layer group\n const element = this.#options.rootDocument.getElementById(viewConfig.divId);\n const layerGroup = this.#stage.addLayerGroup(element);\n // bind events\n this.#bindLayerGroupToApp(layerGroup);\n }\n\n /**\n * Set the layer groups binders.\n *\n * @param {string[]} list The list of binder names.\n */\n setLayerGroupsBinders(list) {\n // create instances\n const instances = [];\n for (let i = 0; i < list.length; ++i) {\n if (typeof binderList[list[i]] !== 'undefined') {\n instances.push(new binderList[list[i]]);\n }\n }\n // pass to stage\n this.#stage.setBinders(instances);\n }\n\n /**\n * Render the current data.\n *\n * @param {string} dataId The data id to render.\n * @param {ViewConfig[]} [viewConfigs] The list of configs to render.\n */\n render(dataId, viewConfigs) {\n if (typeof dataId === 'undefined' || dataId === null) {\n throw new Error('Cannot render without data id');\n }\n // guess data type\n const isImage =\n typeof this.getData(dataId).image !== 'undefined';\n const isMeasurement =\n typeof this.getData(dataId).annotationGroup !== 'undefined';\n\n // create layer groups if not done yet\n // (create all to allow for ratio sync)\n if (this.#stage.getNumberOfLayerGroups() === 0) {\n this.#createLayerGroups(this.#options.dataViewConfigs);\n }\n\n // use options list if non provided\n if (typeof viewConfigs === 'undefined') {\n viewConfigs = this.getViewConfigs(dataId);\n }\n\n // nothing to do if no view config\n if (viewConfigs.length === 0) {\n logger.info('Not rendering data: ' + dataId +\n ' (no data view config)');\n return;\n }\n\n // loop on configs\n for (let i = 0; i < viewConfigs.length; ++i) {\n const config = viewConfigs[i];\n const layerGroup =\n this.#stage.getLayerGroupByDivId(config.divId);\n // layer group must exist\n if (!layerGroup) {\n throw new Error('No layer group for ' + config.divId);\n }\n // create layer if needed\n // warn: needs a loaded DOM\n if (typeof this.#dataController.get(dataId) !== 'undefined') {\n if (isImage &&\n layerGroup.getViewLayersByDataId(dataId).length === 0\n ) {\n this.#addViewLayer(dataId, config);\n } else if (isMeasurement &&\n layerGroup.getDrawLayersByDataId(dataId).length === 0\n ) {\n this.addDrawLayer(dataId, config);\n }\n }\n // draw\n layerGroup.draw();\n }\n }\n\n /**\n * Zoom the layers of the active layer group.\n *\n * @param {number} step The step to add to the current zoom.\n * @param {number} cx The zoom center X coordinate.\n * @param {number} cy The zoom center Y coordinate.\n */\n zoom(step, cx, cy) {\n const layerGroup = this.#stage.getActiveLayerGroup();\n const viewController = layerGroup.getActiveViewLayer().getViewController();\n const k = viewController.getCurrentScrollPosition();\n const center = new Point3D(cx, cy, k);\n layerGroup.addScale(step, center);\n layerGroup.draw();\n }\n\n /**\n * Apply a translation to the layers of the active layer group.\n *\n * @param {number} tx The translation along X.\n * @param {number} ty The translation along Y.\n */\n translate(tx, ty) {\n const layerGroup = this.#stage.getActiveLayerGroup();\n layerGroup.addTranslation({x: tx, y: ty, z: 0});\n layerGroup.draw();\n }\n\n /**\n * Set the active view layer (of the active layer group) opacity.\n *\n * @param {number} alpha The opacity ([0:1] range).\n * @deprecated Since v0.33, pplease set the opacity\n * of the desired view layer directly.\n */\n setOpacity(alpha) {\n const viewLayer = this.#stage.getActiveLayerGroup().getActiveViewLayer();\n viewLayer.setOpacity(alpha);\n viewLayer.draw();\n }\n\n /**\n * Set the drawings of the active layer group.\n *\n * @deprecated Since v0.34, please switch to DICOM SR annotations.\n * @param {Array} drawings An array of drawings.\n * @param {Array} drawingsDetails An array of drawings details.\n * @param {string} dataId The converted data id.\n */\n setDrawings(drawings, drawingsDetails, dataId) {\n const layerGroup = this.#stage.getActiveLayerGroup();\n const viewLayer = layerGroup.getActiveViewLayer();\n const refDataId = viewLayer.getDataId();\n const viewController = viewLayer.getViewController();\n\n // convert konva to annotation\n const annotations = konvaToAnnotation(drawings, drawingsDetails);\n // create data\n const data = this.createAnnotationData(refDataId);\n // add annotations to data\n for (const annotation of annotations) {\n annotation.setViewController(viewController);\n data.annotationGroup.add(annotation);\n }\n // add to data controller\n this.#dataController.add(dataId, data);\n // render\n this.render(dataId);\n }\n\n /**\n * Apply a JSON state to this app.\n *\n * @deprecated Since v0.34, please switch to DICOM SR\n * for annotations.\n * @param {string} jsonState The state of the app as a JSON string.\n * @param {string} dataId The state data id.\n */\n applyJsonState(jsonState, dataId) {\n const state = new State(dataId);\n state.apply(this, state.fromJSON(jsonState));\n }\n\n // Handler Methods -----------------------------------------------------------\n\n /**\n * Handle resize: fit the display to the window.\n * To be called once the image is loaded.\n * Can be connected to a window 'resize' event.\n *\n * @function\n */\n onResize = () => {\n this.fitToContainer();\n };\n\n /**\n * Key down callback. Meant to be used in tools.\n *\n * @param {KeyboardEvent} event The key down event.\n * @fires App#keydown\n * @function\n */\n onKeydown = (event) => {\n /**\n * Key down event.\n *\n * @event App#keydown\n * @type {KeyboardEvent}\n * @property {string} type The event type: keydown.\n * @property {string} context The tool where the event originated.\n */\n this.#fireEvent(event);\n };\n\n /**\n * Key down event handler example.\n * - CRTL-Z: undo,\n * - CRTL-Y: redo,\n * - CRTL-ARROW_LEFT: next element on fourth dim,\n * - CRTL-ARROW_UP: next element on third dim,\n * - CRTL-ARROW_RIGHT: previous element on fourth dim,\n * - CRTL-ARROW_DOWN: previous element on third dim.\n *\n * Applies to the active view of the active layer group.\n *\n * @param {KeyboardEvent} event The key down event.\n * @fires UndoStack#undo\n * @fires UndoStack#redo\n * @function\n */\n defaultOnKeydown = (event) => {\n if (event.ctrlKey) {\n if (event.shiftKey) {\n const layerGroup = this.#stage.getActiveLayerGroup();\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n if (event.key === 'ArrowLeft') { // crtl-shift-arrow-left\n if (viewController.moreThanOne(3)) {\n viewController.decrementIndex(3);\n }\n } else if (event.key === 'ArrowUp') { // crtl-shift-arrow-up\n if (layerGroup.canScroll()) {\n viewController.incrementScrollIndex();\n }\n } else if (event.key === 'ArrowRight') { // crtl-shift-arrow-right\n if (layerGroup.moreThanOne(3)) {\n viewController.incrementIndex(3);\n }\n } else if (event.key === 'ArrowDown') { // crtl-shift-arrow-down\n if (layerGroup.canScroll()) {\n viewController.decrementScrollIndex();\n }\n }\n } else if (event.key === 'y') { // crtl-y\n this.#undoStack.redo();\n } else if (event.key === 'z') { // crtl-z\n this.#undoStack.undo();\n } else if (event.key === ' ') { // crtl-space\n for (let i = 0; i < this.#stage.getNumberOfLayerGroups(); ++i) {\n this.#stage.getLayerGroup(i).setShowCrosshair(\n !this.#stage.getLayerGroup(i).getShowCrosshair()\n );\n }\n }\n }\n };\n\n // Internal members shortcuts-----------------------------------------------\n\n /**\n * Reset the display.\n */\n resetDisplay() {\n this.resetLayout();\n this.initWLDisplay();\n }\n\n /**\n * Reset the app zoom.\n */\n resetZoom() {\n this.resetLayout();\n }\n\n /**\n * Set the colour map of the active view of the active layer group.\n *\n * @param {string} name The colour map name.\n * @deprecated Since v0.33, please use the ViewController\n * equivalent directly instead.\n */\n setColourMap(name) {\n const viewController =\n this.#stage.getActiveLayerGroup()\n .getActiveViewLayer().getViewController();\n viewController.setColourMap(name);\n }\n\n /**\n * Set the window/level preset of the active view of the active layer group.\n *\n * @param {string} preset The window/level preset.\n * @deprecated Since v0.33, please use the ViewController\n * equivalent directly instead.\n */\n setWindowLevelPreset(preset) {\n const viewController =\n this.#stage.getActiveLayerGroup()\n .getActiveViewLayer().getViewController();\n viewController.setWindowLevelPreset(preset);\n }\n\n /**\n * Set the tool.\n *\n * @param {string} tool The tool.\n */\n setTool(tool) {\n // bind tool to active layer\n for (let i = 0; i < this.#stage.getNumberOfLayerGroups(); ++i) {\n const layerGroup = this.#stage.getLayerGroup(i);\n // draw or view layer\n const isDrawTool = tool === 'Draw' ||\n tool === 'Livewire' ||\n tool === 'Floodfill';\n let layer;\n if (isDrawTool &&\n typeof layerGroup.getActiveDrawLayer() !== 'undefined') {\n layer = layerGroup.getActiveDrawLayer();\n } else {\n layer = layerGroup.getActiveViewLayer();\n }\n if (typeof layer !== 'undefined') {\n this.#toolboxController.bindLayerGroup(layerGroup, layer);\n }\n }\n\n // set toolbox tool\n this.#toolboxController.setSelectedTool(tool);\n }\n\n /**\n * Set the tool live features.\n *\n * @param {object} list The list of features.\n */\n setToolFeatures(list) {\n this.#toolboxController.setToolFeatures(list);\n }\n\n /**\n * Undo the last action.\n *\n * @fires UndoStack#undo\n */\n undo() {\n this.#undoStack.undo();\n }\n\n /**\n * Redo the last action.\n *\n * @fires UndoStack#redo\n */\n redo() {\n this.#undoStack.redo();\n }\n\n /**\n * Get the undo stack size.\n *\n * @returns {number} The size of the stack.\n */\n getStackSize() {\n return this.#undoStack.getStackSize();\n }\n\n /**\n * Get the current undo stack index.\n *\n * @returns {number} The stack index.\n */\n getCurrentStackIndex() {\n return this.#undoStack.getCurrentStackIndex();\n }\n\n /**\n * Get the overlay data for a data id.\n *\n * @param {string} dataId The data id.\n * @returns {OverlayData|undefined} The overlay data.\n */\n getOverlayData(dataId) {\n let data;\n if (typeof this.#overlayDatas !== 'undefined') {\n data = this.#overlayDatas[dataId];\n }\n return data;\n }\n\n /**\n * Toggle overlay listeners.\n *\n * @param {string} dataId The data id.\n */\n toggleOverlayListeners(dataId) {\n const data = this.getOverlayData(dataId);\n if (typeof data !== 'undefined') {\n if (data.isListening()) {\n data.removeAppListeners();\n } else {\n data.addAppListeners();\n }\n }\n }\n\n /**\n * Create new annotation data based on the data of\n * the active view layer.\n *\n * @param {string} refDataId The reference data id.\n * @returns {DicomData} The new data.\n */\n createAnnotationData(refDataId) {\n const refData = this.getData(refDataId);\n const refMeta = refData.image.getMeta();\n\n const data = new DicomData({});\n data.annotationGroup = new AnnotationGroup();\n data.annotationGroup.setMetaValue('Modality', 'SR');\n data.annotationGroup.setMetaValue(\n 'PatientID', refMeta.PatientID);\n data.annotationGroup.setMetaValue(\n 'StudyInstanceUID', refMeta.StudyInstanceUID);\n data.annotationGroup.setMetaValue(\n 'ReferencedSeriesSequence', {\n value: [{\n SeriesInstanceUID: refMeta.SeriesInstanceUID\n }]\n });\n return data;\n }\n\n /**\n * Add new data and render it with a simple new data view config.\n *\n * @param {DicomData} data The data to add.\n * @param {string} divId The div where to draw.\n * @param {string} refDataId The reference data id.\n */\n addAndRenderAnnotationData(data, divId, refDataId) {\n // add new data\n const dataId = this.addData(data);\n // add data view config based on reference data\n const refDataViewConfigs = this.getViewConfigs(refDataId);\n const refDataViewConfig = refDataViewConfigs.find(\n element => element.divId === divId);\n if (typeof refDataViewConfig === 'undefined') {\n throw new Error('No reference data view config for draw');\n }\n const drawDataViewConfig = new ViewConfig(divId);\n drawDataViewConfig.orientation = refDataViewConfig.orientation;\n this.addDataViewConfig(dataId, drawDataViewConfig);\n // render (will create draw layer)\n this.render(dataId);\n }\n\n // Private Methods -----------------------------------------------------------\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n /**\n * Data load start callback.\n *\n * @param {object} event The load start event.\n */\n #onloadstart = (event) => {\n // create overlay data\n if (typeof this.#options.overlayConfig !== 'undefined') {\n this.#overlayDatas[event.dataid] = new OverlayData(\n this, event.dataid, this.#options.overlayConfig);\n }\n /**\n * Load start event.\n *\n * @event App#loadstart\n * @type {object}\n * @property {string} type The event type: loadstart.\n * @property {string} loadType The load type: image or state.\n * @property {*} source The load source: string for an url,\n * File for a file.\n */\n event.type = 'loadstart';\n this.#fireEvent(event);\n };\n\n /**\n * Data load progress callback.\n *\n * @param {object} event The progress event.\n */\n #onloadprogress = (event) => {\n /**\n * Load progress event.\n *\n * @event App#loadprogress\n * @type {object}\n * @property {string} type The event type: loadprogress.\n * @property {string} loadType The load type: image or state.\n * @property {*} source The load source: string for an url,\n * File for a file.\n * @property {number} loaded The loaded percentage.\n * @property {number} total The total percentage.\n */\n event.type = 'loadprogress';\n this.#fireEvent(event);\n };\n\n /**\n * Data load callback.\n *\n * @param {object} event The load event.\n */\n #onloaditem = (event) => {\n // check event\n if (typeof event.data === 'undefined') {\n logger.error('Missing loaditem event data.');\n }\n if (typeof event.loadtype === 'undefined') {\n logger.error('Missing loaditem event load type.');\n }\n\n const isFirstLoadItem = event.isfirstitem;\n\n let eventMetaData = null;\n if (event.loadtype === 'image') {\n if (isFirstLoadItem) {\n this.#dataController.add(event.dataid, event.data);\n } else {\n this.#dataController.update(event.dataid, event.data);\n }\n eventMetaData = event.data.meta;\n } else if (event.loadtype === 'state') {\n this.applyJsonState(event.data, event.dataid);\n eventMetaData = 'state';\n }\n\n /**\n * Load item event: fired when a load item is successfull.\n *\n * @event App#loaditem\n * @type {object}\n * @property {string} type The event type.\n * @property {string} loadType The load type: image or state.\n * @property {*} source The load source: string for an url,\n * File for a file.\n * @property {object} data The loaded meta data.\n */\n this.#fireEvent({\n type: 'loaditem',\n data: eventMetaData,\n source: event.source,\n loadtype: event.loadtype,\n dataid: event.dataid,\n isfirstitem: event.isfirstitem,\n warn: event.warn\n });\n\n // update overlay data if present\n if (typeof this.#overlayDatas !== 'undefined' &&\n typeof this.#overlayDatas[event.dataid] !== 'undefined') {\n this.#overlayDatas[event.dataid].addItemMeta(eventMetaData);\n }\n\n // render if first and flag allows\n if (event.loadtype === 'image' &&\n this.getViewConfigs(event.dataid).length !== 0 &&\n isFirstLoadItem && this.#options.viewOnFirstLoadItem) {\n this.render(event.dataid);\n }\n };\n\n /**\n * Data load callback.\n *\n * @param {object} event The load event.\n */\n #onload = (event) => {\n /**\n * Load event: fired when a load finishes successfully.\n *\n * @event App#load\n * @type {object}\n * @property {string} type The event type: load.\n * @property {string} loadType The load type: image or state.\n */\n event.type = 'load';\n this.#fireEvent(event);\n };\n\n /**\n * Data load end callback.\n *\n * @param {object} event The load end event.\n */\n #onloadend = (event) => {\n /**\n * Main load end event: fired when the load finishes,\n * successfully or not.\n *\n * @event App#loadend\n * @type {object}\n * @property {string} type The event type: loadend.\n * @property {string} loadType The load type: image or state.\n * @property {*} source The load source: string for an url,\n * File for a file.\n */\n event.type = 'loadend';\n this.#fireEvent(event);\n };\n\n /**\n * Data load error callback.\n *\n * @param {object} event The error event.\n */\n #onloaderror = (event) => {\n /**\n * Load error event.\n *\n * @event App#error\n * @type {object}\n * @property {string} type The event type: error.\n * @property {string} loadType The load type: image or state.\n * @property {*} source The load source: string for an url,\n * File for a file.\n * @property {object} error The error.\n * @property {object} target The event target.\n */\n if (typeof event.type === 'undefined') {\n event.type = 'error';\n }\n this.#fireEvent(event);\n };\n\n /**\n * Data load abort callback.\n *\n * @param {object} event The abort event.\n */\n #onloadabort = (event) => {\n /**\n * Load abort event.\n *\n * @event App#abort\n * @type {object}\n * @property {string} type The event type: abort.\n * @property {string} loadType The load type: image or state.\n * @property {*} source The load source: string for an url,\n * File for a file.\n */\n if (typeof event.type === 'undefined') {\n event.type = 'abort';\n }\n this.#fireEvent(event);\n };\n\n /**\n * Bind layer group events to app.\n *\n * @param {LayerGroup} group The layer group.\n */\n #bindLayerGroupToApp(group) {\n // propagate layer group events\n group.addEventListener('zoomchange', this.#fireEvent);\n group.addEventListener('offsetchange', this.#fireEvent);\n // propagate viewLayer events\n group.addEventListener('renderstart', this.#fireEvent);\n group.addEventListener('renderend', this.#fireEvent);\n // propagate view events\n for (let j = 0; j < viewEventNames.length; ++j) {\n group.addEventListener(viewEventNames[j], this.#fireEvent);\n }\n // propagate drawLayer events\n if (this.#toolboxController && this.#toolboxController.hasTool('Draw')) {\n group.addEventListener('drawcreate', this.#fireEvent);\n group.addEventListener('drawdelete', this.#fireEvent);\n }\n // updata data view config\n group.addEventListener('wlchange', (event) => {\n const layerDetails = getLayerDetailsFromLayerDivId(event.srclayerid);\n const groupId = layerDetails.groupDivId;\n const config = this.getViewConfig(event.dataid, groupId, true);\n if (typeof config !== 'undefined') {\n // reset previous values\n config.windowCenter = undefined;\n config.windowWidth = undefined;\n config.wlPresetName = undefined;\n // window width, center and name\n if (event.value.length === 3) {\n config.windowCenter = event.value[0];\n config.windowWidth = event.value[1];\n config.wlPresetName = event.value[2];\n }\n }\n });\n group.addEventListener('opacitychange', (event) => {\n const layerDetails = getLayerDetailsFromLayerDivId(event.srclayerid);\n const groupId = layerDetails.groupDivId;\n const config = this.getViewConfig(event.dataid, groupId, true);\n if (typeof config !== 'undefined') {\n config.opacity = event.value[0];\n }\n });\n group.addEventListener('colourmapchange', (event) => {\n const layerDetails = getLayerDetailsFromLayerDivId(event.srclayerid);\n const groupId = layerDetails.groupDivId;\n const config = this.getViewConfig(event.dataid, groupId, true);\n if (typeof config !== 'undefined') {\n config.colourMap = event.value[0];\n }\n });\n }\n\n /**\n * Add a view layer.\n *\n * @param {string} dataId The data id.\n * @param {ViewConfig} viewConfig The data view config.\n */\n #addViewLayer(dataId, viewConfig) {\n const data = this.#dataController.get(dataId);\n if (!data) {\n throw new Error('Cannot initialise layer with missing data, id: ' +\n dataId);\n }\n const layerGroup = this.#stage.getLayerGroupByDivId(viewConfig.divId);\n if (!layerGroup) {\n throw new Error('Cannot initialise layer with missing group, id: ' +\n viewConfig.divId);\n }\n const imageGeometry = data.image.getGeometry();\n\n // un-bind\n this.#stage.unbindLayerGroups();\n\n // create and setup view\n const viewFactory = new ViewFactory();\n const view = viewFactory.create(data.meta, data.image);\n const viewOrientation = getViewOrientation(\n imageGeometry.getOrientation(),\n getMatrixFromName(viewConfig.orientation)\n );\n view.setOrientation(viewOrientation);\n\n // make pixel of value 0 transparent for segmentation\n // (assuming RGB data)\n if (data.image.getMeta().Modality === 'SEG') {\n view.setAlphaFunction(function (value /*, index*/) {\n if (value === 0) {\n return 0;\n } else {\n return 0xff;\n }\n });\n }\n\n // do we have more than one layer\n // (the layer has not been added to the layer group yet)\n const isBaseLayer = layerGroup.getNumberOfViewLayers() === 0;\n\n // opacity\n let opacity = 1;\n if (typeof viewConfig.opacity !== 'undefined') {\n opacity = viewConfig.opacity;\n } else {\n if (!isBaseLayer) {\n opacity = 0.5;\n }\n }\n\n // view layer\n const viewLayer = layerGroup.addViewLayer();\n viewLayer.setView(view, dataId);\n const size2D = imageGeometry.getSize(viewOrientation).get2D();\n const spacing2D = imageGeometry.getSpacing(viewOrientation).get2D();\n viewLayer.initialise(size2D, spacing2D, opacity);\n\n // view controller\n const viewController = viewLayer.getViewController();\n // window/level\n if (typeof viewConfig.wlPresetName !== 'undefined') {\n viewController.setWindowLevelPreset(viewConfig.wlPresetName);\n } else if (typeof viewConfig.windowCenter !== 'undefined' &&\n typeof viewConfig.windowWidth !== 'undefined') {\n const wl = new WindowLevel(\n viewConfig.windowCenter, viewConfig.windowWidth);\n viewController.setWindowLevel(wl);\n }\n // colour map\n if (typeof viewConfig.colourMap !== 'undefined') {\n viewController.setColourMap(viewConfig.colourMap);\n } else {\n if (!isBaseLayer) {\n if (data.image.getMeta().Modality === 'PT') {\n viewController.setColourMap('hot');\n } else {\n viewController.setColourMap('rainbow');\n }\n }\n }\n\n // listen to image set\n this.#dataController.addEventListener(\n 'dataimageset', viewLayer.onimageset);\n\n // sync layers position\n const value = [\n viewController.getCurrentIndex().getValues(),\n viewController.getCurrentPosition().getValues()\n ];\n layerGroup.updateLayersToPositionChange({\n value: value,\n srclayerid: viewLayer.getId()\n });\n\n // sync layer groups\n this.#stage.fitToContainer();\n\n // layer offset (done before scale)\n viewLayer.setOffset(layerGroup.getOffset());\n\n // get and apply flip flags\n const flipFlags = this.#getViewFlipFlags(\n imageGeometry.getOrientation(),\n viewConfig.orientation);\n this.#applyFlipFlags(flipFlags, viewLayer);\n\n // layer scale (done after possible flip)\n if (!isBaseLayer) {\n // use zoom offset of base layer\n const baseViewLayer = layerGroup.getBaseViewLayer();\n viewLayer.initScale(\n layerGroup.getScale(),\n baseViewLayer.getAbsoluteZoomOffset()\n );\n } else {\n viewLayer.setScale(layerGroup.getScale());\n }\n\n // bind\n this.#stage.bindLayerGroups();\n if (this.#toolboxController) {\n this.#toolboxController.bindLayerGroup(layerGroup, viewLayer);\n }\n\n /**\n * Add view layer event.\n *\n * @event App#viewlayeradd\n * @type {object}\n * @property {string} type The event type.\n * @property {string} layerid The layer id.\n * @property {string} layergroupid The layer group id.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'viewlayeradd',\n layerid: viewLayer.getId(),\n layergroupid: layerGroup.getDivId(),\n dataid: dataId\n });\n\n // initialise the toolbox for base\n if (isBaseLayer) {\n if (this.#toolboxController) {\n this.#toolboxController.init();\n }\n }\n }\n\n /**\n * Add a draw layer.\n *\n * @param {string} dataId The data id.\n * @param {ViewConfig} viewConfig The data view config.\n */\n addDrawLayer(dataId, viewConfig) {\n const layerGroup = this.#stage.getLayerGroupByDivId(viewConfig.divId);\n if (!layerGroup) {\n throw new Error('Cannot initialise layer with missing group, id: ' +\n viewConfig.divId);\n }\n\n // reference is the data of the view layer with the\n // same StudyInstanceUID\n const data = this.#dataController.get(dataId);\n if (!data) {\n throw new Error('Cannot initialise layer with missing data, id: ' +\n dataId);\n }\n const refSeriesSeq =\n data.annotationGroup.getMetaValue('ReferencedSeriesSequence');\n const refSeriesInstanceUID = refSeriesSeq.value[0].SeriesInstanceUID;\n const viewLayers = layerGroup.searchViewLayers({\n SeriesInstanceUID: refSeriesInstanceUID\n });\n if (viewLayers.length === 0) {\n console.warn(\n 'No loaded data that matches the measurement reference series UID');\n return;\n }\n const refViewLayer = viewLayers[0];\n const refDataId = refViewLayer.getDataId();\n\n // un-bind\n this.#stage.unbindLayerGroups();\n\n // set annotation view controller (allows quantification)\n const refViewController = refViewLayer.getViewController();\n data.annotationGroup.setViewController(refViewController);\n\n // reference data to use as base for layer properties\n const refData = this.#dataController.get(refDataId);\n if (!refData) {\n throw new Error(\n 'Cannot initialise layer without reference data, id: ' +\n refDataId);\n }\n const imageGeometry = refData.image.getGeometry();\n\n const viewOrientation = getViewOrientation(\n imageGeometry.getOrientation(),\n getMatrixFromName(viewConfig.orientation)\n );\n const size2D = imageGeometry.getSize(viewOrientation).get2D();\n const spacing2D = imageGeometry.getSpacing(viewOrientation).get2D();\n\n const drawLayer = layerGroup.addDrawLayer();\n drawLayer.initialise(size2D, spacing2D, refViewLayer.getId());\n\n const planeHelper = new PlaneHelper(\n imageGeometry,\n viewOrientation\n );\n drawLayer.setPlaneHelper(planeHelper);\n\n // sync layers position\n const value = [\n refViewController.getCurrentIndex().getValues(),\n refViewController.getCurrentPosition().getValues()\n ];\n layerGroup.updateLayersToPositionChange({\n value: value,\n srclayerid: drawLayer.getId()\n });\n\n // sync layer groups\n this.#stage.fitToContainer();\n\n // layer offset (done before scale)\n drawLayer.setOffset(layerGroup.getOffset());\n\n // get and apply flip flags\n const flipFlags = this.#getViewFlipFlags(\n imageGeometry.getOrientation(),\n viewConfig.orientation);\n this.#applyFlipFlags(flipFlags, drawLayer);\n\n // layer scale (done after possible flip)\n // use zoom offset of ref layer\n drawLayer.initScale(\n layerGroup.getScale(),\n refViewLayer.getAbsoluteZoomOffset()\n );\n\n // add possible existing data\n drawLayer.setAnnotationGroup(\n data.annotationGroup,\n dataId,\n this.addToUndoStack);\n\n drawLayer.setCurrentPosition(\n refViewController.getCurrentPosition(),\n refViewController.getCurrentIndex()\n );\n\n // bind\n this.#stage.bindLayerGroups();\n if (this.#toolboxController) {\n this.#toolboxController.bindLayerGroup(layerGroup, drawLayer);\n }\n\n /**\n * Add draw layer event.\n *\n * @event App#drawlayeradd\n * @type {object}\n * @property {string} type The event type.\n * @property {string} layerid The layer id.\n * @property {string} layergroupid The layer group id.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'drawlayeradd',\n layerid: drawLayer.getId(),\n layergroupid: layerGroup.getDivId(),\n dataid: dataId\n });\n }\n\n /**\n * Get the view flip flags: offset (x, y) and scale (x, y, z) flags.\n *\n * @param {Matrix33} imageOrientation The image orientation.\n * @param {string} viewConfigOrientation The view config orientation.\n * @returns {object} Offset and scale flip flags.\n */\n #getViewFlipFlags(imageOrientation, viewConfigOrientation) {\n // 'simple' orientation code (does not take into account angles)\n const orientationCode =\n getOrientationStringLPS(imageOrientation.asOneAndZeros());\n if (typeof orientationCode === 'undefined') {\n throw new Error('Unsupported undefined orientation code');\n }\n\n // view orientation flags\n const isViewUndefined = typeof viewConfigOrientation === 'undefined';\n const isViewAxial = !isViewUndefined &&\n viewConfigOrientation === Orientation.Axial;\n const isViewCoronal = !isViewUndefined &&\n viewConfigOrientation === Orientation.Coronal;\n const isViewSagittal = !isViewUndefined &&\n viewConfigOrientation === Orientation.Sagittal;\n\n // default flags\n const flipOffset = {\n x: false,\n y: false\n };\n const flipScale = {\n x: false,\n y: false,\n z: false\n };\n\n if (orientationCode === 'LPS') {\n // axial\n if (isViewCoronal || isViewSagittal) {\n flipScale.z = true;\n flipOffset.y = true;\n }\n } else if (orientationCode === 'LAI') {\n // axial\n if (isViewUndefined || isViewAxial) {\n flipOffset.y = true;\n } else if (isViewCoronal) {\n flipScale.z = true;\n } else if (isViewSagittal) {\n flipScale.z = true;\n flipOffset.x = true;\n }\n } else if (orientationCode === 'RPI') {\n // axial\n if (isViewUndefined || isViewAxial) {\n flipOffset.x = true;\n } else if (isViewCoronal) {\n flipScale.z = true;\n flipOffset.x = true;\n } else if (isViewSagittal) {\n flipScale.z = true;\n }\n } else if (orientationCode === 'RAS') {\n // axial\n flipOffset.x = true;\n flipOffset.y = true;\n if (isViewCoronal || isViewSagittal) {\n flipScale.z = true;\n }\n } else if (orientationCode === 'LSA') {\n // coronal\n flipOffset.y = true;\n if (isViewUndefined || isViewCoronal) {\n flipScale.z = true;\n } else if (isViewAxial) {\n flipScale.y = true;\n } else if (isViewSagittal) {\n flipOffset.x = true;\n flipScale.y = true;\n flipScale.z = true;\n }\n // } else if (orientationCode === 'LIP') { // nothing to do\n } else if (orientationCode === 'RSP') {\n // coronal\n if (isViewUndefined || isViewCoronal) {\n flipOffset.x = true;\n flipOffset.y = true;\n flipScale.x = true;\n flipScale.z = true;\n } else if (isViewAxial) {\n flipOffset.x = true;\n flipScale.x = true;\n } else if (isViewSagittal) {\n flipOffset.y = true;\n flipScale.z = true;\n }\n } else if (orientationCode === 'RIA') {\n // coronal\n flipOffset.x = true;\n if (isViewUndefined || isViewCoronal) {\n flipScale.x = true;\n } else if (isViewAxial) {\n flipOffset.y = true;\n flipScale.x = true;\n flipScale.y = true;\n } else if (isViewSagittal) {\n flipScale.y = true;\n }\n } else if (orientationCode === 'PSL') {\n // sagittal\n flipScale.z = true;\n if (isViewUndefined || isViewSagittal) {\n flipOffset.y = true;\n } else if (isViewCoronal) {\n flipOffset.y = true;\n }\n } else if (orientationCode === 'PIR') {\n // sagittal\n flipScale.z = true;\n if (isViewAxial || isViewCoronal) {\n flipOffset.x = true;\n }\n } else if (orientationCode === 'ASR') {\n // sagittal\n flipOffset.x = true;\n flipOffset.y = true;\n if (isViewUndefined || isViewSagittal) {\n flipScale.z = true;\n } else if (isViewCoronal) {\n flipScale.z = true;\n }\n } else if (orientationCode === 'AIL') {\n // sagittal\n if (isViewUndefined || isViewSagittal) {\n flipOffset.x = true;\n flipScale.z = true;\n } else if (isViewAxial) {\n flipOffset.y = true;\n } else if (isViewCoronal) {\n flipScale.z = true;\n }\n } else {\n logger.warn('Unsupported orientation code: ' +\n orientationCode + ', display could be incorrect');\n }\n\n return {\n scale: flipScale,\n offset: flipOffset\n };\n }\n\n #applyFlipFlags(flipFlags, layer) {\n if (flipFlags.offset.x) {\n layer.addFlipOffsetX();\n }\n if (flipFlags.offset.y) {\n layer.addFlipOffsetY();\n }\n if (flipFlags.scale.x) {\n layer.flipScaleX();\n }\n if (flipFlags.scale.y) {\n layer.flipScaleY();\n }\n if (flipFlags.scale.z) {\n layer.flipScaleZ();\n }\n }\n\n} // class App\n","import {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {MaskSegment} from '../dicom/dicomSegment';\n/* eslint-enable no-unused-vars */\n\n/**\n * Mask segment helper: helps handling the segments list,\n * but does *NOT* update the associated mask (use special commands\n * for that such as DeleteSegmentCommand, ChangeSegmentColourCommand...).\n */\nexport class MaskSegmentHelper {\n\n /**\n * The associated mask.\n *\n * @type {Image}\n */\n #mask;\n\n /**\n * The segments: array of segment description.\n *\n * @type {MaskSegment[]}\n */\n #segments;\n\n /**\n * @param {Image} mask The associated mask image.\n */\n constructor(mask) {\n this.#mask = mask;\n // check segments in meta\n const meta = mask.getMeta();\n if (typeof meta.custom === 'undefined') {\n meta.custom = {};\n }\n if (typeof meta.custom.segments === 'undefined') {\n meta.custom.segments = [];\n }\n this.#segments = meta.custom.segments;\n }\n\n /**\n * Find the index of a segment in the segments list.\n *\n * @param {number} segmentNumber The number to find.\n * @returns {number} The index in the segments list, -1 if not found.\n */\n #findSegmentIndex(segmentNumber) {\n return this.#segments.findIndex(function (item) {\n return item.number === segmentNumber;\n });\n }\n\n /**\n * Check if a segment is part of the segments list.\n *\n * @param {number} segmentNumber The segment number.\n * @returns {boolean} True if the segment is included.\n */\n hasSegment(segmentNumber) {\n return this.#findSegmentIndex(segmentNumber) !== -1;\n }\n\n /**\n * Get the number of segments of the segmentation.\n *\n * @returns {number} The number of segments.\n */\n getNumberOfSegments() {\n return this.#segments.length;\n }\n\n /**\n * Check if a segment is present in a mask image.\n *\n * @param {number[]} numbers Array of segment numbers.\n * @returns {boolean[]} Array of boolean set to true\n * if the segment is present in the mask.\n */\n maskHasSegments(numbers) {\n // create values using displayValue\n const values = [];\n const unknowns = [];\n for (let i = 0; i < numbers.length; ++i) {\n const segment = this.getSegment(numbers[i]);\n if (typeof segment !== 'undefined') {\n if (typeof segment.displayValue !== 'undefined') {\n values.push(segment.displayValue);\n } else {\n values.push(segment.displayRGBValue);\n }\n } else {\n logger.warn('Unknown segment in maskHasSegments: ' + numbers[i]);\n unknowns.push(i);\n }\n }\n const res = this.#mask.hasValues(values);\n // insert unknowns as false in result\n for (let j = 0; j < unknowns.length; ++j) {\n res.splice(unknowns[j], 0, false);\n }\n return res;\n }\n\n /**\n * Get a segment from the inner segment list.\n *\n * @param {number} segmentNumber The segment number.\n * @returns {MaskSegment|undefined} The segment or undefined if not found.\n */\n getSegment(segmentNumber) {\n let segment;\n const index = this.#findSegmentIndex(segmentNumber);\n if (index !== -1) {\n segment = this.#segments[index];\n }\n return segment;\n }\n\n /**\n * Add a segment to the segments list.\n *\n * @param {MaskSegment} segment The segment to add.\n */\n addSegment(segment) {\n const index = this.#findSegmentIndex(segment.number);\n if (index === -1) {\n this.#segments.push(segment);\n // update palette colour map\n if (typeof segment.displayRGBValue !== 'undefined') {\n this.#mask.updatePaletteColourMap(\n segment.number, segment.displayRGBValue);\n }\n } else {\n logger.warn(\n 'Not adding segment, it is allready in the segments list: ' +\n segment.number);\n }\n }\n\n /**\n * Remove a segment from the segments list.\n *\n * @param {number} segmentNumber The segment number.\n */\n removeSegment(segmentNumber) {\n const index = this.#findSegmentIndex(segmentNumber);\n if (index !== -1) {\n this.#segments.splice(index, 1);\n } else {\n logger.warn(\n 'Cannot remove segment, it is not in the segments list: ' +\n segmentNumber);\n }\n }\n\n /**\n * Update a segment of the segments list.\n *\n * @param {MaskSegment} segment The segment to update.\n */\n updateSegment(segment) {\n const index = this.#findSegmentIndex(segment.number);\n if (index !== -1) {\n this.#segments[index] = segment;\n } else {\n logger.warn(\n 'Cannot update segment, it is not in the segments list: ' +\n segment.number);\n }\n }\n\n} // class MaskSegmentHelper\n","import {MaskSegmentHelper} from './maskSegmentHelper';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {MaskSegment} from '../dicom/dicomSegment';\n/* eslint-enable no-unused-vars */\n\n/**\n * Delete segment command.\n */\nexport class DeleteSegmentCommand {\n\n /**\n * The associated mask.\n *\n * @type {Image}\n */\n #mask;\n\n /**\n * The segment to remove.\n *\n * @type {MaskSegment}\n */\n #segment;\n\n /**\n * Flag to send creation events.\n *\n * @type {boolean}\n */\n #isSilent;\n\n /**\n * List of offsets.\n *\n * @type {number[]}\n */\n #offsets;\n\n /**\n * @param {Image} mask The mask image.\n * @param {MaskSegment} segment The segment to remove.\n * @param {boolean} [silent] Whether to send a creation event or not.\n */\n constructor(mask, segment, silent) {\n this.#mask = mask;\n this.#segment = segment;\n this.#isSilent = (typeof silent === 'undefined') ? false : silent;\n // list of offsets with the colour to delete\n if (typeof segment.displayRGBValue !== 'undefined') {\n this.#offsets = mask.getOffsets(segment.number);\n } else {\n this.#offsets = mask.getOffsets(segment.displayValue);\n }\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'Delete-segment';\n }\n\n /**\n * Check if a command is valid and can be executed.\n *\n * @returns {boolean} True if the command is valid.\n */\n isValid() {\n // check that input segment is still there\n const segments = this.#mask.getMeta().custom.segments;\n return segments.some(segmentItem =>\n segmentItem.number === this.#segment.number\n );\n }\n\n /**\n * Execute the command.\n *\n * @fires DeleteSegmentCommand#masksegmentdelete\n */\n execute() {\n if (this.#offsets.length !== 0) {\n // remove from image\n this.#mask.setAtOffsets(this.#offsets, 0);\n }\n\n // remove from segments\n const segHelper = new MaskSegmentHelper(this.#mask);\n segHelper.removeSegment(this.#segment.number);\n\n // callback\n if (!this.#isSilent) {\n /**\n * Segment delete event.\n *\n * @event DeleteSegmentCommand#masksegmentdelete\n * @type {object}\n * @property {number} segmentnumber The segment number.\n */\n this.onExecute({\n type: 'masksegmentdelete',\n segmentnumber: this.#segment.number\n });\n }\n }\n\n /**\n * Undo the command.\n *\n * @fires DeleteSegmentCommand#masksegmentredraw\n */\n undo() {\n if (this.#offsets.length !== 0) {\n // re-draw in image\n if (typeof this.#segment.displayRGBValue !== 'undefined') {\n this.#mask.setAtOffsets(this.#offsets, this.#segment.number);\n } else {\n this.#mask.setAtOffsets(this.#offsets, this.#segment.displayValue);\n }\n }\n // add back to segments\n const segHelper = new MaskSegmentHelper(this.#mask);\n segHelper.addSegment(this.#segment);\n\n // callback\n /**\n * Segment redraw event.\n *\n * @event DeleteSegmentCommand#masksegmentredraw\n * @type {object}\n * @property {number} segmentnumber The segment number.\n */\n this.onUndo({\n type: 'masksegmentredraw',\n segmentnumber: this.#segment.number\n });\n }\n\n /**\n * Handle an execute event.\n *\n * @param {object} _event The execute event with type and id.\n */\n onExecute(_event) {\n // default does nothing.\n }\n\n /**\n * Handle an undo event.\n *\n * @param {object} _event The undo event with type and id.\n */\n onUndo(_event) {\n // default does nothing.\n }\n\n} // DeleteSegmentCommand class\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {MaskSegment} from '../dicom/dicomSegment';\nimport {RGB} from '../utils/colour';\n/* eslint-enable no-unused-vars */\n\n/**\n * Change segment colour command.\n */\nexport class ChangeSegmentColourCommand {\n\n /**\n * The associated mask.\n *\n * @type {Image}\n */\n #mask;\n\n /**\n * The segment to modify.\n *\n * @type {MaskSegment}\n */\n #segment;\n\n /**\n * The new segment colour.\n *\n * @type {RGB|number}\n */\n #newColour;\n\n /**\n * The previous segment colour.\n *\n * @type {RGB|number}\n */\n #previousColour;\n\n /**\n * Flag to send creation events.\n *\n * @type {boolean}\n */\n #isSilent;\n\n /**\n * List of offsets.\n *\n * @type {number[]}\n */\n #offsets;\n\n /**\n * @param {Image} mask The mask image.\n * @param {MaskSegment} segment The segment to modify.\n * @param {RGB|number} newColour The new segment colour.\n * @param {boolean} [silent] Whether to send a creation event or not.\n */\n constructor(mask, segment, newColour, silent) {\n this.#mask = mask;\n this.#segment = segment;\n this.#newColour = newColour;\n\n this.#isSilent = (typeof silent === 'undefined') ? false : silent;\n // list of offsets with the colour to delete\n if (typeof segment.displayRGBValue !== 'undefined') {\n this.#previousColour = segment.displayRGBValue;\n } else {\n this.#previousColour = segment.displayValue;\n this.#offsets = mask.getOffsets(this.#previousColour);\n }\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'Change-segment-colour';\n }\n\n /**\n * Check if a command is valid and can be executed.\n *\n * @returns {boolean} True if the command is valid.\n */\n isValid() {\n let valid = true;\n if (typeof this.#offsets !== 'undefined') {\n valid = this.#offsets.length !== 0;\n }\n return valid;\n }\n\n /**\n * Execute the command.\n *\n * @fires ChangeSegmentColourCommand#changemasksegmentcolour\n */\n execute() {\n // update segment property\n if (typeof this.#newColour === 'number') {\n // remove\n this.#mask.setAtOffsets(this.#offsets, this.#newColour);\n // update segment\n this.#segment.displayValue = this.#newColour;\n } else {\n // update palette colour map (sends update event)\n this.#mask.updatePaletteColourMap(\n this.#segment.number,\n this.#newColour\n );\n // update segment\n this.#segment.displayRGBValue = this.#newColour;\n }\n\n // callback\n if (!this.#isSilent) {\n /**\n * Segment delete event.\n *\n * @event ChangeSegmentColourCommand#changemasksegmentcolour\n * @type {object}\n * @property {number} segmentnumber The segment number.\n */\n this.onExecute({\n type: 'changemasksegmentcolour',\n segmentnumber: this.#segment.number,\n value: [this.#newColour]\n });\n }\n }\n\n /**\n * Undo the command.\n *\n * @fires ChangeSegmentColourCommand#changemasksegmentcolour\n */\n undo() {\n // update segment property\n if (typeof this.#previousColour === 'number') {\n // update values\n this.#mask.setAtOffsets(this.#offsets, this.#previousColour);\n // update segment\n this.#segment.displayValue = this.#previousColour;\n } else {\n // update palette colour map (sends update event)\n this.#mask.updatePaletteColourMap(\n this.#segment.number,\n this.#previousColour\n );\n // udpate segment\n this.#segment.displayRGBValue = this.#previousColour;\n }\n\n // callback\n /**\n * Segment redraw event.\n *\n * @event ChangeSegmentColourCommand#changemasksegmentcolour\n * @type {object}\n * @property {number} segmentnumber The segment number.\n */\n this.onUndo({\n type: 'changemasksegmentcolour',\n segmentnumber: this.#segment.number,\n value: [this.#previousColour]\n });\n }\n\n /**\n * Handle an execute event.\n *\n * @param {object} _event The execute event with type and id.\n */\n onExecute(_event) {\n // default does nothing.\n }\n\n /**\n * Handle an undo event.\n *\n * @param {object} _event The undo event with type and id.\n */\n onUndo(_event) {\n // default does nothing.\n }\n\n} // ChangeSegmentColourCommand class\n","import {logger} from '../utils/logger';\n\n/**\n * Mask segment view helper: handles hidden segments.\n */\nexport class MaskSegmentViewHelper {\n\n /**\n * List of hidden segment numbers.\n *\n * @type {number[]}\n */\n #hiddenNumbers = [];\n\n /**\n * Get the index of a segment in the hidden list.\n *\n * @param {number} segmentNumber The segment number.\n * @returns {number} The index in the array, -1 if not found.\n */\n #findHiddenIndex(segmentNumber) {\n return this.#hiddenNumbers.indexOf(segmentNumber);\n }\n\n /**\n * Check if a segment is in the hidden list.\n *\n * @param {number} segmentNumber The segment number.\n * @returns {boolean} True if the segment is in the list.\n */\n isHidden(segmentNumber) {\n return this.#findHiddenIndex(segmentNumber) !== -1;\n }\n\n /**\n * Add a segment to the hidden list.\n *\n * @param {number} segmentNumber The segment number.\n */\n addToHidden(segmentNumber) {\n if (!this.isHidden(segmentNumber)) {\n this.#hiddenNumbers.push(segmentNumber);\n } else {\n logger.warn(\n 'Not hidding segment, it is allready in the hidden list: ' +\n segmentNumber);\n }\n }\n\n /**\n * Remove a segment from the hidden list.\n *\n * @param {number} segmentNumber The segment number.\n */\n removeFromHidden(segmentNumber) {\n const index = this.#findHiddenIndex(segmentNumber);\n if (index !== -1) {\n this.#hiddenNumbers.splice(index, 1);\n } else {\n logger.warn(\n 'Cannot remove segment, it is not in the hidden list: ' +\n segmentNumber);\n }\n }\n\n /**\n * @callback alphaFn\n * @param {number|number[]} value The pixel value.\n * @param {number} index The values' index.\n * @returns {number} The opacity of the input value.\n */\n\n /**\n * Get the alpha function to apply hidden colors.\n *\n * @returns {alphaFn} The corresponding alpha function.\n */\n getAlphaFunc() {\n // create alpha function\n // (zero is hidden by default)\n return (value/*, index*/) => {\n if (!Array.isArray(value) && (\n value === 0 ||\n this.#hiddenNumbers.includes(value))) {\n return 0;\n }\n // default\n return 255;\n };\n }\n}","/**\n * Mutable 2D scalar ({x,y}).\n */\nexport class Scalar2D {\n /**\n * X value.\n *\n * @type {number}\n */\n x;\n\n /**\n * Y value.\n *\n * @type {number}\n */\n y;\n}\n\n/**\n * Mutable 3D scalar ({x,y,z}).\n */\nexport class Scalar3D {\n /**\n * X value.\n *\n * @type {number}\n */\n x;\n\n /**\n * Y value.\n *\n * @type {number}\n */\n y;\n\n /**\n * Z value.\n *\n * @type {number}\n */\n z;\n}"],"names":["root","factory","exports","module","require","define","amd","this","__WEBPACK_EXTERNAL_MODULE__944__","__WEBPACK_EXTERNAL_MODULE__324__","__WEBPACK_EXTERNAL_MODULE__654__","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","n","getter","__esModule","d","a","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","r","Symbol","toStringTag","value","Index","constructor","values","Error","length","every","val","isNaN","i","toString","getValues","slice","canCompare","rhs","equals","leni","compare","diffDims","push","add","getWithNew2D","j","l","lenl","ModalityLut","rsi","bitsStored","isID","Math","pow","Float32Array","apply","getRSI","getLength","getValue","offset","logger","levels","TRACE","DEBUG","INFO","WARN","ERROR","level","trace","msg","console","debug","info","warn","error","WindowLevel","center","width","defaultPresets","CT","mediastinum","lung","bone","brain","head","VoiLut","wl","getWindowLevel","c","setSignedOffset","WindowLut","modalityLut","isSigned","isDiscrete","size","getVoiLut","getModalityLut","setVoiLut","lut","getSlope","Uint8ClampedArray","floor","buildLut","func","id","invId","lut_range_max","ColourMap","red","green","blue","luts","plain","invPlain","rainbow","hot","third","hot_iron","pet","hot_metal_blue","pet_20step","RGB","g","b","isEqualRgb","c1","c2","labToUintLab","triplet","d65","x","y","z","srgbToCielab","labFunc","res","illuminant","fy","ciexyzToCielab","invGammaFunc","rl","gl","bl","srgbToCiexyz","colourNameToHex","name","dict","Yellow","Red","White","Green","Blue","Lime","Fuchsia","Black","Vector3D","getX","getY","getZ","norm","sqrt","crossProduct","vector3D","dotProduct","isCodirectional","Number","EPSILON","REAL_WORLD_EPSILON","isSimilar","tol","abs","Matrix33","row","col","getInverse","m","m00","m01","m02","m10","m11","m12","m20","m21","m22","a1212","a2012","a0112","det","getMatrixInverse","p","str","multiply","tmp","k","getAbs","multiplyArray3D","array3D","multiplyVector3D","multiplyPoint3D","point3D","Point3D","multiplyIndex3D","index3D","getRowAbsMax","absMax","max","index","indexOf","getColAbsMax","asOneAndZeros","sign","getThirdColMajorDirection","getIdentityMat33","isIdentityMat33","mat33","Point2D","getCentroid","getDistance","point2D","dx","dy","dz","getClosest","pointList","minIndex","minDist","dist","minus","Point","get3D","values0","values1","mergeWith3D","i18n","t","props","split","mm","cm2","degree","startsWith","search","rawPos","pos","substring","endsWith","getFlags","inputStr","flags","regex","match","exec","getFileExtension","filePath","ext","pathSplit","toLowerCase","pop","test","includes","stringToUint8Array","arr","Uint8Array","charCodeAt","precisionRound","number","precision","factor","delta","round","toStringId","dims","arraySortEquals","arr0","arr1","arrayEquals","sort","element","uint8ArrayToString","String","fromCharCode","findInArraySubset","callbackFn","start","end","getFindArrayInArrayCallback","buildMultipart","parts","boundary","lineBreak","partsSize","headers","headerStr","partKeys","keys","header","byteLength","data","trailer","buffer","set","dictionary","addTagsToDictionary","group","tags","tagGroups","vr32bitVL","OB","OD","OF","OL","OV","OW","SQ","SV","UC","UN","UR","UT","UV","ox","is32bitVLVR","vr","vrCharSetString","SH","LO","ST","LT","PN","isCharSetStringVR","vrTypes","AE","AS","AT","CS","DA","DS","DT","FL","FD","IS","SL","SS","TM","UI","UL","US","transferSyntaxes","transferSyntaxKeywords","Tag","getGroup","getElement","getKey","getNameFromDictionary","getGroupName","isWithVR","isPrivate","parseInt","getVrFromDictionary","tagCompareFunction","getTagFromKey","getItemTag","isItemTag","tag","isItemDelimitationItemTag","isSequenceDelimitationItemTag","getPixelDataTag","isPixelDataTag","getTagFromDictionary","tagName","keys0","keys1","foundTag","k0","lenK0","k1","lenK1","DataElement","vl","undefinedLength","startOffset","endOffset","items","flipArrayEndianness","array","blen","u8","byteOffset","bpe","BYTES_PER_ELEMENT","DataReader","Int8Array","Int16Array","isNativeLittleEndian","isLittleEndian","DataView","readUint16","getUint16","readInt16","getInt16","readUint32","getUint32","readBigUint64","getBigUint64","readInt32","getInt32","readBigInt64","getBigInt64","readFloat32","getFloat32","readFloat64","getFloat64","readBinaryArray","bitArray","byteArrayLength","bitNumber","bitIndex","readUint8Array","readInt8Array","readUint16Array","Uint16Array","arraySize","readInt16Array","readUint32Array","Uint32Array","readUint64Array","BigUint64Array","readInt32Array","Int32Array","readInt64Array","BigInt64Array","readFloat32Array","readFloat64Array","Float64Array","readHex","toUpperCase","getDwvVersion","hasDicomPrefix","reduce","previous","current","ZWS","DefaultTextDecoder","decode","result","getReverseOrientation","ori","rlabels","L","R","A","P","H","F","rori","isImplicitTransferSyntax","syntax","isBigEndianTransferSyntax","isJpegBaselineTransferSyntax","isJpegLosslessTransferSyntax","isJpeg2000TransferSyntax","isRleTransferSyntax","getTypedArray","bitsAllocated","pixelRepresentation","RangeError","powerOf2","log","getDataElementPrefixByteSize","isImplicit","TagKeys","DicomParser","getDefaultCharacterSet","setDefaultCharacterSet","characterSet","setDecoderCharacterSet","TextDecoder","getDicomElements","reader","implicit","itemData","item","isSeqDelim","isItemDelim","offsetTableVl","readTagRes","is32bitVL","concat","isKnownVR","pixItemData","sqEndOffset","vrType","Array","from","stream","lastIndex","trim","cleanString","raw","stri","stri1","sqBitsAllocated","sqPixelRepresentation","dataElement","subElement","elements","parse","metaReader","dataReader","magicword","metaEnd","tsElement","firstDataElement","oEightGroupLittleEndian","vr0","vr1","guessTransferSyntax","isReadSupportedTransferSyntax","getTransferSyntaxName","charSetTerm","label","getUtfLabel","numberOfFrames","pixItems","nItemPerFrame","newPixItems","f","newBuffer","fragOffset","ListenerHandler","type","callback","remove","nFound","splice","fireEvent","event","stack","range","dataAccessor","maxIter","increment","blockMaxIter","blockIncrement","reverse1","reverse2","nextIndex","finalBlockIncrement","mainCount","blockCount","next","done","getIteratorValues","iterator","ival","getSliceIterator","image","position","isRescaled","viewOrientation","getGeometry","getSize","dirMax2Index","posValues","posStart","map","indexToOffset","getRescaledValueAtOffset","getValueAtOffset","ncols","nrows","nslices","sliceSize","getDimSize","ncomp","getNumberOfComponents","isPlanar","getPlanarConfiguration","getRange","iters","r0","r1","r2","range3d","rangeObj","dirMax0","dirMax2","simpleRange","componentIncrement","nextIndex1","nextIndex2","simpleRange3d","valueRange","nextValueIndex","RescaleSlopeAndIntercept","slope","intercept","getIntercept","Size","moreThanOne","dimension","canScroll3D","canScroll","getTotalSize","isInBounds","dirs","offsetToIndex","off","dimSize","get2D","Statistics","min","mean","stdDev","median","p25","p75","getStats","includesFullStatsFlags","stats","getBasicStats","getPercentile","getFullStats","sum","sumSqr","variance","ratio","i0","v0","guid","random","NumberRange","Spacing","Geometry","origin","spacing","orientation","time","getInitialTime","getCurrentTotalNumberOfSlices","count","hasSlicesAtTime","getCurrentNumberOfSlicesBeforeTime","getOrigin","getOrigins","includesOrigin","getOrientedArray3D","geoSliceSpacing","origins","spacings","origin1","origin2","sliceSpacing","getSliceGeometrySpacing","getSpacing","orientedValues","getRealSpacing","getOrientation","getSliceIndex","point","localOrigins","closestOriginIndex","closestOrigin","pointDir","appendOrigin","equalToOrigin","find","appendFrame","sizeValues","spacingValues","isIndexInBounds","worldToIndex","indexToWorld","orientedPoint3D","pointToWorld","worldToPoint","getDeOrientedArray3D","padZeroTwoDigit","getDate","daValue","monthBeginIndex","dayBeginIndex","year","monthIndex","day","getTime","tmValue","tmHours","tmMinutes","tmSeconds","tmFracSecondsStr","hours","minutes","seconds","milliseconds","dateToDateObj","date","getFullYear","getMonth","dateToTimeObj","getHours","getMinutes","getSeconds","getDicomDate","dateObj","getDicomTime","getCoronalMat33","Orientation","Axial","Coronal","Sagittal","getMatrixFromName","matrix","getOrientationStringLPS","v1","v2","getVectorStringLPS","vector","orientationX","orientationY","orientationZ","threshold","getOrientationName","cosines","orientMatrix","getOrientationFromCosines","code","orientStr","getLPSGroup","orientationMatrix","rowCosines","colCosines","normal","getViewOrientation","imageOrientation","targetOrientation","getImage2DSize","rows","columns","getSpacingFromMeasure","dataElements","pixelSpacing","parseFloat","isMonochrome","photometricInterpretation","checkTag","warning","TagValueExtractor","_elements","ImageFactory","getWarning","checkElements","modality","syntaxElement","spp","samplesPerPixel","photo","jpeg2000","jpegBase","jpegLoss","getPhotometricInterpretation","SOPClassUID","getSopClassUid","isSecondatyCapture","suvFactor","patWeight","patWeightEl","weight","decayedDose","seriesDateObj","totalDose","halfLife","radioStart","radioInfoSq","totalDoseStr","totalDoseEl","dose","halfLifeStr","halfLifeEl","hl","radioStartDateTimeEl","radioStartDateObj","radioStartTimeObj","radioStartDateTime","dtValue","dateDataElement","dtDate","timeDataElement","getDateTime","Date","seriesTimeObj","scanStart","acqDateEl","acqTimeEl","acqDateObj","acqTimeObj","acqDate","frameRefTime","frameRefTimeElStr","frameRefTimeEl","actualFrameDuration","actualFrameDurationElStr","actualFrameDurationEl","decayConstant","decayDuringFrame","offsetSeconds","exp","decayTime","getDecayedDose","getSuvFactor","create","pixelBuffer","numberOfFiles","size2D","numberOfFramesEl","rowSpacing","columnSpacing","getPixelSpacing","imagePositionPatient","slicePosition","imageOrientationPatient","getOrientationMatrix","geometry","sopInstanceUid","siu","bufferSize","Image","setPhotometricInterpretation","planarConfiguration","setPlanarConfiguration","rescaleSlope","rescaleIntercept","meta","Modality","isPetWithSuv","intensityFactor","setRescaleSlopeAndIntercept","safeGet","TransferSyntaxUID","MediaStorageSOPClassUID","ImageType","SamplesPerPixel","PhotometricInterpretation","PixelRepresentation","BitsAllocated","BitsStored","HighBit","StudyDate","StudyTime","StudyInstanceUID","StudyID","SeriesInstanceUID","SeriesNumber","ReferringPhysicianName","PatientName","PatientID","PatientBirthDate","PatientSex","Manufacturer","ManufacturerModelName","DeviceSerialNumber","SoftwareVersions","ImageOrientationPatient","FrameOfReferenceUID","IsSigned","pixelUnit","unit","getPixelUnit","windowPresets","windowCenter","windowWidth","windowCWExplanation","redLutElement","greenLutElement","blueLutElement","redLut","greenLut","blueLut","descriptor","doScale","descSize","vlSize","scaleTo8","clone","setPaletteColourMap","recommendedDisplayFrameRate","RecommendedDisplayFrameRate","setMeta","DataWriter","writeUint8","setUint8","writeInt8","setInt8","writeUint16","setUint16","writeInt16","setInt16","writeUint32","setUint32","writeUint64","setBigUint64","writeInt32","setInt32","writeInt64","setBigInt64","writeFloat32","setFloat32","writeFloat64","setFloat64","writeHex","writeBinaryArray","byte","len","writeUint8Array","writeInt8Array","writeUint16Array","writeInt16Array","writeUint32Array","writeUint64Array","writeInt32Array","writeInt64Array","writeFloat32Array","writeFloat64Array","_uidCount","WriterRule","action","writerActions","copy","clear","replace","getUID","prefix","getDwvUIDPrefix","uid","datePart","toISOString","countPart","nonTagLength","tagNumber","isEven","isStringVr","uint8ArrayPush","newArr","DefaultTextEncoder","encode","DicomWriter","default","setUseUnVrForPrivateSq","flag","setFixUnknownVR","setRules","rules","addMissingTags","rule","tagKey","isKey","useSpecialTextEncoder","TextEncoder","getElementToWrite","groupName","writer","itemTag","subItem","itemElement","itemDelimElement","hexString","hexString1","hexString2","atValue","diff","message","finalValue","initialArray","initialArrayLength","arrayLength","flattenendArrayLength","flattenedArray","indexFlattenedArray","flattenArrayOfTypedArrays","isTagWithVR","undefinedLengthSequence","undefinedLengthItem","seqDelimElement","getBuffer","isBigEndian","oldscs","totalSize","localSize","metaElements","rawElements","metaLength","fmiglTag","fmivTag","icUIDTag","ivnTag","missingTags","originalElement","checkAndFixUnknownVR","fmiv","getDataElement","fmivSize","icUID","icUIDSize","icUIDValue","ivn","ivnSize","ivnValue","elemSortFunc","fmigl","fmiglSize","ArrayBuffer","metaWriter","dataWriter","lenj","metaOffset","lenk","newItems","oldItemElements","newItemElements","subSize","itemKeys","itemKey","padStr","pad","getVrPad","join","padOBValue","isTypedArrayVr","isArray","itemPrefixSize","getBpeForVrType","dictVr","getUint8ToVrValue","getElementsFromJSONTags","simpleTags","simpleTag","CodeValue","CodingSchemeDesignator","CodeMeaning","LongCodeValue","URNCodeValue","DicomCode","meaning","longValue","urnValue","schemeDesignator","isEqualCode","code1","code2","getCode","getDicomCodeItem","DcmCodes","SctCodes","UcumCodes","deg","getDicomCode","scheme","getMeasurementGroupCode","getReferenceGeometryCode","getSourceImageCode","getTrackingIdentifierCode","getShortLabelCode","getReferencePointsCode","getColourCode","QuantificationName2DictItem","angle","surface","height","radius","stddev","getQuantificationName","propKey","QuantificationUnit2UcumKey","HU","MGML","ED","PCT","CNTS","NONE","CM2","CM2ML","PCNT","CPS","BQML","MGMINML","UMOLMINML","MLMING","MLG","UMOLML","PROPCNTS","PROPCPS","MLMINML","MLML","GML","SUV","getQuantificationUnit","ucumKey","MaskSegment","algorithmType","algorithmName","displayValue","displayRGBValue","propertyTypeCode","propertyCategoryCode","trackingUid","trackingId","getSegment","segment","cielabElement","rgb","gammaFunc","ciexyzToSrgb","invLabFunc","l0","cielabToCiexyz","cielabToSrgb","getDicomSegmentItem","algoType","segmentItem","SegmentNumber","SegmentLabel","SegmentAlgorithmType","SegmentAlgorithmName","cieLab","RecommendedDisplayCIELabValue","RecommendedDisplayGrayscaleValue","SegmentedPropertyCategoryCodeSequence","SegmentedPropertyTypeCodeSequence","TrackingID","TrackingUID","DicomSegmentFrameInfo","dimIndex","imagePosPat","derivationImages","refSegmentNumber","getSegmentFrameInfo","derivationImageSq","sourceImages","sourceImageSq","sourceImage","referencedSOPClassUID","referencedSOPInstanceUID","segmentIdSq","frameInfo","framePlaneOrientationSeq","frameImageOrientation","framePixelMeasuresSeq","frameSpacing","getDicomSegmentFrameInfoItem","FrameContentSequence","DimensionIndexValues","PlanePositionSequence","ImagePositionPatient","SegmentIdentificationSequence","ReferencedSegmentNumber","sourceImgPurposeOfReferenceCode","segDerivationCode","derivationImageItems","derivationImage","PurposeOfReferenceCodeSequence","ReferencedSOPClassUID","ReferencedSOPInstanceUID","DerivationCodeSequence","SourceImageSequence","DerivationImageSequence","equalPosPat","pos1","pos2","JSON","stringify","tagDefinition","tagValue","enum","createRoiSliceBuffers","segments","sliceOffset","buffers","inputOffset","pixelValue","segmentIndex","RequiredDicomSegTags","getDefaultDicomSegJson","reqTag","MaskFactory","_dicomElements","frames","framesElem","orgSq","orgUID","indices","indexSqElem","indexSq","indexPointer","indexOrg","DimensionOrganizationUID","DimensionIndexPointer","DimensionDescriptionLabel","organizations","getDimensionOrganization","segSequence","paletteColourMap","hasDisplayRGBValue","sharedFunctionalGroupsSeq","funcGroup0","planeOrientationSeq","pixelMeasuresSeq","includesPosPat","some","arrVal","findIndexPosPat","findIndex","perFrameFuncGroupSequence","frameInfos","framePosPats","ii","invOrientation","p1","p2","getComparePosPat","point3DFromArray","frameOrigins","tmpGeometry","isAboveEpsilon","posPats","sliceIndex","frameOrigin","distPrevious","numberOfSlices","uids","getFindSegmentFunc","fill","frameOffset","frameSegment","SeriesDate","SeriesTime","DimensionOrganizationSequence","DimensionIndexSequence","custom","SOPInstanceUID","frameOfReferenceUID","lossyImageCompression","LossyImageCompression","toDicom","extraTags","getMeta","Rows","Columns","now","ContentDate","ContentTime","segmentItems","SegmentSequence","SharedFunctionalGroupsSequence","PlaneOrientationSequence","PixelMeasuresSequence","SpacingBetweenSlices","PixelSpacing","roiBuffers","key0","createRoiBuffers","finalBuffers","referencedSOPs","number40","number4","key1","posPat","posPatArray","sourceIndex","getImageUid","NumberOfFrames","frameInfosTag","PerFrameFunctionalGroupsSequence","refSeriesTag","ReferencedInstanceSequence","ReferencedSeriesSequence","tags1","tags2","keys2","tagName2","mergeTags","dicomElements","pixVl","de","createImage","createMaskImage","imageUids","getSecondaryOffset","getOriginForImageUid","uidIndex","includesImageUid","containsImageUids","itemArr1","arrayContains","canQuantify","canWindowLevel","nFiles","getRescaleSlopeAndIntercept","isConstantRSI","inRsi","isIdentityRSI","interp","getPaletteColourMap","updatePaletteColourMap","colour","config","getOffsets","bufferValue","offsets","equal","hasValues","finalValues","equalFunc","getEqualCallback","valuesToFind","indicesToRemove","v","clonedBuffer","tmpBuffer","appendSlice","rhsSize","rhsRange","getDataRange","rhsResRange","getRescaledDataRange","resRange","timeId","isNewFrame","volumeGeometry","sliceGeometry","fullBufferSize","fullSliceIndex","indexOffset","maxOffset","subarray","numberOfImages","rhsPresets","pkey","rhsPreset","windowPreset","perslice","appendFrameBuffer","frameBuffer","frameIndex","frameSize","calculateDataRange","calculateRescaledDataRange","getHistogram","calculateHistogram","dataRange","rescaledDataRange","histogram","addEventListener","removeEventListener","setAtOffsets","setAtOffsetsAndGetOriginals","offsetsLists","originalValuesLists","previousValue","originalValues","currentValue","setAtOffsetsWithIterator","isValueArray","getValueAtIndex","getRescaledValue","getRescaledValueAtIndex","resmin","resmax","rmin","rmax","rvalue","histo","convolute2D","weights","newImage","imgSize","dimOffset","convoluteBuffer","componentOffset","wOff","wOff00","wOff0x","wOff0n","wOffx0","wOffxn","wOffn0","wOffnx","wOffnn","pixelOffset","newValue","wOffFinal","wi","transform","operator","compose","ViewFactory","view","View","setColourMap","minmax","preset","setWindowPresets","init","viewEventNames","createView","getCurrentIndex","setCurrentIndex","getImage","setImage","inImage","setOrientation","setInitialIndex","getPlaybackMilliseconds","_value","_index","getAlphaFunction","setAlphaFunction","currentIndex","sliceWl","setWindowLevel","setWindowLevelPresetById","voiLut","voiLutWl","getWindowPresets","getWindowPresetsNames","presets","addWindowPresets","getCurrentWindowPresetName","getColourMap","getCurrentPosition","getCurrentImageUid","isPositionInBounds","getScrollIndex","originIndex","setCurrentPosition","silent","valid","minLen","maxLen","posEvent","imageUid","pixValue","isNewWl","isNewName","manual","wc","ww","skipGenerate","setWindowLevelPreset","getWindowLevelMinMax","setWindowLevelMinMax","generateImageData","photoInterpretation","alphaFunc","windowLut","colourMap","pxValue","generateImageDataMonochrome","is16BitsStored","to8","generateImageDataPaletteColor","generateImageDataRgb","cb","cr","generateImageDataYbrFull","isAquisitionOrientation","PlaneHelper","imageGeometry","getTargetOrientation","getOffset3DFromPlaneOffset","offset2D","planeOffset","getTargetDeOrientedVector3D","getPlaneOffsetFromOffset3D","offset3D","getTargetOrientedVector3D","planeVector","getTargetDeOrientedPoint3D","planePoint","getImageOrientedVector3D","getImageOrientedPoint3D","getImageDeOrientedVector3D","getImageDeOrientedPoint3D","getPositionFromPlanePoint","getPlanePointFromPosition","getCosines","getPlanePoints","planeOrigin","getTargetOrientedPositiveXYZ","getNativeScrollIndex","ViewController","getPlaneHelper","isMask","initialise","getModality","getWindowLevelPresetsNames","addWindowLevelPresets","isPlaying","getCurrentOrientedIndex","getCurrentScrollIndexValue","getCurrentScrollPosition","scrollIndex","img","get2DSpacing","getRescaledImageValue","sliceValues","sliceOrigin","getImageRegionValues","rescaled","iter","rangeNumberOfColumns","regionSize","regionOffset","regionElementCount","rangeRegion","getRegionSliceIterator","getImageVariableRegionValues","regions","offsetRegions","region","regionIndex","regionCount","rangeRegions","getVariableRegionSliceIterator","canQuantifyImage","getImageSize","dim","getImageWorldSize","getImageRescaledDataRange","equalImageMeta","imageMeta","metaKeys","metaKey","getPlanePositionFromPosition","getIndexFromPosition","getPlanePositionFromPlanePoint","incr","getIncrementPosition","getDecrementPosition","getIncrementScrollPosition","getDecrementScrollPosition","incrementIndex","decrementIndex","decrementScrollIndex","incrementScrollIndex","play","window","setInterval","canDoMore","stop","clearInterval","setViewAlphaFunction","bindImageAndLayer","viewLayer","onimagecontentchange","onimagegeometrychange","unbindImageAndLayer","ScrollSum","getSum","wheelDeltaY","deltaY","getSpinY","isTick","ScrollWheel","app","wheel","up","preventDefault","layerDetails","getLayerDetailsFromEvent","layerGroup","getLayerGroupByDivId","groupDivId","viewController","getActiveViewLayer","getViewController","newPosition","Line","begin","getBegin","getEnd","getDeltaX","getDeltaY","getWorldLength","spacing2D","wlen","dxs","dys","getMidpoint","getInclination","atan2","PI","quantify","quant","getAngle","line0","line1","dx0","dy0","dx1","dy1","dot","areOrthogonal","getPerpendicularLine","line","perpSlope","getLineFromEquation","getPerpendicularLineAtDistance","distance","lineFromEq","startPoint","minX","maxX","minY","maxY","isPointInLineRange","beginX","beginY","endX","endY","sx2","sy2","AnnotationGroup","list","getList","isEditable","setEditable","getColour","setColour","annotation","update","propKeys","setViewController","updateQuantification","hasMeta","getMetaValue","setMetaValue","DrawController","getAnnotation","getAnnotationGroup","isAnnotationGroupEditable","setAnnotationGroupEditable","addAnnotation","updateAnnotation","removeAnnotation","removeAnnotationWithCommand","exeCallback","command","RemoveAnnotationCommand","execute","updateAnnotationWithCommand","originalProps","newProps","UpdateAnnotationCommand","removeAllAnnotationsWithCommand","hasAnnotationMeta","setAnnotationMeta","Style","getFontFamily","getFontSize","getStrokeWidth","getTextColour","getLineColour","setLineColour","setBaseScale","scale","setZoomScale","getBaseScale","getZoomScale","applyZoomScale","applyZoomRatio","getShadowOffset","getTagOpacity","getTextPadding","getFontStr","getLineHeight","getScaledFontSize","getScaledStrokeWidth","getShadowLineColour","hexColour","hexStr","isNodeNameLabel","node","isNodeNameShape","isPositionNode","getLineShape","kshape","getChildren","Konva","getAnchorShape","isNodeWithId","getDefaultAnchor","style","absRadius","stroke","strokeWidth","strokeScaleEnabled","radiusX","radiusY","dragOnTop","draggable","visible","getAnchorIndex","Rectangle","getSurface","getWorldSurface","mulABC","getRealWidth","getRealHeight","getWidth","getHeight","getRound","quantif","getRectangleIndices","dir","centerValues","sizeI","halfSizeI","sizeJ","halfSizeJ","di","dj","ROI","points","getPoint","getPoints","addPoint","addPoints","cx","cy","pi","pi1","ai","a1","Protractor","_viewController","_flags","Ellipse","centre","getCenter","getA","getB","centerX","centerY","radiusRatio","rySquare","transX","getEllipseIndices","radiusI","radiusJ","radiusJ2","jmax","jmin","imax","imin","Circle","getRadius","rSquare","DrawShapeEditor","eventCallback","setShape","inshape","drawLayer","getFactory","getShape","isActive","enable","getLayer","draw","disable","reset","resetAnchors","getParent","forEach","anchor","setAnchorsActive","anchors","getAnchors","getStyle","on","cancelBubble","mathShape","referencePoints","target","stageSize","changed","boundNodePosition","validateAnchorPosition","getBaseSize","constrainAnchorMove","updateAnnotationOnAnchorMove","updateShapeGroupOnAnchorMove","getDrawController","addToUndoStack","dataid","getDataId","moveToTop","DrawTrash","createTrashIcon","trashLine1","trashLine2","activate","stage","getKonvaStage","konvaLayer","getKonvaLayer","invscale","changeChildrenColourOnTrashHover","eventPosition","shapeGroup","originalShapeColour","isOverTrash","changeGroupChildrenColour","tshape","trashHalfWidth","scaleX","trashHalfHeight","scaleY","DrawShapeHandler","setEditorShape","shape","drawController","getEditorShapeGroup","getEditorAnnotation","disableAndResetEditor","storeMouseOverCursor","cursor","document","body","opacity","onMouseOutShapeGroup","addShapeGroupListeners","originalTextExpr","textExpr","customUI","openRoiDialog","newTextExpr","dragStartPos","previousPos","getShapePositionRange","boundRect","getClientRect","relativeTo","isShapeInRange","children","labelWithDefaultPosition","labelPosition","child","move","updateAnnotationOnTranslation","updateLabelContent","updateConnector","mousePoint","getMousePoint","evt","eventPos","translation","originalLabelPosition","newLabelPosition","removeShapeListeners","DrawLayer","containerDiv","className","setShapeHandler","handler","getReferenceLayerId","getLayers","setPlaneHelper","helper","getId","removeFromDOM","getOpacity","setOpacity","alpha","addFlipOffsetX","addFlipOffsetY","flipScaleX","flipScaleY","flipScaleZ","setScale","newScale","orientedNewScale","finalNewScale","resetOffset","worldCenter","newOffset","getScaledOffset","newZoomOffset","initScale","absoluteZoomOffset","setOffset","planeNewOffset","setBaseOffset","scrollOffset","needsUpdate","display","isVisible","refLayerId","container","listening","getContent","setAttribute","setAnnotationGroup","annotationGroup","dataId","activateCurrentPositionShapes","AddAnnotationCommand","allPosGroups","posGroup","shapeGroups","getCurrentPosGroup","planePoints","posGroupId","layerChildren","posChildren","isCompatibleView","createShapeGroup","setLabelVisibility","fitToContainer","containerSize","divToWorldSizeRatio","fitOffset","divToImageSizeRatio","newViewOffset","scaledImageSize","newFlipOffset","isAnnotationVisible","setAnnotationVisibility","setLabelsVisibility","posGroups","getText","text","connector","deleteDraw","_id","_exeCallback","deleteDraws","getNumberOfDraws","bindInteraction","pointerEvents","names","InteractionEventNames","unbindInteraction","findOne","srclayerid","ratioX","ratioY","labels","getName","undo","originaProps","Path","inputPointArray","inputControlPointIndexArray","pointArray","controlPointIndexArray","isControlPoint","addControlPoint","newPointArray","appenPath","other","oldSize","indexArray","BucketQueue","bits","cost_functor","bucketCount","mask","loc","cost","buckets","buildArray","bucket","getBucket","ret","isEmpty","newSize","__twothirdpi","gradUnitVector","gradX","gradY","px","py","out","oy","gvm","Scissors","curPoint","searchGranBits","searchGran","pointsPerPost","greyscale","laplace","gradient","parents","working","trained","trainingPoints","edgeWidth","trainingLength","edgeGran","edgeTraining","gradPointsNeeded","gradGran","gradTraining","insideGran","insideTraining","outsideGran","outsideTraining","getTrainingIdx","granularity","getTrainedEdge","edge","getTrainedGrad","grad","getTrainedInside","inside","getTrainedOutside","outside","setWorking","setDimensions","setData","gradMagnitude","lap","computeGreyscale","computeLaplace","computeGradient","computeGradX","computeGradY","sides","guv","ix","iy","computeSides","findTrainingPoints","resetTraining","doTraining","calculateTraining","addInStaticGrad","input","output","maxVal","idx","gaussianBlur","have","need","gradDirection","qx","qy","__dgpuv","__gdquv","dp","dq","SQRT1_2","acos","adj","sx","sy","ex","ey","setPoint","sp","visited","MAX_VALUE","pq","doWork","timeout","pointCount","newPoints","adjList","q","pqCost","defaults","labelText","arrow","circle","ellipse","protractor","rectangle","roi","ruler","LabelFactory","positionGetter","getPosition","ktext","fontSize","fontFamily","padding","shadowColor","shadowOffset","setText","zoomScale","labelScale","klabel","updatePosition","getLabelAnchorsPosition","lx","ly","getClosestPoints","points1","points2","point1","point2","getConnector","connectorsPos","labelAnchorsPos","anchorPoints","dash","kconnect","updateContent","ThresholdFilter","getMin","setMin","getMax","setMax","setOriginalImage","getOriginalImage","imageMin","SharpenFilter","SobelFilter","RunFilterCommand","filter","render","onExecute","onUndo","_event","toolList","toolOptions","defaultToolList","divId","diffX","diffY","pixelToIntensity","WindowLevelValues","mousedown","mousemove","mouseup","mouseout","touchstart","touchPoints","getTouchPoints","touchmove","touchend","dblclick","displayToPlaneIndex","getData","keydown","context","onKeydown","_bool","setFeatures","_features","Scroll","planePos","displayToPlanePos","yMove","xMove","setTimeout","clearTimeout","showTooltip","removeTooltipDiv","features","displayTooltip","ZoomAndPan","tx","ty","displayToPlaneScale","addTranslation","#twoTouchUpdate","lineRatio","zoom","displayToMainPlanePos","addScale","step","Opacity","op","Draw","getActiveDrawLayer","refDataId","seriesInstanceUID","createAnnotationData","addAndRenderAnnotationData","setActiveDrawLayerByDataId","getIntersection","selectedShape","annotationid","getNPoints","timer","getTimeout","getActiveLayerGroup","destroy","tmpPoints","colours","drawLayerId","layerId","Annotation","groupColour","setAnnotationMathShape","finalPoints","layer","drawLayers","getDrawLayers","layerid","setOptions","options","getOptionsType","autoShapeColour","shapeColour","shapeName","hasShape","mouseOverCursor","withScroll","blacklist","getEventNames","listener","Filter","bool","getSelectedFilter","filterName","hasFilter","run","args","runArgs","getFilterList","Floodfill","setExtend","getExtend","#getIndex","simple","bytes","MagicWand","cs","icsl","newMathShape","originalMathShape","extend","ini","imageSize","jl","onThresholdChange","getImageData","getAbsoluteScale","movedpoint","Livewire","pn","p0","results","_p","_q","defaultToolOptions","ArrowFactory","supports","setTextExpr","extras","extra","positions","_anchor","kline","pointBegin","pointEnd","endPoint","newBegin","newEnd","_style","linePerp0","linePerp1","hitFunc","beginPath","moveTo","lineTo","closePath","fillStrokeShape","perpLine","closed","ktriangle","_annotation","_group","CircleFactory","left","right","bottom","top","anchorPoint","newRadius","newCenter","swapX","swapY","offsetX","offsetY","kshadow","pixelLine","EllipseFactory","ProtractorFactory","mid","pointMid","newPointList","inclination","innerRadius","outerRadius","rotation","midX","midY","karc","arcPos","RectangleFactory","topLeft","bottomRight","pointTopLeft","pointBottomRight","krect","topRight","bottomLeft","rWidth","rHeight","RoiFactory","kroi","newPoint","RulerFactory","ktick0","ktick1","Threshold","Sobel","Sharpen","referenceSopUID","quantification","planeHelper","cosine1","cosine2","originPoint","valueObj","valueStr","toPrecision","replaceFlags","fac","factoryName","prompt","getTouchesPositions","touches","offsetLeft","offsetTop","offsetParent","pageX","pageY","targetTouches","changedTouches","canCreateCanvas","testCvs","createElement","cropCvs","testCtx","getContext","cropCtx","fillRect","drawImage","ViewLayer","getScale","getAbsoluteZoomOffset","setImageSmoothing","setView","bindImage","onimageset","unbindImage","vcSize","origin0","layerGroupOrigin","layerGroupOrigin0","deScaled","planePosToDisplay","posX","posY","globalAlpha","setTransform","imageSmoothingEnabled","appendChild","alert","clearRect","createImageData","needsDraw","eventName","passive","putImageData","dims3D","indexScrollIndex","save","restore","getLayerDetailsFromLayerDivId","idString","layerIndex","layerDiv","closest","indexCenter","LayerGroup","getShowCrosshair","setShowCrosshair","getDivId","getAddedScale","getOffset","getNumberOfLayers","getViewLayers","someViewLayer","hasOne","getNumberOfViewLayers","tmpLayer","getBaseViewLayer","baseLayer","getViewLayersByDataId","searchViewLayers","getViewDataIndices","getDrawLayersByDataId","setActiveViewLayer","setActiveViewLayerByDataId","setActiveDrawLayer","addViewLayer","viewLayerIndex","div","append","addDrawLayer","updateLayersToPositionChange","empty","getElementsByClassName","removeLayersByDataId","removeLayer","displayPos","lineH","offsetWidth","lineV","offsetHeight","span","createTextNode","viewLayerOffsets","baseViewLayerOrigin0","baseViewLayerOrigin","hasSetOffset","vc","scrollDiff","planeDiff","scroll","plane","refOffsets","hasSetPos","getDivToWorldSizeRatio","maxWorldSize","getMaxWorldSize","maxSize","scaleStep","binderList","WindowLevelBinder","getEventType","getCallback","viewLayers","PositionBinder","pointValues","currentPos","currentDims","inputDims","ZoomBinder","OffsetBinder","OpacityBinder","ColourMapBinder","Stage","getLayerGroup","getNumberOfLayerGroups","setActiveLayerGroup","addLayerGroup","htmlElement","isBound","unbindLayerGroups","bindLayerGroups","setBinders","removeLayerGroup","minRatio","hasRatio","binder","binderObj","elem","State","fromJSON","json","version","baseScale","scaleCenter","originX","originY","oldTx","oldTy","setDrawings","drawings","drawingsDetails","v02DAndD","inputDrawings","newDrawings","drawGroups","drawGroup","lenf","newFrameDrawings","leng","karcs","ktexts","toObject","txtLen","longText","v01Tov02DrawingsAndDetails","v02Tov03Drawings","v03Tov04DrawingsDetails","v04Tov05Data","v04Tov05Drawings","details","groupDetails","v02Tov03DrawingsDetails","groupShapes","parentGroup","groupDrawings","currentPosition","gnode","detail","ids","attrs","sliceNumber","frameNumber","newId","getUrlFromUri","uri","base","location","URL","splitUri","sepIndex","hashIndex","query","pairs","pair","splitKeyValueString","UndoStack","getStackSize","getCurrentStackIndex","cmd","redo","ToolboxController","enableShortcuts","getToolList","hasTool","getSelectedTool","getSelectedToolEventHandler","eventType","setSelectedTool","setToolFeatures","bindLayerGroup","layerGroupDivId","applySelectedTool","MultiProgressHandler","setNumberOfDimensions","num","setNToLoad","onprogress","lengthComputable","subindex","percent","loaded","total","source","lenprog","getMonoProgressHandler","getUndefinedMonoProgressHandler","UrlsLoader","request","loader","onload","onloadend","load","onloadstart","status","onerror","responseURL","statusText","response","mproghandler","loaders","loaderList","foundLoader","canLoadUrl","defaultCharacterSet","onloaditem","onabort","lastRunRequestIndex","requestOnLoadEnd","send","XMLHttpRequest","open","requestHeaders","setRequestHeader","withCredentials","errorCallback","abortCallback","loadUrlAs","responseType","batchSize","dicomDirUrl","urls","parser","dirSeq","records","series","study","recType","refFileIds","getFileListFromDicomDir","rootUrl","fullUrls","abort","readyState","isLoading","ThreadPool","poolSize","taskQueue","freeThreads","WorkerThread","runningThreads","addWorkerTask","workerTask","onworkstart","workerThread","shift","onworkend","onTaskEnd","onwork","handleWorkerError","onworkitem","parentPool","runningTask","worker","Worker","script","onmessage","postMessage","startMessage","terminate","itemNumber","numberOfItems","WorkerTask","hasJpegBaselineDecoder","JpegImage","hasJpegLosslessDecoder","jpeg","lossless","hasJpeg2000Decoder","JpxImage","decoderScripts","rle","AsynchPixelBufferDecoder","_numberOfData","pixelMeta","ondecodestart","ondecodeditem","ondecoded","ondecodeend","SynchPixelBufferDecoder","algoName","numberOfData","decoder","decodedBuffer","buf","Decoder","decoded","tiles","dwvdecoder","RleDecoder","PixelBufferDecoder","NumericValue","FloatingPointValue","RationalNumeratorValue","RationalDenominatorValue","MeasurementUnitsCodeSequence","MeasuredValue","numericValue","floatingPointValue","rationalNumeratorValue","rationalDenominatorValue","measurementUnitsCode","getDicomMeasuredValueItem","MeasuredValueSequence","NumericValueQualifierCodeSequence","NumericMeasurement","measuredValue","numericValueQualifierCode","getDicomNumericMeasurementItem","measurement","SopInstanceReference","getSopInstanceReference","ref","getDicomSopInstanceReferenceItem","ReferencedFrameNumber","ReferencedSOPSequence","ImageReference","referencedSOPSequence","referencedFrameNumber","referencedSegmentNumber","fiducialUID","getDicomImageReferenceItem","PixelOriginInterpretation","GraphicData","GraphicType","FiducialUID","GraphicTypes","SpatialCoordinate","graphicData","graphicType","pixelOriginInterpretation","getDicomSpatialCoordinateItem","scoord","ReferencedFrameofReferenceUID","SpatialCoordinate3D","referencedFrameofReferenceUID","getDicomSpatialCoordinate3DItem","RelationshipType","ValueType","ConceptNameCodeSequence","ConceptCodeSequence","ContentSequence","DateTime","Time","UID","PersonName","TextValue","ContinuityOfContent","RelationshipTypes","ValueTypes","datetime","uidref","pname","composite","waveform","scoord3d","tcoord","table","ValueTypeValueTagName","TEXT","DATE","TIME","DATETIME","UIDREF","PNAME","CONTAINER","DicomSRContent","valueType","conceptNameCode","relationshipType","contentSequence","getSRContent","content","getMeasuredValue","getNumericMeasurement","getImageReference","getSpatialCoordinate","getSpatialCoordinate3D","valueTagName","getDicomSRContentItem","contentItem","getSRContentFromValue","getConceptNameCode","measure","getMeasurementUnitsCode","numMeasure","AnnotationGroupFactory","srContent","dataLength","isClosed","numberOfPoints","firstPoint","lastPoint","line2","line3","getShapeFromScoord","subsubItem","nPoints","quantifName","quantifUnit","annotations","seriesElement","srScoord","pointPerimeter","getScoordFromShape","itemContentSequence","srImage","sopRef","imageRef","srUid","shortLabel","labelPosScoord","refPointsScoord","pointsScoord","quatifContent","CompletionFlag","VerificationFlag","DicomData","DataController","getNextDataId","getDataIds","getDataIdsFromSopUids","dataToUpdate","idKey","obj1","obj2","valueKey","mergedObj1","merged","id1","id2","value1","subValue1","value2","subValue2","mergeObjects","DicomBufferToView","opt","modalityElement","dicomParser","columnsElement","rowsElement","samplesPerPixelElement","planarConfigurationElement","dataIndex","decodedData","fullSize","algo","getSyntaxDecompressionName","convert","MemoryLoader","canLoadMemory","filename","imageDataToBuffer","imageData","dataLen","getDefaultImage","imageBuffer","imageSpacing","canLoadFile","file","url","forceLoader","isNameAccept","acceptHeader","acceptValue","urlObjext","pathname","hasNoExt","hasDcmExt","contentType","searchParams","mem","tmpFile","File","loadFileAs","fileContentTypes","_opt","Text","memoryIO","progress","u8Array","partHeaderEndCb","partHeaderEndIndex","lines","boundaryStr","boundaryCb","boundaryLen","nextBoundaryIndex","part","partHeaderLines","semiColonIndex","dataBeginIndex","dataEndIndex","parseMultipart","_file","_mem","dataType","imageType","Blob","createObjectURL","domImage","canvas","ctx","lastModified","getViewFromDOMImage","src","hasImageExt","DataURL","videoDataStr","btoa","video","onloadedmetadata","videoWidth","videoHeight","ceil","duration","onseeked","imgBuffer","storeFrame","nextTime","currentTime","getViewFromDOMVideo","unzipPercent","async","then","JSZip","zip","FilesLoader","FileReader","readAsText","readAsDataURL","readAsArrayBuffer","LoadController","loadFiles","files","loadURLs","loadImageObject","getLoadingDataIds","fileIO","urlIO","loadType","eventInfo","loadtype","isFirstItem","eventInfoItem","isfirstitem","getNumberToPrecision","createDefaultReplaceFormat","OverlayData","configs","addAppListeners","addItemMeta","dataUid","overlays","modElement","overlay","format","poElement","po0","po1","createOverlayData","DOM","infoKeys","createOverlayDataForDom","sliceOverlayData","mapFunc","isListening","removeAppListeners","ViewConfig","wlPresetName","ToolConfig","AppOptions","dataViewConfigs","tools","binders","viewOnFirstLoadItem","overlayConfig","rootDocument","App","addData","getMetaData","getToolboxController","removeFromUndoStack","appToolList","toolName","toolClass","toolParams","appToolOptions","optionName","optionClassName","toolNamespace","charAt","optionClass","tOptions","resetLayout","loadFromUri","getUriQuery","onLoadEnd","state","protocol","host","decodeURIComponent","manifest","rootURL","getElementsByTagName","getAttribute","patientList","studyList","studyUID","seriesList","seriesUID","instanceList","link","decodeManifest","responseXML","decodeManifestQuery","replaceMode","repeatKeyReplaceMode","queryUri","inputQueryPairs","repeatKey","repeatList","baseUrl","gotOneArg","decodeKeyValueUri","dwvReplaceMode","decodeQuery","abortAllLoads","abortLoad","initWLDisplay","getViewConfigs","excludeStarConfig","getViewConfig","getDataViewConfigs","setDataViewConfigs","addDataViewConfig","removeDataViewConfig","itemIndex","lg","vls","dls","updateDataViewConfig","configToUpdate","dataKeys","divIds","viewConfigs","viewConfig","getElementById","setLayerGroupsBinders","instances","isImage","isMeasurement","translate","statePosGroups","statePosKids","stateGroup","pointsArray","absPosition","absolutePosition","konvaToAnnotation","applyJsonState","jsonState","onResize","defaultOnKeydown","ctrlKey","shiftKey","resetDisplay","resetZoom","setTool","tool","getOverlayData","toggleOverlayListeners","refMeta","refDataViewConfig","drawDataViewConfig","isFirstLoadItem","eventMetaData","groupId","isBaseLayer","flipFlags","baseViewLayer","layergroupid","refSeriesInstanceUID","refViewLayer","refViewController","refData","viewConfigOrientation","orientationCode","isViewUndefined","isViewAxial","isViewCoronal","isViewSagittal","flipOffset","flipScale","MaskSegmentHelper","segmentNumber","hasSegment","getNumberOfSegments","maskHasSegments","numbers","unknowns","addSegment","removeSegment","updateSegment","DeleteSegmentCommand","isValid","segmentnumber","ChangeSegmentColourCommand","newColour","MaskSegmentViewHelper","isHidden","addToHidden","removeFromHidden","getAlphaFunc","Scalar2D","Scalar3D"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"dwv.min.js","mappings":"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AK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAC35BD,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,GACllCD,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,G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,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC1sCC,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC58BC,KAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,MAM12BQ,IAAK,CACHV,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC1kCC,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC9lCC,KAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,MAMrpCS,eAAgB,CACdX,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC7iCC,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC19BC,KAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,MAMxmCU,WAAY,CACVZ,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KACpnCC,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC3lCC,KAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EA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","sources":["webpack://dwv/webpack/universalModuleDefinition","webpack://dwv/external umd {\"root\":\"JSZip\",\"commonjs\":\"jszip\",\"commonjs2\":\"jszip\",\"amd\":\"jszip\"}","webpack://dwv/external umd {\"root\":\"Konva\",\"commonjs\":\"konva\",\"commonjs2\":\"konva\",\"amd\":\"konva\"}","webpack://dwv/external umd {\"root\":\"MagicWand\",\"commonjs\":\"magic-wand-tool\",\"commonjs2\":\"magic-wand-tool\",\"amd\":\"konmagic-wand-tool\"}","webpack://dwv/webpack/bootstrap","webpack://dwv/webpack/runtime/compat get default export","webpack://dwv/webpack/runtime/define property getters","webpack://dwv/webpack/runtime/hasOwnProperty shorthand","webpack://dwv/webpack/runtime/make namespace object","webpack://dwv/./src/math/index.js","webpack://dwv/./src/image/modalityLut.js","webpack://dwv/./src/utils/logger.js","webpack://dwv/./src/image/windowLevel.js","webpack://dwv/./src/image/voiLut.js","webpack://dwv/./src/image/windowLut.js","webpack://dwv/./src/image/luts.js","webpack://dwv/./src/utils/colour.js","webpack://dwv/./src/math/vector.js","webpack://dwv/./src/math/matrix.js","webpack://dwv/./src/math/point.js","webpack://dwv/./src/utils/i18n.js","webpack://dwv/./src/utils/string.js","webpack://dwv/./src/utils/array.js","webpack://dwv/./src/dicom/dictionary.js","webpack://dwv/./src/dicom/dicomTag.js","webpack://dwv/./src/dicom/dataElement.js","webpack://dwv/./src/dicom/dataReader.js","webpack://dwv/./src/dicom/dicomParser.js","webpack://dwv/./src/utils/listen.js","webpack://dwv/./src/image/iterator.js","webpack://dwv/./src/image/rsi.js","webpack://dwv/./src/image/size.js","webpack://dwv/./src/math/stats.js","webpack://dwv/./src/image/spacing.js","webpack://dwv/./src/image/geometry.js","webpack://dwv/./src/dicom/dicomDate.js","webpack://dwv/./src/math/orientation.js","webpack://dwv/./src/dicom/dicomElementsWrapper.js","webpack://dwv/./src/image/imageFactory.js","webpack://dwv/./src/dicom/dataWriter.js","webpack://dwv/./src/dicom/dicomWriter.js","webpack://dwv/./src/dicom/dicomCode.js","webpack://dwv/./src/dicom/dicomSegment.js","webpack://dwv/./src/dicom/dicomSegmentFrameInfo.js","webpack://dwv/./src/image/maskFactory.js","webpack://dwv/./src/image/image.js","webpack://dwv/./src/image/viewFactory.js","webpack://dwv/./src/image/view.js","webpack://dwv/./src/image/viewMonochrome.js","webpack://dwv/./src/image/viewPaletteColor.js","webpack://dwv/./src/image/viewRgb.js","webpack://dwv/./src/image/viewYbrFull.js","webpack://dwv/./src/image/planeHelper.js","webpack://dwv/./src/app/viewController.js","webpack://dwv/./src/tools/scrollWheel.js","webpack://dwv/./src/math/line.js","webpack://dwv/./src/image/annotationGroup.js","webpack://dwv/./src/app/drawController.js","webpack://dwv/./src/gui/style.js","webpack://dwv/./src/tools/drawBounds.js","webpack://dwv/./src/math/rectangle.js","webpack://dwv/./src/math/roi.js","webpack://dwv/./src/math/protractor.js","webpack://dwv/./src/math/ellipse.js","webpack://dwv/./src/math/circle.js","webpack://dwv/./src/tools/drawShapeEditor.js","webpack://dwv/./src/tools/drawTrash.js","webpack://dwv/./src/tools/drawShapeHandler.js","webpack://dwv/./src/gui/drawLayer.js","webpack://dwv/./src/tools/drawCommands.js","webpack://dwv/./src/math/path.js","webpack://dwv/./src/math/bucketQueue.js","webpack://dwv/./src/math/scissors.js","webpack://dwv/./src/app/defaults.js","webpack://dwv/./src/tools/labelFactory.js","webpack://dwv/./src/image/filter.js","webpack://dwv/./src/tools/filter.js","webpack://dwv/./src/tools/index.js","webpack://dwv/./src/tools/windowLevel.js","webpack://dwv/./src/tools/scroll.js","webpack://dwv/./src/tools/zoomPan.js","webpack://dwv/./src/tools/opacity.js","webpack://dwv/./src/tools/draw.js","webpack://dwv/./src/tools/floodfill.js","webpack://dwv/./src/tools/livewire.js","webpack://dwv/./src/tools/arrow.js","webpack://dwv/./src/tools/circle.js","webpack://dwv/./src/tools/ellipse.js","webpack://dwv/./src/tools/protractor.js","webpack://dwv/./src/tools/rectangle.js","webpack://dwv/./src/tools/roi.js","webpack://dwv/./src/tools/ruler.js","webpack://dwv/./src/image/annotation.js","webpack://dwv/./src/gui/generic.js","webpack://dwv/./src/gui/viewLayer.js","webpack://dwv/./src/gui/layerGroup.js","webpack://dwv/./src/gui/stage.js","webpack://dwv/./src/io/state.js","webpack://dwv/./src/utils/uri.js","webpack://dwv/./src/utils/undoStack.js","webpack://dwv/./src/app/toolboxController.js","webpack://dwv/./src/utils/progress.js","webpack://dwv/./src/io/urlsLoader.js","webpack://dwv/./src/utils/thread.js","webpack://dwv/./src/image/decoder.js","webpack://dwv/./src/dicom/dicomMeasuredValue.js","webpack://dwv/./src/dicom/dicomNumericMeasurement.js","webpack://dwv/./src/dicom/dicomSopInstanceReference.js","webpack://dwv/./src/dicom/dicomImageReference.js","webpack://dwv/./src/dicom/dicomSpatialCoordinate.js","webpack://dwv/./src/dicom/dicomSpatialCoordinate3D.js","webpack://dwv/./src/dicom/dicomSRContent.js","webpack://dwv/./src/image/annotationGroupFactory.js","webpack://dwv/./src/app/dataController.js","webpack://dwv/./src/utils/operator.js","webpack://dwv/./src/image/dicomBufferToView.js","webpack://dwv/./src/io/memoryLoader.js","webpack://dwv/./src/image/domReader.js","webpack://dwv/./src/io/loaderList.js","webpack://dwv/./src/io/dicomDataLoader.js","webpack://dwv/./src/io/jsonTextLoader.js","webpack://dwv/./src/io/multipartLoader.js","webpack://dwv/./src/io/rawImageLoader.js","webpack://dwv/./src/io/rawVideoLoader.js","webpack://dwv/./src/io/zipLoader.js","webpack://dwv/./src/io/filesLoader.js","webpack://dwv/./src/app/loadController.js","webpack://dwv/./src/gui/overlayData.js","webpack://dwv/./src/app/application.js","webpack://dwv/./src/image/maskSegmentHelper.js","webpack://dwv/./src/image/deleteSegmentCommand.js","webpack://dwv/./src/image/changeSegmentColourCommand.js","webpack://dwv/./src/image/maskSegmentViewHelper.js","webpack://dwv/./src/math/scalar.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"konva\"), require(\"magic-wand-tool\"), require(\"jszip\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"konva\", \"konmagic-wand-tool\", \"jszip\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"dwv\"] = factory(require(\"konva\"), require(\"magic-wand-tool\"), require(\"jszip\"));\n\telse\n\t\troot[\"dwv\"] = factory(root[\"Konva\"], root[\"MagicWand\"], root[\"JSZip\"]);\n})(this, function(__WEBPACK_EXTERNAL_MODULE__944__, __WEBPACK_EXTERNAL_MODULE__324__, __WEBPACK_EXTERNAL_MODULE__654__) {\nreturn ","module.exports = __WEBPACK_EXTERNAL_MODULE__654__;","module.exports = __WEBPACK_EXTERNAL_MODULE__944__;","module.exports = __WEBPACK_EXTERNAL_MODULE__324__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = function(module) {\n\tvar getter = module && module.__esModule ?\n\t\tfunction() { return module['default']; } :\n\t\tfunction() { return module; };\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Immutable index.\n * Warning: the input array is NOT cloned, modifying it will\n * modify the index values.\n */\nexport class Index {\n\n /**\n * Index values.\n *\n * @type {number[]}\n */\n #values;\n\n /**\n * @param {number[]} values The index values.\n */\n constructor(values) {\n if (!values || typeof values === 'undefined') {\n throw new Error('Cannot create index with no values.');\n }\n if (values.length === 0) {\n throw new Error('Cannot create index with empty values.');\n }\n const valueCheck = function (val) {\n return !isNaN(val);\n };\n if (!values.every(valueCheck)) {\n throw new Error('Cannot create index with non number values.');\n }\n this.#values = values;\n }\n\n /**\n * Get the index value at the given array index.\n *\n * @param {number} i The index to get.\n * @returns {number|undefined} The value or undefined if not in range.\n */\n get(i) {\n return this.#values[i];\n }\n\n /**\n * Get the length of the index.\n *\n * @returns {number} The length.\n */\n length() {\n return this.#values.length;\n }\n\n /**\n * Get a string representation of the Index.\n *\n * @returns {string} The Index as a string.\n */\n toString() {\n return '(' + this.#values.toString() + ')';\n }\n\n /**\n * Get the values of this index.\n *\n * @returns {number[]} The array of values.\n */\n getValues() {\n return this.#values.slice();\n }\n\n /**\n * Check if the input index can be compared to this one.\n *\n * @param {Index} rhs The index to compare to.\n * @returns {boolean} True if both indices are comparable.\n */\n canCompare(rhs) {\n // check input\n if (!rhs) {\n return false;\n }\n // check length\n if (this.length() !== rhs.length()) {\n return false;\n }\n // seems ok!\n return true;\n }\n\n /**\n * Check for Index equality.\n *\n * @param {Index} rhs The index to compare to.\n * @returns {boolean} True if both indices are equal.\n */\n equals(rhs) {\n // check if can compare\n if (!this.canCompare(rhs)) {\n return false;\n }\n // check values\n for (let i = 0, leni = this.length(); i < leni; ++i) {\n if (this.get(i) !== rhs.get(i)) {\n return false;\n }\n }\n // seems ok!\n return true;\n }\n\n /**\n * Compare indices and return different dimensions.\n *\n * @param {Index} rhs The index to compare to.\n * @returns {number[]} The list of different dimensions.\n */\n compare(rhs) {\n // check if can compare\n if (!this.canCompare(rhs)) {\n return null;\n }\n // check values\n const diffDims = [];\n for (let i = 0, leni = this.length(); i < leni; ++i) {\n if (this.get(i) !== rhs.get(i)) {\n diffDims.push(i);\n }\n }\n return diffDims;\n }\n\n /**\n * Add another index to this one.\n *\n * @param {Index} rhs The index to add.\n * @returns {Index} The index representing the sum of both indices.\n */\n add(rhs) {\n // check if can compare\n if (!this.canCompare(rhs)) {\n return null;\n }\n // add values\n const values = [];\n for (let i = 0, leni = this.length(); i < leni; ++i) {\n values.push(this.get(i) + rhs.get(i));\n }\n // seems ok!\n return new Index(values);\n }\n\n /**\n * Get the current index with a new 2D base.\n *\n * @param {number} i The new 0 index.\n * @param {number} j The new 1 index.\n * @returns {Index} The new index.\n */\n getWithNew2D(i, j) {\n const values = [i, j];\n for (let l = 2, lenl = this.length(); l < lenl; ++l) {\n values.push(this.get(l));\n }\n return new Index(values);\n }\n\n} // Index class\n\n/**\n * Get an index with values set to 0 and the input size.\n *\n * @param {number} size The size of the index.\n * @returns {Index} The zero index.\n */\nexport function getZeroIndex(size) {\n const values = new Array(size);\n values.fill(0);\n return new Index(values);\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {RescaleSlopeAndIntercept} from './rsi';\n/* eslint-enable no-unused-vars */\n\n/**\n * Modality LUT class: compensates for any modality-specific presentation.\n * Typically consists of a rescale slope and intercept to\n * rescale the data range.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.11.html}.\n */\nexport class ModalityLut {\n\n /**\n * The rescale slope.\n *\n * @type {RescaleSlopeAndIntercept}\n */\n #rsi;\n\n /**\n * Is the RSI an identity one.\n *\n * @type {boolean}\n */\n #isIdRsi;\n\n /**\n * The size of the LUT array.\n *\n * @type {number}\n */\n #length;\n\n /**\n * The internal LUT array.\n *\n * @type {Float32Array}\n */\n #lut;\n\n /**\n * @param {RescaleSlopeAndIntercept} rsi The rescale slope and intercept.\n * @param {number} bitsStored The number of bits used to store the data.\n */\n constructor(rsi, bitsStored) {\n this.#rsi = rsi;\n this.#isIdRsi = rsi.isID();\n\n this.#length = Math.pow(2, bitsStored);\n\n // create lut if not identity RSI\n if (!this.#isIdRsi) {\n this.#lut = new Float32Array(this.#length);\n for (let i = 0; i < this.#length; ++i) {\n this.#lut[i] = this.#rsi.apply(i);\n }\n }\n }\n\n /**\n * Get the Rescale Slope and Intercept (RSI).\n *\n * @returns {RescaleSlopeAndIntercept} The rescale slope and intercept object.\n */\n getRSI() {\n return this.#rsi;\n }\n\n /**\n * Get the length of the LUT array.\n *\n * @returns {number} The length of the LUT array.\n */\n getLength() {\n return this.#length;\n }\n\n /**\n * Get the value of the LUT at the given offset.\n *\n * @param {number} offset The input offset in [0,2^bitsStored] range\n * or full range for ID rescale.\n * @returns {number} The float32 value of the LUT at the given offset.\n */\n getValue(offset) {\n return this.#isIdRsi ? offset : this.#lut[offset];\n }\n\n} // class ModalityLut\n","export const logger = {\n /**\n * Available log levels.\n * Note: need to activate verbose level in\n * Chrome console to see DEBUG messages.\n */\n levels: {\n TRACE: 0,\n DEBUG: 1,\n INFO: 2,\n WARN: 3,\n ERROR: 4\n },\n\n /**\n * Logger level: default to WARN.\n */\n level: 3,\n\n /**\n * Log a trace message.\n *\n * @param {string} msg The message to log.\n */\n trace: function (msg) {\n if (this.level <= this.levels.TRACE) {\n console.trace(msg);\n }\n },\n\n /**\n * Log a debug message.\n * Careful: depends on console settings.\n *\n * @param {string} msg The message to log.\n */\n debug: function (msg) {\n if (this.level <= this.levels.DEBUG) {\n console.debug(msg);\n }\n },\n\n /**\n * Log an info message.\n *\n * @param {string} msg The message to log.\n */\n info: function (msg) {\n if (this.level <= this.levels.INFO) {\n console.info(msg);\n }\n },\n\n /**\n * Log a warn message.\n *\n * @param {string} msg The message to log.\n */\n warn: function (msg) {\n if (this.level <= this.levels.WARN) {\n console.warn(msg);\n }\n },\n\n /**\n * Log an error message.\n *\n * @param {string} msg The message to log.\n */\n error: function (msg) {\n if (this.level <= this.levels.ERROR) {\n console.error(msg);\n }\n }\n\n}; // logger\n","import {logger} from '../utils/logger';\n\n/**\n * Minimum window width value.\n *\n * Ref: {@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.11.2.html#sect_C.11.2.1.2}.\n */\nconst minWindowWidth = 1;\n\n/**\n * Validate an input window width.\n *\n * @param {number} value The value to test.\n * @returns {number} A valid window width.\n */\nexport function validateWindowWidth(value) {\n return value < minWindowWidth ? minWindowWidth : value;\n}\n\n/**\n * Window and Level also known as window width and center.\n */\nexport class WindowLevel {\n /**\n * The window center.\n *\n * @type {number}\n */\n center;\n\n /**\n * The window width.\n *\n * @type {number}\n */\n width;\n\n /**\n * @param {number} center The window center.\n * @param {number} width The window width.\n */\n constructor(center, width) {\n // check width\n if (width < minWindowWidth) {\n logger.warn('Using minimum window width since input is not valid: ' +\n width);\n width = minWindowWidth;\n }\n this.center = center;\n this.width = width;\n }\n\n /**\n * Check for equality.\n *\n * @param {WindowLevel} rhs The other object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n typeof rhs !== 'undefined' &&\n this.center === rhs.center &&\n this.width === rhs.width;\n }\n\n} // WindowLevel class\n\n/**\n * List of default window level presets.\n *\n * @type {Object.>}\n */\nexport const defaultPresets = {\n CT: {\n mediastinum: new WindowLevel(40, 400),\n lung: new WindowLevel(-500, 1500),\n bone: new WindowLevel(500, 2000),\n brain: new WindowLevel(40, 80),\n head: new WindowLevel(90, 350)\n }\n};\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {WindowLevel} from './windowLevel';\n/* eslint-enable no-unused-vars */\n\n/**\n * VOI (Values of Interest) LUT class: apply window centre and width.\n *\n * ```\n * if (x <= c - 0.5 - (w-1)/2) then y = ymin\n * else if (x > c - 0.5 + (w-1)/2) then y = ymax\n * else y = ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax - ymin) + ymin\n * ```\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.11.2.html}.\n */\nexport class VoiLut {\n\n /**\n * The window and level.\n *\n * @type {WindowLevel}\n */\n #windowLevel;\n\n /**\n * Signed data offset. Defaults to 0.\n *\n * @type {number}\n */\n #signedOffset = 0;\n\n /**\n * Output value minimum. Defaults to 0.\n *\n * @type {number}\n */\n #ymin = 0;\n\n /**\n * Output value maximum. Defaults to 255.\n *\n * @type {number}\n */\n #ymax = 255;\n\n /**\n * Input value minimum (calculated).\n *\n * @type {number}\n */\n #xmin = null;\n\n /**\n * Input value maximum (calculated).\n *\n * @type {number}\n */\n #xmax = null;\n\n /**\n * Window level equation slope (calculated).\n *\n * @type {number}\n */\n #slope = null;\n\n /**\n * Window level equation intercept (calculated).\n *\n * @type {number}\n */\n #inter = null;\n\n /**\n * @param {WindowLevel} wl The window center and width.\n */\n constructor(wl) {\n this.#windowLevel = wl;\n this.#init();\n }\n\n /**\n * Get the window and level.\n *\n * @returns {WindowLevel} The window center and width.\n */\n getWindowLevel() {\n return this.#windowLevel;\n }\n\n /**\n * Initialise members. Called at construction.\n *\n */\n #init() {\n const center = this.#windowLevel.center;\n const width = this.#windowLevel.width;\n const c = center + this.#signedOffset;\n // from the standard\n this.#xmin = c - 0.5 - ((width - 1) / 2);\n this.#xmax = c - 0.5 + ((width - 1) / 2);\n // develop the equation:\n // y = ( ( x - (c - 0.5) ) / (w-1) + 0.5 ) * (ymax - ymin) + ymin\n // y = ( x / (w-1) ) * (ymax - ymin) +\n // ( -(c - 0.5) / (w-1) + 0.5 ) * (ymax - ymin) + ymin\n this.#slope = (this.#ymax - this.#ymin) / (width - 1);\n this.#inter = (-(c - 0.5) / (width - 1) + 0.5) *\n (this.#ymax - this.#ymin) + this.#ymin;\n }\n\n /**\n * Set the signed offset.\n *\n * @param {number} offset The signed data offset,\n * typically: slope * ( size / 2).\n */\n setSignedOffset(offset) {\n this.#signedOffset = offset;\n // re-initialise\n this.#init();\n }\n\n /**\n * Apply the window level on an input value.\n *\n * @param {number} value The value to rescale as an integer.\n * @returns {number} The leveled value, in the\n * [ymin, ymax] range (default [0,255]).\n */\n apply(value) {\n if (value <= this.#xmin) {\n return this.#ymin;\n } else if (value > this.#xmax) {\n return this.#ymax;\n } else {\n return (value * this.#slope) + this.#inter;\n }\n }\n\n} // class VoiLut\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {ModalityLut} from './modalityLut';\nimport {VoiLut} from './voiLut';\n/* eslint-enable no-unused-vars */\n\n/**\n * Window LUT class: combines a modality LUT and a VOI LUT.\n */\nexport class WindowLut {\n\n /**\n * The modality LUT.\n *\n * @type {ModalityLut}\n */\n #modalityLut;\n\n /**\n * The VOI LUT.\n *\n * @type {VoiLut}\n */\n #voiLut;\n\n /**\n * The internal LUT array: Uint8ClampedArray clamps between 0 and 255.\n *\n * @type {Uint8ClampedArray}\n */\n #lut;\n\n /**\n * Shift for signed data.\n *\n * @type {number}\n */\n #signedShift = 0;\n\n /**\n * Is the RSI discrete.\n *\n * @type {boolean}\n */\n #isDiscrete = true;\n\n /**\n * Construct a window LUT object, VOI LUT is set with\n * the 'setVoiLut' method.\n *\n * @param {ModalityLut} modalityLut The associated rescale LUT.\n * @param {boolean} isSigned Flag to know if the data is signed or not.\n * @param {boolean} isDiscrete Flag to know if the input data is discrete.\n */\n constructor(modalityLut, isSigned, isDiscrete) {\n this.#modalityLut = modalityLut;\n\n if (isSigned) {\n const size = this.#modalityLut.getLength();\n this.#signedShift = size / 2;\n } else {\n this.#signedShift = 0;\n }\n\n this.#isDiscrete = isDiscrete;\n }\n\n /**\n * Get the VOI LUT.\n *\n * @returns {VoiLut} The VOI LUT.\n */\n getVoiLut() {\n return this.#voiLut;\n }\n\n /**\n * Get the modality LUT.\n *\n * @returns {ModalityLut} The modality LUT.\n */\n getModalityLut() {\n return this.#modalityLut;\n }\n\n /**\n * Set the VOI LUT.\n *\n * @param {VoiLut} lut The VOI LUT.\n */\n setVoiLut(lut) {\n // store the window values\n this.#voiLut = lut;\n\n // possible signed shift (LUT indices are positive)\n this.#voiLut.setSignedOffset(\n this.#modalityLut.getRSI().getSlope() * this.#signedShift);\n\n // create lut if not continous\n if (this.#isDiscrete) {\n const size = this.#modalityLut.getLength();\n // use clamped array (polyfilled in env.js)\n this.#lut = new Uint8ClampedArray(size);\n // by default WindowLevel returns a value in the [0,255] range\n // this is ok with regular Arrays and ClampedArray.\n for (let i = 0; i < size; ++i) {\n this.#lut[i] = this.#voiLut.apply(this.#modalityLut.getValue(i));\n }\n }\n }\n\n /**\n * Get the value of the LUT at the given offset.\n *\n * @param {number} offset The input offset in [0,2^bitsStored] range\n * for discrete data or full range for non discrete.\n * @returns {number} The integer value (default [0,255]) of the LUT\n * at the given offset.\n */\n getValue(offset) {\n if (this.#isDiscrete) {\n return this.#lut[offset + this.#signedShift];\n } else {\n return Math.floor(this.#voiLut.apply(offset + this.#signedShift));\n }\n }\n\n} // class WindowLut\n","/**\n * Lookup tables for image colour display.\n */\n\nconst lut_range_max = 256;\n\n/**\n * Build a LUT of size lut_range_max.\n *\n * @param {Function} func The i to lut function.\n * @returns {number[]} The LUT.\n */\nfunction buildLut(func) {\n const lut = [];\n for (let i = 0; i < lut_range_max; ++i) {\n lut.push(func(i));\n }\n return lut;\n}\n\n/**\n * Ramp to lut_range_max minus one on the first third values.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction toMaxFirstThird(i) {\n const val = i * 3;\n if (val > lut_range_max - 1) {\n return lut_range_max - 1;\n }\n return val;\n}\n\n/**\n * Ramp to lut_range_max minus one on the second third values,\n * otherwise return 0 for the first third and\n * lut_range_max minus one for the last third.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction toMaxSecondThird(i) {\n const third = lut_range_max / 3;\n let val = 0;\n if (i >= third) {\n val = (i - third) * 3;\n if (val > lut_range_max - 1) {\n return lut_range_max - 1;\n }\n }\n return val;\n}\n\n/**\n * Ramp to lut_range_max minus one on the last third values,\n * otherwise return 0.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction toMaxThirdThird(i) {\n const third = lut_range_max / 3;\n let val = 0;\n if (i >= 2 * third) {\n val = (i - 2 * third) * 3;\n if (val > lut_range_max - 1) {\n return lut_range_max - 1;\n }\n }\n return val;\n}\n\n/**\n * Identity, returns i.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction id(i) {\n return i;\n}\n\n/**\n * Returns lut_range_max minus one minus i.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction invId(i) {\n return (lut_range_max - 1) - i;\n}\n\n/**\n * Colour map: red, green and blue components\n * to associate with intensity values.\n */\nexport class ColourMap {\n /**\n * Red component: 256 values in the [0, 255] range.\n *\n * @type {number[]}\n */\n red;\n /**\n * Green component: 256 values in the [0, 255] range.\n *\n * @type {number[]}\n */\n green;\n /**\n * Blue component: 256 values in the [0, 255] range.\n *\n * @type {number[]}\n */\n blue;\n\n /**\n * @param {number[]} red Red component.\n * @param {number[]} green Green component.\n * @param {number[]} blue Blue component.\n */\n constructor(red, green, blue) {\n this.red = red;\n this.green = green;\n this.blue = blue;\n }\n}\n\n/**\n * List of available lookup tables (lut).\n *\n * @type {Object}\n */\nexport const luts = {\n // plain\n plain: {\n red: buildLut(id),\n green: buildLut(id),\n blue: buildLut(id)\n },\n\n // inverse plain\n invPlain: {\n red: buildLut(invId),\n green: buildLut(invId),\n blue: buildLut(invId)\n },\n\n // rainbow\n /* eslint-disable @stylistic/js/max-len */\n rainbow: {\n blue: [0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 255, 247, 239, 231, 223, 215, 207, 199, 191, 183, 175, 167, 159, 151, 143, 135, 127, 119, 111, 103, 95, 87, 79, 71, 63, 55, 47, 39, 31, 23, 15, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n green: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 251, 249, 247, 245, 243, 241, 239, 237, 235, 233, 231, 229, 227, 225, 223, 221, 219, 217, 215, 213, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 192, 189, 186, 183, 180, 177, 174, 171, 168, 165, 162, 159, 156, 153, 150, 147, 144, 141, 138, 135, 132, 129, 126, 123, 120, 117, 114, 111, 108, 105, 102, 99, 96, 93, 90, 87, 84, 81, 78, 75, 72, 69, 66, 63, 60, 57, 54, 51, 48, 45, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3],\n red: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]\n },\n /* eslint-enable @stylistic/js/max-len */\n\n // hot\n hot: {\n red: buildLut(toMaxFirstThird),\n green: buildLut(toMaxSecondThird),\n blue: buildLut(toMaxThirdThird)\n },\n\n // hot iron\n /* eslint-disable @stylistic/js/max-len */\n hot_iron: {\n red: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n green: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 255],\n blue: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 255]\n },\n /* eslint-enable @stylistic/js/max-len */\n\n // pet\n /* eslint-disable @stylistic/js/max-len */\n pet: {\n red: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n green: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 128, 126, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98, 96, 94, 92, 90, 88, 86, 84, 82, 80, 78, 76, 74, 72, 70, 68, 66, 64, 63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 255],\n blue: [0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 252, 248, 244, 240, 236, 232, 228, 224, 220, 216, 212, 208, 204, 200, 196, 192, 188, 184, 180, 176, 172, 168, 164, 160, 156, 152, 148, 144, 140, 136, 132, 128, 124, 120, 116, 112, 108, 104, 100, 96, 92, 88, 84, 80, 76, 72, 68, 64, 60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 214, 218, 222, 226, 230, 234, 238, 242, 246, 250, 255]\n },\n /* eslint-enable @stylistic/js/max-len */\n\n // hot metal blue\n /* eslint-disable @stylistic/js/max-len */\n hot_metal_blue: {\n red: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 9, 12, 15, 18, 21, 24, 26, 29, 32, 35, 38, 41, 44, 47, 50, 52, 55, 57, 59, 62, 64, 66, 69, 71, 74, 76, 78, 81, 83, 85, 88, 90, 93, 96, 99, 102, 105, 108, 111, 114, 116, 119, 122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 161, 164, 166, 169, 172, 175, 178, 181, 184, 187, 190, 194, 198, 201, 205, 209, 213, 217, 221, 224, 228, 232, 236, 240, 244, 247, 251, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n green: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 9, 11, 13, 15, 17, 19, 21, 23, 24, 26, 28, 30, 32, 34, 36, 38, 40, 41, 43, 45, 47, 49, 51, 53, 55, 56, 58, 60, 62, 64, 66, 68, 70, 72, 73, 75, 77, 79, 81, 83, 85, 87, 88, 90, 92, 94, 96, 98, 100, 102, 104, 105, 107, 109, 111, 113, 115, 117, 119, 120, 122, 124, 126, 128, 130, 132, 134, 136, 137, 139, 141, 143, 145, 147, 149, 151, 152, 154, 156, 158, 160, 162, 164, 166, 168, 169, 171, 173, 175, 177, 179, 181, 183, 184, 186, 188, 190, 192, 194, 196, 198, 200, 201, 203, 205, 207, 209, 211, 213, 215, 216, 218, 220, 222, 224, 226, 228, 229, 231, 233, 235, 237, 239, 240, 242, 244, 246, 248, 250, 251, 253, 255],\n blue: [0, 2, 4, 6, 8, 10, 12, 14, 16, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 184, 186, 188, 190, 192, 194, 196, 198, 200, 197, 194, 191, 188, 185, 182, 179, 176, 174, 171, 168, 165, 162, 159, 156, 153, 150, 144, 138, 132, 126, 121, 115, 109, 103, 97, 91, 85, 79, 74, 68, 62, 56, 50, 47, 44, 41, 38, 35, 32, 29, 26, 24, 21, 18, 15, 12, 9, 6, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 9, 12, 15, 18, 21, 24, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 76, 79, 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 126, 129, 132, 135, 138, 141, 144, 147, 150, 153, 156, 159, 162, 165, 168, 171, 174, 176, 179, 182, 185, 188, 191, 194, 197, 200, 203, 206, 210, 213, 216, 219, 223, 226, 229, 232, 236, 239, 242, 245, 249, 252, 255]\n },\n /* eslint-enable @stylistic/js/max-len */\n\n // pet 20 step\n /* eslint-disable @stylistic/js/max-len */\n pet_20step: {\n red: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n green: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n blue: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]\n }\n /* eslint-enable @stylistic/js/max-len */\n};\n","// example implementation: dcmtk/dcmiod/libsrc/cielabutil.cc\n// https://github.com/DCMTK/dcmtk/blob/DCMTK-3.6.6/dcmiod/libsrc/cielabutil.cc\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Scalar3D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * RGB colour class.\n */\nexport class RGB {\n /**\n * Red component.\n *\n * @type {number}\n */\n r;\n /**\n * Green component.\n *\n * @type {number}\n */\n g;\n /**\n * Blue component.\n *\n * @type {number}\n */\n b;\n /**\n * @param {number} r Red component.\n * @param {number} g Green component.\n * @param {number} b Blue component.\n */\n constructor(r, g, b) {\n this.r = r;\n this.g = g;\n this.b = b;\n }\n}\n\n/**\n * Check if two rgb objects are equal.\n *\n * @param {RGB} c1 The first colour.\n * @param {RGB} c2 The second colour.\n * @returns {boolean} True if both colour are equal.\n */\nexport function isEqualRgb(c1, c2) {\n return c1 !== null &&\n c2 !== null &&\n typeof c1 !== 'undefined' &&\n typeof c2 !== 'undefined' &&\n c1.r === c2.r &&\n c1.g === c2.g &&\n c1.b === c2.b;\n}\n\n/**\n * Convert YBR to RGB.\n *\n * Ref:\n * - {@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.7.6.3.html#sect_C.7.6.3.1.2},\n * - {@link https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion}.\n *\n * @param {number} y The Y component.\n * @param {number} cb The Cb component.\n * @param {number} cr The Cr component.\n * @returns {RGB} RGB equivalent as {r,g,b}.\n */\nexport function ybrToRgb(y, cb, cr) {\n return {\n r: y + 1.402 * (cr - 128),\n g: y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128),\n b: y + 1.772 * (cb - 128)\n };\n}\n\n/**\n * Convert a hex color into RGB.\n *\n * @param {string} hexStr The hex color as '#ab01ef'.\n * @returns {RGB} The RGB values as {r,g,b}.\n */\nexport function hexToRgb(hexStr) {\n return {\n r: parseInt(hexStr.substring(1, 3), 16),\n g: parseInt(hexStr.substring(3, 5), 16),\n b: parseInt(hexStr.substring(5, 7), 16)\n };\n}\n\n/**\n * Convert RGB to its hex equivalent.\n *\n * @param {RGB} rgb The RGB object as {r,g,b}.\n * @returns {string} A string representing the hex color as '#ab01ef'.\n */\nexport function rgbToHex(rgb) {\n return '#' +\n ((1 << 24) + (rgb.r << 16) + (rgb.g << 8) + rgb.b).toString(16).slice(1);\n}\n\n/**\n * Get the brightness of a RGB colour: calculates\n * the luma (Y) of the YIQ colour space.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/YIQ#From_RGB_to_YIQ}.\n *\n * @param {RGB} rgb RGB triplet.\n * @returns {number} The brightness ([0,1]).\n */\nexport function getBrightness(rgb) {\n // 0.001172549 = 0.299 / 255\n // 0.002301961 = 0.587 / 255\n // 0.000447059 = 0.114 / 255\n return rgb.r * 0.001172549 +\n rgb.g * 0.002301961 +\n rgb.b * 0.000447059;\n}\n\n/**\n * Check if a colour given in hexadecimal format is dark.\n *\n * @param {string} hexColour The colour (as '#ab01ef').\n * @returns {boolean} True if the colour is dark (brightness < 0.5).\n */\nexport function isDarkColour(hexColour) {\n return getBrightness(hexToRgb(hexColour)) < 0.5;\n}\n\n/**\n * Get the shadow colour of an input colour.\n *\n * @param {string} hexColour The colour (as '#ab01ef').\n * @returns {string} The shadow colour (white or black).\n */\nexport function getShadowColour(hexColour) {\n return isDarkColour(hexColour) ? '#fff' : '#000';\n}\n\n/**\n * Unsigned int CIE LAB value ([0, 65535]) to CIE LAB value\n * (L: [0, 100], a: [-128, 127], b: [-128, 127]).\n *\n * @param {object} triplet CIE LAB triplet as {l,a,b} with unsigned range.\n * @returns {object} CIE LAB triplet as {l,a,b} with CIE LAB range.\n */\nexport function uintLabToLab(triplet) {\n // 0.001525902 = 100 / 65535\n // 0.003891051 = 255 / 65535\n return {\n l: 0.001525902 * triplet.l,\n a: 0.003891051 * triplet.a - 128,\n b: 0.003891051 * triplet.b - 128,\n };\n}\n\n/**\n * CIE LAB value (L: [0, 100], a: [-128, 127], b: [-128, 127]) to\n * unsigned int CIE LAB ([0, 65535]).\n *\n * @param {object} triplet CIE XYZ triplet as {l,a,b} with CIE LAB range.\n * @returns {object} CIE LAB triplet as {l,a,b} with unsigned range.\n */\nexport function labToUintLab(triplet) {\n // 655.35 = 65535 / 100\n // aUint = (a + 128) * 65535 / 255\n // 257 = 65535 / 255\n // 32896 = 257 * 128\n return {\n l: 655.35 * triplet.l,\n a: 257 * triplet.a + 32896,\n b: 257 * triplet.b + 32896,\n };\n}\n\n/**\n * CIE Standard Illuminant D65, standard 2° observer.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/Illuminant_D65}.\n */\nconst d65 = {\n x: 95.0489,\n y: 100,\n z: 108.884\n};\n\n/**\n * Convert CIE LAB to CIE XYZ (standard illuminant D65, 2degree 1931).\n *\n * Ref: {@link https://en.wikipedia.org/wiki/CIELAB_color_space#From_CIELAB_to_CIEXYZ}.\n *\n * @param {object} triplet CIE LAB triplet as {l,a,b}.\n * @returns {Scalar3D} CIE XYZ triplet as {x,y,z}.\n */\nexport function cielabToCiexyz(triplet) {\n /**\n * Apply the inverse lab function.\n *\n * @param {number} x The input value.\n * @returns {number} The result.\n */\n function invLabFunc(x) {\n let res = null;\n // delta = 6 / 29 = 0.206896552\n if (x > 0.206896552) {\n res = Math.pow(x, 3);\n } else {\n // 0.128418549 = 3 * delta^2\n // 0.017712903 = 3 * delta^2 * (4 / 29)\n res = 0.128418549 * x - 0.017712903;\n }\n return res;\n }\n\n const illuminant = d65;\n const l0 = (triplet.l + 16) / 116;\n\n return {\n x: illuminant.x * invLabFunc(l0 + triplet.a / 500),\n y: illuminant.y * invLabFunc(l0),\n z: illuminant.z * invLabFunc(l0 - triplet.b / 200)\n };\n}\n\n/**\n * Convert CIE XYZ to CIE LAB (standard illuminant D65, 2degree 1931).\n *\n * Ref: {@link https://en.wikipedia.org/wiki/CIELAB_color_space#From_CIEXYZ_to_CIELAB}.\n *\n * @param {Scalar3D} triplet CIE XYZ triplet as {x,y,z}.\n * @returns {object} CIE LAB triplet as {l,a,b}.\n */\nexport function ciexyzToCielab(triplet) {\n /**\n * Apply the lab function.\n *\n * @param {number} x The input value.\n * @returns {number} The result.\n */\n function labFunc(x) {\n let res = null;\n // delta = 6 / 29 = 0.206896552\n // delta^3 = 0.008856452\n if (x > 0.008856452) {\n res = Math.pow(x, 0.333333333);\n } else {\n // 7.787037037 = 1 / 3 * delta^2\n // 0.137931034 = 4 / 29\n res = 7.787037037 * x + 0.137931034;\n }\n return res;\n }\n\n const illuminant = d65;\n const fy = labFunc(triplet.y / illuminant.y);\n\n return {\n l: 116 * fy - 16,\n a: 500 * (labFunc(triplet.x / illuminant.x) - fy),\n b: 200 * (fy - labFunc(triplet.z / illuminant.z))\n };\n}\n\n/**\n * Convert CIE XYZ to sRGB.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/SRGB#From_CIE_XYZ_to_sRGB}.\n *\n * @param {Scalar3D} triplet CIE XYZ triplet as {x,y,z}.\n * @returns {RGB} 'sRGB' triplet as {r,g,b}.\n */\nexport function ciexyzToSrgb(triplet) {\n /**\n * Apply the gamma function.\n *\n * @param {number} x The input value.\n * @returns {number} The result.\n */\n function gammaFunc(x) {\n let res = null;\n if (x <= 0.0031308) {\n res = 12.92 * x;\n } else {\n // 0.416666667 = 1 / 2.4\n res = 1.055 * Math.pow(x, 0.416666667) - 0.055;\n }\n // clip [0,1]\n return Math.min(1, Math.max(0, res));\n }\n\n const x = triplet.x / 100;\n const y = triplet.y / 100;\n const z = triplet.z / 100;\n\n return {\n r: Math.round(255 * gammaFunc(3.2406 * x - 1.5372 * y - 0.4986 * z)),\n g: Math.round(255 * gammaFunc(-0.9689 * x + 1.8758 * y + 0.0415 * z)),\n b: Math.round(255 * gammaFunc(0.0557 * x - 0.2040 * y + 1.0570 * z))\n };\n}\n\n/**\n * Convert sRGB to CIE XYZ.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/SRGB#From_sRGB_to_CIE_XYZ}.\n *\n * @param {RGB} triplet 'sRGB' triplet as {r,g,b}.\n * @returns {Scalar3D} CIE XYZ triplet as {x,y,z}.\n */\nexport function srgbToCiexyz(triplet) {\n /**\n * Apply the inverse gamma function.\n *\n * @param {number} x The input value.\n * @returns {number} The result.\n */\n function invGammaFunc(x) {\n let res = null;\n if (x <= 0.04045) {\n res = x / 12.92;\n } else {\n res = Math.pow((x + 0.055) / 1.055, 2.4);\n }\n return res;\n }\n\n const rl = invGammaFunc(triplet.r / 255);\n const gl = invGammaFunc(triplet.g / 255);\n const bl = invGammaFunc(triplet.b / 255);\n\n return {\n x: 100 * (0.4124 * rl + 0.3576 * gl + 0.1805 * bl),\n y: 100 * (0.2126 * rl + 0.7152 * gl + 0.0722 * bl),\n z: 100 * (0.0193 * rl + 0.1192 * gl + 0.9505 * bl)\n };\n}\n\n/**\n * Convert CIE LAB to sRGB (standard illuminant D65).\n *\n * @param {object} triplet CIE LAB triplet as {l,a,b}.\n * @returns {RGB} 'sRGB' triplet as {r,g,b}.\n */\nexport function cielabToSrgb(triplet) {\n return ciexyzToSrgb(cielabToCiexyz(triplet));\n}\n\n/**\n * Convert sRGB to CIE LAB (standard illuminant D65).\n *\n * @param {RGB} triplet 'sRGB' triplet as {r,g,b}.\n * @returns {object} CIE LAB triplet as {l,a,b}.\n */\nexport function srgbToCielab(triplet) {\n return ciexyzToCielab(srgbToCiexyz(triplet));\n}\n\n/**\n * Get the hex code of a string colour for a colour used in pre dwv v0.17.\n *\n * @param {string} name The name of a colour.\n * @returns {string} The hex representing the colour.\n */\nexport function colourNameToHex(name) {\n // default colours used in dwv version < 0.17\n const dict = {\n Yellow: '#ffff00',\n Red: '#ff0000',\n White: '#ffffff',\n Green: '#008000',\n Blue: '#0000ff',\n Lime: '#00ff00',\n Fuchsia: '#ff00ff',\n Black: '#000000'\n };\n let res = '#ffff00';\n if (typeof dict[name] !== 'undefined') {\n res = dict[name];\n }\n return res;\n}\n","/**\n * Immutable 3D vector.\n */\nexport class Vector3D {\n\n /**\n * X coordinate.\n *\n * @type {number}\n */\n #x;\n\n /**\n * Y coordinate.\n *\n * @type {number}\n */\n #y;\n\n /**\n * Z coordinate.\n *\n * @type {number}\n */\n #z;\n\n /**\n * @param {number} x The X component of the vector.\n * @param {number} y The Y component of the vector.\n * @param {number} z The Z component of the vector.\n */\n constructor(x, y, z) {\n this.#x = x;\n this.#y = y;\n this.#z = z;\n }\n\n /**\n * Get the X component of the vector.\n *\n * @returns {number} The X component of the vector.\n */\n getX() {\n return this.#x;\n }\n\n /**\n * Get the Y component of the vector.\n *\n * @returns {number} The Y component of the vector.\n */\n getY() {\n return this.#y;\n }\n\n /**\n * Get the Z component of the vector.\n *\n * @returns {number} The Z component of the vector.\n */\n getZ() {\n return this.#z;\n }\n\n /**\n * Check for Vector3D equality.\n *\n * @param {Vector3D} rhs The other vector to compare to.\n * @returns {boolean} True if both vectors are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.#x === rhs.getX() &&\n this.#y === rhs.getY() &&\n this.#z === rhs.getZ();\n }\n\n /**\n * Get a string representation of the Vector3D.\n *\n * @returns {string} The vector as a string.\n */\n toString() {\n return '(' + this.#x +\n ', ' + this.#y +\n ', ' + this.#z + ')';\n }\n\n /**\n * Get the norm of the vector.\n *\n * @returns {number} The norm.\n */\n norm() {\n return Math.sqrt(\n (this.#x * this.#x) +\n (this.#y * this.#y) +\n (this.#z * this.#z)\n );\n }\n\n /**\n * Get the cross product with another Vector3D, ie the\n * vector that is perpendicular to both a and b.\n * If both vectors are parallel, the cross product is a zero vector.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/Cross_product}.\n *\n * @param {Vector3D} vector3D The input vector.\n * @returns {Vector3D} The result vector.\n */\n crossProduct(vector3D) {\n return new Vector3D(\n (this.#y * vector3D.getZ()) - (vector3D.getY() * this.#z),\n (this.#z * vector3D.getX()) - (vector3D.getZ() * this.#x),\n (this.#x * vector3D.getY()) - (vector3D.getX() * this.#y));\n }\n\n /**\n * Get the dot product with another Vector3D.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/Dot_product}.\n *\n * @param {Vector3D} vector3D The input vector.\n * @returns {number} The dot product.\n */\n dotProduct(vector3D) {\n return (this.#x * vector3D.getX()) +\n (this.#y * vector3D.getY()) +\n (this.#z * vector3D.getZ());\n }\n\n /**\n * Is this vector codirectional to an input one.\n *\n * @param {Vector3D} vector3D The vector to test.\n * @returns {boolean} True if codirectional, false is opposite.\n */\n isCodirectional(vector3D) {\n // a.dot(b) = ||a|| * ||b|| * cos(theta)\n // (https://en.wikipedia.org/wiki/Dot_product#Geometric_definition)\n // -> the sign of the dot product depends on the cosinus of\n // the angle between the vectors\n // -> >0 => vectors are codirectional\n // -> <0 => vectors are opposite\n return this.dotProduct(vector3D) > 0;\n }\n\n} // Vector3D class","import {Vector3D} from './vector';\nimport {Point3D} from './point';\nimport {Index} from './index';\nimport {logger} from '../utils/logger';\n\n// Number.EPSILON is difference between 1 and the smallest\n// floating point number greater than 1\n// -> ~2e-16\n// BIG_EPSILON -> ~2e-12\nexport const BIG_EPSILON = Number.EPSILON * 1e4;\n// 'real world', for example when comparing positions\nexport const REAL_WORLD_EPSILON = 1e-4;\n\n/**\n * Check if two numbers are similar.\n *\n * @param {number} a The first number.\n * @param {number} b The second number.\n * @param {number} tol The comparison tolerance,\n * default to Number.EPSILON.\n * @returns {boolean} True if similar.\n */\nexport function isSimilar(a, b, tol) {\n if (typeof tol === 'undefined') {\n tol = Number.EPSILON;\n }\n return Math.abs(a - b) < tol;\n}\n\n/**\n * Immutable 3x3 Matrix.\n */\nexport class Matrix33 {\n\n /**\n * Matrix values.\n *\n * @type {number[]}\n */\n #values;\n\n /**\n * Matrix inverse, calculated at first ask.\n *\n * @type {Matrix33}\n */\n #inverse;\n\n /**\n * @param {number[]} values Row-major ordered 9 values.\n */\n constructor(values) {\n this.#values = values;\n }\n\n /**\n * Get a value of the matrix.\n *\n * @param {number} row The row at wich to get the value.\n * @param {number} col The column at wich to get the value.\n * @returns {number|undefined} The value at the position.\n */\n get(row, col) {\n return this.#values[row * 3 + col];\n }\n\n /**\n * Get the inverse of this matrix.\n *\n * @returns {Matrix33|undefined} The inverse matrix or undefined\n * if the determinant is zero.\n */\n getInverse() {\n if (typeof this.#inverse === 'undefined') {\n this.#inverse = getMatrixInverse(this);\n }\n return this.#inverse;\n }\n\n /**\n * Check for Matrix33 equality.\n *\n * @param {Matrix33} rhs The other matrix to compare to.\n * @param {number} [p] A numeric expression for the precision to use in check\n * (ex: 0.001). Defaults to Number.EPSILON if not provided.\n * @returns {boolean} True if both matrices are equal.\n */\n equals(rhs, p) {\n // TODO: add type check\n // check values\n for (let i = 0; i < 3; ++i) {\n for (let j = 0; j < 3; ++j) {\n if (!isSimilar(this.get(i, j), rhs.get(i, j), p)) {\n return false;\n }\n }\n }\n return true;\n }\n\n /**\n * Get a string representation of the Matrix33.\n *\n * @returns {string} The matrix as a string.\n */\n toString() {\n let str = '[';\n for (let i = 0; i < 3; ++i) {\n if (i !== 0) {\n str += ', \\n ';\n }\n for (let j = 0; j < 3; ++j) {\n if (j !== 0) {\n str += ', ';\n }\n str += this.get(i, j);\n }\n }\n str += ']';\n return str;\n }\n\n /**\n * Multiply this matrix by another.\n *\n * @param {Matrix33} rhs The matrix to multiply by.\n * @returns {Matrix33} The product matrix.\n */\n multiply(rhs) {\n const values = [];\n for (let i = 0; i < 3; ++i) {\n for (let j = 0; j < 3; ++j) {\n let tmp = 0;\n for (let k = 0; k < 3; ++k) {\n tmp += this.get(i, k) * rhs.get(k, j);\n }\n values.push(tmp);\n }\n }\n return new Matrix33(values);\n }\n\n /**\n * Get the absolute value of this matrix.\n *\n * @returns {Matrix33} The result matrix.\n */\n getAbs() {\n const values = [];\n for (let i = 0; i < 3; ++i) {\n for (let j = 0; j < 3; ++j) {\n values.push(Math.abs(this.get(i, j)));\n }\n }\n return new Matrix33(values);\n }\n\n /**\n * Multiply this matrix by a 3D array.\n *\n * @param {number[]} array3D The input 3D array.\n * @returns {number[]} The result 3D array.\n */\n multiplyArray3D(array3D) {\n if (array3D.length !== 3) {\n throw new Error('Cannot multiply 3x3 matrix with non 3D array: ' +\n array3D.length);\n }\n const values = [];\n for (let i = 0; i < 3; ++i) {\n let tmp = 0;\n for (let j = 0; j < 3; ++j) {\n tmp += this.get(i, j) * array3D[j];\n }\n values.push(tmp);\n }\n return values;\n }\n\n /**\n * Multiply this matrix by a 3D vector.\n *\n * @param {Vector3D} vector3D The input 3D vector.\n * @returns {Vector3D} The result 3D vector.\n */\n multiplyVector3D(vector3D) {\n const array3D = this.multiplyArray3D(\n [vector3D.getX(), vector3D.getY(), vector3D.getZ()]\n );\n return new Vector3D(array3D[0], array3D[1], array3D[2]);\n }\n\n /**\n * Multiply this matrix by a 3D point.\n *\n * @param {Point3D} point3D The input 3D point.\n * @returns {Point3D} The result 3D point.\n */\n multiplyPoint3D(point3D) {\n const array3D = this.multiplyArray3D(\n [point3D.getX(), point3D.getY(), point3D.getZ()]\n );\n return new Point3D(array3D[0], array3D[1], array3D[2]);\n }\n\n /**\n * Multiply this matrix by a 3D index.\n *\n * @param {Index} index3D The input 3D index.\n * @returns {Index} The result 3D index.\n */\n multiplyIndex3D(index3D) {\n const array3D = this.multiplyArray3D(index3D.getValues());\n return new Index(array3D);\n }\n\n /**\n * Get the index of the maximum in absolute value of a row.\n *\n * @param {number} row The row to get the maximum from.\n * @returns {object} The {value,index} of the maximum.\n */\n getRowAbsMax(row) {\n const values = [\n Math.abs(this.get(row, 0)),\n Math.abs(this.get(row, 1)),\n Math.abs(this.get(row, 2))\n ];\n const absMax = Math.max.apply(null, values);\n const index = values.indexOf(absMax);\n return {\n value: this.get(row, index),\n index: index\n };\n }\n\n /**\n * Get the index of the maximum in absolute value of a column.\n *\n * @param {number} col The column to get the maximum from.\n * @returns {object} The {value,index} of the maximum.\n */\n getColAbsMax(col) {\n const values = [\n Math.abs(this.get(0, col)),\n Math.abs(this.get(1, col)),\n Math.abs(this.get(2, col))\n ];\n const absMax = Math.max.apply(null, values);\n const index = values.indexOf(absMax);\n return {\n value: this.get(index, col),\n index: index\n };\n }\n\n /**\n * Get this matrix with only zero and +/- ones instead of the maximum.\n *\n * @returns {Matrix33} The simplified matrix.\n */\n asOneAndZeros() {\n const res = [];\n for (let j = 0; j < 3; ++j) {\n const max = this.getRowAbsMax(j);\n const sign = max.value > 0 ? 1 : -1;\n for (let i = 0; i < 3; ++i) {\n if (i === max.index) {\n res.push(1 * sign);\n } else {\n res.push(0);\n }\n }\n }\n return new Matrix33(res);\n }\n\n /**\n * Get the third column direction index of an orientation matrix.\n *\n * @returns {number} The index of the absolute maximum of the last column.\n */\n getThirdColMajorDirection() {\n return this.getColAbsMax(2).index;\n }\n\n} // Matrix33\n\n/**\n * Get the inverse of an input 3*3 matrix.\n *\n * Ref:\n * - {@link https://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3_%C3%97_3_matrices},\n * - {@link https://github.com/willnode/N-Matrix-Programmer}.\n *\n * @param {Matrix33} m The input matrix.\n * @returns {Matrix33|undefined} The inverse matrix or undefined\n * if the determinant is zero.\n */\nfunction getMatrixInverse(m) {\n const m00 = m.get(0, 0);\n const m01 = m.get(0, 1);\n const m02 = m.get(0, 2);\n const m10 = m.get(1, 0);\n const m11 = m.get(1, 1);\n const m12 = m.get(1, 2);\n const m20 = m.get(2, 0);\n const m21 = m.get(2, 1);\n const m22 = m.get(2, 2);\n\n const a1212 = m11 * m22 - m12 * m21;\n const a2012 = m12 * m20 - m10 * m22;\n const a0112 = m10 * m21 - m11 * m20;\n\n let det = m00 * a1212 + m01 * a2012 + m02 * a0112;\n if (det === 0) {\n logger.warn('Cannot invert 3*3 matrix with zero determinant.');\n return undefined;\n }\n det = 1 / det;\n\n const values = [\n det * a1212,\n det * (m02 * m21 - m01 * m22),\n det * (m01 * m12 - m02 * m11),\n det * a2012,\n det * (m00 * m22 - m02 * m20),\n det * (m02 * m10 - m00 * m12),\n det * a0112,\n det * (m01 * m20 - m00 * m21),\n det * (m00 * m11 - m01 * m10)\n ];\n\n return new Matrix33(values);\n}\n\n/**\n * Create a 3x3 identity matrix.\n *\n * @returns {Matrix33} The identity matrix.\n */\nexport function getIdentityMat33() {\n /* eslint-disable @stylistic/js/array-element-newline */\n return new Matrix33([\n 1, 0, 0,\n 0, 1, 0,\n 0, 0, 1\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n}\n\n/**\n * Check if a matrix is a 3x3 identity matrix.\n *\n * @param {Matrix33} mat33 The matrix to test.\n * @returns {boolean} True if identity.\n */\nexport function isIdentityMat33(mat33) {\n return mat33.equals(getIdentityMat33());\n}\n","import {isSimilar} from './matrix';\nimport {Vector3D} from './vector';\n\n/**\n * Immutable 2D point.\n */\nexport class Point2D {\n\n /**\n * X position.\n *\n * @type {number}\n */\n #x;\n\n /**\n * Y position.\n *\n * @type {number}\n */\n #y;\n\n /**\n * @param {number} x The X coordinate for the point.\n * @param {number} y The Y coordinate for the point.\n */\n constructor(x, y) {\n this.#x = x;\n this.#y = y;\n }\n\n /**\n * Get the X position of the point.\n *\n * @returns {number} The X position of the point.\n */\n getX() {\n return this.#x;\n }\n\n /**\n * Get the Y position of the point.\n *\n * @returns {number} The Y position of the point.\n */\n getY() {\n return this.#y;\n }\n\n /**\n * Get the values of this point.\n *\n * @returns {number[]} The array of values.\n */\n getValues() {\n return [this.#x, this.#y];\n }\n\n /**\n * Get the centroid of the point, ie itself.\n *\n * @returns {Point2D} The centroid point.\n */\n getCentroid() {\n return this;\n }\n\n /**\n * Check for Point2D equality.\n *\n * @param {Point2D} rhs The other point to compare to.\n * @returns {boolean} True if both points are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n typeof rhs !== 'undefined' &&\n this.#x === rhs.getX() &&\n this.#y === rhs.getY();\n }\n\n /**\n * Get a string representation of the Point2D.\n *\n * @returns {string} The point as a string.\n */\n toString() {\n return '(' + this.#x + ', ' + this.#y + ')';\n }\n\n /**\n * Get the distance to another Point2D.\n *\n * @param {Point2D} point2D The input point.\n * @returns {number} Ths distance to the input point.\n */\n getDistance(point2D) {\n const dx = this.#x - point2D.getX();\n const dy = this.#y - point2D.getY();\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n} // Point2D class\n\n/**\n * Immutable 3D point.\n */\nexport class Point3D {\n\n /**\n * X position.\n *\n * @type {number}\n */\n #x;\n\n /**\n * Y position.\n *\n * @type {number}\n */\n #y;\n\n /**\n * Z position.\n *\n * @type {number}\n */\n #z;\n\n /**\n * @param {number} x The X coordinate for the point.\n * @param {number} y The Y coordinate for the point.\n * @param {number} z The Z coordinate for the point.\n */\n constructor(x, y, z) {\n this.#x = x;\n this.#y = y;\n this.#z = z;\n }\n\n /**\n * Get the X position of the point.\n *\n * @returns {number} The X position of the point.\n */\n getX() {\n return this.#x;\n }\n\n /**\n * Get the Y position of the point.\n *\n * @returns {number} The Y position of the point.\n */\n getY() {\n return this.#y;\n }\n\n /**\n * Get the Z position of the point.\n *\n * @returns {number} The Z position of the point.\n */\n getZ() {\n return this.#z;\n }\n\n /**\n * Get the values of this point.\n *\n * @returns {number[]} The array of values.\n */\n getValues() {\n return [this.#x, this.#y, this.#z];\n }\n\n /**\n * Check for Point3D equality.\n *\n * @param {Point3D} rhs The other point to compare to.\n * @returns {boolean} True if both points are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.#x === rhs.getX() &&\n this.#y === rhs.getY() &&\n this.#z === rhs.getZ();\n }\n\n /**\n * Check for Point3D similarity.\n *\n * @param {Point3D} rhs The other point to compare to.\n * @param {number} tol Optional comparison tolerance,\n * default to Number.EPSILON.\n * @returns {boolean} True if both points are equal.\n */\n isSimilar(rhs, tol) {\n return rhs !== null &&\n isSimilar(this.#x, rhs.getX(), tol) &&\n isSimilar(this.#y, rhs.getY(), tol) &&\n isSimilar(this.#z, rhs.getZ(), tol);\n }\n\n /**\n * Get a string representation of the Point3D.\n *\n * @returns {string} The point as a string.\n */\n toString() {\n return '(' + this.#x +\n ', ' + this.#y +\n ', ' + this.#z + ')';\n }\n\n /**\n * Get the distance to another Point3D.\n *\n * @param {Point3D} point3D The input point.\n * @returns {number} Ths distance to the input point.\n */\n getDistance(point3D) {\n return Math.sqrt(this.#getSquaredDistance(point3D));\n }\n\n /**\n * Get the square of the distance between this and\n * an input point. Used for sorting.\n *\n * @param {Point3D} point3D The input point.\n * @returns {number} The square of the distance.\n */\n #getSquaredDistance(point3D) {\n const dx = this.#x - point3D.getX();\n const dy = this.#y - point3D.getY();\n const dz = this.#z - point3D.getZ();\n return dx * dx + dy * dy + dz * dz;\n }\n\n /**\n * Get the closest point to this in a Point3D list.\n *\n * @param {Point3D[]} pointList The list to check.\n * @returns {number} The index of the closest point in the input list.\n */\n getClosest(pointList) {\n let minIndex = 0;\n // the order between squared distances and distances is the same\n let minDist = this.#getSquaredDistance(pointList[minIndex]);\n for (let i = 0; i < pointList.length; ++i) {\n const dist = this.#getSquaredDistance(pointList[i]);\n if (dist < minDist) {\n minIndex = i;\n minDist = dist;\n }\n }\n return minIndex;\n }\n\n /**\n * Get the difference to another Point3D.\n *\n * @param {Point3D} point3D The input point.\n * @returns {Vector3D} The 3D vector from the input point to this one.\n */\n minus(point3D) {\n return new Vector3D(\n (this.#x - point3D.getX()),\n (this.#y - point3D.getY()),\n (this.#z - point3D.getZ()));\n }\n\n} // Point3D class\n\n/**\n * Get an array find callback for an equal input point.\n *\n * @param {Point3D} point The point to compare to.\n * @returns {Function} A function that compares, using `equals`,\n * its input point to the one given as input to this function.\n */\nexport function getEqualPoint3DFunction(point) {\n return function (element) {\n return element.equals(point);\n };\n}\n\n/**\n * Immutable point.\n * Warning: the input array is NOT cloned, modifying it will\n * modify the point values.\n */\nexport class Point {\n\n /**\n * Point values.\n *\n * @type {number[]}\n */\n #values;\n\n /**\n * @param {number[]} values The point values.\n */\n constructor(values) {\n if (!values || typeof values === 'undefined') {\n throw new Error('Cannot create point with no values.');\n }\n if (values.length === 0) {\n throw new Error('Cannot create point with empty values.');\n }\n const valueCheck = function (val) {\n return !isNaN(val);\n };\n if (!values.every(valueCheck)) {\n throw new Error('Cannot create point with non number values.');\n }\n this.#values = values;\n }\n\n /**\n * Get the point value at the given array index.\n *\n * @param {number} i The index to get.\n * @returns {number} The value.\n */\n get(i) {\n return this.#values[i];\n }\n\n /**\n * Get the length of the point.\n *\n * @returns {number} The length.\n */\n length() {\n return this.#values.length;\n }\n\n /**\n * Get a string representation of the point.\n *\n * @returns {string} The point as a string.\n */\n toString() {\n return '(' + this.#values.toString() + ')';\n }\n\n /**\n * Get the values of this point.\n *\n * @returns {number[]} The array of values.\n */\n getValues() {\n return this.#values.slice();\n }\n\n /**\n * Check if the input point can be compared to this one.\n *\n * @param {Point} rhs The point to compare to.\n * @returns {boolean} True if both points are comparable.\n */\n canCompare(rhs) {\n // check input\n if (!rhs) {\n return false;\n }\n // check length\n if (this.length() !== rhs.length()) {\n return false;\n }\n // seems ok!\n return true;\n }\n\n /**\n * Check for Point equality.\n *\n * @param {Point} rhs The point to compare to.\n * @returns {boolean} True if both points are equal.\n */\n equals(rhs) {\n // check if can compare\n if (!this.canCompare(rhs)) {\n return false;\n }\n // check values\n for (let i = 0, leni = this.length(); i < leni; ++i) {\n if (this.get(i) !== rhs.get(i)) {\n return false;\n }\n }\n // seems ok!\n return true;\n }\n\n /**\n * Compare points and return different dimensions.\n *\n * @param {Point} rhs The point to compare to.\n * @returns {number[]} The list of different dimensions.\n */\n compare(rhs) {\n // check if can compare\n if (!this.canCompare(rhs)) {\n return null;\n }\n // check values\n const diffDims = [];\n for (let i = 0, leni = this.length(); i < leni; ++i) {\n if (this.get(i) !== rhs.get(i)) {\n diffDims.push(i);\n }\n }\n return diffDims;\n }\n\n /**\n * Get the 3D part of this point.\n *\n * @returns {Point3D} The Point3D.\n */\n get3D() {\n return new Point3D(this.get(0), this.get(1), this.get(2));\n }\n\n /**\n * Add another point to this one.\n *\n * @param {Point} rhs The point to add.\n * @returns {Point} The point representing the sum of both points.\n */\n add(rhs) {\n // check if can compare\n if (!this.canCompare(rhs)) {\n return null;\n }\n const values = [];\n const values0 = this.getValues();\n const values1 = rhs.getValues();\n for (let i = 0; i < values0.length; ++i) {\n values.push(values0[i] + values1[i]);\n }\n return new Point(values);\n }\n\n /**\n * Merge this point with a Point3D to create a new point.\n *\n * @param {Point3D} rhs The Point3D to merge with.\n * @returns {Point} The merge result.\n */\n mergeWith3D(rhs) {\n const values = this.getValues();\n values[0] = rhs.getX();\n values[1] = rhs.getY();\n values[2] = rhs.getZ();\n return new Point(values);\n }\n\n} // Point class\n","/**\n * Namespace for translation function\n * (in a namespace to allow for override from client).\n */\nexport const i18n = {\n\n /**\n * Get the translated text.\n *\n * @param {string} key The key to the text entry.\n * @returns {string|undefined} The translated text.\n */\n t(key) {\n let res = key;\n const props = key.split('.');\n // defaut units look like 'unit.cm2'\n if (props.length === 2 &&\n props[0] === 'unit') {\n const units = {\n mm: 'mm',\n cm2: 'cm²',\n degree: '°'\n };\n res = units[props[1]];\n }\n return res;\n }\n\n};\n","\nimport {i18n} from './i18n';\n\n/**\n * Capitalise the first letter of a string.\n *\n * @param {string} string The string to capitalise the first letter.\n * @returns {string} The new string.\n */\nexport function capitaliseFirstLetter(string) {\n let res = string;\n if (string) {\n res = string.charAt(0).toUpperCase() + string.slice(1);\n }\n return res;\n}\n\n/**\n * Check if a string starts with the input element.\n *\n * @param {string} str The input string.\n * @param {string} search The searched start.\n * @param {number} [rawPos] The position in this string at which to begin\n * searching for searchString. Defaults to 0.\n * @returns {boolean} True if the input string starts with the searched string.\n */\nexport function startsWith(str, search, rawPos) {\n if (typeof str === 'undefined' || str === null ||\n typeof search === 'undefined' || search === null) {\n return false;\n }\n const pos = rawPos > 0 ? rawPos | 0 : 0;\n return str.substring(pos, pos + search.length) === search;\n}\n\n/**\n * Check if a string ends with the input element.\n *\n * @param {string} str The input string.\n * @param {string} search The searched ending.\n * @returns {boolean} True if the input string ends with the searched string.\n */\nexport function endsWith(str, search) {\n if (typeof str === 'undefined' || str === null ||\n typeof search === 'undefined' || search === null) {\n return false;\n }\n return str.substring(str.length - search.length) === search;\n}\n\n/**\n * Split key/value string: `key0=val00&key0=val01&key1=val10\n * will return `{key0 : [val00, val01], key1 : val1}`.\n *\n * @param {string} inputStr The string to split.\n * @returns {object} The split string.\n */\nexport function splitKeyValueString(inputStr) {\n // result\n const result = {};\n // check input string\n if (inputStr) {\n // split key/value pairs\n const pairs = inputStr.split('&');\n for (let i = 0; i < pairs.length; ++i) {\n const pair = pairs[i].split('=');\n // if the key does not exist, create it\n if (!result[pair[0]]) {\n result[pair[0]] = pair[1];\n } else {\n // make it an array\n if (!(result[pair[0]] instanceof Array)) {\n result[pair[0]] = [result[pair[0]]];\n }\n result[pair[0]].push(pair[1]);\n }\n }\n }\n return result;\n}\n\n/**\n * Get flags from an input string. Flags are words surrounded with curly\n * braces.\n *\n * @param {string} inputStr The input string.\n * @returns {string[]} An array of found flags.\n */\nexport function getFlags(inputStr) {\n const flags = [];\n // check input string\n if (inputStr === null || typeof inputStr === 'undefined') {\n return flags;\n }\n\n // word surrounded by curly braces\n const regex = /{(\\w+)}/g;\n\n let match = regex.exec(inputStr);\n while (match) {\n flags.push(match[1]); // first matching group\n match = regex.exec(inputStr);\n }\n return flags;\n}\n\n/**\n * Replace flags in a input string. Flags are keywords surrounded with curly\n * braces.\n *\n * @param {string} inputStr The input string.\n * @param {object} values A object of {value, unit}.\n * @returns {string} The result string.\n */\nexport function replaceFlags(inputStr, values) {\n let res = '';\n // check input string\n if (inputStr === null || typeof inputStr === 'undefined') {\n return res;\n }\n res = inputStr;\n // check values\n if (values === null || typeof values === 'undefined') {\n return res;\n }\n\n // loop through flags\n const keys = getFlags(inputStr);\n for (let i = 0; i < keys.length; ++i) {\n const valueObj = values[keys[i]];\n if (valueObj !== null && typeof valueObj !== 'undefined' &&\n valueObj.value !== null && typeof valueObj.value !== 'undefined') {\n // value string\n let valueStr = valueObj.value.toPrecision(4);\n // add unit if available\n // space or no space? Yes apart from degree...\n // check: https://en.wikipedia.org/wiki/Space_(punctuation)#Spaces_and_unit_symbols\n if (valueObj.unit !== null &&\n typeof valueObj.unit !== 'undefined' &&\n valueObj.unit.length !== 0) {\n if (valueObj.unit !== 'unit.degree') {\n valueStr += ' ';\n }\n valueStr += i18n.t(valueObj.unit);\n }\n // flag to replace\n const flag = '{' + keys[i] + '}';\n // replace\n res = res.replace(flag, valueStr);\n }\n }\n // return\n return res;\n}\n\n/**\n * Get the root of an input path.\n * Splits using `/` as separator.\n *\n * @param {string} path The input path.\n * @returns {string} The input path without its last part.\n */\nexport function getRootPath(path) {\n return path.split('/').slice(0, -1).join('/');\n}\n\n/**\n * Get a file extension: anything after the last dot.\n * File name starting with a dot are discarded.\n * Extensions are expected to contain at least one letter.\n *\n * @param {string} filePath The file path containing the file name.\n * @returns {string} The lower case file extension or null for none.\n */\nexport function getFileExtension(filePath) {\n let ext = null;\n if (typeof filePath !== 'undefined' &&\n filePath !== null &&\n filePath[0] !== '.') {\n const pathSplit = filePath.toLowerCase().split('.');\n if (pathSplit.length !== 1) {\n ext = pathSplit.pop();\n // extension should contain at least one letter and no slash\n const regExp = /[a-z]/;\n if (!regExp.test(ext) || ext.includes('/')) {\n ext = null;\n }\n }\n }\n return ext;\n}\n\n/**\n * Convert a string to a Uint8Array.\n *\n * @param {string} str The string to convert.\n * @returns {Uint8Array} The Uint8Array.\n */\nexport function stringToUint8Array(str) {\n const arr = new Uint8Array(str.length);\n for (let i = 0, leni = str.length; i < leni; i++) {\n arr[i] = str.charCodeAt(i);\n }\n return arr;\n}\n\n/**\n * Round a float number to a given precision.\n *\n * Inspired from {@link https://stackoverflow.com/a/49729715/3639892}.\n *\n * Can be a solution to not have trailing zero as when\n * using toFixed or toPrecision.\n * '+number.toFixed(precision)' does not pass all the tests...\n *\n * @param {number} number The number to round.\n * @param {number} precision The rounding precision.\n * @returns {number} The rounded number.\n */\nexport function precisionRound(number, precision) {\n const factor = Math.pow(10, precision);\n const delta = 0.01 / factor; // fixes precisionRound(1.005, 2)\n return Math.round(number * factor + delta) / factor;\n}\n","import {stringToUint8Array} from './string';\n\n/**\n * Get a string id from array values in the form of: '#0-1_#1-2'.\n *\n * @param {Array} arr The input array.\n * @param {number[]} [dims] Optional list of dimensions to use.\n * @returns {string} The string id.\n */\nexport function toStringId(arr, dims) {\n // use all dims if not as input\n if (typeof dims === 'undefined') {\n dims = [];\n for (let i = 0; i < arr.length; ++i) {\n dims.push(i);\n }\n }\n // check dims\n for (let i = 0; i < dims.length; ++i) {\n if (dims[i] >= arr.length) {\n throw new Error('Non valid dimension for toStringId');\n }\n }\n // build string\n let res = '';\n for (let i = 0; i < dims.length; ++i) {\n if (i !== 0) {\n res += '_';\n }\n res += '#' + dims[i] + '-' + arr[dims[i]];\n }\n return res;\n}\n\n/**\n * Get an array from an id string in the form of: '#0-1_#1-2'\n * (result of toStringId).\n *\n * @param {string} inputStr The input string.\n * @returns {Array} The corresponding array (minimum size is 3D).\n */\nexport function getArrayFromStringId(inputStr) {\n // split ids\n const strIds = inputStr.split('_');\n // get the size of the index (minimum 3)\n let numberOfDims = 3;\n let dim;\n for (let i = 0; i < strIds.length; ++i) {\n // expecting dim < 10\n dim = parseInt(strIds[i].substring(1, 2), 10);\n // dim is zero based\n if (dim + 1 > numberOfDims) {\n numberOfDims = dim + 1;\n }\n }\n // default values\n const values = new Array(numberOfDims);\n values.fill(0);\n // get other values from the input string\n for (let j = 0; j < strIds.length; ++j) {\n // expecting dim < 10\n dim = parseInt(strIds[j].substring(1, 2), 10);\n const value = parseInt(strIds[j].substring(3), 10);\n values[dim] = value;\n }\n\n return values;\n}\n\n/**\n * Check if the first input array contains all the\n * elements of the second input array.\n *\n * @param {string[]} arr0 The test array.\n * @param {string[]} arr1 The elements to check in the first array.\n * @returns {boolean} True if all the elements of arr1 are included in arr0.\n */\nexport function arrayContains(arr0, arr1) {\n // check input\n if (arr0 === null ||\n arr1 === null ||\n typeof arr0 === 'undefined' ||\n typeof arr1 === 'undefined') {\n return false;\n }\n if (arr0.length === 0 ||\n arr1.length === 0 ||\n arr1.length > arr0.length) {\n return false;\n }\n // check values\n for (const itemArr1 of arr1) {\n if (!arr0.includes(itemArr1)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Check for array equality after sorting.\n *\n * @param {Array} arr0 First array.\n * @param {Array} arr1 Second array.\n * @returns {boolean} True if both array are defined and contain same values.\n */\nexport function arraySortEquals(arr0, arr1) {\n if (arr0 === null ||\n arr1 === null ||\n typeof arr0 === 'undefined' ||\n typeof arr1 === 'undefined') {\n return false;\n }\n const arr0sorted = arr0.slice().sort();\n const arr1sorted = arr1.slice().sort();\n return arrayEquals(arr0sorted, arr1sorted);\n}\n\n/**\n * Check for array equality.\n *\n * @param {Array} arr0 First array.\n * @param {Array} arr1 Second array.\n * @returns {boolean} True if both array are defined and contain same values.\n */\nexport function arrayEquals(arr0, arr1) {\n if (arr0 === null ||\n arr1 === null ||\n typeof arr0 === 'undefined' ||\n typeof arr1 === 'undefined') {\n return false;\n }\n if (arr0.length !== arr1.length) {\n return false;\n }\n return arr0.every(function (element, index) {\n return element === arr1[index];\n });\n}\n\n/**\n * Convert a Uint8Array to a string.\n *\n * @param {Uint8Array} arr The array to convert.\n * @returns {string} The array as string.\n */\nexport function uint8ArrayToString(arr) {\n return String.fromCharCode.apply(String, arr);\n}\n\n/**\n * Array find in a subset of the input array.\n * Equivalent to: `arr.slice(start, end).find(callbackFn)`.\n *\n * @param {Uint8Array} arr The input array to search.\n * @param {Function} callbackFn The find function.\n * @param {number|undefined} start The array start index.\n * @param {number|undefined} [end] The array end index.\n * @returns {number|undefined} The index where the element was found.\n */\nexport function findInArraySubset(arr, callbackFn, start, end) {\n // check inputs\n if (typeof start === 'undefined' ||\n start < 0 ||\n start >= arr.length\n ) {\n start = 0;\n }\n if (typeof end === 'undefined' ||\n end <= start ||\n end > arr.length) {\n end = arr.length;\n }\n // run\n for (let i = start; i < end; ++i) {\n if (callbackFn(arr[i], i, arr)) {\n return i;\n }\n }\n return undefined;\n}\n\n/**\n * Get a find in array callback.\n *\n * @param {Uint8Array} arr1 The array to find.\n * @returns {Function} The find callback function.\n */\nexport function getFindArrayInArrayCallback(arr1) {\n return function (element, index, arr0) {\n for (let i = 0; i < arr1.length; ++i) {\n if (arr0[index + i] !== arr1[i]) {\n return false;\n }\n }\n return true;\n };\n}\n\n/**\n * Extract each element of a multipart ArrayBuffer.\n *\n * Ref: {@link https://en.wikipedia.org/wiki/MIME#Multipart_messages}.\n *\n * @param {ArrayBuffer} arr The multipart array.\n * @returns {Array} The multipart parts as an array of object as\n * {'Content-Type', ..., data} (depending on header tags).\n */\nexport function parseMultipart(arr) {\n const u8Array = new Uint8Array(arr);\n\n const parts = [];\n // check input\n if (u8Array.length === 0) {\n return parts;\n }\n\n // \\r\\n\\r\\n\n const doubleReturnNew = new Uint8Array([0x0d, 0x0a, 0x0d, 0x0a]);\n const partHeaderEndCb = getFindArrayInArrayCallback(doubleReturnNew);\n\n // look for boundary in first part header\n let partHeaderEndIndex = findInArraySubset(\n u8Array, partHeaderEndCb, 0\n );\n if (typeof partHeaderEndIndex === 'undefined') {\n throw new Error('Can\\'t find the end of the first multipart header');\n }\n const firstPartHeader = u8Array.slice(0, partHeaderEndIndex);\n // switch to string to use split\n const lines = uint8ArrayToString(firstPartHeader).split('\\r\\n');\n // boundary should start with '--'\n let boundaryStr;\n for (let i = 0; i < lines.length; ++i) {\n if (lines[i][0] === '-' && lines[i][1] === '-') {\n boundaryStr = lines[i];\n break;\n }\n }\n if (typeof boundaryStr === 'undefined') {\n throw new Error('Can\\'t find the boundary between multi-parts');\n }\n const boundary = stringToUint8Array(boundaryStr);\n const boundaryCb = getFindArrayInArrayCallback(boundary);\n const boundaryLen = boundaryStr.length;\n\n // skip mime header\n let nextBoundaryIndex = findInArraySubset(\n u8Array, boundaryCb, 0\n );\n\n // loop through content\n while (typeof partHeaderEndIndex !== 'undefined') {\n const part = {};\n\n // header\n const partHeader = u8Array.slice(\n nextBoundaryIndex + boundaryLen, partHeaderEndIndex);\n // split into object\n const partHeaderLines =\n uint8ArrayToString(partHeader).split('\\r\\n');\n for (let l = 0; l < partHeaderLines.length; ++l) {\n const line = partHeaderLines[l];\n const semiColonIndex = line.indexOf(':');\n if (semiColonIndex !== -1) {\n const key = line.substring(0, semiColonIndex).trim();\n const val = line.substring(semiColonIndex + 1).trim();\n part[key] = val;\n }\n }\n\n // find next boundary\n nextBoundaryIndex = findInArraySubset(\n u8Array, boundaryCb, partHeaderEndIndex\n );\n // exit if none\n if (typeof nextBoundaryIndex === 'undefined') {\n break;\n }\n\n // get part\n // partHeaderEndIndex plus the size of the '\\r\\n\\r\\n' separator\n const dataBeginIndex = partHeaderEndIndex + 4;\n // nextBoundaryIndex minus the previous '\\r\\n'\n const dataEndIndex = nextBoundaryIndex - 2;\n if (dataBeginIndex < dataEndIndex) {\n part.data = u8Array.slice(dataBeginIndex, dataEndIndex).buffer;\n } else {\n part.data = new Uint8Array();\n }\n\n // store part\n parts.push(part);\n\n // find next part header end\n partHeaderEndIndex = findInArraySubset(\n u8Array, partHeaderEndCb,\n nextBoundaryIndex + boundaryLen\n );\n }\n\n return parts;\n}\n\n/**\n * Build a multipart message.\n *\n * Ref:\n * - {@link https://en.wikipedia.org/wiki/MIME#Multipart_messages},\n * - {@link https://hg.orthanc-server.com/orthanc-dicomweb/file/tip/Resources/Samples/JavaScript/stow-rs.js}.\n *\n * @param {Array} parts The message parts as an array of object containing\n * content headers and messages as the data property (as returned by parse).\n * @param {string} boundary The message boundary.\n * @returns {Uint8Array} The full multipart message.\n */\nexport function buildMultipart(parts, boundary) {\n const lineBreak = '\\r\\n';\n // build headers and calculate size\n let partsSize = 0;\n const headers = [];\n for (let i = 0; i < parts.length; ++i) {\n let headerStr = '';\n if (i !== 0) {\n headerStr += lineBreak;\n }\n headerStr += '--' + boundary + lineBreak;\n const partKeys = Object.keys(parts[i]);\n for (let k = 0; k < partKeys.length; ++k) {\n const key = partKeys[k];\n if (key !== 'data') {\n headerStr += key + ': ' + parts[i][key] + lineBreak;\n }\n }\n headerStr += lineBreak;\n const header = stringToUint8Array(headerStr);\n headers.push(header);\n partsSize += header.byteLength + parts[i].data.byteLength;\n }\n // build trailer\n const trailerStr = lineBreak + '--' + boundary + '--' + lineBreak;\n const trailer = stringToUint8Array(trailerStr);\n\n // final buffer\n const buffer = new Uint8Array(partsSize + trailer.byteLength);\n let offset = 0;\n // concatenate parts\n for (let j = 0; j < parts.length; ++j) {\n buffer.set(headers[j], offset);\n offset += headers[j].byteLength;\n buffer.set(new Uint8Array(parts[j].data), offset);\n offset += parts[j].data.byteLength;\n }\n // end buffer with trailer\n buffer.set(trailer, offset);\n\n // return\n return buffer;\n}\n","/* eslint-disable @stylistic/js/quote-props */\n/* eslint @stylistic/js/max-len:0 */\n\n/**\n * DICOM tag dictionary 2022a.\n * Generated using xml standard conversion from {@link https://github.com/ivmartel/dcmStdToJs} v0.1.0.\n *\n * Conversion changes:\n * - (vr) 'See Note' -> 'NONE',\n * - (vr) 'OB or OW' -> 'ox',\n * - (vr) 'US or SS' -> 'xs',\n * - (vr) 'US or OW' -> 'xx',\n * - (vr) 'US or SS or OW' -> 'xs',\n * - added 'GenericGroupLength' element to each group.\n *\n * Local changes:\n * - tag numbers with 'xx' were replaced with '00', 'xxx' with '001' and\n * 'xxxx' with '0004'.\n *\n * @type {Object>}\n */\nexport const dictionary = {\n '0000': {\n '0000': ['UL', '1', 'CommandGroupLength'],\n '0001': ['UL', '1', 'CommandLengthToEnd'],\n '0002': ['UI', '1', 'AffectedSOPClassUID'],\n '0003': ['UI', '1', 'RequestedSOPClassUID'],\n '0010': ['SH', '1', 'CommandRecognitionCode'],\n '0100': ['US', '1', 'CommandField'],\n '0110': ['US', '1', 'MessageID'],\n '0120': ['US', '1', 'MessageIDBeingRespondedTo'],\n '0200': ['AE', '1', 'Initiator'],\n '0300': ['AE', '1', 'Receiver'],\n '0400': ['AE', '1', 'FindLocation'],\n '0600': ['AE', '1', 'MoveDestination'],\n '0700': ['US', '1', 'Priority'],\n '0800': ['US', '1', 'CommandDataSetType'],\n '0850': ['US', '1', 'NumberOfMatches'],\n '0860': ['US', '1', 'ResponseSequenceNumber'],\n '0900': ['US', '1', 'Status'],\n '0901': ['AT', '1-n', 'OffendingElement'],\n '0902': ['LO', '1', 'ErrorComment'],\n '0903': ['US', '1', 'ErrorID'],\n '1000': ['UI', '1', 'AffectedSOPInstanceUID'],\n '1001': ['UI', '1', 'RequestedSOPInstanceUID'],\n '1002': ['US', '1', 'EventTypeID'],\n '1005': ['AT', '1-n', 'AttributeIdentifierList'],\n '1008': ['US', '1', 'ActionTypeID'],\n '1020': ['US', '1', 'NumberOfRemainingSuboperations'],\n '1021': ['US', '1', 'NumberOfCompletedSuboperations'],\n '1022': ['US', '1', 'NumberOfFailedSuboperations'],\n '1023': ['US', '1', 'NumberOfWarningSuboperations'],\n '1030': ['AE', '1', 'MoveOriginatorApplicationEntityTitle'],\n '1031': ['US', '1', 'MoveOriginatorMessageID'],\n '4000': ['LT', '1', 'DialogReceiver'],\n '4010': ['LT', '1', 'TerminalType'],\n '5010': ['SH', '1', 'MessageSetID'],\n '5020': ['SH', '1', 'EndMessageID'],\n '5110': ['LT', '1', 'DisplayFormat'],\n '5120': ['LT', '1', 'PagePositionID'],\n '5130': ['CS', '1', 'TextFormatID'],\n '5140': ['CS', '1', 'NormalReverse'],\n '5150': ['CS', '1', 'AddGrayScale'],\n '5160': ['CS', '1', 'Borders'],\n '5170': ['IS', '1', 'Copies'],\n '5180': ['CS', '1', 'CommandMagnificationType'],\n '5190': ['CS', '1', 'Erase'],\n '51A0': ['CS', '1', 'Print'],\n '51B0': ['US', '1-n', 'Overlays']\n },\n '0002': {\n '0000': ['UL', '1', 'FileMetaInformationGroupLength'],\n '0001': ['OB', '1', 'FileMetaInformationVersion'],\n '0002': ['UI', '1', 'MediaStorageSOPClassUID'],\n '0003': ['UI', '1', 'MediaStorageSOPInstanceUID'],\n '0010': ['UI', '1', 'TransferSyntaxUID'],\n '0012': ['UI', '1', 'ImplementationClassUID'],\n '0013': ['SH', '1', 'ImplementationVersionName'],\n '0016': ['AE', '1', 'SourceApplicationEntityTitle'],\n '0017': ['AE', '1', 'SendingApplicationEntityTitle'],\n '0018': ['AE', '1', 'ReceivingApplicationEntityTitle'],\n '0026': ['UR', '1', 'SourcePresentationAddress'],\n '0027': ['UR', '1', 'SendingPresentationAddress'],\n '0028': ['UR', '1', 'ReceivingPresentationAddress'],\n '0031': ['OB', '1', 'RTVMetaInformationVersion'],\n '0032': ['UI', '1', 'RTVCommunicationSOPClassUID'],\n '0033': ['UI', '1', 'RTVCommunicationSOPInstanceUID'],\n '0035': ['OB', '1', 'RTVSourceIdentifier'],\n '0036': ['OB', '1', 'RTVFlowIdentifier'],\n '0037': ['UL', '1', 'RTVFlowRTPSamplingRate'],\n '0038': ['FD', '1', 'RTVFlowActualFrameDuration'],\n '0100': ['UI', '1', 'PrivateInformationCreatorUID'],\n '0102': ['OB', '1', 'PrivateInformation']\n },\n '0004': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '1130': ['CS', '1', 'FileSetID'],\n '1141': ['CS', '1-8', 'FileSetDescriptorFileID'],\n '1142': ['CS', '1', 'SpecificCharacterSetOfFileSetDescriptorFile'],\n '1200': ['UL', '1', 'OffsetOfTheFirstDirectoryRecordOfTheRootDirectoryEntity'],\n '1202': ['UL', '1', 'OffsetOfTheLastDirectoryRecordOfTheRootDirectoryEntity'],\n '1212': ['US', '1', 'FileSetConsistencyFlag'],\n '1220': ['SQ', '1', 'DirectoryRecordSequence'],\n '1400': ['UL', '1', 'OffsetOfTheNextDirectoryRecord'],\n '1410': ['US', '1', 'RecordInUseFlag'],\n '1420': ['UL', '1', 'OffsetOfReferencedLowerLevelDirectoryEntity'],\n '1430': ['CS', '1', 'DirectoryRecordType'],\n '1432': ['UI', '1', 'PrivateRecordUID'],\n '1500': ['CS', '1-8', 'ReferencedFileID'],\n '1504': ['UL', '1', 'MRDRDirectoryRecordOffset'],\n '1510': ['UI', '1', 'ReferencedSOPClassUIDInFile'],\n '1511': ['UI', '1', 'ReferencedSOPInstanceUIDInFile'],\n '1512': ['UI', '1', 'ReferencedTransferSyntaxUIDInFile'],\n '151A': ['UI', '1-n', 'ReferencedRelatedGeneralSOPClassUIDInFile'],\n '1600': ['UL', '1', 'NumberOfReferences']\n },\n '0008': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['UL', '1', 'LengthToEnd'],\n '0005': ['CS', '1-n', 'SpecificCharacterSet'],\n '0006': ['SQ', '1', 'LanguageCodeSequence'],\n '0008': ['CS', '2-n', 'ImageType'],\n '0010': ['SH', '1', 'RecognitionCode'],\n '0012': ['DA', '1', 'InstanceCreationDate'],\n '0013': ['TM', '1', 'InstanceCreationTime'],\n '0014': ['UI', '1', 'InstanceCreatorUID'],\n '0015': ['DT', '1', 'InstanceCoercionDateTime'],\n '0016': ['UI', '1', 'SOPClassUID'],\n '0018': ['UI', '1', 'SOPInstanceUID'],\n '001A': ['UI', '1-n', 'RelatedGeneralSOPClassUID'],\n '001B': ['UI', '1', 'OriginalSpecializedSOPClassUID'],\n '0020': ['DA', '1', 'StudyDate'],\n '0021': ['DA', '1', 'SeriesDate'],\n '0022': ['DA', '1', 'AcquisitionDate'],\n '0023': ['DA', '1', 'ContentDate'],\n '0024': ['DA', '1', 'OverlayDate'],\n '0025': ['DA', '1', 'CurveDate'],\n '002A': ['DT', '1', 'AcquisitionDateTime'],\n '0030': ['TM', '1', 'StudyTime'],\n '0031': ['TM', '1', 'SeriesTime'],\n '0032': ['TM', '1', 'AcquisitionTime'],\n '0033': ['TM', '1', 'ContentTime'],\n '0034': ['TM', '1', 'OverlayTime'],\n '0035': ['TM', '1', 'CurveTime'],\n '0040': ['US', '1', 'DataSetType'],\n '0041': ['LO', '1', 'DataSetSubtype'],\n '0042': ['CS', '1', 'NuclearMedicineSeriesType'],\n '0050': ['SH', '1', 'AccessionNumber'],\n '0051': ['SQ', '1', 'IssuerOfAccessionNumberSequence'],\n '0052': ['CS', '1', 'QueryRetrieveLevel'],\n '0053': ['CS', '1', 'QueryRetrieveView'],\n '0054': ['AE', '1-n', 'RetrieveAETitle'],\n '0055': ['AE', '1', 'StationAETitle'],\n '0056': ['CS', '1', 'InstanceAvailability'],\n '0058': ['UI', '1-n', 'FailedSOPInstanceUIDList'],\n '0060': ['CS', '1', 'Modality'],\n '0061': ['CS', '1-n', 'ModalitiesInStudy'],\n '0062': ['UI', '1-n', 'SOPClassesInStudy'],\n '0063': ['SQ', '1', 'AnatomicRegionsInStudyCodeSequence'],\n '0064': ['CS', '1', 'ConversionType'],\n '0068': ['CS', '1', 'PresentationIntentType'],\n '0070': ['LO', '1', 'Manufacturer'],\n '0080': ['LO', '1', 'InstitutionName'],\n '0081': ['ST', '1', 'InstitutionAddress'],\n '0082': ['SQ', '1', 'InstitutionCodeSequence'],\n '0090': ['PN', '1', 'ReferringPhysicianName'],\n '0092': ['ST', '1', 'ReferringPhysicianAddress'],\n '0094': ['SH', '1-n', 'ReferringPhysicianTelephoneNumbers'],\n '0096': ['SQ', '1', 'ReferringPhysicianIdentificationSequence'],\n '009C': ['PN', '1-n', 'ConsultingPhysicianName'],\n '009D': ['SQ', '1', 'ConsultingPhysicianIdentificationSequence'],\n '0100': ['SH', '1', 'CodeValue'],\n '0101': ['LO', '1', 'ExtendedCodeValue'],\n '0102': ['SH', '1', 'CodingSchemeDesignator'],\n '0103': ['SH', '1', 'CodingSchemeVersion'],\n '0104': ['LO', '1', 'CodeMeaning'],\n '0105': ['CS', '1', 'MappingResource'],\n '0106': ['DT', '1', 'ContextGroupVersion'],\n '0107': ['DT', '1', 'ContextGroupLocalVersion'],\n '0108': ['LT', '1', 'ExtendedCodeMeaning'],\n '0109': ['SQ', '1', 'CodingSchemeResourcesSequence'],\n '010A': ['CS', '1', 'CodingSchemeURLType'],\n '010B': ['CS', '1', 'ContextGroupExtensionFlag'],\n '010C': ['UI', '1', 'CodingSchemeUID'],\n '010D': ['UI', '1', 'ContextGroupExtensionCreatorUID'],\n '010E': ['UR', '1', 'CodingSchemeURL'],\n '010F': ['CS', '1', 'ContextIdentifier'],\n '0110': ['SQ', '1', 'CodingSchemeIdentificationSequence'],\n '0112': ['LO', '1', 'CodingSchemeRegistry'],\n '0114': ['ST', '1', 'CodingSchemeExternalID'],\n '0115': ['ST', '1', 'CodingSchemeName'],\n '0116': ['ST', '1', 'CodingSchemeResponsibleOrganization'],\n '0117': ['UI', '1', 'ContextUID'],\n '0118': ['UI', '1', 'MappingResourceUID'],\n '0119': ['UC', '1', 'LongCodeValue'],\n '0120': ['UR', '1', 'URNCodeValue'],\n '0121': ['SQ', '1', 'EquivalentCodeSequence'],\n '0122': ['LO', '1', 'MappingResourceName'],\n '0123': ['SQ', '1', 'ContextGroupIdentificationSequence'],\n '0124': ['SQ', '1', 'MappingResourceIdentificationSequence'],\n '0201': ['SH', '1', 'TimezoneOffsetFromUTC'],\n '0202': ['', '', ''],\n '0220': ['SQ', '1', 'ResponsibleGroupCodeSequence'],\n '0221': ['CS', '1', 'EquipmentModality'],\n '0222': ['LO', '1', 'ManufacturerRelatedModelGroup'],\n '0300': ['SQ', '1', 'PrivateDataElementCharacteristicsSequence'],\n '0301': ['US', '1', 'PrivateGroupReference'],\n '0302': ['LO', '1', 'PrivateCreatorReference'],\n '0303': ['CS', '1', 'BlockIdentifyingInformationStatus'],\n '0304': ['US', '1-n', 'NonidentifyingPrivateElements'],\n '0305': ['SQ', '1', 'DeidentificationActionSequence'],\n '0306': ['US', '1-n', 'IdentifyingPrivateElements'],\n '0307': ['CS', '1', 'DeidentificationAction'],\n '0308': ['US', '1', 'PrivateDataElement'],\n '0309': ['UL', '1-3', 'PrivateDataElementValueMultiplicity'],\n '030A': ['CS', '1', 'PrivateDataElementValueRepresentation'],\n '030B': ['UL', '1-2', 'PrivateDataElementNumberOfItems'],\n '030C': ['UC', '1', 'PrivateDataElementName'],\n '030D': ['UC', '1', 'PrivateDataElementKeyword'],\n '030E': ['UT', '1', 'PrivateDataElementDescription'],\n '030F': ['UT', '1', 'PrivateDataElementEncoding'],\n '0310': ['SQ', '1', 'PrivateDataElementDefinitionSequence'],\n '1000': ['AE', '1', 'NetworkID'],\n '1010': ['SH', '1', 'StationName'],\n '1030': ['LO', '1', 'StudyDescription'],\n '1032': ['SQ', '1', 'ProcedureCodeSequence'],\n '103E': ['LO', '1', 'SeriesDescription'],\n '103F': ['SQ', '1', 'SeriesDescriptionCodeSequence'],\n '1040': ['LO', '1', 'InstitutionalDepartmentName'],\n '1041': ['SQ', '1', 'InstitutionalDepartmentTypeCodeSequence'],\n '1048': ['PN', '1-n', 'PhysiciansOfRecord'],\n '1049': ['SQ', '1', 'PhysiciansOfRecordIdentificationSequence'],\n '1050': ['PN', '1-n', 'PerformingPhysicianName'],\n '1052': ['SQ', '1', 'PerformingPhysicianIdentificationSequence'],\n '1060': ['PN', '1-n', 'NameOfPhysiciansReadingStudy'],\n '1062': ['SQ', '1', 'PhysiciansReadingStudyIdentificationSequence'],\n '1070': ['PN', '1-n', 'OperatorsName'],\n '1072': ['SQ', '1', 'OperatorIdentificationSequence'],\n '1080': ['LO', '1-n', 'AdmittingDiagnosesDescription'],\n '1084': ['SQ', '1', 'AdmittingDiagnosesCodeSequence'],\n '1090': ['LO', '1', 'ManufacturerModelName'],\n '1100': ['SQ', '1', 'ReferencedResultsSequence'],\n '1110': ['SQ', '1', 'ReferencedStudySequence'],\n '1111': ['SQ', '1', 'ReferencedPerformedProcedureStepSequence'],\n '1115': ['SQ', '1', 'ReferencedSeriesSequence'],\n '1120': ['SQ', '1', 'ReferencedPatientSequence'],\n '1125': ['SQ', '1', 'ReferencedVisitSequence'],\n '1130': ['SQ', '1', 'ReferencedOverlaySequence'],\n '1134': ['SQ', '1', 'ReferencedStereometricInstanceSequence'],\n '113A': ['SQ', '1', 'ReferencedWaveformSequence'],\n '1140': ['SQ', '1', 'ReferencedImageSequence'],\n '1145': ['SQ', '1', 'ReferencedCurveSequence'],\n '114A': ['SQ', '1', 'ReferencedInstanceSequence'],\n '114B': ['SQ', '1', 'ReferencedRealWorldValueMappingInstanceSequence'],\n '1150': ['UI', '1', 'ReferencedSOPClassUID'],\n '1155': ['UI', '1', 'ReferencedSOPInstanceUID'],\n '1156': ['SQ', '1', 'DefinitionSourceSequence'],\n '115A': ['UI', '1-n', 'SOPClassesSupported'],\n '1160': ['IS', '1-n', 'ReferencedFrameNumber'],\n '1161': ['UL', '1-n', 'SimpleFrameList'],\n '1162': ['UL', '3-3n', 'CalculatedFrameList'],\n '1163': ['FD', '2', 'TimeRange'],\n '1164': ['SQ', '1', 'FrameExtractionSequence'],\n '1167': ['UI', '1', 'MultiFrameSourceSOPInstanceUID'],\n '1190': ['UR', '1', 'RetrieveURL'],\n '1195': ['UI', '1', 'TransactionUID'],\n '1196': ['US', '1', 'WarningReason'],\n '1197': ['US', '1', 'FailureReason'],\n '1198': ['SQ', '1', 'FailedSOPSequence'],\n '1199': ['SQ', '1', 'ReferencedSOPSequence'],\n '119A': ['SQ', '1', 'OtherFailuresSequence'],\n '1200': ['SQ', '1', 'StudiesContainingOtherReferencedInstancesSequence'],\n '1250': ['SQ', '1', 'RelatedSeriesSequence'],\n '2110': ['CS', '1', 'LossyImageCompressionRetired'],\n '2111': ['ST', '1', 'DerivationDescription'],\n '2112': ['SQ', '1', 'SourceImageSequence'],\n '2120': ['SH', '1', 'StageName'],\n '2122': ['IS', '1', 'StageNumber'],\n '2124': ['IS', '1', 'NumberOfStages'],\n '2127': ['SH', '1', 'ViewName'],\n '2128': ['IS', '1', 'ViewNumber'],\n '2129': ['IS', '1', 'NumberOfEventTimers'],\n '212A': ['IS', '1', 'NumberOfViewsInStage'],\n '2130': ['DS', '1-n', 'EventElapsedTimes'],\n '2132': ['LO', '1-n', 'EventTimerNames'],\n '2133': ['SQ', '1', 'EventTimerSequence'],\n '2134': ['FD', '1', 'EventTimeOffset'],\n '2135': ['SQ', '1', 'EventCodeSequence'],\n '2142': ['IS', '1', 'StartTrim'],\n '2143': ['IS', '1', 'StopTrim'],\n '2144': ['IS', '1', 'RecommendedDisplayFrameRate'],\n '2200': ['CS', '1', 'TransducerPosition'],\n '2204': ['CS', '1', 'TransducerOrientation'],\n '2208': ['CS', '1', 'AnatomicStructure'],\n '2218': ['SQ', '1', 'AnatomicRegionSequence'],\n '2220': ['SQ', '1', 'AnatomicRegionModifierSequence'],\n '2228': ['SQ', '1', 'PrimaryAnatomicStructureSequence'],\n '2229': ['SQ', '1', 'AnatomicStructureSpaceOrRegionSequence'],\n '2230': ['SQ', '1', 'PrimaryAnatomicStructureModifierSequence'],\n '2240': ['SQ', '1', 'TransducerPositionSequence'],\n '2242': ['SQ', '1', 'TransducerPositionModifierSequence'],\n '2244': ['SQ', '1', 'TransducerOrientationSequence'],\n '2246': ['SQ', '1', 'TransducerOrientationModifierSequence'],\n '2251': ['SQ', '1', 'AnatomicStructureSpaceOrRegionCodeSequenceTrial'],\n '2253': ['SQ', '1', 'AnatomicPortalOfEntranceCodeSequenceTrial'],\n '2255': ['SQ', '1', 'AnatomicApproachDirectionCodeSequenceTrial'],\n '2256': ['ST', '1', 'AnatomicPerspectiveDescriptionTrial'],\n '2257': ['SQ', '1', 'AnatomicPerspectiveCodeSequenceTrial'],\n '2258': ['ST', '1', 'AnatomicLocationOfExaminingInstrumentDescriptionTrial'],\n '2259': ['SQ', '1', 'AnatomicLocationOfExaminingInstrumentCodeSequenceTrial'],\n '225A': ['SQ', '1', 'AnatomicStructureSpaceOrRegionModifierCodeSequenceTrial'],\n '225C': ['SQ', '1', 'OnAxisBackgroundAnatomicStructureCodeSequenceTrial'],\n '3001': ['SQ', '1', 'AlternateRepresentationSequence'],\n '3002': ['UI', '1-n', 'AvailableTransferSyntaxUID'],\n '3010': ['UI', '1-n', 'IrradiationEventUID'],\n '3011': ['SQ', '1', 'SourceIrradiationEventSequence'],\n '3012': ['UI', '1', 'RadiopharmaceuticalAdministrationEventUID'],\n '4000': ['LT', '1', 'IdentifyingComments'],\n '9007': ['CS', '4', 'FrameType'],\n '9092': ['SQ', '1', 'ReferencedImageEvidenceSequence'],\n '9121': ['SQ', '1', 'ReferencedRawDataSequence'],\n '9123': ['UI', '1', 'CreatorVersionUID'],\n '9124': ['SQ', '1', 'DerivationImageSequence'],\n '9154': ['SQ', '1', 'SourceImageEvidenceSequence'],\n '9205': ['CS', '1', 'PixelPresentation'],\n '9206': ['CS', '1', 'VolumetricProperties'],\n '9207': ['CS', '1', 'VolumeBasedCalculationTechnique'],\n '9208': ['CS', '1', 'ComplexImageComponent'],\n '9209': ['CS', '1', 'AcquisitionContrast'],\n '9215': ['SQ', '1', 'DerivationCodeSequence'],\n '9237': ['SQ', '1', 'ReferencedPresentationStateSequence'],\n '9410': ['SQ', '1', 'ReferencedOtherPlaneSequence'],\n '9458': ['SQ', '1', 'FrameDisplaySequence'],\n '9459': ['FL', '1', 'RecommendedDisplayFrameRateInFloat'],\n '9460': ['CS', '1', 'SkipFrameRangeFlag']\n },\n '0010': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['PN', '1', 'PatientName'],\n '0020': ['LO', '1', 'PatientID'],\n '0021': ['LO', '1', 'IssuerOfPatientID'],\n '0022': ['CS', '1', 'TypeOfPatientID'],\n '0024': ['SQ', '1', 'IssuerOfPatientIDQualifiersSequence'],\n '0026': ['SQ', '1', 'SourcePatientGroupIdentificationSequence'],\n '0027': ['SQ', '1', 'GroupOfPatientsIdentificationSequence'],\n '0028': ['US', '3', 'SubjectRelativePositionInImage'],\n '0030': ['DA', '1', 'PatientBirthDate'],\n '0032': ['TM', '1', 'PatientBirthTime'],\n '0033': ['LO', '1', 'PatientBirthDateInAlternativeCalendar'],\n '0034': ['LO', '1', 'PatientDeathDateInAlternativeCalendar'],\n '0035': ['CS', '1', 'PatientAlternativeCalendar'],\n '0040': ['CS', '1', 'PatientSex'],\n '0050': ['SQ', '1', 'PatientInsurancePlanCodeSequence'],\n '0101': ['SQ', '1', 'PatientPrimaryLanguageCodeSequence'],\n '0102': ['SQ', '1', 'PatientPrimaryLanguageModifierCodeSequence'],\n '0200': ['CS', '1', 'QualityControlSubject'],\n '0201': ['SQ', '1', 'QualityControlSubjectTypeCodeSequence'],\n '0212': ['UC', '1', 'StrainDescription'],\n '0213': ['LO', '1', 'StrainNomenclature'],\n '0214': ['LO', '1', 'StrainStockNumber'],\n '0215': ['SQ', '1', 'StrainSourceRegistryCodeSequence'],\n '0216': ['SQ', '1', 'StrainStockSequence'],\n '0217': ['LO', '1', 'StrainSource'],\n '0218': ['UT', '1', 'StrainAdditionalInformation'],\n '0219': ['SQ', '1', 'StrainCodeSequence'],\n '0221': ['SQ', '1', 'GeneticModificationsSequence'],\n '0222': ['UC', '1', 'GeneticModificationsDescription'],\n '0223': ['LO', '1', 'GeneticModificationsNomenclature'],\n '0229': ['SQ', '1', 'GeneticModificationsCodeSequence'],\n '1000': ['LO', '1-n', 'OtherPatientIDs'],\n '1001': ['PN', '1-n', 'OtherPatientNames'],\n '1002': ['SQ', '1', 'OtherPatientIDsSequence'],\n '1005': ['PN', '1', 'PatientBirthName'],\n '1010': ['AS', '1', 'PatientAge'],\n '1020': ['DS', '1', 'PatientSize'],\n '1021': ['SQ', '1', 'PatientSizeCodeSequence'],\n '1022': ['DS', '1', 'PatientBodyMassIndex'],\n '1023': ['DS', '1', 'MeasuredAPDimension'],\n '1024': ['DS', '1', 'MeasuredLateralDimension'],\n '1030': ['DS', '1', 'PatientWeight'],\n '1040': ['LO', '1', 'PatientAddress'],\n '1050': ['LO', '1-n', 'InsurancePlanIdentification'],\n '1060': ['PN', '1', 'PatientMotherBirthName'],\n '1080': ['LO', '1', 'MilitaryRank'],\n '1081': ['LO', '1', 'BranchOfService'],\n '1090': ['LO', '1', 'MedicalRecordLocator'],\n '1100': ['SQ', '1', 'ReferencedPatientPhotoSequence'],\n '2000': ['LO', '1-n', 'MedicalAlerts'],\n '2110': ['LO', '1-n', 'Allergies'],\n '2150': ['LO', '1', 'CountryOfResidence'],\n '2152': ['LO', '1', 'RegionOfResidence'],\n '2154': ['SH', '1-n', 'PatientTelephoneNumbers'],\n '2155': ['LT', '1', 'PatientTelecomInformation'],\n '2160': ['SH', '1', 'EthnicGroup'],\n '2180': ['SH', '1', 'Occupation'],\n '21A0': ['CS', '1', 'SmokingStatus'],\n '21B0': ['LT', '1', 'AdditionalPatientHistory'],\n '21C0': ['US', '1', 'PregnancyStatus'],\n '21D0': ['DA', '1', 'LastMenstrualDate'],\n '21F0': ['LO', '1', 'PatientReligiousPreference'],\n '2201': ['LO', '1', 'PatientSpeciesDescription'],\n '2202': ['SQ', '1', 'PatientSpeciesCodeSequence'],\n '2203': ['CS', '1', 'PatientSexNeutered'],\n '2210': ['CS', '1', 'AnatomicalOrientationType'],\n '2292': ['LO', '1', 'PatientBreedDescription'],\n '2293': ['SQ', '1', 'PatientBreedCodeSequence'],\n '2294': ['SQ', '1', 'BreedRegistrationSequence'],\n '2295': ['LO', '1', 'BreedRegistrationNumber'],\n '2296': ['SQ', '1', 'BreedRegistryCodeSequence'],\n '2297': ['PN', '1', 'ResponsiblePerson'],\n '2298': ['CS', '1', 'ResponsiblePersonRole'],\n '2299': ['LO', '1', 'ResponsibleOrganization'],\n '4000': ['LT', '1', 'PatientComments'],\n '9431': ['FL', '1', 'ExaminedBodyThickness']\n },\n '0012': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['LO', '1', 'ClinicalTrialSponsorName'],\n '0020': ['LO', '1', 'ClinicalTrialProtocolID'],\n '0021': ['LO', '1', 'ClinicalTrialProtocolName'],\n '0030': ['LO', '1', 'ClinicalTrialSiteID'],\n '0031': ['LO', '1', 'ClinicalTrialSiteName'],\n '0040': ['LO', '1', 'ClinicalTrialSubjectID'],\n '0042': ['LO', '1', 'ClinicalTrialSubjectReadingID'],\n '0050': ['LO', '1', 'ClinicalTrialTimePointID'],\n '0051': ['ST', '1', 'ClinicalTrialTimePointDescription'],\n '0052': ['FD', '1', 'LongitudinalTemporalOffsetFromEvent'],\n '0053': ['CS', '1', 'LongitudinalTemporalEventType'],\n '0060': ['LO', '1', 'ClinicalTrialCoordinatingCenterName'],\n '0062': ['CS', '1', 'PatientIdentityRemoved'],\n '0063': ['LO', '1-n', 'DeidentificationMethod'],\n '0064': ['SQ', '1', 'DeidentificationMethodCodeSequence'],\n '0071': ['LO', '1', 'ClinicalTrialSeriesID'],\n '0072': ['LO', '1', 'ClinicalTrialSeriesDescription'],\n '0081': ['LO', '1', 'ClinicalTrialProtocolEthicsCommitteeName'],\n '0082': ['LO', '1', 'ClinicalTrialProtocolEthicsCommitteeApprovalNumber'],\n '0083': ['SQ', '1', 'ConsentForClinicalTrialUseSequence'],\n '0084': ['CS', '1', 'DistributionType'],\n '0085': ['CS', '1', 'ConsentForDistributionFlag'],\n '0086': ['DA', '1', 'EthicsCommitteeApprovalEffectivenessStartDate'],\n '0087': ['DA', '1', 'EthicsCommitteeApprovalEffectivenessEndDate']\n },\n '0014': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0023': ['ST', '1', 'CADFileFormat'],\n '0024': ['ST', '1', 'ComponentReferenceSystem'],\n '0025': ['ST', '1', 'ComponentManufacturingProcedure'],\n '0028': ['ST', '1', 'ComponentManufacturer'],\n '0030': ['DS', '1-n', 'MaterialThickness'],\n '0032': ['DS', '1-n', 'MaterialPipeDiameter'],\n '0034': ['DS', '1-n', 'MaterialIsolationDiameter'],\n '0042': ['ST', '1', 'MaterialGrade'],\n '0044': ['ST', '1', 'MaterialPropertiesDescription'],\n '0045': ['ST', '1', 'MaterialPropertiesFileFormatRetired'],\n '0046': ['LT', '1', 'MaterialNotes'],\n '0050': ['CS', '1', 'ComponentShape'],\n '0052': ['CS', '1', 'CurvatureType'],\n '0054': ['DS', '1', 'OuterDiameter'],\n '0056': ['DS', '1', 'InnerDiameter'],\n '0100': ['LO', '1-n', 'ComponentWelderIDs'],\n '0101': ['CS', '1', 'SecondaryApprovalStatus'],\n '0102': ['DA', '1', 'SecondaryReviewDate'],\n '0103': ['TM', '1', 'SecondaryReviewTime'],\n '0104': ['PN', '1', 'SecondaryReviewerName'],\n '0105': ['ST', '1', 'RepairID'],\n '0106': ['SQ', '1', 'MultipleComponentApprovalSequence'],\n '0107': ['CS', '1-n', 'OtherApprovalStatus'],\n '0108': ['CS', '1-n', 'OtherSecondaryApprovalStatus'],\n '1010': ['ST', '1', 'ActualEnvironmentalConditions'],\n '1020': ['DA', '1', 'ExpiryDate'],\n '1040': ['ST', '1', 'EnvironmentalConditions'],\n '2002': ['SQ', '1', 'EvaluatorSequence'],\n '2004': ['IS', '1', 'EvaluatorNumber'],\n '2006': ['PN', '1', 'EvaluatorName'],\n '2008': ['IS', '1', 'EvaluationAttempt'],\n '2012': ['SQ', '1', 'IndicationSequence'],\n '2014': ['IS', '1', 'IndicationNumber'],\n '2016': ['SH', '1', 'IndicationLabel'],\n '2018': ['ST', '1', 'IndicationDescription'],\n '201A': ['CS', '1-n', 'IndicationType'],\n '201C': ['CS', '1', 'IndicationDisposition'],\n '201E': ['SQ', '1', 'IndicationROISequence'],\n '2030': ['SQ', '1', 'IndicationPhysicalPropertySequence'],\n '2032': ['SH', '1', 'PropertyLabel'],\n '2202': ['IS', '1', 'CoordinateSystemNumberOfAxes'],\n '2204': ['SQ', '1', 'CoordinateSystemAxesSequence'],\n '2206': ['ST', '1', 'CoordinateSystemAxisDescription'],\n '2208': ['CS', '1', 'CoordinateSystemDataSetMapping'],\n '220A': ['IS', '1', 'CoordinateSystemAxisNumber'],\n '220C': ['CS', '1', 'CoordinateSystemAxisType'],\n '220E': ['CS', '1', 'CoordinateSystemAxisUnits'],\n '2210': ['OB', '1', 'CoordinateSystemAxisValues'],\n '2220': ['SQ', '1', 'CoordinateSystemTransformSequence'],\n '2222': ['ST', '1', 'TransformDescription'],\n '2224': ['IS', '1', 'TransformNumberOfAxes'],\n '2226': ['IS', '1-n', 'TransformOrderOfAxes'],\n '2228': ['CS', '1', 'TransformedAxisUnits'],\n '222A': ['DS', '1-n', 'CoordinateSystemTransformRotationAndScaleMatrix'],\n '222C': ['DS', '1-n', 'CoordinateSystemTransformTranslationMatrix'],\n '3011': ['DS', '1', 'InternalDetectorFrameTime'],\n '3012': ['DS', '1', 'NumberOfFramesIntegrated'],\n '3020': ['SQ', '1', 'DetectorTemperatureSequence'],\n '3022': ['ST', '1', 'SensorName'],\n '3024': ['DS', '1', 'HorizontalOffsetOfSensor'],\n '3026': ['DS', '1', 'VerticalOffsetOfSensor'],\n '3028': ['DS', '1', 'SensorTemperature'],\n '3040': ['SQ', '1', 'DarkCurrentSequence'],\n '3050': ['ox', '1', 'DarkCurrentCounts'],\n '3060': ['SQ', '1', 'GainCorrectionReferenceSequence'],\n '3070': ['ox', '1', 'AirCounts'],\n '3071': ['DS', '1', 'KVUsedInGainCalibration'],\n '3072': ['DS', '1', 'MAUsedInGainCalibration'],\n '3073': ['DS', '1', 'NumberOfFramesUsedForIntegration'],\n '3074': ['LO', '1', 'FilterMaterialUsedInGainCalibration'],\n '3075': ['DS', '1', 'FilterThicknessUsedInGainCalibration'],\n '3076': ['DA', '1', 'DateOfGainCalibration'],\n '3077': ['TM', '1', 'TimeOfGainCalibration'],\n '3080': ['OB', '1', 'BadPixelImage'],\n '3099': ['LT', '1', 'CalibrationNotes'],\n '3100': ['LT', '1', 'LinearityCorrectionTechnique'],\n '3101': ['LT', '1', 'BeamHardeningCorrectionTechnique'],\n '4002': ['SQ', '1', 'PulserEquipmentSequence'],\n '4004': ['CS', '1', 'PulserType'],\n '4006': ['LT', '1', 'PulserNotes'],\n '4008': ['SQ', '1', 'ReceiverEquipmentSequence'],\n '400A': ['CS', '1', 'AmplifierType'],\n '400C': ['LT', '1', 'ReceiverNotes'],\n '400E': ['SQ', '1', 'PreAmplifierEquipmentSequence'],\n '400F': ['LT', '1', 'PreAmplifierNotes'],\n '4010': ['SQ', '1', 'TransmitTransducerSequence'],\n '4011': ['SQ', '1', 'ReceiveTransducerSequence'],\n '4012': ['US', '1', 'NumberOfElements'],\n '4013': ['CS', '1', 'ElementShape'],\n '4014': ['DS', '1', 'ElementDimensionA'],\n '4015': ['DS', '1', 'ElementDimensionB'],\n '4016': ['DS', '1', 'ElementPitchA'],\n '4017': ['DS', '1', 'MeasuredBeamDimensionA'],\n '4018': ['DS', '1', 'MeasuredBeamDimensionB'],\n '4019': ['DS', '1', 'LocationOfMeasuredBeamDiameter'],\n '401A': ['DS', '1', 'NominalFrequency'],\n '401B': ['DS', '1', 'MeasuredCenterFrequency'],\n '401C': ['DS', '1', 'MeasuredBandwidth'],\n '401D': ['DS', '1', 'ElementPitchB'],\n '4020': ['SQ', '1', 'PulserSettingsSequence'],\n '4022': ['DS', '1', 'PulseWidth'],\n '4024': ['DS', '1', 'ExcitationFrequency'],\n '4026': ['CS', '1', 'ModulationType'],\n '4028': ['DS', '1', 'Damping'],\n '4030': ['SQ', '1', 'ReceiverSettingsSequence'],\n '4031': ['DS', '1', 'AcquiredSoundpathLength'],\n '4032': ['CS', '1', 'AcquisitionCompressionType'],\n '4033': ['IS', '1', 'AcquisitionSampleSize'],\n '4034': ['DS', '1', 'RectifierSmoothing'],\n '4035': ['SQ', '1', 'DACSequence'],\n '4036': ['CS', '1', 'DACType'],\n '4038': ['DS', '1-n', 'DACGainPoints'],\n '403A': ['DS', '1-n', 'DACTimePoints'],\n '403C': ['DS', '1-n', 'DACAmplitude'],\n '4040': ['SQ', '1', 'PreAmplifierSettingsSequence'],\n '4050': ['SQ', '1', 'TransmitTransducerSettingsSequence'],\n '4051': ['SQ', '1', 'ReceiveTransducerSettingsSequence'],\n '4052': ['DS', '1', 'IncidentAngle'],\n '4054': ['ST', '1', 'CouplingTechnique'],\n '4056': ['ST', '1', 'CouplingMedium'],\n '4057': ['DS', '1', 'CouplingVelocity'],\n '4058': ['DS', '1', 'ProbeCenterLocationX'],\n '4059': ['DS', '1', 'ProbeCenterLocationZ'],\n '405A': ['DS', '1', 'SoundPathLength'],\n '405C': ['ST', '1', 'DelayLawIdentifier'],\n '4060': ['SQ', '1', 'GateSettingsSequence'],\n '4062': ['DS', '1', 'GateThreshold'],\n '4064': ['DS', '1', 'VelocityOfSound'],\n '4070': ['SQ', '1', 'CalibrationSettingsSequence'],\n '4072': ['ST', '1', 'CalibrationProcedure'],\n '4074': ['SH', '1', 'ProcedureVersion'],\n '4076': ['DA', '1', 'ProcedureCreationDate'],\n '4078': ['DA', '1', 'ProcedureExpirationDate'],\n '407A': ['DA', '1', 'ProcedureLastModifiedDate'],\n '407C': ['TM', '1-n', 'CalibrationTime'],\n '407E': ['DA', '1-n', 'CalibrationDate'],\n '4080': ['SQ', '1', 'ProbeDriveEquipmentSequence'],\n '4081': ['CS', '1', 'DriveType'],\n '4082': ['LT', '1', 'ProbeDriveNotes'],\n '4083': ['SQ', '1', 'DriveProbeSequence'],\n '4084': ['DS', '1', 'ProbeInductance'],\n '4085': ['DS', '1', 'ProbeResistance'],\n '4086': ['SQ', '1', 'ReceiveProbeSequence'],\n '4087': ['SQ', '1', 'ProbeDriveSettingsSequence'],\n '4088': ['DS', '1', 'BridgeResistors'],\n '4089': ['DS', '1', 'ProbeOrientationAngle'],\n '408B': ['DS', '1', 'UserSelectedGainY'],\n '408C': ['DS', '1', 'UserSelectedPhase'],\n '408D': ['DS', '1', 'UserSelectedOffsetX'],\n '408E': ['DS', '1', 'UserSelectedOffsetY'],\n '4091': ['SQ', '1', 'ChannelSettingsSequence'],\n '4092': ['DS', '1', 'ChannelThreshold'],\n '409A': ['SQ', '1', 'ScannerSettingsSequence'],\n '409B': ['ST', '1', 'ScanProcedure'],\n '409C': ['DS', '1', 'TranslationRateX'],\n '409D': ['DS', '1', 'TranslationRateY'],\n '409F': ['DS', '1', 'ChannelOverlap'],\n '40A0': ['LO', '1-n', 'ImageQualityIndicatorType'],\n '40A1': ['LO', '1-n', 'ImageQualityIndicatorMaterial'],\n '40A2': ['LO', '1-n', 'ImageQualityIndicatorSize'],\n '5002': ['IS', '1', 'LINACEnergy'],\n '5004': ['IS', '1', 'LINACOutput'],\n '5100': ['US', '1', 'ActiveAperture'],\n '5101': ['DS', '1', 'TotalAperture'],\n '5102': ['DS', '1', 'ApertureElevation'],\n '5103': ['DS', '1', 'MainLobeAngle'],\n '5104': ['DS', '1', 'MainRoofAngle'],\n '5105': ['CS', '1', 'ConnectorType'],\n '5106': ['SH', '1', 'WedgeModelNumber'],\n '5107': ['DS', '1', 'WedgeAngleFloat'],\n '5108': ['DS', '1', 'WedgeRoofAngle'],\n '5109': ['CS', '1', 'WedgeElement1Position'],\n '510A': ['DS', '1', 'WedgeMaterialVelocity'],\n '510B': ['SH', '1', 'WedgeMaterial'],\n '510C': ['DS', '1', 'WedgeOffsetZ'],\n '510D': ['DS', '1', 'WedgeOriginOffsetX'],\n '510E': ['DS', '1', 'WedgeTimeDelay'],\n '510F': ['SH', '1', 'WedgeName'],\n '5110': ['SH', '1', 'WedgeManufacturerName'],\n '5111': ['LO', '1', 'WedgeDescription'],\n '5112': ['DS', '1', 'NominalBeamAngle'],\n '5113': ['DS', '1', 'WedgeOffsetX'],\n '5114': ['DS', '1', 'WedgeOffsetY'],\n '5115': ['DS', '1', 'WedgeTotalLength'],\n '5116': ['DS', '1', 'WedgeInContactLength'],\n '5117': ['DS', '1', 'WedgeFrontGap'],\n '5118': ['DS', '1', 'WedgeTotalHeight'],\n '5119': ['DS', '1', 'WedgeFrontHeight'],\n '511A': ['DS', '1', 'WedgeRearHeight'],\n '511B': ['DS', '1', 'WedgeTotalWidth'],\n '511C': ['DS', '1', 'WedgeInContactWidth'],\n '511D': ['DS', '1', 'WedgeChamferHeight'],\n '511E': ['CS', '1', 'WedgeCurve'],\n '511F': ['DS', '1', 'RadiusAlongWedge']\n },\n '0016': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['DS', '1', 'WhitePoint'],\n '0002': ['DS', '3', 'PrimaryChromaticities'],\n '0003': ['UT', '1', 'BatteryLevel'],\n '0004': ['DS', '1', 'ExposureTimeInSeconds'],\n '0005': ['DS', '1', 'FNumber'],\n '0006': ['IS', '1', 'OECFRows'],\n '0007': ['IS', '1', 'OECFColumns'],\n '0008': ['UC', '1-n', 'OECFColumnNames'],\n '0009': ['DS', '1-n', 'OECFValues'],\n '000A': ['IS', '1', 'SpatialFrequencyResponseRows'],\n '000B': ['IS', '1', 'SpatialFrequencyResponseColumns'],\n '000C': ['UC', '1-n', 'SpatialFrequencyResponseColumnNames'],\n '000D': ['DS', '1-n', 'SpatialFrequencyResponseValues'],\n '000E': ['IS', '1', 'ColorFilterArrayPatternRows'],\n '000F': ['IS', '1', 'ColorFilterArrayPatternColumns'],\n '0010': ['DS', '1-n', 'ColorFilterArrayPatternValues'],\n '0011': ['US', '1', 'FlashFiringStatus'],\n '0012': ['US', '1', 'FlashReturnStatus'],\n '0013': ['US', '1', 'FlashMode'],\n '0014': ['US', '1', 'FlashFunctionPresent'],\n '0015': ['US', '1', 'FlashRedEyeMode'],\n '0016': ['US', '1', 'ExposureProgram'],\n '0017': ['UT', '1', 'SpectralSensitivity'],\n '0018': ['IS', '1', 'PhotographicSensitivity'],\n '0019': ['IS', '1', 'SelfTimerMode'],\n '001A': ['US', '1', 'SensitivityType'],\n '001B': ['IS', '1', 'StandardOutputSensitivity'],\n '001C': ['IS', '1', 'RecommendedExposureIndex'],\n '001D': ['IS', '1', 'ISOSpeed'],\n '001E': ['IS', '1', 'ISOSpeedLatitudeyyy'],\n '001F': ['IS', '1', 'ISOSpeedLatitudezzz'],\n '0020': ['UT', '1', 'EXIFVersion'],\n '0021': ['DS', '1', 'ShutterSpeedValue'],\n '0022': ['DS', '1', 'ApertureValue'],\n '0023': ['DS', '1', 'BrightnessValue'],\n '0024': ['DS', '1', 'ExposureBiasValue'],\n '0025': ['DS', '1', 'MaxApertureValue'],\n '0026': ['DS', '1', 'SubjectDistance'],\n '0027': ['US', '1', 'MeteringMode'],\n '0028': ['US', '1', 'LightSource'],\n '0029': ['DS', '1', 'FocalLength'],\n '002A': ['IS', '2-4', 'SubjectArea'],\n '002B': ['OB', '1', 'MakerNote'],\n '0030': ['DS', '1', 'Temperature'],\n '0031': ['DS', '1', 'Humidity'],\n '0032': ['DS', '1', 'Pressure'],\n '0033': ['DS', '1', 'WaterDepth'],\n '0034': ['DS', '1', 'Acceleration'],\n '0035': ['DS', '1', 'CameraElevationAngle'],\n '0036': ['DS', '1-2', 'FlashEnergy'],\n '0037': ['IS', '2', 'SubjectLocation'],\n '0038': ['DS', '1', 'PhotographicExposureIndex'],\n '0039': ['US', '1', 'SensingMethod'],\n '003A': ['US', '1', 'FileSource'],\n '003B': ['US', '1', 'SceneType'],\n '0041': ['US', '1', 'CustomRendered'],\n '0042': ['US', '1', 'ExposureMode'],\n '0043': ['US', '1', 'WhiteBalance'],\n '0044': ['DS', '1', 'DigitalZoomRatio'],\n '0045': ['IS', '1', 'FocalLengthIn35mmFilm'],\n '0046': ['US', '1', 'SceneCaptureType'],\n '0047': ['US', '1', 'GainControl'],\n '0048': ['US', '1', 'Contrast'],\n '0049': ['US', '1', 'Saturation'],\n '004A': ['US', '1', 'Sharpness'],\n '004B': ['OB', '1', 'DeviceSettingDescription'],\n '004C': ['US', '1', 'SubjectDistanceRange'],\n '004D': ['UT', '1', 'CameraOwnerName'],\n '004E': ['DS', '4', 'LensSpecification'],\n '004F': ['UT', '1', 'LensMake'],\n '0050': ['UT', '1', 'LensModel'],\n '0051': ['UT', '1', 'LensSerialNumber'],\n '0061': ['CS', '1', 'InteroperabilityIndex'],\n '0062': ['OB', '1', 'InteroperabilityVersion'],\n '0070': ['OB', '1', 'GPSVersionID'],\n '0071': ['CS', '1', 'GPSLatitudeRef'],\n '0072': ['DS', '3', 'GPSLatitude'],\n '0073': ['CS', '1', 'GPSLongitudeRef'],\n '0074': ['DS', '3', 'GPSLongitude'],\n '0075': ['US', '1', 'GPSAltitudeRef'],\n '0076': ['DS', '1', 'GPSAltitude'],\n '0077': ['DT', '1', 'GPSTimeStamp'],\n '0078': ['UT', '1', 'GPSSatellites'],\n '0079': ['CS', '1', 'GPSStatus'],\n '007A': ['CS', '1', 'GPSMeasureMode'],\n '007B': ['DS', '1', 'GPSDOP'],\n '007C': ['CS', '1', 'GPSSpeedRef'],\n '007D': ['DS', '1', 'GPSSpeed'],\n '007E': ['CS', '1', 'GPSTrackRef'],\n '007F': ['DS', '1', 'GPSTrack'],\n '0080': ['CS', '1', 'GPSImgDirectionRef'],\n '0081': ['DS', '1', 'GPSImgDirection'],\n '0082': ['UT', '1', 'GPSMapDatum'],\n '0083': ['CS', '1', 'GPSDestLatitudeRef'],\n '0084': ['DS', '3', 'GPSDestLatitude'],\n '0085': ['CS', '1', 'GPSDestLongitudeRef'],\n '0086': ['DS', '3', 'GPSDestLongitude'],\n '0087': ['CS', '1', 'GPSDestBearingRef'],\n '0088': ['DS', '1', 'GPSDestBearing'],\n '0089': ['CS', '1', 'GPSDestDistanceRef'],\n '008A': ['DS', '1', 'GPSDestDistance'],\n '008B': ['OB', '1', 'GPSProcessingMethod'],\n '008C': ['OB', '1', 'GPSAreaInformation'],\n '008D': ['DT', '1', 'GPSDateStamp'],\n '008E': ['IS', '1', 'GPSDifferential'],\n '1001': ['CS', '1', 'LightSourcePolarization'],\n '1002': ['DS', '1', 'EmitterColorTemperature'],\n '1003': ['CS', '1', 'ContactMethod'],\n '1004': ['CS', '1-n', 'ImmersionMedia'],\n '1005': ['DS', '1', 'OpticalMagnificationFactor']\n },\n '0018': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['LO', '1', 'ContrastBolusAgent'],\n '0012': ['SQ', '1', 'ContrastBolusAgentSequence'],\n '0013': ['FL', '1', 'ContrastBolusT1Relaxivity'],\n '0014': ['SQ', '1', 'ContrastBolusAdministrationRouteSequence'],\n '0015': ['CS', '1', 'BodyPartExamined'],\n '0020': ['CS', '1-n', 'ScanningSequence'],\n '0021': ['CS', '1-n', 'SequenceVariant'],\n '0022': ['CS', '1-n', 'ScanOptions'],\n '0023': ['CS', '1', 'MRAcquisitionType'],\n '0024': ['SH', '1', 'SequenceName'],\n '0025': ['CS', '1', 'AngioFlag'],\n '0026': ['SQ', '1', 'InterventionDrugInformationSequence'],\n '0027': ['TM', '1', 'InterventionDrugStopTime'],\n '0028': ['DS', '1', 'InterventionDrugDose'],\n '0029': ['SQ', '1', 'InterventionDrugCodeSequence'],\n '002A': ['SQ', '1', 'AdditionalDrugSequence'],\n '0030': ['LO', '1-n', 'Radionuclide'],\n '0031': ['LO', '1', 'Radiopharmaceutical'],\n '0032': ['DS', '1', 'EnergyWindowCenterline'],\n '0033': ['DS', '1-n', 'EnergyWindowTotalWidth'],\n '0034': ['LO', '1', 'InterventionDrugName'],\n '0035': ['TM', '1', 'InterventionDrugStartTime'],\n '0036': ['SQ', '1', 'InterventionSequence'],\n '0037': ['CS', '1', 'TherapyType'],\n '0038': ['CS', '1', 'InterventionStatus'],\n '0039': ['CS', '1', 'TherapyDescription'],\n '003A': ['ST', '1', 'InterventionDescription'],\n '0040': ['IS', '1', 'CineRate'],\n '0042': ['CS', '1', 'InitialCineRunState'],\n '0050': ['DS', '1', 'SliceThickness'],\n '0060': ['DS', '1', 'KVP'],\n '0061': ['DS', '1', ''],\n '0070': ['IS', '1', 'CountsAccumulated'],\n '0071': ['CS', '1', 'AcquisitionTerminationCondition'],\n '0072': ['DS', '1', 'EffectiveDuration'],\n '0073': ['CS', '1', 'AcquisitionStartCondition'],\n '0074': ['IS', '1', 'AcquisitionStartConditionData'],\n '0075': ['IS', '1', 'AcquisitionTerminationConditionData'],\n '0080': ['DS', '1', 'RepetitionTime'],\n '0081': ['DS', '1', 'EchoTime'],\n '0082': ['DS', '1', 'InversionTime'],\n '0083': ['DS', '1', 'NumberOfAverages'],\n '0084': ['DS', '1', 'ImagingFrequency'],\n '0085': ['SH', '1', 'ImagedNucleus'],\n '0086': ['IS', '1-n', 'EchoNumbers'],\n '0087': ['DS', '1', 'MagneticFieldStrength'],\n '0088': ['DS', '1', 'SpacingBetweenSlices'],\n '0089': ['IS', '1', 'NumberOfPhaseEncodingSteps'],\n '0090': ['DS', '1', 'DataCollectionDiameter'],\n '0091': ['IS', '1', 'EchoTrainLength'],\n '0093': ['DS', '1', 'PercentSampling'],\n '0094': ['DS', '1', 'PercentPhaseFieldOfView'],\n '0095': ['DS', '1', 'PixelBandwidth'],\n '1000': ['LO', '1', 'DeviceSerialNumber'],\n '1002': ['UI', '1', 'DeviceUID'],\n '1003': ['LO', '1', 'DeviceID'],\n '1004': ['LO', '1', 'PlateID'],\n '1005': ['LO', '1', 'GeneratorID'],\n '1006': ['LO', '1', 'GridID'],\n '1007': ['LO', '1', 'CassetteID'],\n '1008': ['LO', '1', 'GantryID'],\n '1009': ['UT', '1', 'UniqueDeviceIdentifier'],\n '100A': ['SQ', '1', 'UDISequence'],\n '100B': ['UI', '1-n', 'ManufacturerDeviceClassUID'],\n '1010': ['LO', '1', 'SecondaryCaptureDeviceID'],\n '1011': ['LO', '1', 'HardcopyCreationDeviceID'],\n '1012': ['DA', '1', 'DateOfSecondaryCapture'],\n '1014': ['TM', '1', 'TimeOfSecondaryCapture'],\n '1016': ['LO', '1', 'SecondaryCaptureDeviceManufacturer'],\n '1017': ['LO', '1', 'HardcopyDeviceManufacturer'],\n '1018': ['LO', '1', 'SecondaryCaptureDeviceManufacturerModelName'],\n '1019': ['LO', '1-n', 'SecondaryCaptureDeviceSoftwareVersions'],\n '101A': ['LO', '1-n', 'HardcopyDeviceSoftwareVersion'],\n '101B': ['LO', '1', 'HardcopyDeviceManufacturerModelName'],\n '1020': ['LO', '1-n', 'SoftwareVersions'],\n '1022': ['SH', '1', 'VideoImageFormatAcquired'],\n '1023': ['LO', '1', 'DigitalImageFormatAcquired'],\n '1030': ['LO', '1', 'ProtocolName'],\n '1040': ['LO', '1', 'ContrastBolusRoute'],\n '1041': ['DS', '1', 'ContrastBolusVolume'],\n '1042': ['TM', '1', 'ContrastBolusStartTime'],\n '1043': ['TM', '1', 'ContrastBolusStopTime'],\n '1044': ['DS', '1', 'ContrastBolusTotalDose'],\n '1045': ['IS', '1', 'SyringeCounts'],\n '1046': ['DS', '1-n', 'ContrastFlowRate'],\n '1047': ['DS', '1-n', 'ContrastFlowDuration'],\n '1048': ['CS', '1', 'ContrastBolusIngredient'],\n '1049': ['DS', '1', 'ContrastBolusIngredientConcentration'],\n '1050': ['DS', '1', 'SpatialResolution'],\n '1060': ['DS', '1', 'TriggerTime'],\n '1061': ['LO', '1', 'TriggerSourceOrType'],\n '1062': ['IS', '1', 'NominalInterval'],\n '1063': ['DS', '1', 'FrameTime'],\n '1064': ['LO', '1', 'CardiacFramingType'],\n '1065': ['DS', '1-n', 'FrameTimeVector'],\n '1066': ['DS', '1', 'FrameDelay'],\n '1067': ['DS', '1', 'ImageTriggerDelay'],\n '1068': ['DS', '1', 'MultiplexGroupTimeOffset'],\n '1069': ['DS', '1', 'TriggerTimeOffset'],\n '106A': ['CS', '1', 'SynchronizationTrigger'],\n '106C': ['US', '2', 'SynchronizationChannel'],\n '106E': ['UL', '1', 'TriggerSamplePosition'],\n '1070': ['LO', '1', 'RadiopharmaceuticalRoute'],\n '1071': ['DS', '1', 'RadiopharmaceuticalVolume'],\n '1072': ['TM', '1', 'RadiopharmaceuticalStartTime'],\n '1073': ['TM', '1', 'RadiopharmaceuticalStopTime'],\n '1074': ['DS', '1', 'RadionuclideTotalDose'],\n '1075': ['DS', '1', 'RadionuclideHalfLife'],\n '1076': ['DS', '1', 'RadionuclidePositronFraction'],\n '1077': ['DS', '1', 'RadiopharmaceuticalSpecificActivity'],\n '1078': ['DT', '1', 'RadiopharmaceuticalStartDateTime'],\n '1079': ['DT', '1', 'RadiopharmaceuticalStopDateTime'],\n '1080': ['CS', '1', 'BeatRejectionFlag'],\n '1081': ['IS', '1', 'LowRRValue'],\n '1082': ['IS', '1', 'HighRRValue'],\n '1083': ['IS', '1', 'IntervalsAcquired'],\n '1084': ['IS', '1', 'IntervalsRejected'],\n '1085': ['LO', '1', 'PVCRejection'],\n '1086': ['IS', '1', 'SkipBeats'],\n '1088': ['IS', '1', 'HeartRate'],\n '1090': ['IS', '1', 'CardiacNumberOfImages'],\n '1094': ['IS', '1', 'TriggerWindow'],\n '1100': ['DS', '1', 'ReconstructionDiameter'],\n '1110': ['DS', '1', 'DistanceSourceToDetector'],\n '1111': ['DS', '1', 'DistanceSourceToPatient'],\n '1114': ['DS', '1', 'EstimatedRadiographicMagnificationFactor'],\n '1120': ['DS', '1', 'GantryDetectorTilt'],\n '1121': ['DS', '1', 'GantryDetectorSlew'],\n '1130': ['DS', '1', 'TableHeight'],\n '1131': ['DS', '1', 'TableTraverse'],\n '1134': ['CS', '1', 'TableMotion'],\n '1135': ['DS', '1-n', 'TableVerticalIncrement'],\n '1136': ['DS', '1-n', 'TableLateralIncrement'],\n '1137': ['DS', '1-n', 'TableLongitudinalIncrement'],\n '1138': ['DS', '1', 'TableAngle'],\n '113A': ['CS', '1', 'TableType'],\n '1140': ['CS', '1', 'RotationDirection'],\n '1141': ['DS', '1', 'AngularPosition'],\n '1142': ['DS', '1-n', 'RadialPosition'],\n '1143': ['DS', '1', 'ScanArc'],\n '1144': ['DS', '1', 'AngularStep'],\n '1145': ['DS', '1', 'CenterOfRotationOffset'],\n '1146': ['DS', '1-n', 'RotationOffset'],\n '1147': ['CS', '1', 'FieldOfViewShape'],\n '1149': ['IS', '1-2', 'FieldOfViewDimensions'],\n '1150': ['IS', '1', 'ExposureTime'],\n '1151': ['IS', '1', 'XRayTubeCurrent'],\n '1152': ['IS', '1', 'Exposure'],\n '1153': ['IS', '1', 'ExposureInuAs'],\n '1154': ['DS', '1', 'AveragePulseWidth'],\n '1155': ['CS', '1', 'RadiationSetting'],\n '1156': ['CS', '1', 'RectificationType'],\n '115A': ['CS', '1', 'RadiationMode'],\n '115E': ['DS', '1', 'ImageAndFluoroscopyAreaDoseProduct'],\n '1160': ['SH', '1', 'FilterType'],\n '1161': ['LO', '1-n', 'TypeOfFilters'],\n '1162': ['DS', '1', 'IntensifierSize'],\n '1164': ['DS', '2', 'ImagerPixelSpacing'],\n '1166': ['CS', '1-n', 'Grid'],\n '1170': ['IS', '1', 'GeneratorPower'],\n '1180': ['SH', '1', 'CollimatorGridName'],\n '1181': ['CS', '1', 'CollimatorType'],\n '1182': ['IS', '1-2', 'FocalDistance'],\n '1183': ['DS', '1-2', 'XFocusCenter'],\n '1184': ['DS', '1-2', 'YFocusCenter'],\n '1190': ['DS', '1-n', 'FocalSpots'],\n '1191': ['CS', '1', 'AnodeTargetMaterial'],\n '11A0': ['DS', '1', 'BodyPartThickness'],\n '11A2': ['DS', '1', 'CompressionForce'],\n '11A3': ['DS', '1', 'CompressionPressure'],\n '11A4': ['LO', '1', 'PaddleDescription'],\n '11A5': ['DS', '1', 'CompressionContactArea'],\n '11B0': ['LO', '1', 'AcquisitionMode'],\n '11B1': ['LO', '1', 'DoseModeName'],\n '11B2': ['CS', '1', 'AcquiredSubtractionMaskFlag'],\n '11B3': ['CS', '1', 'FluoroscopyPersistenceFlag'],\n '11B4': ['CS', '1', 'FluoroscopyLastImageHoldPersistenceFlag'],\n '11B5': ['IS', '1', 'UpperLimitNumberOfPersistentFluoroscopyFrames'],\n '11B6': ['CS', '1', 'ContrastBolusAutoInjectionTriggerFlag'],\n '11B7': ['FD', '1', 'ContrastBolusInjectionDelay'],\n '11B8': ['SQ', '1', 'XAAcquisitionPhaseDetailsSequence'],\n '11B9': ['FD', '1', 'XAAcquisitionFrameRate'],\n '11BA': ['SQ', '1', 'XAPlaneDetailsSequence'],\n '11BB': ['LO', '1', 'AcquisitionFieldOfViewLabel'],\n '11BC': ['SQ', '1', 'XRayFilterDetailsSequence'],\n '11BD': ['FD', '1', 'XAAcquisitionDuration'],\n '11BE': ['CS', '1', 'ReconstructionPipelineType'],\n '11BF': ['SQ', '1', 'ImageFilterDetailsSequence'],\n '11C0': ['CS', '1', 'AppliedMaskSubtractionFlag'],\n '11C1': ['SQ', '1', 'RequestedSeriesDescriptionCodeSequence'],\n '1200': ['DA', '1-n', 'DateOfLastCalibration'],\n '1201': ['TM', '1-n', 'TimeOfLastCalibration'],\n '1202': ['DT', '1', 'DateTimeOfLastCalibration'],\n '1203': ['DT', '1', 'CalibrationDateTime'],\n '1210': ['SH', '1-n', 'ConvolutionKernel'],\n '1240': ['IS', '1-n', 'UpperLowerPixelValues'],\n '1242': ['IS', '1', 'ActualFrameDuration'],\n '1243': ['IS', '1', 'CountRate'],\n '1244': ['US', '1', 'PreferredPlaybackSequencing'],\n '1250': ['SH', '1', 'ReceiveCoilName'],\n '1251': ['SH', '1', 'TransmitCoilName'],\n '1260': ['SH', '1', 'PlateType'],\n '1261': ['LO', '1', 'PhosphorType'],\n '1271': ['FD', '1', 'WaterEquivalentDiameter'],\n '1272': ['SQ', '1', 'WaterEquivalentDiameterCalculationMethodCodeSequence'],\n '1300': ['DS', '1', 'ScanVelocity'],\n '1301': ['CS', '1-n', 'WholeBodyTechnique'],\n '1302': ['IS', '1', 'ScanLength'],\n '1310': ['US', '4', 'AcquisitionMatrix'],\n '1312': ['CS', '1', 'InPlanePhaseEncodingDirection'],\n '1314': ['DS', '1', 'FlipAngle'],\n '1315': ['CS', '1', 'VariableFlipAngleFlag'],\n '1316': ['DS', '1', 'SAR'],\n '1318': ['DS', '1', 'dBdt'],\n '1320': ['FL', '1', 'B1rms'],\n '1400': ['LO', '1', 'AcquisitionDeviceProcessingDescription'],\n '1401': ['LO', '1', 'AcquisitionDeviceProcessingCode'],\n '1402': ['CS', '1', 'CassetteOrientation'],\n '1403': ['CS', '1', 'CassetteSize'],\n '1404': ['US', '1', 'ExposuresOnPlate'],\n '1405': ['IS', '1', 'RelativeXRayExposure'],\n '1411': ['DS', '1', 'ExposureIndex'],\n '1412': ['DS', '1', 'TargetExposureIndex'],\n '1413': ['DS', '1', 'DeviationIndex'],\n '1450': ['DS', '1', 'ColumnAngulation'],\n '1460': ['DS', '1', 'TomoLayerHeight'],\n '1470': ['DS', '1', 'TomoAngle'],\n '1480': ['DS', '1', 'TomoTime'],\n '1490': ['CS', '1', 'TomoType'],\n '1491': ['CS', '1', 'TomoClass'],\n '1495': ['IS', '1', 'NumberOfTomosynthesisSourceImages'],\n '1500': ['CS', '1', 'PositionerMotion'],\n '1508': ['CS', '1', 'PositionerType'],\n '1510': ['DS', '1', 'PositionerPrimaryAngle'],\n '1511': ['DS', '1', 'PositionerSecondaryAngle'],\n '1520': ['DS', '1-n', 'PositionerPrimaryAngleIncrement'],\n '1521': ['DS', '1-n', 'PositionerSecondaryAngleIncrement'],\n '1530': ['DS', '1', 'DetectorPrimaryAngle'],\n '1531': ['DS', '1', 'DetectorSecondaryAngle'],\n '1600': ['CS', '1-3', 'ShutterShape'],\n '1602': ['IS', '1', 'ShutterLeftVerticalEdge'],\n '1604': ['IS', '1', 'ShutterRightVerticalEdge'],\n '1606': ['IS', '1', 'ShutterUpperHorizontalEdge'],\n '1608': ['IS', '1', 'ShutterLowerHorizontalEdge'],\n '1610': ['IS', '2', 'CenterOfCircularShutter'],\n '1612': ['IS', '1', 'RadiusOfCircularShutter'],\n '1620': ['IS', '2-2n', 'VerticesOfThePolygonalShutter'],\n '1622': ['US', '1', 'ShutterPresentationValue'],\n '1623': ['US', '1', 'ShutterOverlayGroup'],\n '1624': ['US', '3', 'ShutterPresentationColorCIELabValue'],\n '1630': ['CS', '1', 'OutlineShapeType'],\n '1631': ['FD', '1', 'OutlineLeftVerticalEdge'],\n '1632': ['FD', '1', 'OutlineRightVerticalEdge'],\n '1633': ['FD', '1', 'OutlineUpperHorizontalEdge'],\n '1634': ['FD', '1', 'OutlineLowerHorizontalEdge'],\n '1635': ['FD', '2', 'CenterOfCircularOutline'],\n '1636': ['FD', '1', 'DiameterOfCircularOutline'],\n '1637': ['UL', '1', 'NumberOfPolygonalVertices'],\n '1638': ['OF', '1', 'VerticesOfThePolygonalOutline'],\n '1700': ['CS', '1-3', 'CollimatorShape'],\n '1702': ['IS', '1', 'CollimatorLeftVerticalEdge'],\n '1704': ['IS', '1', 'CollimatorRightVerticalEdge'],\n '1706': ['IS', '1', 'CollimatorUpperHorizontalEdge'],\n '1708': ['IS', '1', 'CollimatorLowerHorizontalEdge'],\n '1710': ['IS', '2', 'CenterOfCircularCollimator'],\n '1712': ['IS', '1', 'RadiusOfCircularCollimator'],\n '1720': ['IS', '2-2n', 'VerticesOfThePolygonalCollimator'],\n '1800': ['CS', '1', 'AcquisitionTimeSynchronized'],\n '1801': ['SH', '1', 'TimeSource'],\n '1802': ['CS', '1', 'TimeDistributionProtocol'],\n '1803': ['LO', '1', 'NTPSourceAddress'],\n '2001': ['IS', '1-n', 'PageNumberVector'],\n '2002': ['SH', '1-n', 'FrameLabelVector'],\n '2003': ['DS', '1-n', 'FramePrimaryAngleVector'],\n '2004': ['DS', '1-n', 'FrameSecondaryAngleVector'],\n '2005': ['DS', '1-n', 'SliceLocationVector'],\n '2006': ['SH', '1-n', 'DisplayWindowLabelVector'],\n '2010': ['DS', '2', 'NominalScannedPixelSpacing'],\n '2020': ['CS', '1', 'DigitizingDeviceTransportDirection'],\n '2030': ['DS', '1', 'RotationOfScannedFilm'],\n '2041': ['SQ', '1', 'BiopsyTargetSequence'],\n '2042': ['UI', '1', 'TargetUID'],\n '2043': ['FL', '2', 'LocalizingCursorPosition'],\n '2044': ['FL', '3', 'CalculatedTargetPosition'],\n '2045': ['SH', '1', 'TargetLabel'],\n '2046': ['FL', '1', 'DisplayedZValue'],\n '3100': ['CS', '1', 'IVUSAcquisition'],\n '3101': ['DS', '1', 'IVUSPullbackRate'],\n '3102': ['DS', '1', 'IVUSGatedRate'],\n '3103': ['IS', '1', 'IVUSPullbackStartFrameNumber'],\n '3104': ['IS', '1', 'IVUSPullbackStopFrameNumber'],\n '3105': ['IS', '1-n', 'LesionNumber'],\n '4000': ['LT', '1', 'AcquisitionComments'],\n '5000': ['SH', '1-n', 'OutputPower'],\n '5010': ['LO', '1-n', 'TransducerData'],\n '5011': ['SQ', '1', 'TransducerIdentificationSequence'],\n '5012': ['DS', '1', 'FocusDepth'],\n '5020': ['LO', '1', 'ProcessingFunction'],\n '5021': ['LO', '1', 'PostprocessingFunction'],\n '5022': ['DS', '1', 'MechanicalIndex'],\n '5024': ['DS', '1', 'BoneThermalIndex'],\n '5026': ['DS', '1', 'CranialThermalIndex'],\n '5027': ['DS', '1', 'SoftTissueThermalIndex'],\n '5028': ['DS', '1', 'SoftTissueFocusThermalIndex'],\n '5029': ['DS', '1', 'SoftTissueSurfaceThermalIndex'],\n '5030': ['DS', '1', 'DynamicRange'],\n '5040': ['DS', '1', 'TotalGain'],\n '5050': ['IS', '1', 'DepthOfScanField'],\n '5100': ['CS', '1', 'PatientPosition'],\n '5101': ['CS', '1', 'ViewPosition'],\n '5104': ['SQ', '1', 'ProjectionEponymousNameCodeSequence'],\n '5210': ['DS', '6', 'ImageTransformationMatrix'],\n '5212': ['DS', '3', 'ImageTranslationVector'],\n '6000': ['DS', '1', 'Sensitivity'],\n '6011': ['SQ', '1', 'SequenceOfUltrasoundRegions'],\n '6012': ['US', '1', 'RegionSpatialFormat'],\n '6014': ['US', '1', 'RegionDataType'],\n '6016': ['UL', '1', 'RegionFlags'],\n '6018': ['UL', '1', 'RegionLocationMinX0'],\n '601A': ['UL', '1', 'RegionLocationMinY0'],\n '601C': ['UL', '1', 'RegionLocationMaxX1'],\n '601E': ['UL', '1', 'RegionLocationMaxY1'],\n '6020': ['SL', '1', 'ReferencePixelX0'],\n '6022': ['SL', '1', 'ReferencePixelY0'],\n '6024': ['US', '1', 'PhysicalUnitsXDirection'],\n '6026': ['US', '1', 'PhysicalUnitsYDirection'],\n '6028': ['FD', '1', 'ReferencePixelPhysicalValueX'],\n '602A': ['FD', '1', 'ReferencePixelPhysicalValueY'],\n '602C': ['FD', '1', 'PhysicalDeltaX'],\n '602E': ['FD', '1', 'PhysicalDeltaY'],\n '6030': ['UL', '1', 'TransducerFrequency'],\n '6031': ['CS', '1', 'TransducerType'],\n '6032': ['UL', '1', 'PulseRepetitionFrequency'],\n '6034': ['FD', '1', 'DopplerCorrectionAngle'],\n '6036': ['FD', '1', 'SteeringAngle'],\n '6038': ['UL', '1', 'DopplerSampleVolumeXPositionRetired'],\n '6039': ['SL', '1', 'DopplerSampleVolumeXPosition'],\n '603A': ['UL', '1', 'DopplerSampleVolumeYPositionRetired'],\n '603B': ['SL', '1', 'DopplerSampleVolumeYPosition'],\n '603C': ['UL', '1', 'TMLinePositionX0Retired'],\n '603D': ['SL', '1', 'TMLinePositionX0'],\n '603E': ['UL', '1', 'TMLinePositionY0Retired'],\n '603F': ['SL', '1', 'TMLinePositionY0'],\n '6040': ['UL', '1', 'TMLinePositionX1Retired'],\n '6041': ['SL', '1', 'TMLinePositionX1'],\n '6042': ['UL', '1', 'TMLinePositionY1Retired'],\n '6043': ['SL', '1', 'TMLinePositionY1'],\n '6044': ['US', '1', 'PixelComponentOrganization'],\n '6046': ['UL', '1', 'PixelComponentMask'],\n '6048': ['UL', '1', 'PixelComponentRangeStart'],\n '604A': ['UL', '1', 'PixelComponentRangeStop'],\n '604C': ['US', '1', 'PixelComponentPhysicalUnits'],\n '604E': ['US', '1', 'PixelComponentDataType'],\n '6050': ['UL', '1', 'NumberOfTableBreakPoints'],\n '6052': ['UL', '1-n', 'TableOfXBreakPoints'],\n '6054': ['FD', '1-n', 'TableOfYBreakPoints'],\n '6056': ['UL', '1', 'NumberOfTableEntries'],\n '6058': ['UL', '1-n', 'TableOfPixelValues'],\n '605A': ['FL', '1-n', 'TableOfParameterValues'],\n '6060': ['FL', '1-n', 'RWaveTimeVector'],\n '6070': ['US', '1', 'ActiveImageAreaOverlayGroup'],\n '7000': ['CS', '1', 'DetectorConditionsNominalFlag'],\n '7001': ['DS', '1', 'DetectorTemperature'],\n '7004': ['CS', '1', 'DetectorType'],\n '7005': ['CS', '1', 'DetectorConfiguration'],\n '7006': ['LT', '1', 'DetectorDescription'],\n '7008': ['LT', '1', 'DetectorMode'],\n '700A': ['SH', '1', 'DetectorID'],\n '700C': ['DA', '1', 'DateOfLastDetectorCalibration'],\n '700E': ['TM', '1', 'TimeOfLastDetectorCalibration'],\n '7010': ['IS', '1', 'ExposuresOnDetectorSinceLastCalibration'],\n '7011': ['IS', '1', 'ExposuresOnDetectorSinceManufactured'],\n '7012': ['DS', '1', 'DetectorTimeSinceLastExposure'],\n '7014': ['DS', '1', 'DetectorActiveTime'],\n '7016': ['DS', '1', 'DetectorActivationOffsetFromExposure'],\n '701A': ['DS', '2', 'DetectorBinning'],\n '7020': ['DS', '2', 'DetectorElementPhysicalSize'],\n '7022': ['DS', '2', 'DetectorElementSpacing'],\n '7024': ['CS', '1', 'DetectorActiveShape'],\n '7026': ['DS', '1-2', 'DetectorActiveDimensions'],\n '7028': ['DS', '2', 'DetectorActiveOrigin'],\n '702A': ['LO', '1', 'DetectorManufacturerName'],\n '702B': ['LO', '1', 'DetectorManufacturerModelName'],\n '7030': ['DS', '2', 'FieldOfViewOrigin'],\n '7032': ['DS', '1', 'FieldOfViewRotation'],\n '7034': ['CS', '1', 'FieldOfViewHorizontalFlip'],\n '7036': ['FL', '2', 'PixelDataAreaOriginRelativeToFOV'],\n '7038': ['FL', '1', 'PixelDataAreaRotationAngleRelativeToFOV'],\n '7040': ['LT', '1', 'GridAbsorbingMaterial'],\n '7041': ['LT', '1', 'GridSpacingMaterial'],\n '7042': ['DS', '1', 'GridThickness'],\n '7044': ['DS', '1', 'GridPitch'],\n '7046': ['IS', '2', 'GridAspectRatio'],\n '7048': ['DS', '1', 'GridPeriod'],\n '704C': ['DS', '1', 'GridFocalDistance'],\n '7050': ['CS', '1-n', 'FilterMaterial'],\n '7052': ['DS', '1-n', 'FilterThicknessMinimum'],\n '7054': ['DS', '1-n', 'FilterThicknessMaximum'],\n '7056': ['FL', '1-n', 'FilterBeamPathLengthMinimum'],\n '7058': ['FL', '1-n', 'FilterBeamPathLengthMaximum'],\n '7060': ['CS', '1', 'ExposureControlMode'],\n '7062': ['LT', '1', 'ExposureControlModeDescription'],\n '7064': ['CS', '1', 'ExposureStatus'],\n '7065': ['DS', '1', 'PhototimerSetting'],\n '8150': ['DS', '1', 'ExposureTimeInuS'],\n '8151': ['DS', '1', 'XRayTubeCurrentInuA'],\n '9004': ['CS', '1', 'ContentQualification'],\n '9005': ['SH', '1', 'PulseSequenceName'],\n '9006': ['SQ', '1', 'MRImagingModifierSequence'],\n '9008': ['CS', '1', 'EchoPulseSequence'],\n '9009': ['CS', '1', 'InversionRecovery'],\n '9010': ['CS', '1', 'FlowCompensation'],\n '9011': ['CS', '1', 'MultipleSpinEcho'],\n '9012': ['CS', '1', 'MultiPlanarExcitation'],\n '9014': ['CS', '1', 'PhaseContrast'],\n '9015': ['CS', '1', 'TimeOfFlightContrast'],\n '9016': ['CS', '1', 'Spoiling'],\n '9017': ['CS', '1', 'SteadyStatePulseSequence'],\n '9018': ['CS', '1', 'EchoPlanarPulseSequence'],\n '9019': ['FD', '1', 'TagAngleFirstAxis'],\n '9020': ['CS', '1', 'MagnetizationTransfer'],\n '9021': ['CS', '1', 'T2Preparation'],\n '9022': ['CS', '1', 'BloodSignalNulling'],\n '9024': ['CS', '1', 'SaturationRecovery'],\n '9025': ['CS', '1', 'SpectrallySelectedSuppression'],\n '9026': ['CS', '1', 'SpectrallySelectedExcitation'],\n '9027': ['CS', '1', 'SpatialPresaturation'],\n '9028': ['CS', '1', 'Tagging'],\n '9029': ['CS', '1', 'OversamplingPhase'],\n '9030': ['FD', '1', 'TagSpacingFirstDimension'],\n '9032': ['CS', '1', 'GeometryOfKSpaceTraversal'],\n '9033': ['CS', '1', 'SegmentedKSpaceTraversal'],\n '9034': ['CS', '1', 'RectilinearPhaseEncodeReordering'],\n '9035': ['FD', '1', 'TagThickness'],\n '9036': ['CS', '1', 'PartialFourierDirection'],\n '9037': ['CS', '1', 'CardiacSynchronizationTechnique'],\n '9041': ['LO', '1', 'ReceiveCoilManufacturerName'],\n '9042': ['SQ', '1', 'MRReceiveCoilSequence'],\n '9043': ['CS', '1', 'ReceiveCoilType'],\n '9044': ['CS', '1', 'QuadratureReceiveCoil'],\n '9045': ['SQ', '1', 'MultiCoilDefinitionSequence'],\n '9046': ['LO', '1', 'MultiCoilConfiguration'],\n '9047': ['SH', '1', 'MultiCoilElementName'],\n '9048': ['CS', '1', 'MultiCoilElementUsed'],\n '9049': ['SQ', '1', 'MRTransmitCoilSequence'],\n '9050': ['LO', '1', 'TransmitCoilManufacturerName'],\n '9051': ['CS', '1', 'TransmitCoilType'],\n '9052': ['FD', '1-2', 'SpectralWidth'],\n '9053': ['FD', '1-2', 'ChemicalShiftReference'],\n '9054': ['CS', '1', 'VolumeLocalizationTechnique'],\n '9058': ['US', '1', 'MRAcquisitionFrequencyEncodingSteps'],\n '9059': ['CS', '1', 'Decoupling'],\n '9060': ['CS', '1-2', 'DecoupledNucleus'],\n '9061': ['FD', '1-2', 'DecouplingFrequency'],\n '9062': ['CS', '1', 'DecouplingMethod'],\n '9063': ['FD', '1-2', 'DecouplingChemicalShiftReference'],\n '9064': ['CS', '1', 'KSpaceFiltering'],\n '9065': ['CS', '1-2', 'TimeDomainFiltering'],\n '9066': ['US', '1-2', 'NumberOfZeroFills'],\n '9067': ['CS', '1', 'BaselineCorrection'],\n '9069': ['FD', '1', 'ParallelReductionFactorInPlane'],\n '9070': ['FD', '1', 'CardiacRRIntervalSpecified'],\n '9073': ['FD', '1', 'AcquisitionDuration'],\n '9074': ['DT', '1', 'FrameAcquisitionDateTime'],\n '9075': ['CS', '1', 'DiffusionDirectionality'],\n '9076': ['SQ', '1', 'DiffusionGradientDirectionSequence'],\n '9077': ['CS', '1', 'ParallelAcquisition'],\n '9078': ['CS', '1', 'ParallelAcquisitionTechnique'],\n '9079': ['FD', '1-n', 'InversionTimes'],\n '9080': ['ST', '1', 'MetaboliteMapDescription'],\n '9081': ['CS', '1', 'PartialFourier'],\n '9082': ['FD', '1', 'EffectiveEchoTime'],\n '9083': ['SQ', '1', 'MetaboliteMapCodeSequence'],\n '9084': ['SQ', '1', 'ChemicalShiftSequence'],\n '9085': ['CS', '1', 'CardiacSignalSource'],\n '9087': ['FD', '1', 'DiffusionBValue'],\n '9089': ['FD', '3', 'DiffusionGradientOrientation'],\n '9090': ['FD', '3', 'VelocityEncodingDirection'],\n '9091': ['FD', '1', 'VelocityEncodingMinimumValue'],\n '9092': ['SQ', '1', 'VelocityEncodingAcquisitionSequence'],\n '9093': ['US', '1', 'NumberOfKSpaceTrajectories'],\n '9094': ['CS', '1', 'CoverageOfKSpace'],\n '9095': ['UL', '1', 'SpectroscopyAcquisitionPhaseRows'],\n '9096': ['FD', '1', 'ParallelReductionFactorInPlaneRetired'],\n '9098': ['FD', '1-2', 'TransmitterFrequency'],\n '9100': ['CS', '1-2', 'ResonantNucleus'],\n '9101': ['CS', '1', 'FrequencyCorrection'],\n '9103': ['SQ', '1', 'MRSpectroscopyFOVGeometrySequence'],\n '9104': ['FD', '1', 'SlabThickness'],\n '9105': ['FD', '3', 'SlabOrientation'],\n '9106': ['FD', '3', 'MidSlabPosition'],\n '9107': ['SQ', '1', 'MRSpatialSaturationSequence'],\n '9112': ['SQ', '1', 'MRTimingAndRelatedParametersSequence'],\n '9114': ['SQ', '1', 'MREchoSequence'],\n '9115': ['SQ', '1', 'MRModifierSequence'],\n '9117': ['SQ', '1', 'MRDiffusionSequence'],\n '9118': ['SQ', '1', 'CardiacSynchronizationSequence'],\n '9119': ['SQ', '1', 'MRAveragesSequence'],\n '9125': ['SQ', '1', 'MRFOVGeometrySequence'],\n '9126': ['SQ', '1', 'VolumeLocalizationSequence'],\n '9127': ['UL', '1', 'SpectroscopyAcquisitionDataColumns'],\n '9147': ['CS', '1', 'DiffusionAnisotropyType'],\n '9151': ['DT', '1', 'FrameReferenceDateTime'],\n '9152': ['SQ', '1', 'MRMetaboliteMapSequence'],\n '9155': ['FD', '1', 'ParallelReductionFactorOutOfPlane'],\n '9159': ['UL', '1', 'SpectroscopyAcquisitionOutOfPlanePhaseSteps'],\n '9166': ['CS', '1', 'BulkMotionStatus'],\n '9168': ['FD', '1', 'ParallelReductionFactorSecondInPlane'],\n '9169': ['CS', '1', 'CardiacBeatRejectionTechnique'],\n '9170': ['CS', '1', 'RespiratoryMotionCompensationTechnique'],\n '9171': ['CS', '1', 'RespiratorySignalSource'],\n '9172': ['CS', '1', 'BulkMotionCompensationTechnique'],\n '9173': ['CS', '1', 'BulkMotionSignalSource'],\n '9174': ['CS', '1', 'ApplicableSafetyStandardAgency'],\n '9175': ['LO', '1', 'ApplicableSafetyStandardDescription'],\n '9176': ['SQ', '1', 'OperatingModeSequence'],\n '9177': ['CS', '1', 'OperatingModeType'],\n '9178': ['CS', '1', 'OperatingMode'],\n '9179': ['CS', '1', 'SpecificAbsorptionRateDefinition'],\n '9180': ['CS', '1', 'GradientOutputType'],\n '9181': ['FD', '1', 'SpecificAbsorptionRateValue'],\n '9182': ['FD', '1', 'GradientOutput'],\n '9183': ['CS', '1', 'FlowCompensationDirection'],\n '9184': ['FD', '1', 'TaggingDelay'],\n '9185': ['ST', '1', 'RespiratoryMotionCompensationTechniqueDescription'],\n '9186': ['SH', '1', 'RespiratorySignalSourceID'],\n '9195': ['FD', '1', 'ChemicalShiftMinimumIntegrationLimitInHz'],\n '9196': ['FD', '1', 'ChemicalShiftMaximumIntegrationLimitInHz'],\n '9197': ['SQ', '1', 'MRVelocityEncodingSequence'],\n '9198': ['CS', '1', 'FirstOrderPhaseCorrection'],\n '9199': ['CS', '1', 'WaterReferencedPhaseCorrection'],\n '9200': ['CS', '1', 'MRSpectroscopyAcquisitionType'],\n '9214': ['CS', '1', 'RespiratoryCyclePosition'],\n '9217': ['FD', '1', 'VelocityEncodingMaximumValue'],\n '9218': ['FD', '1', 'TagSpacingSecondDimension'],\n '9219': ['SS', '1', 'TagAngleSecondAxis'],\n '9220': ['FD', '1', 'FrameAcquisitionDuration'],\n '9226': ['SQ', '1', 'MRImageFrameTypeSequence'],\n '9227': ['SQ', '1', 'MRSpectroscopyFrameTypeSequence'],\n '9231': ['US', '1', 'MRAcquisitionPhaseEncodingStepsInPlane'],\n '9232': ['US', '1', 'MRAcquisitionPhaseEncodingStepsOutOfPlane'],\n '9234': ['UL', '1', 'SpectroscopyAcquisitionPhaseColumns'],\n '9236': ['CS', '1', 'CardiacCyclePosition'],\n '9239': ['SQ', '1', 'SpecificAbsorptionRateSequence'],\n '9240': ['US', '1', 'RFEchoTrainLength'],\n '9241': ['US', '1', 'GradientEchoTrainLength'],\n '9250': ['CS', '1', 'ArterialSpinLabelingContrast'],\n '9251': ['SQ', '1', 'MRArterialSpinLabelingSequence'],\n '9252': ['LO', '1', 'ASLTechniqueDescription'],\n '9253': ['US', '1', 'ASLSlabNumber'],\n '9254': ['FD', '1', 'ASLSlabThickness'],\n '9255': ['FD', '3', 'ASLSlabOrientation'],\n '9256': ['FD', '3', 'ASLMidSlabPosition'],\n '9257': ['CS', '1', 'ASLContext'],\n '9258': ['UL', '1', 'ASLPulseTrainDuration'],\n '9259': ['CS', '1', 'ASLCrusherFlag'],\n '925A': ['FD', '1', 'ASLCrusherFlowLimit'],\n '925B': ['LO', '1', 'ASLCrusherDescription'],\n '925C': ['CS', '1', 'ASLBolusCutoffFlag'],\n '925D': ['SQ', '1', 'ASLBolusCutoffTimingSequence'],\n '925E': ['LO', '1', 'ASLBolusCutoffTechnique'],\n '925F': ['UL', '1', 'ASLBolusCutoffDelayTime'],\n '9260': ['SQ', '1', 'ASLSlabSequence'],\n '9295': ['FD', '1', 'ChemicalShiftMinimumIntegrationLimitInppm'],\n '9296': ['FD', '1', 'ChemicalShiftMaximumIntegrationLimitInppm'],\n '9297': ['CS', '1', 'WaterReferenceAcquisition'],\n '9298': ['IS', '1', 'EchoPeakPosition'],\n '9301': ['SQ', '1', 'CTAcquisitionTypeSequence'],\n '9302': ['CS', '1', 'AcquisitionType'],\n '9303': ['FD', '1', 'TubeAngle'],\n '9304': ['SQ', '1', 'CTAcquisitionDetailsSequence'],\n '9305': ['FD', '1', 'RevolutionTime'],\n '9306': ['FD', '1', 'SingleCollimationWidth'],\n '9307': ['FD', '1', 'TotalCollimationWidth'],\n '9308': ['SQ', '1', 'CTTableDynamicsSequence'],\n '9309': ['FD', '1', 'TableSpeed'],\n '9310': ['FD', '1', 'TableFeedPerRotation'],\n '9311': ['FD', '1', 'SpiralPitchFactor'],\n '9312': ['SQ', '1', 'CTGeometrySequence'],\n '9313': ['FD', '3', 'DataCollectionCenterPatient'],\n '9314': ['SQ', '1', 'CTReconstructionSequence'],\n '9315': ['CS', '1', 'ReconstructionAlgorithm'],\n '9316': ['CS', '1', 'ConvolutionKernelGroup'],\n '9317': ['FD', '2', 'ReconstructionFieldOfView'],\n '9318': ['FD', '3', 'ReconstructionTargetCenterPatient'],\n '9319': ['FD', '1', 'ReconstructionAngle'],\n '9320': ['SH', '1', 'ImageFilter'],\n '9321': ['SQ', '1', 'CTExposureSequence'],\n '9322': ['FD', '2', 'ReconstructionPixelSpacing'],\n '9323': ['CS', '1-n', 'ExposureModulationType'],\n '9324': ['FD', '1', 'EstimatedDoseSaving'],\n '9325': ['SQ', '1', 'CTXRayDetailsSequence'],\n '9326': ['SQ', '1', 'CTPositionSequence'],\n '9327': ['FD', '1', 'TablePosition'],\n '9328': ['FD', '1', 'ExposureTimeInms'],\n '9329': ['SQ', '1', 'CTImageFrameTypeSequence'],\n '9330': ['FD', '1', 'XRayTubeCurrentInmA'],\n '9332': ['FD', '1', 'ExposureInmAs'],\n '9333': ['CS', '1', 'ConstantVolumeFlag'],\n '9334': ['CS', '1', 'FluoroscopyFlag'],\n '9335': ['FD', '1', 'DistanceSourceToDataCollectionCenter'],\n '9337': ['US', '1', 'ContrastBolusAgentNumber'],\n '9338': ['SQ', '1', 'ContrastBolusIngredientCodeSequence'],\n '9340': ['SQ', '1', 'ContrastAdministrationProfileSequence'],\n '9341': ['SQ', '1', 'ContrastBolusUsageSequence'],\n '9342': ['CS', '1', 'ContrastBolusAgentAdministered'],\n '9343': ['CS', '1', 'ContrastBolusAgentDetected'],\n '9344': ['CS', '1', 'ContrastBolusAgentPhase'],\n '9345': ['FD', '1', 'CTDIvol'],\n '9346': ['SQ', '1', 'CTDIPhantomTypeCodeSequence'],\n '9351': ['FL', '1', 'CalciumScoringMassFactorPatient'],\n '9352': ['FL', '3', 'CalciumScoringMassFactorDevice'],\n '9353': ['FL', '1', 'EnergyWeightingFactor'],\n '9360': ['SQ', '1', 'CTAdditionalXRaySourceSequence'],\n '9361': ['CS', '1', 'MultienergyCTAcquisition'],\n '9362': ['SQ', '1', 'MultienergyCTAcquisitionSequence'],\n '9363': ['SQ', '1', 'MultienergyCTProcessingSequence'],\n '9364': ['SQ', '1', 'MultienergyCTCharacteristicsSequence'],\n '9365': ['SQ', '1', 'MultienergyCTXRaySourceSequence'],\n '9366': ['US', '1', 'XRaySourceIndex'],\n '9367': ['UC', '1', 'XRaySourceID'],\n '9368': ['CS', '1', 'MultienergySourceTechnique'],\n '9369': ['DT', '1', 'SourceStartDateTime'],\n '936A': ['DT', '1', 'SourceEndDateTime'],\n '936B': ['US', '1', 'SwitchingPhaseNumber'],\n '936C': ['DS', '1', 'SwitchingPhaseNominalDuration'],\n '936D': ['DS', '1', 'SwitchingPhaseTransitionDuration'],\n '936E': ['DS', '1', 'EffectiveBinEnergy'],\n '936F': ['SQ', '1', 'MultienergyCTXRayDetectorSequence'],\n '9370': ['US', '1', 'XRayDetectorIndex'],\n '9371': ['UC', '1', 'XRayDetectorID'],\n '9372': ['CS', '1', 'MultienergyDetectorType'],\n '9373': ['ST', '1', 'XRayDetectorLabel'],\n '9374': ['DS', '1', 'NominalMaxEnergy'],\n '9375': ['DS', '1', 'NominalMinEnergy'],\n '9376': ['US', '1-n', 'ReferencedXRayDetectorIndex'],\n '9377': ['US', '1-n', 'ReferencedXRaySourceIndex'],\n '9378': ['US', '1-n', 'ReferencedPathIndex'],\n '9379': ['SQ', '1', 'MultienergyCTPathSequence'],\n '937A': ['US', '1', 'MultienergyCTPathIndex'],\n '937B': ['UT', '1', 'MultienergyAcquisitionDescription'],\n '937C': ['FD', '1', 'MonoenergeticEnergyEquivalent'],\n '937D': ['SQ', '1', 'MaterialCodeSequence'],\n '937E': ['CS', '1', 'DecompositionMethod'],\n '937F': ['UT', '1', 'DecompositionDescription'],\n '9380': ['SQ', '1', 'DecompositionAlgorithmIdentificationSequence'],\n '9381': ['SQ', '1', 'DecompositionMaterialSequence'],\n '9382': ['SQ', '1', 'MaterialAttenuationSequence'],\n '9383': ['DS', '1', 'PhotonEnergy'],\n '9384': ['DS', '1', 'XRayMassAttenuationCoefficient'],\n '9401': ['SQ', '1', 'ProjectionPixelCalibrationSequence'],\n '9402': ['FL', '1', 'DistanceSourceToIsocenter'],\n '9403': ['FL', '1', 'DistanceObjectToTableTop'],\n '9404': ['FL', '2', 'ObjectPixelSpacingInCenterOfBeam'],\n '9405': ['SQ', '1', 'PositionerPositionSequence'],\n '9406': ['SQ', '1', 'TablePositionSequence'],\n '9407': ['SQ', '1', 'CollimatorShapeSequence'],\n '9410': ['CS', '1', 'PlanesInAcquisition'],\n '9412': ['SQ', '1', 'XAXRFFrameCharacteristicsSequence'],\n '9417': ['SQ', '1', 'FrameAcquisitionSequence'],\n '9420': ['CS', '1', 'XRayReceptorType'],\n '9423': ['LO', '1', 'AcquisitionProtocolName'],\n '9424': ['LT', '1', 'AcquisitionProtocolDescription'],\n '9425': ['CS', '1', 'ContrastBolusIngredientOpaque'],\n '9426': ['FL', '1', 'DistanceReceptorPlaneToDetectorHousing'],\n '9427': ['CS', '1', 'IntensifierActiveShape'],\n '9428': ['FL', '1-2', 'IntensifierActiveDimensions'],\n '9429': ['FL', '2', 'PhysicalDetectorSize'],\n '9430': ['FL', '2', 'PositionOfIsocenterProjection'],\n '9432': ['SQ', '1', 'FieldOfViewSequence'],\n '9433': ['LO', '1', 'FieldOfViewDescription'],\n '9434': ['SQ', '1', 'ExposureControlSensingRegionsSequence'],\n '9435': ['CS', '1', 'ExposureControlSensingRegionShape'],\n '9436': ['SS', '1', 'ExposureControlSensingRegionLeftVerticalEdge'],\n '9437': ['SS', '1', 'ExposureControlSensingRegionRightVerticalEdge'],\n '9438': ['SS', '1', 'ExposureControlSensingRegionUpperHorizontalEdge'],\n '9439': ['SS', '1', 'ExposureControlSensingRegionLowerHorizontalEdge'],\n '9440': ['SS', '2', 'CenterOfCircularExposureControlSensingRegion'],\n '9441': ['US', '1', 'RadiusOfCircularExposureControlSensingRegion'],\n '9442': ['SS', '2-n', 'VerticesOfThePolygonalExposureControlSensingRegion'],\n '9445': ['', '', ''],\n '9447': ['FL', '1', 'ColumnAngulationPatient'],\n '9449': ['FL', '1', 'BeamAngle'],\n '9451': ['SQ', '1', 'FrameDetectorParametersSequence'],\n '9452': ['FL', '1', 'CalculatedAnatomyThickness'],\n '9455': ['SQ', '1', 'CalibrationSequence'],\n '9456': ['SQ', '1', 'ObjectThicknessSequence'],\n '9457': ['CS', '1', 'PlaneIdentification'],\n '9461': ['FL', '1-2', 'FieldOfViewDimensionsInFloat'],\n '9462': ['SQ', '1', 'IsocenterReferenceSystemSequence'],\n '9463': ['FL', '1', 'PositionerIsocenterPrimaryAngle'],\n '9464': ['FL', '1', 'PositionerIsocenterSecondaryAngle'],\n '9465': ['FL', '1', 'PositionerIsocenterDetectorRotationAngle'],\n '9466': ['FL', '1', 'TableXPositionToIsocenter'],\n '9467': ['FL', '1', 'TableYPositionToIsocenter'],\n '9468': ['FL', '1', 'TableZPositionToIsocenter'],\n '9469': ['FL', '1', 'TableHorizontalRotationAngle'],\n '9470': ['FL', '1', 'TableHeadTiltAngle'],\n '9471': ['FL', '1', 'TableCradleTiltAngle'],\n '9472': ['SQ', '1', 'FrameDisplayShutterSequence'],\n '9473': ['FL', '1', 'AcquiredImageAreaDoseProduct'],\n '9474': ['CS', '1', 'CArmPositionerTabletopRelationship'],\n '9476': ['SQ', '1', 'XRayGeometrySequence'],\n '9477': ['SQ', '1', 'IrradiationEventIdentificationSequence'],\n '9504': ['SQ', '1', 'XRay3DFrameTypeSequence'],\n '9506': ['SQ', '1', 'ContributingSourcesSequence'],\n '9507': ['SQ', '1', 'XRay3DAcquisitionSequence'],\n '9508': ['FL', '1', 'PrimaryPositionerScanArc'],\n '9509': ['FL', '1', 'SecondaryPositionerScanArc'],\n '9510': ['FL', '1', 'PrimaryPositionerScanStartAngle'],\n '9511': ['FL', '1', 'SecondaryPositionerScanStartAngle'],\n '9514': ['FL', '1', 'PrimaryPositionerIncrement'],\n '9515': ['FL', '1', 'SecondaryPositionerIncrement'],\n '9516': ['DT', '1', 'StartAcquisitionDateTime'],\n '9517': ['DT', '1', 'EndAcquisitionDateTime'],\n '9518': ['SS', '1', 'PrimaryPositionerIncrementSign'],\n '9519': ['SS', '1', 'SecondaryPositionerIncrementSign'],\n '9524': ['LO', '1', 'ApplicationName'],\n '9525': ['LO', '1', 'ApplicationVersion'],\n '9526': ['LO', '1', 'ApplicationManufacturer'],\n '9527': ['CS', '1', 'AlgorithmType'],\n '9528': ['LO', '1', 'AlgorithmDescription'],\n '9530': ['SQ', '1', 'XRay3DReconstructionSequence'],\n '9531': ['LO', '1', 'ReconstructionDescription'],\n '9538': ['SQ', '1', 'PerProjectionAcquisitionSequence'],\n '9541': ['SQ', '1', 'DetectorPositionSequence'],\n '9542': ['SQ', '1', 'XRayAcquisitionDoseSequence'],\n '9543': ['FD', '1', 'XRaySourceIsocenterPrimaryAngle'],\n '9544': ['FD', '1', 'XRaySourceIsocenterSecondaryAngle'],\n '9545': ['FD', '1', 'BreastSupportIsocenterPrimaryAngle'],\n '9546': ['FD', '1', 'BreastSupportIsocenterSecondaryAngle'],\n '9547': ['FD', '1', 'BreastSupportXPositionToIsocenter'],\n '9548': ['FD', '1', 'BreastSupportYPositionToIsocenter'],\n '9549': ['FD', '1', 'BreastSupportZPositionToIsocenter'],\n '9550': ['FD', '1', 'DetectorIsocenterPrimaryAngle'],\n '9551': ['FD', '1', 'DetectorIsocenterSecondaryAngle'],\n '9552': ['FD', '1', 'DetectorXPositionToIsocenter'],\n '9553': ['FD', '1', 'DetectorYPositionToIsocenter'],\n '9554': ['FD', '1', 'DetectorZPositionToIsocenter'],\n '9555': ['SQ', '1', 'XRayGridSequence'],\n '9556': ['SQ', '1', 'XRayFilterSequence'],\n '9557': ['FD', '3', 'DetectorActiveAreaTLHCPosition'],\n '9558': ['FD', '6', 'DetectorActiveAreaOrientation'],\n '9559': ['CS', '1', 'PositionerPrimaryAngleDirection'],\n '9601': ['SQ', '1', 'DiffusionBMatrixSequence'],\n '9602': ['FD', '1', 'DiffusionBValueXX'],\n '9603': ['FD', '1', 'DiffusionBValueXY'],\n '9604': ['FD', '1', 'DiffusionBValueXZ'],\n '9605': ['FD', '1', 'DiffusionBValueYY'],\n '9606': ['FD', '1', 'DiffusionBValueYZ'],\n '9607': ['FD', '1', 'DiffusionBValueZZ'],\n '9621': ['SQ', '1', 'FunctionalMRSequence'],\n '9622': ['CS', '1', 'FunctionalSettlingPhaseFramesPresent'],\n '9623': ['DT', '1', 'FunctionalSyncPulse'],\n '9624': ['CS', '1', 'SettlingPhaseFrame'],\n '9701': ['DT', '1', 'DecayCorrectionDateTime'],\n '9715': ['FD', '1', 'StartDensityThreshold'],\n '9716': ['FD', '1', 'StartRelativeDensityDifferenceThreshold'],\n '9717': ['FD', '1', 'StartCardiacTriggerCountThreshold'],\n '9718': ['FD', '1', 'StartRespiratoryTriggerCountThreshold'],\n '9719': ['FD', '1', 'TerminationCountsThreshold'],\n '9720': ['FD', '1', 'TerminationDensityThreshold'],\n '9721': ['FD', '1', 'TerminationRelativeDensityThreshold'],\n '9722': ['FD', '1', 'TerminationTimeThreshold'],\n '9723': ['FD', '1', 'TerminationCardiacTriggerCountThreshold'],\n '9724': ['FD', '1', 'TerminationRespiratoryTriggerCountThreshold'],\n '9725': ['CS', '1', 'DetectorGeometry'],\n '9726': ['FD', '1', 'TransverseDetectorSeparation'],\n '9727': ['FD', '1', 'AxialDetectorDimension'],\n '9729': ['US', '1', 'RadiopharmaceuticalAgentNumber'],\n '9732': ['SQ', '1', 'PETFrameAcquisitionSequence'],\n '9733': ['SQ', '1', 'PETDetectorMotionDetailsSequence'],\n '9734': ['SQ', '1', 'PETTableDynamicsSequence'],\n '9735': ['SQ', '1', 'PETPositionSequence'],\n '9736': ['SQ', '1', 'PETFrameCorrectionFactorsSequence'],\n '9737': ['SQ', '1', 'RadiopharmaceuticalUsageSequence'],\n '9738': ['CS', '1', 'AttenuationCorrectionSource'],\n '9739': ['US', '1', 'NumberOfIterations'],\n '9740': ['US', '1', 'NumberOfSubsets'],\n '9749': ['SQ', '1', 'PETReconstructionSequence'],\n '9751': ['SQ', '1', 'PETFrameTypeSequence'],\n '9755': ['CS', '1', 'TimeOfFlightInformationUsed'],\n '9756': ['CS', '1', 'ReconstructionType'],\n '9758': ['CS', '1', 'DecayCorrected'],\n '9759': ['CS', '1', 'AttenuationCorrected'],\n '9760': ['CS', '1', 'ScatterCorrected'],\n '9761': ['CS', '1', 'DeadTimeCorrected'],\n '9762': ['CS', '1', 'GantryMotionCorrected'],\n '9763': ['CS', '1', 'PatientMotionCorrected'],\n '9764': ['CS', '1', 'CountLossNormalizationCorrected'],\n '9765': ['CS', '1', 'RandomsCorrected'],\n '9766': ['CS', '1', 'NonUniformRadialSamplingCorrected'],\n '9767': ['CS', '1', 'SensitivityCalibrated'],\n '9768': ['CS', '1', 'DetectorNormalizationCorrection'],\n '9769': ['CS', '1', 'IterativeReconstructionMethod'],\n '9770': ['CS', '1', 'AttenuationCorrectionTemporalRelationship'],\n '9771': ['SQ', '1', 'PatientPhysiologicalStateSequence'],\n '9772': ['SQ', '1', 'PatientPhysiologicalStateCodeSequence'],\n '9801': ['FD', '1-n', 'DepthsOfFocus'],\n '9803': ['SQ', '1', 'ExcludedIntervalsSequence'],\n '9804': ['DT', '1', 'ExclusionStartDateTime'],\n '9805': ['FD', '1', 'ExclusionDuration'],\n '9806': ['SQ', '1', 'USImageDescriptionSequence'],\n '9807': ['SQ', '1', 'ImageDataTypeSequence'],\n '9808': ['CS', '1', 'DataType'],\n '9809': ['SQ', '1', 'TransducerScanPatternCodeSequence'],\n '980B': ['CS', '1', 'AliasedDataType'],\n '980C': ['CS', '1', 'PositionMeasuringDeviceUsed'],\n '980D': ['SQ', '1', 'TransducerGeometryCodeSequence'],\n '980E': ['SQ', '1', 'TransducerBeamSteeringCodeSequence'],\n '980F': ['SQ', '1', 'TransducerApplicationCodeSequence'],\n '9810': ['xs', '1', 'ZeroVelocityPixelValue'],\n '9900': ['LO', '1', 'ReferenceLocationLabel'],\n '9901': ['UT', '1', 'ReferenceLocationDescription'],\n '9902': ['SQ', '1', 'ReferenceBasisCodeSequence'],\n '9903': ['SQ', '1', 'ReferenceGeometryCodeSequence'],\n '9904': ['DS', '1', 'OffsetDistance'],\n '9905': ['CS', '1', 'OffsetDirection'],\n '9906': ['SQ', '1', 'PotentialScheduledProtocolCodeSequence'],\n '9907': ['SQ', '1', 'PotentialRequestedProcedureCodeSequence'],\n '9908': ['UC', '1-n', 'PotentialReasonsForProcedure'],\n '9909': ['SQ', '1', 'PotentialReasonsForProcedureCodeSequence'],\n '990A': ['UC', '1-n', 'PotentialDiagnosticTasks'],\n '990B': ['SQ', '1', 'ContraindicationsCodeSequence'],\n '990C': ['SQ', '1', 'ReferencedDefinedProtocolSequence'],\n '990D': ['SQ', '1', 'ReferencedPerformedProtocolSequence'],\n '990E': ['SQ', '1', 'PredecessorProtocolSequence'],\n '990F': ['UT', '1', 'ProtocolPlanningInformation'],\n '9910': ['UT', '1', 'ProtocolDesignRationale'],\n '9911': ['SQ', '1', 'PatientSpecificationSequence'],\n '9912': ['SQ', '1', 'ModelSpecificationSequence'],\n '9913': ['SQ', '1', 'ParametersSpecificationSequence'],\n '9914': ['SQ', '1', 'InstructionSequence'],\n '9915': ['US', '1', 'InstructionIndex'],\n '9916': ['LO', '1', 'InstructionText'],\n '9917': ['UT', '1', 'InstructionDescription'],\n '9918': ['CS', '1', 'InstructionPerformedFlag'],\n '9919': ['DT', '1', 'InstructionPerformedDateTime'],\n '991A': ['UT', '1', 'InstructionPerformanceComment'],\n '991B': ['SQ', '1', 'PatientPositioningInstructionSequence'],\n '991C': ['SQ', '1', 'PositioningMethodCodeSequence'],\n '991D': ['SQ', '1', 'PositioningLandmarkSequence'],\n '991E': ['UI', '1', 'TargetFrameOfReferenceUID'],\n '991F': ['SQ', '1', 'AcquisitionProtocolElementSpecificationSequence'],\n '9920': ['SQ', '1', 'AcquisitionProtocolElementSequence'],\n '9921': ['US', '1', 'ProtocolElementNumber'],\n '9922': ['LO', '1', 'ProtocolElementName'],\n '9923': ['UT', '1', 'ProtocolElementCharacteristicsSummary'],\n '9924': ['UT', '1', 'ProtocolElementPurpose'],\n '9930': ['CS', '1', 'AcquisitionMotion'],\n '9931': ['SQ', '1', 'AcquisitionStartLocationSequence'],\n '9932': ['SQ', '1', 'AcquisitionEndLocationSequence'],\n '9933': ['SQ', '1', 'ReconstructionProtocolElementSpecificationSequence'],\n '9934': ['SQ', '1', 'ReconstructionProtocolElementSequence'],\n '9935': ['SQ', '1', 'StorageProtocolElementSpecificationSequence'],\n '9936': ['SQ', '1', 'StorageProtocolElementSequence'],\n '9937': ['LO', '1', 'RequestedSeriesDescription'],\n '9938': ['US', '1-n', 'SourceAcquisitionProtocolElementNumber'],\n '9939': ['US', '1-n', 'SourceAcquisitionBeamNumber'],\n '993A': ['US', '1-n', 'SourceReconstructionProtocolElementNumber'],\n '993B': ['SQ', '1', 'ReconstructionStartLocationSequence'],\n '993C': ['SQ', '1', 'ReconstructionEndLocationSequence'],\n '993D': ['SQ', '1', 'ReconstructionAlgorithmSequence'],\n '993E': ['SQ', '1', 'ReconstructionTargetCenterLocationSequence'],\n '9941': ['UT', '1', 'ImageFilterDescription'],\n '9942': ['FD', '1', 'CTDIvolNotificationTrigger'],\n '9943': ['FD', '1', 'DLPNotificationTrigger'],\n '9944': ['CS', '1', 'AutoKVPSelectionType'],\n '9945': ['FD', '1', 'AutoKVPUpperBound'],\n '9946': ['FD', '1', 'AutoKVPLowerBound'],\n '9947': ['CS', '1', 'ProtocolDefinedPatientPosition'],\n 'A001': ['SQ', '1', 'ContributingEquipmentSequence'],\n 'A002': ['DT', '1', 'ContributionDateTime'],\n 'A003': ['ST', '1', 'ContributionDescription']\n },\n '0020': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '000D': ['UI', '1', 'StudyInstanceUID'],\n '000E': ['UI', '1', 'SeriesInstanceUID'],\n '0010': ['SH', '1', 'StudyID'],\n '0011': ['IS', '1', 'SeriesNumber'],\n '0012': ['IS', '1', 'AcquisitionNumber'],\n '0013': ['IS', '1', 'InstanceNumber'],\n '0014': ['IS', '1', 'IsotopeNumber'],\n '0015': ['IS', '1', 'PhaseNumber'],\n '0016': ['IS', '1', 'IntervalNumber'],\n '0017': ['IS', '1', 'TimeSlotNumber'],\n '0018': ['IS', '1', 'AngleNumber'],\n '0019': ['IS', '1', 'ItemNumber'],\n '0020': ['CS', '2', 'PatientOrientation'],\n '0022': ['IS', '1', 'OverlayNumber'],\n '0024': ['IS', '1', 'CurveNumber'],\n '0026': ['IS', '1', 'LUTNumber'],\n '0030': ['DS', '3', 'ImagePosition'],\n '0032': ['DS', '3', 'ImagePositionPatient'],\n '0035': ['DS', '6', 'ImageOrientation'],\n '0037': ['DS', '6', 'ImageOrientationPatient'],\n '0050': ['DS', '1', 'Location'],\n '0052': ['UI', '1', 'FrameOfReferenceUID'],\n '0060': ['CS', '1', 'Laterality'],\n '0062': ['CS', '1', 'ImageLaterality'],\n '0070': ['LO', '1', 'ImageGeometryType'],\n '0080': ['CS', '1-n', 'MaskingImage'],\n '00AA': ['IS', '1', 'ReportNumber'],\n '0100': ['IS', '1', 'TemporalPositionIdentifier'],\n '0105': ['IS', '1', 'NumberOfTemporalPositions'],\n '0110': ['DS', '1', 'TemporalResolution'],\n '0200': ['UI', '1', 'SynchronizationFrameOfReferenceUID'],\n '0242': ['UI', '1', 'SOPInstanceUIDOfConcatenationSource'],\n '1000': ['IS', '1', 'SeriesInStudy'],\n '1001': ['IS', '1', 'AcquisitionsInSeries'],\n '1002': ['IS', '1', 'ImagesInAcquisition'],\n '1003': ['IS', '1', 'ImagesInSeries'],\n '1004': ['IS', '1', 'AcquisitionsInStudy'],\n '1005': ['IS', '1', 'ImagesInStudy'],\n '1020': ['LO', '1-n', 'Reference'],\n '103F': ['LO', '1', 'TargetPositionReferenceIndicator'],\n '1040': ['LO', '1', 'PositionReferenceIndicator'],\n '1041': ['DS', '1', 'SliceLocation'],\n '1070': ['IS', '1-n', 'OtherStudyNumbers'],\n '1200': ['IS', '1', 'NumberOfPatientRelatedStudies'],\n '1202': ['IS', '1', 'NumberOfPatientRelatedSeries'],\n '1204': ['IS', '1', 'NumberOfPatientRelatedInstances'],\n '1206': ['IS', '1', 'NumberOfStudyRelatedSeries'],\n '1208': ['IS', '1', 'NumberOfStudyRelatedInstances'],\n '1209': ['IS', '1', 'NumberOfSeriesRelatedInstances'],\n '3100': ['CS', '1-n', 'SourceImageIDs'],\n '3401': ['CS', '1', 'ModifyingDeviceID'],\n '3402': ['CS', '1', 'ModifiedImageID'],\n '3403': ['DA', '1', 'ModifiedImageDate'],\n '3404': ['LO', '1', 'ModifyingDeviceManufacturer'],\n '3405': ['TM', '1', 'ModifiedImageTime'],\n '3406': ['LO', '1', 'ModifiedImageDescription'],\n '4000': ['LT', '1', 'ImageComments'],\n '5000': ['AT', '1-n', 'OriginalImageIdentification'],\n '5002': ['LO', '1-n', 'OriginalImageIdentificationNomenclature'],\n '9056': ['SH', '1', 'StackID'],\n '9057': ['UL', '1', 'InStackPositionNumber'],\n '9071': ['SQ', '1', 'FrameAnatomySequence'],\n '9072': ['CS', '1', 'FrameLaterality'],\n '9111': ['SQ', '1', 'FrameContentSequence'],\n '9113': ['SQ', '1', 'PlanePositionSequence'],\n '9116': ['SQ', '1', 'PlaneOrientationSequence'],\n '9128': ['UL', '1', 'TemporalPositionIndex'],\n '9153': ['FD', '1', 'NominalCardiacTriggerDelayTime'],\n '9154': ['FL', '1', 'NominalCardiacTriggerTimePriorToRPeak'],\n '9155': ['FL', '1', 'ActualCardiacTriggerTimePriorToRPeak'],\n '9156': ['US', '1', 'FrameAcquisitionNumber'],\n '9157': ['UL', '1-n', 'DimensionIndexValues'],\n '9158': ['LT', '1', 'FrameComments'],\n '9161': ['UI', '1', 'ConcatenationUID'],\n '9162': ['US', '1', 'InConcatenationNumber'],\n '9163': ['US', '1', 'InConcatenationTotalNumber'],\n '9164': ['UI', '1', 'DimensionOrganizationUID'],\n '9165': ['AT', '1', 'DimensionIndexPointer'],\n '9167': ['AT', '1', 'FunctionalGroupPointer'],\n '9170': ['SQ', '1', 'UnassignedSharedConvertedAttributesSequence'],\n '9171': ['SQ', '1', 'UnassignedPerFrameConvertedAttributesSequence'],\n '9172': ['SQ', '1', 'ConversionSourceAttributesSequence'],\n '9213': ['LO', '1', 'DimensionIndexPrivateCreator'],\n '9221': ['SQ', '1', 'DimensionOrganizationSequence'],\n '9222': ['SQ', '1', 'DimensionIndexSequence'],\n '9228': ['UL', '1', 'ConcatenationFrameOffsetNumber'],\n '9238': ['LO', '1', 'FunctionalGroupPrivateCreator'],\n '9241': ['FL', '1', 'NominalPercentageOfCardiacPhase'],\n '9245': ['FL', '1', 'NominalPercentageOfRespiratoryPhase'],\n '9246': ['FL', '1', 'StartingRespiratoryAmplitude'],\n '9247': ['CS', '1', 'StartingRespiratoryPhase'],\n '9248': ['FL', '1', 'EndingRespiratoryAmplitude'],\n '9249': ['CS', '1', 'EndingRespiratoryPhase'],\n '9250': ['CS', '1', 'RespiratoryTriggerType'],\n '9251': ['FD', '1', 'RRIntervalTimeNominal'],\n '9252': ['FD', '1', 'ActualCardiacTriggerDelayTime'],\n '9253': ['SQ', '1', 'RespiratorySynchronizationSequence'],\n '9254': ['FD', '1', 'RespiratoryIntervalTime'],\n '9255': ['FD', '1', 'NominalRespiratoryTriggerDelayTime'],\n '9256': ['FD', '1', 'RespiratoryTriggerDelayThreshold'],\n '9257': ['FD', '1', 'ActualRespiratoryTriggerDelayTime'],\n '9301': ['FD', '3', 'ImagePositionVolume'],\n '9302': ['FD', '6', 'ImageOrientationVolume'],\n '9307': ['CS', '1', 'UltrasoundAcquisitionGeometry'],\n '9308': ['FD', '3', 'ApexPosition'],\n '9309': ['FD', '16', 'VolumeToTransducerMappingMatrix'],\n '930A': ['FD', '16', 'VolumeToTableMappingMatrix'],\n '930B': ['CS', '1', 'VolumeToTransducerRelationship'],\n '930C': ['CS', '1', 'PatientFrameOfReferenceSource'],\n '930D': ['FD', '1', 'TemporalPositionTimeOffset'],\n '930E': ['SQ', '1', 'PlanePositionVolumeSequence'],\n '930F': ['SQ', '1', 'PlaneOrientationVolumeSequence'],\n '9310': ['SQ', '1', 'TemporalPositionSequence'],\n '9311': ['CS', '1', 'DimensionOrganizationType'],\n '9312': ['UI', '1', 'VolumeFrameOfReferenceUID'],\n '9313': ['UI', '1', 'TableFrameOfReferenceUID'],\n '9421': ['LO', '1', 'DimensionDescriptionLabel'],\n '9450': ['SQ', '1', 'PatientOrientationInFrameSequence'],\n '9453': ['LO', '1', 'FrameLabel'],\n '9518': ['US', '1-n', 'AcquisitionIndex'],\n '9529': ['SQ', '1', 'ContributingSOPInstancesReferenceSequence'],\n '9536': ['US', '1', 'ReconstructionIndex']\n },\n '0022': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['US', '1', 'LightPathFilterPassThroughWavelength'],\n '0002': ['US', '2', 'LightPathFilterPassBand'],\n '0003': ['US', '1', 'ImagePathFilterPassThroughWavelength'],\n '0004': ['US', '2', 'ImagePathFilterPassBand'],\n '0005': ['CS', '1', 'PatientEyeMovementCommanded'],\n '0006': ['SQ', '1', 'PatientEyeMovementCommandCodeSequence'],\n '0007': ['FL', '1', 'SphericalLensPower'],\n '0008': ['FL', '1', 'CylinderLensPower'],\n '0009': ['FL', '1', 'CylinderAxis'],\n '000A': ['FL', '1', 'EmmetropicMagnification'],\n '000B': ['FL', '1', 'IntraOcularPressure'],\n '000C': ['FL', '1', 'HorizontalFieldOfView'],\n '000D': ['CS', '1', 'PupilDilated'],\n '000E': ['FL', '1', 'DegreeOfDilation'],\n '0010': ['FL', '1', 'StereoBaselineAngle'],\n '0011': ['FL', '1', 'StereoBaselineDisplacement'],\n '0012': ['FL', '1', 'StereoHorizontalPixelOffset'],\n '0013': ['FL', '1', 'StereoVerticalPixelOffset'],\n '0014': ['FL', '1', 'StereoRotation'],\n '0015': ['SQ', '1', 'AcquisitionDeviceTypeCodeSequence'],\n '0016': ['SQ', '1', 'IlluminationTypeCodeSequence'],\n '0017': ['SQ', '1', 'LightPathFilterTypeStackCodeSequence'],\n '0018': ['SQ', '1', 'ImagePathFilterTypeStackCodeSequence'],\n '0019': ['SQ', '1', 'LensesCodeSequence'],\n '001A': ['SQ', '1', 'ChannelDescriptionCodeSequence'],\n '001B': ['SQ', '1', 'RefractiveStateSequence'],\n '001C': ['SQ', '1', 'MydriaticAgentCodeSequence'],\n '001D': ['SQ', '1', 'RelativeImagePositionCodeSequence'],\n '001E': ['FL', '1', 'CameraAngleOfView'],\n '0020': ['SQ', '1', 'StereoPairsSequence'],\n '0021': ['SQ', '1', 'LeftImageSequence'],\n '0022': ['SQ', '1', 'RightImageSequence'],\n '0028': ['CS', '1', 'StereoPairsPresent'],\n '0030': ['FL', '1', 'AxialLengthOfTheEye'],\n '0031': ['SQ', '1', 'OphthalmicFrameLocationSequence'],\n '0032': ['FL', '2-2n', 'ReferenceCoordinates'],\n '0035': ['FL', '1', 'DepthSpatialResolution'],\n '0036': ['FL', '1', 'MaximumDepthDistortion'],\n '0037': ['FL', '1', 'AlongScanSpatialResolution'],\n '0038': ['FL', '1', 'MaximumAlongScanDistortion'],\n '0039': ['CS', '1', 'OphthalmicImageOrientation'],\n '0041': ['FL', '1', 'DepthOfTransverseImage'],\n '0042': ['SQ', '1', 'MydriaticAgentConcentrationUnitsSequence'],\n '0048': ['FL', '1', 'AcrossScanSpatialResolution'],\n '0049': ['FL', '1', 'MaximumAcrossScanDistortion'],\n '004E': ['DS', '1', 'MydriaticAgentConcentration'],\n '0055': ['FL', '1', 'IlluminationWaveLength'],\n '0056': ['FL', '1', 'IlluminationPower'],\n '0057': ['FL', '1', 'IlluminationBandwidth'],\n '0058': ['SQ', '1', 'MydriaticAgentSequence'],\n '1007': ['SQ', '1', 'OphthalmicAxialMeasurementsRightEyeSequence'],\n '1008': ['SQ', '1', 'OphthalmicAxialMeasurementsLeftEyeSequence'],\n '1009': ['CS', '1', 'OphthalmicAxialMeasurementsDeviceType'],\n '1010': ['CS', '1', 'OphthalmicAxialLengthMeasurementsType'],\n '1012': ['SQ', '1', 'OphthalmicAxialLengthSequence'],\n '1019': ['FL', '1', 'OphthalmicAxialLength'],\n '1024': ['SQ', '1', 'LensStatusCodeSequence'],\n '1025': ['SQ', '1', 'VitreousStatusCodeSequence'],\n '1028': ['SQ', '1', 'IOLFormulaCodeSequence'],\n '1029': ['LO', '1', 'IOLFormulaDetail'],\n '1033': ['FL', '1', 'KeratometerIndex'],\n '1035': ['SQ', '1', 'SourceOfOphthalmicAxialLengthCodeSequence'],\n '1036': ['SQ', '1', 'SourceOfCornealSizeDataCodeSequence'],\n '1037': ['FL', '1', 'TargetRefraction'],\n '1039': ['CS', '1', 'RefractiveProcedureOccurred'],\n '1040': ['SQ', '1', 'RefractiveSurgeryTypeCodeSequence'],\n '1044': ['SQ', '1', 'OphthalmicUltrasoundMethodCodeSequence'],\n '1045': ['SQ', '1', 'SurgicallyInducedAstigmatismSequence'],\n '1046': ['CS', '1', 'TypeOfOpticalCorrection'],\n '1047': ['SQ', '1', 'ToricIOLPowerSequence'],\n '1048': ['SQ', '1', 'PredictedToricErrorSequence'],\n '1049': ['CS', '1', 'PreSelectedForImplantation'],\n '104A': ['SQ', '1', 'ToricIOLPowerForExactEmmetropiaSequence'],\n '104B': ['SQ', '1', 'ToricIOLPowerForExactTargetRefractionSequence'],\n '1050': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsSequence'],\n '1053': ['FL', '1', 'IOLPower'],\n '1054': ['FL', '1', 'PredictedRefractiveError'],\n '1059': ['FL', '1', 'OphthalmicAxialLengthVelocity'],\n '1065': ['LO', '1', 'LensStatusDescription'],\n '1066': ['LO', '1', 'VitreousStatusDescription'],\n '1090': ['SQ', '1', 'IOLPowerSequence'],\n '1092': ['SQ', '1', 'LensConstantSequence'],\n '1093': ['LO', '1', 'IOLManufacturer'],\n '1094': ['LO', '1', 'LensConstantDescription'],\n '1095': ['LO', '1', 'ImplantName'],\n '1096': ['SQ', '1', 'KeratometryMeasurementTypeCodeSequence'],\n '1097': ['LO', '1', 'ImplantPartNumber'],\n '1100': ['SQ', '1', 'ReferencedOphthalmicAxialMeasurementsSequence'],\n '1101': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsSegmentNameCodeSequence'],\n '1103': ['SQ', '1', 'RefractiveErrorBeforeRefractiveSurgeryCodeSequence'],\n '1121': ['FL', '1', 'IOLPowerForExactEmmetropia'],\n '1122': ['FL', '1', 'IOLPowerForExactTargetRefraction'],\n '1125': ['SQ', '1', 'AnteriorChamberDepthDefinitionCodeSequence'],\n '1127': ['SQ', '1', 'LensThicknessSequence'],\n '1128': ['SQ', '1', 'AnteriorChamberDepthSequence'],\n '112A': ['SQ', '1', 'CalculationCommentSequence'],\n '112B': ['CS', '1', 'CalculationCommentType'],\n '112C': ['LT', '1', 'CalculationComment'],\n '1130': ['FL', '1', 'LensThickness'],\n '1131': ['FL', '1', 'AnteriorChamberDepth'],\n '1132': ['SQ', '1', 'SourceOfLensThicknessDataCodeSequence'],\n '1133': ['SQ', '1', 'SourceOfAnteriorChamberDepthDataCodeSequence'],\n '1134': ['SQ', '1', 'SourceOfRefractiveMeasurementsSequence'],\n '1135': ['SQ', '1', 'SourceOfRefractiveMeasurementsCodeSequence'],\n '1140': ['CS', '1', 'OphthalmicAxialLengthMeasurementModified'],\n '1150': ['SQ', '1', 'OphthalmicAxialLengthDataSourceCodeSequence'],\n '1153': ['SQ', '1', 'OphthalmicAxialLengthAcquisitionMethodCodeSequence'],\n '1155': ['FL', '1', 'SignalToNoiseRatio'],\n '1159': ['LO', '1', 'OphthalmicAxialLengthDataSourceDescription'],\n '1210': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsTotalLengthSequence'],\n '1211': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsSegmentalLengthSequence'],\n '1212': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsLengthSummationSequence'],\n '1220': ['SQ', '1', 'UltrasoundOphthalmicAxialLengthMeasurementsSequence'],\n '1225': ['SQ', '1', 'OpticalOphthalmicAxialLengthMeasurementsSequence'],\n '1230': ['SQ', '1', 'UltrasoundSelectedOphthalmicAxialLengthSequence'],\n '1250': ['SQ', '1', 'OphthalmicAxialLengthSelectionMethodCodeSequence'],\n '1255': ['SQ', '1', 'OpticalSelectedOphthalmicAxialLengthSequence'],\n '1257': ['SQ', '1', 'SelectedSegmentalOphthalmicAxialLengthSequence'],\n '1260': ['SQ', '1', 'SelectedTotalOphthalmicAxialLengthSequence'],\n '1262': ['SQ', '1', 'OphthalmicAxialLengthQualityMetricSequence'],\n '1265': ['SQ', '1', 'OphthalmicAxialLengthQualityMetricTypeCodeSequence'],\n '1273': ['LO', '1', 'OphthalmicAxialLengthQualityMetricTypeDescription'],\n '1300': ['SQ', '1', 'IntraocularLensCalculationsRightEyeSequence'],\n '1310': ['SQ', '1', 'IntraocularLensCalculationsLeftEyeSequence'],\n '1330': ['SQ', '1', 'ReferencedOphthalmicAxialLengthMeasurementQCImageSequence'],\n '1415': ['CS', '1', 'OphthalmicMappingDeviceType'],\n '1420': ['SQ', '1', 'AcquisitionMethodCodeSequence'],\n '1423': ['SQ', '1', 'AcquisitionMethodAlgorithmSequence'],\n '1436': ['SQ', '1', 'OphthalmicThicknessMapTypeCodeSequence'],\n '1443': ['SQ', '1', 'OphthalmicThicknessMappingNormalsSequence'],\n '1445': ['SQ', '1', 'RetinalThicknessDefinitionCodeSequence'],\n '1450': ['SQ', '1', 'PixelValueMappingToCodedConceptSequence'],\n '1452': ['xs', '1', 'MappedPixelValue'],\n '1454': ['LO', '1', 'PixelValueMappingExplanation'],\n '1458': ['SQ', '1', 'OphthalmicThicknessMapQualityThresholdSequence'],\n '1460': ['FL', '1', 'OphthalmicThicknessMapThresholdQualityRating'],\n '1463': ['FL', '2', 'AnatomicStructureReferencePoint'],\n '1465': ['SQ', '1', 'RegistrationToLocalizerSequence'],\n '1466': ['CS', '1', 'RegisteredLocalizerUnits'],\n '1467': ['FL', '2', 'RegisteredLocalizerTopLeftHandCorner'],\n '1468': ['FL', '2', 'RegisteredLocalizerBottomRightHandCorner'],\n '1470': ['SQ', '1', 'OphthalmicThicknessMapQualityRatingSequence'],\n '1472': ['SQ', '1', 'RelevantOPTAttributesSequence'],\n '1512': ['SQ', '1', 'TransformationMethodCodeSequence'],\n '1513': ['SQ', '1', 'TransformationAlgorithmSequence'],\n '1515': ['CS', '1', 'OphthalmicAxialLengthMethod'],\n '1517': ['FL', '1', 'OphthalmicFOV'],\n '1518': ['SQ', '1', 'TwoDimensionalToThreeDimensionalMapSequence'],\n '1525': ['SQ', '1', 'WideFieldOphthalmicPhotographyQualityRatingSequence'],\n '1526': ['SQ', '1', 'WideFieldOphthalmicPhotographyQualityThresholdSequence'],\n '1527': ['FL', '1', 'WideFieldOphthalmicPhotographyThresholdQualityRating'],\n '1528': ['FL', '1', 'XCoordinatesCenterPixelViewAngle'],\n '1529': ['FL', '1', 'YCoordinatesCenterPixelViewAngle'],\n '1530': ['UL', '1', 'NumberOfMapPoints'],\n '1531': ['OF', '1', 'TwoDimensionalToThreeDimensionalMapData'],\n '1612': ['SQ', '1', 'DerivationAlgorithmSequence'],\n '1615': ['SQ', '1', 'OphthalmicImageTypeCodeSequence'],\n '1616': ['LO', '1', 'OphthalmicImageTypeDescription'],\n '1618': ['SQ', '1', 'ScanPatternTypeCodeSequence'],\n '1620': ['SQ', '1', 'ReferencedSurfaceMeshIdentificationSequence'],\n '1622': ['CS', '1', 'OphthalmicVolumetricPropertiesFlag'],\n '1624': ['FL', '1', 'OphthalmicAnatomicReferencePointXCoordinate'],\n '1626': ['FL', '1', 'OphthalmicAnatomicReferencePointYCoordinate'],\n '1628': ['SQ', '1', 'OphthalmicEnFaceImageQualityRatingSequence'],\n '1630': ['DS', '1', 'QualityThreshold'],\n '1640': ['SQ', '1', 'OCTBscanAnalysisAcquisitionParametersSequence'],\n '1642': ['UL', '1', 'NumberOfBscansPerFrame'],\n '1643': ['FL', '1', 'BscanSlabThickness'],\n '1644': ['FL', '1', 'DistanceBetweenBscanSlabs'],\n '1645': ['FL', '1', 'BscanCycleTime'],\n '1646': ['FL', '1-n', 'BscanCycleTimeVector'],\n '1649': ['FL', '1', 'AscanRate'],\n '1650': ['FL', '1', 'BscanRate'],\n '1658': ['UL', '1', 'SurfaceMeshZPixelOffset']\n },\n '0024': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['FL', '1', 'VisualFieldHorizontalExtent'],\n '0011': ['FL', '1', 'VisualFieldVerticalExtent'],\n '0012': ['CS', '1', 'VisualFieldShape'],\n '0016': ['SQ', '1', 'ScreeningTestModeCodeSequence'],\n '0018': ['FL', '1', 'MaximumStimulusLuminance'],\n '0020': ['FL', '1', 'BackgroundLuminance'],\n '0021': ['SQ', '1', 'StimulusColorCodeSequence'],\n '0024': ['SQ', '1', 'BackgroundIlluminationColorCodeSequence'],\n '0025': ['FL', '1', 'StimulusArea'],\n '0028': ['FL', '1', 'StimulusPresentationTime'],\n '0032': ['SQ', '1', 'FixationSequence'],\n '0033': ['SQ', '1', 'FixationMonitoringCodeSequence'],\n '0034': ['SQ', '1', 'VisualFieldCatchTrialSequence'],\n '0035': ['US', '1', 'FixationCheckedQuantity'],\n '0036': ['US', '1', 'PatientNotProperlyFixatedQuantity'],\n '0037': ['CS', '1', 'PresentedVisualStimuliDataFlag'],\n '0038': ['US', '1', 'NumberOfVisualStimuli'],\n '0039': ['CS', '1', 'ExcessiveFixationLossesDataFlag'],\n '0040': ['CS', '1', 'ExcessiveFixationLosses'],\n '0042': ['US', '1', 'StimuliRetestingQuantity'],\n '0044': ['LT', '1', 'CommentsOnPatientPerformanceOfVisualField'],\n '0045': ['CS', '1', 'FalseNegativesEstimateFlag'],\n '0046': ['FL', '1', 'FalseNegativesEstimate'],\n '0048': ['US', '1', 'NegativeCatchTrialsQuantity'],\n '0050': ['US', '1', 'FalseNegativesQuantity'],\n '0051': ['CS', '1', 'ExcessiveFalseNegativesDataFlag'],\n '0052': ['CS', '1', 'ExcessiveFalseNegatives'],\n '0053': ['CS', '1', 'FalsePositivesEstimateFlag'],\n '0054': ['FL', '1', 'FalsePositivesEstimate'],\n '0055': ['CS', '1', 'CatchTrialsDataFlag'],\n '0056': ['US', '1', 'PositiveCatchTrialsQuantity'],\n '0057': ['CS', '1', 'TestPointNormalsDataFlag'],\n '0058': ['SQ', '1', 'TestPointNormalsSequence'],\n '0059': ['CS', '1', 'GlobalDeviationProbabilityNormalsFlag'],\n '0060': ['US', '1', 'FalsePositivesQuantity'],\n '0061': ['CS', '1', 'ExcessiveFalsePositivesDataFlag'],\n '0062': ['CS', '1', 'ExcessiveFalsePositives'],\n '0063': ['CS', '1', 'VisualFieldTestNormalsFlag'],\n '0064': ['SQ', '1', 'ResultsNormalsSequence'],\n '0065': ['SQ', '1', 'AgeCorrectedSensitivityDeviationAlgorithmSequence'],\n '0066': ['FL', '1', 'GlobalDeviationFromNormal'],\n '0067': ['SQ', '1', 'GeneralizedDefectSensitivityDeviationAlgorithmSequence'],\n '0068': ['FL', '1', 'LocalizedDeviationFromNormal'],\n '0069': ['LO', '1', 'PatientReliabilityIndicator'],\n '0070': ['FL', '1', 'VisualFieldMeanSensitivity'],\n '0071': ['FL', '1', 'GlobalDeviationProbability'],\n '0072': ['CS', '1', 'LocalDeviationProbabilityNormalsFlag'],\n '0073': ['FL', '1', 'LocalizedDeviationProbability'],\n '0074': ['CS', '1', 'ShortTermFluctuationCalculated'],\n '0075': ['FL', '1', 'ShortTermFluctuation'],\n '0076': ['CS', '1', 'ShortTermFluctuationProbabilityCalculated'],\n '0077': ['FL', '1', 'ShortTermFluctuationProbability'],\n '0078': ['CS', '1', 'CorrectedLocalizedDeviationFromNormalCalculated'],\n '0079': ['FL', '1', 'CorrectedLocalizedDeviationFromNormal'],\n '0080': ['CS', '1', 'CorrectedLocalizedDeviationFromNormalProbabilityCalculated'],\n '0081': ['FL', '1', 'CorrectedLocalizedDeviationFromNormalProbability'],\n '0083': ['SQ', '1', 'GlobalDeviationProbabilitySequence'],\n '0085': ['SQ', '1', 'LocalizedDeviationProbabilitySequence'],\n '0086': ['CS', '1', 'FovealSensitivityMeasured'],\n '0087': ['FL', '1', 'FovealSensitivity'],\n '0088': ['FL', '1', 'VisualFieldTestDuration'],\n '0089': ['SQ', '1', 'VisualFieldTestPointSequence'],\n '0090': ['FL', '1', 'VisualFieldTestPointXCoordinate'],\n '0091': ['FL', '1', 'VisualFieldTestPointYCoordinate'],\n '0092': ['FL', '1', 'AgeCorrectedSensitivityDeviationValue'],\n '0093': ['CS', '1', 'StimulusResults'],\n '0094': ['FL', '1', 'SensitivityValue'],\n '0095': ['CS', '1', 'RetestStimulusSeen'],\n '0096': ['FL', '1', 'RetestSensitivityValue'],\n '0097': ['SQ', '1', 'VisualFieldTestPointNormalsSequence'],\n '0098': ['FL', '1', 'QuantifiedDefect'],\n '0100': ['FL', '1', 'AgeCorrectedSensitivityDeviationProbabilityValue'],\n '0102': ['CS', '1', 'GeneralizedDefectCorrectedSensitivityDeviationFlag'],\n '0103': ['FL', '1', 'GeneralizedDefectCorrectedSensitivityDeviationValue'],\n '0104': ['FL', '1', 'GeneralizedDefectCorrectedSensitivityDeviationProbabilityValue'],\n '0105': ['FL', '1', 'MinimumSensitivityValue'],\n '0106': ['CS', '1', 'BlindSpotLocalized'],\n '0107': ['FL', '1', 'BlindSpotXCoordinate'],\n '0108': ['FL', '1', 'BlindSpotYCoordinate'],\n '0110': ['SQ', '1', 'VisualAcuityMeasurementSequence'],\n '0112': ['SQ', '1', 'RefractiveParametersUsedOnPatientSequence'],\n '0113': ['CS', '1', 'MeasurementLaterality'],\n '0114': ['SQ', '1', 'OphthalmicPatientClinicalInformationLeftEyeSequence'],\n '0115': ['SQ', '1', 'OphthalmicPatientClinicalInformationRightEyeSequence'],\n '0117': ['CS', '1', 'FovealPointNormativeDataFlag'],\n '0118': ['FL', '1', 'FovealPointProbabilityValue'],\n '0120': ['CS', '1', 'ScreeningBaselineMeasured'],\n '0122': ['SQ', '1', 'ScreeningBaselineMeasuredSequence'],\n '0124': ['CS', '1', 'ScreeningBaselineType'],\n '0126': ['FL', '1', 'ScreeningBaselineValue'],\n '0202': ['LO', '1', 'AlgorithmSource'],\n '0306': ['LO', '1', 'DataSetName'],\n '0307': ['LO', '1', 'DataSetVersion'],\n '0308': ['LO', '1', 'DataSetSource'],\n '0309': ['LO', '1', 'DataSetDescription'],\n '0317': ['SQ', '1', 'VisualFieldTestReliabilityGlobalIndexSequence'],\n '0320': ['SQ', '1', 'VisualFieldGlobalResultsIndexSequence'],\n '0325': ['SQ', '1', 'DataObservationSequence'],\n '0338': ['CS', '1', 'IndexNormalsFlag'],\n '0341': ['FL', '1', 'IndexProbability'],\n '0344': ['SQ', '1', 'IndexProbabilitySequence']\n },\n '0028': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['US', '1', 'SamplesPerPixel'],\n '0003': ['US', '1', 'SamplesPerPixelUsed'],\n '0004': ['CS', '1', 'PhotometricInterpretation'],\n '0005': ['US', '1', 'ImageDimensions'],\n '0006': ['US', '1', 'PlanarConfiguration'],\n '0008': ['IS', '1', 'NumberOfFrames'],\n '0009': ['AT', '1-n', 'FrameIncrementPointer'],\n '000A': ['AT', '1-n', 'FrameDimensionPointer'],\n '0010': ['US', '1', 'Rows'],\n '0011': ['US', '1', 'Columns'],\n '0012': ['US', '1', 'Planes'],\n '0014': ['US', '1', 'UltrasoundColorDataPresent'],\n '0020': ['', '', ''],\n '0030': ['DS', '2', 'PixelSpacing'],\n '0031': ['DS', '2', 'ZoomFactor'],\n '0032': ['DS', '2', 'ZoomCenter'],\n '0034': ['IS', '2', 'PixelAspectRatio'],\n '0040': ['CS', '1', 'ImageFormat'],\n '0050': ['LO', '1-n', 'ManipulatedImage'],\n '0051': ['CS', '1-n', 'CorrectedImage'],\n '005F': ['LO', '1', 'CompressionRecognitionCode'],\n '0060': ['CS', '1', 'CompressionCode'],\n '0061': ['SH', '1', 'CompressionOriginator'],\n '0062': ['LO', '1', 'CompressionLabel'],\n '0063': ['SH', '1', 'CompressionDescription'],\n '0065': ['CS', '1-n', 'CompressionSequence'],\n '0066': ['AT', '1-n', 'CompressionStepPointers'],\n '0068': ['US', '1', 'RepeatInterval'],\n '0069': ['US', '1', 'BitsGrouped'],\n '0070': ['US', '1-n', 'PerimeterTable'],\n '0071': ['xs', '1', 'PerimeterValue'],\n '0080': ['US', '1', 'PredictorRows'],\n '0081': ['US', '1', 'PredictorColumns'],\n '0082': ['US', '1-n', 'PredictorConstants'],\n '0090': ['CS', '1', 'BlockedPixels'],\n '0091': ['US', '1', 'BlockRows'],\n '0092': ['US', '1', 'BlockColumns'],\n '0093': ['US', '1', 'RowOverlap'],\n '0094': ['US', '1', 'ColumnOverlap'],\n '0100': ['US', '1', 'BitsAllocated'],\n '0101': ['US', '1', 'BitsStored'],\n '0102': ['US', '1', 'HighBit'],\n '0103': ['US', '1', 'PixelRepresentation'],\n '0104': ['xs', '1', 'SmallestValidPixelValue'],\n '0105': ['xs', '1', 'LargestValidPixelValue'],\n '0106': ['xs', '1', 'SmallestImagePixelValue'],\n '0107': ['xs', '1', 'LargestImagePixelValue'],\n '0108': ['xs', '1', 'SmallestPixelValueInSeries'],\n '0109': ['xs', '1', 'LargestPixelValueInSeries'],\n '0110': ['xs', '1', 'SmallestImagePixelValueInPlane'],\n '0111': ['xs', '1', 'LargestImagePixelValueInPlane'],\n '0120': ['xs', '1', 'PixelPaddingValue'],\n '0121': ['xs', '1', 'PixelPaddingRangeLimit'],\n '0122': ['FL', '1', 'FloatPixelPaddingValue'],\n '0123': ['FD', '1', 'DoubleFloatPixelPaddingValue'],\n '0124': ['FL', '1', 'FloatPixelPaddingRangeLimit'],\n '0125': ['FD', '1', 'DoubleFloatPixelPaddingRangeLimit'],\n '0200': ['US', '1', 'ImageLocation'],\n '0300': ['CS', '1', 'QualityControlImage'],\n '0301': ['CS', '1', 'BurnedInAnnotation'],\n '0302': ['CS', '1', 'RecognizableVisualFeatures'],\n '0303': ['CS', '1', 'LongitudinalTemporalInformationModified'],\n '0304': ['UI', '1', 'ReferencedColorPaletteInstanceUID'],\n '0400': ['LO', '1', 'TransformLabel'],\n '0401': ['LO', '1', 'TransformVersionNumber'],\n '0402': ['US', '1', 'NumberOfTransformSteps'],\n '0403': ['LO', '1-n', 'SequenceOfCompressedData'],\n '0404': ['AT', '1-n', 'DetailsOfCoefficients'],\n '04x0': ['US', '1', 'RowsForNthOrderCoefficients'],\n '04x1': ['US', '1', 'ColumnsForNthOrderCoefficients'],\n '04x2': ['LO', '1-n', 'CoefficientCoding'],\n '04x3': ['AT', '1-n', 'CoefficientCodingPointers'],\n '0700': ['LO', '1', 'DCTLabel'],\n '0701': ['CS', '1-n', 'DataBlockDescription'],\n '0702': ['AT', '1-n', 'DataBlock'],\n '0710': ['US', '1', 'NormalizationFactorFormat'],\n '0720': ['US', '1', 'ZonalMapNumberFormat'],\n '0721': ['AT', '1-n', 'ZonalMapLocation'],\n '0722': ['US', '1', 'ZonalMapFormat'],\n '0730': ['US', '1', 'AdaptiveMapFormat'],\n '0740': ['US', '1', 'CodeNumberFormat'],\n '08x0': ['CS', '1-n', 'CodeLabel'],\n '08x2': ['US', '1', 'NumberOfTables'],\n '08x3': ['AT', '1-n', 'CodeTableLocation'],\n '08x4': ['US', '1', 'BitsForCodeWord'],\n '08x8': ['AT', '1-n', 'ImageDataLocation'],\n '0A02': ['CS', '1', 'PixelSpacingCalibrationType'],\n '0A04': ['LO', '1', 'PixelSpacingCalibrationDescription'],\n '1040': ['CS', '1', 'PixelIntensityRelationship'],\n '1041': ['SS', '1', 'PixelIntensityRelationshipSign'],\n '1050': ['DS', '1-n', 'WindowCenter'],\n '1051': ['DS', '1-n', 'WindowWidth'],\n '1052': ['DS', '1', 'RescaleIntercept'],\n '1053': ['DS', '1', 'RescaleSlope'],\n '1054': ['LO', '1', 'RescaleType'],\n '1055': ['LO', '1-n', 'WindowCenterWidthExplanation'],\n '1056': ['CS', '1', 'VOILUTFunction'],\n '1080': ['CS', '1', 'GrayScale'],\n '1090': ['CS', '1', 'RecommendedViewingMode'],\n '1100': ['xs', '3', 'GrayLookupTableDescriptor'],\n '1101': ['xs', '3', 'RedPaletteColorLookupTableDescriptor'],\n '1102': ['xs', '3', 'GreenPaletteColorLookupTableDescriptor'],\n '1103': ['xs', '3', 'BluePaletteColorLookupTableDescriptor'],\n '1104': ['US', '3', 'AlphaPaletteColorLookupTableDescriptor'],\n '1111': ['xs', '4', 'LargeRedPaletteColorLookupTableDescriptor'],\n '1112': ['xs', '4', 'LargeGreenPaletteColorLookupTableDescriptor'],\n '1113': ['xs', '4', 'LargeBluePaletteColorLookupTableDescriptor'],\n '1199': ['UI', '1', 'PaletteColorLookupTableUID'],\n '1200': ['xs', '1-n or 1', 'GrayLookupTableData'],\n '1201': ['OW', '1', 'RedPaletteColorLookupTableData'],\n '1202': ['OW', '1', 'GreenPaletteColorLookupTableData'],\n '1203': ['OW', '1', 'BluePaletteColorLookupTableData'],\n '1204': ['OW', '1', 'AlphaPaletteColorLookupTableData'],\n '1211': ['OW', '1', 'LargeRedPaletteColorLookupTableData'],\n '1212': ['OW', '1', 'LargeGreenPaletteColorLookupTableData'],\n '1213': ['OW', '1', 'LargeBluePaletteColorLookupTableData'],\n '1214': ['UI', '1', 'LargePaletteColorLookupTableUID'],\n '1221': ['OW', '1', 'SegmentedRedPaletteColorLookupTableData'],\n '1222': ['OW', '1', 'SegmentedGreenPaletteColorLookupTableData'],\n '1223': ['OW', '1', 'SegmentedBluePaletteColorLookupTableData'],\n '1224': ['OW', '1', 'SegmentedAlphaPaletteColorLookupTableData'],\n '1230': ['SQ', '1', 'StoredValueColorRangeSequence'],\n '1231': ['FD', '1', 'MinimumStoredValueMapped'],\n '1232': ['FD', '1', 'MaximumStoredValueMapped'],\n '1300': ['CS', '1', 'BreastImplantPresent'],\n '1350': ['CS', '1', 'PartialView'],\n '1351': ['ST', '1', 'PartialViewDescription'],\n '1352': ['SQ', '1', 'PartialViewCodeSequence'],\n '135A': ['CS', '1', 'SpatialLocationsPreserved'],\n '1401': ['SQ', '1', 'DataFrameAssignmentSequence'],\n '1402': ['CS', '1', 'DataPathAssignment'],\n '1403': ['US', '1', 'BitsMappedToColorLookupTable'],\n '1404': ['SQ', '1', 'BlendingLUT1Sequence'],\n '1405': ['CS', '1', 'BlendingLUT1TransferFunction'],\n '1406': ['FD', '1', 'BlendingWeightConstant'],\n '1407': ['US', '3', 'BlendingLookupTableDescriptor'],\n '1408': ['OW', '1', 'BlendingLookupTableData'],\n '140B': ['SQ', '1', 'EnhancedPaletteColorLookupTableSequence'],\n '140C': ['SQ', '1', 'BlendingLUT2Sequence'],\n '140D': ['CS', '1', 'BlendingLUT2TransferFunction'],\n '140E': ['CS', '1', 'DataPathID'],\n '140F': ['CS', '1', 'RGBLUTTransferFunction'],\n '1410': ['CS', '1', 'AlphaLUTTransferFunction'],\n '2000': ['OB', '1', 'ICCProfile'],\n '2002': ['CS', '1', 'ColorSpace'],\n '2110': ['CS', '1', 'LossyImageCompression'],\n '2112': ['DS', '1-n', 'LossyImageCompressionRatio'],\n '2114': ['CS', '1-n', 'LossyImageCompressionMethod'],\n '3000': ['SQ', '1', 'ModalityLUTSequence'],\n '3002': ['xs', '3', 'LUTDescriptor'],\n '3003': ['LO', '1', 'LUTExplanation'],\n '3004': ['LO', '1', 'ModalityLUTType'],\n '3006': ['xx', '1-n or 1', 'LUTData'],\n '3010': ['SQ', '1', 'VOILUTSequence'],\n '3110': ['SQ', '1', 'SoftcopyVOILUTSequence'],\n '4000': ['LT', '1', 'ImagePresentationComments'],\n '5000': ['SQ', '1', 'BiPlaneAcquisitionSequence'],\n '6010': ['US', '1', 'RepresentativeFrameNumber'],\n '6020': ['US', '1-n', 'FrameNumbersOfInterest'],\n '6022': ['LO', '1-n', 'FrameOfInterestDescription'],\n '6023': ['CS', '1-n', 'FrameOfInterestType'],\n '6030': ['US', '1-n', 'MaskPointers'],\n '6040': ['US', '1-n', 'RWavePointer'],\n '6100': ['SQ', '1', 'MaskSubtractionSequence'],\n '6101': ['CS', '1', 'MaskOperation'],\n '6102': ['US', '2-2n', 'ApplicableFrameRange'],\n '6110': ['US', '1-n', 'MaskFrameNumbers'],\n '6112': ['US', '1', 'ContrastFrameAveraging'],\n '6114': ['FL', '2', 'MaskSubPixelShift'],\n '6120': ['SS', '1', 'TIDOffset'],\n '6190': ['ST', '1', 'MaskOperationExplanation'],\n '7000': ['SQ', '1', 'EquipmentAdministratorSequence'],\n '7001': ['US', '1', 'NumberOfDisplaySubsystems'],\n '7002': ['US', '1', 'CurrentConfigurationID'],\n '7003': ['US', '1', 'DisplaySubsystemID'],\n '7004': ['SH', '1', 'DisplaySubsystemName'],\n '7005': ['LO', '1', 'DisplaySubsystemDescription'],\n '7006': ['CS', '1', 'SystemStatus'],\n '7007': ['LO', '1', 'SystemStatusComment'],\n '7008': ['SQ', '1', 'TargetLuminanceCharacteristicsSequence'],\n '7009': ['US', '1', 'LuminanceCharacteristicsID'],\n '700A': ['SQ', '1', 'DisplaySubsystemConfigurationSequence'],\n '700B': ['US', '1', 'ConfigurationID'],\n '700C': ['SH', '1', 'ConfigurationName'],\n '700D': ['LO', '1', 'ConfigurationDescription'],\n '700E': ['US', '1', 'ReferencedTargetLuminanceCharacteristicsID'],\n '700F': ['SQ', '1', 'QAResultsSequence'],\n '7010': ['SQ', '1', 'DisplaySubsystemQAResultsSequence'],\n '7011': ['SQ', '1', 'ConfigurationQAResultsSequence'],\n '7012': ['SQ', '1', 'MeasurementEquipmentSequence'],\n '7013': ['CS', '1-n', 'MeasurementFunctions'],\n '7014': ['CS', '1', 'MeasurementEquipmentType'],\n '7015': ['SQ', '1', 'VisualEvaluationResultSequence'],\n '7016': ['SQ', '1', 'DisplayCalibrationResultSequence'],\n '7017': ['US', '1', 'DDLValue'],\n '7018': ['FL', '2', 'CIExyWhitePoint'],\n '7019': ['CS', '1', 'DisplayFunctionType'],\n '701A': ['FL', '1', 'GammaValue'],\n '701B': ['US', '1', 'NumberOfLuminancePoints'],\n '701C': ['SQ', '1', 'LuminanceResponseSequence'],\n '701D': ['FL', '1', 'TargetMinimumLuminance'],\n '701E': ['FL', '1', 'TargetMaximumLuminance'],\n '701F': ['FL', '1', 'LuminanceValue'],\n '7020': ['LO', '1', 'LuminanceResponseDescription'],\n '7021': ['CS', '1', 'WhitePointFlag'],\n '7022': ['SQ', '1', 'DisplayDeviceTypeCodeSequence'],\n '7023': ['SQ', '1', 'DisplaySubsystemSequence'],\n '7024': ['SQ', '1', 'LuminanceResultSequence'],\n '7025': ['CS', '1', 'AmbientLightValueSource'],\n '7026': ['CS', '1-n', 'MeasuredCharacteristics'],\n '7027': ['SQ', '1', 'LuminanceUniformityResultSequence'],\n '7028': ['SQ', '1', 'VisualEvaluationTestSequence'],\n '7029': ['CS', '1', 'TestResult'],\n '702A': ['LO', '1', 'TestResultComment'],\n '702B': ['CS', '1', 'TestImageValidation'],\n '702C': ['SQ', '1', 'TestPatternCodeSequence'],\n '702D': ['SQ', '1', 'MeasurementPatternCodeSequence'],\n '702E': ['SQ', '1', 'VisualEvaluationMethodCodeSequence'],\n '7FE0': ['UR', '1', 'PixelDataProviderURL'],\n '9001': ['UL', '1', 'DataPointRows'],\n '9002': ['UL', '1', 'DataPointColumns'],\n '9003': ['CS', '1', 'SignalDomainColumns'],\n '9099': ['US', '1', 'LargestMonochromePixelValue'],\n '9108': ['CS', '1', 'DataRepresentation'],\n '9110': ['SQ', '1', 'PixelMeasuresSequence'],\n '9132': ['SQ', '1', 'FrameVOILUTSequence'],\n '9145': ['SQ', '1', 'PixelValueTransformationSequence'],\n '9235': ['CS', '1', 'SignalDomainRows'],\n '9411': ['FL', '1', 'DisplayFilterPercentage'],\n '9415': ['SQ', '1', 'FramePixelShiftSequence'],\n '9416': ['US', '1', 'SubtractionItemID'],\n '9422': ['SQ', '1', 'PixelIntensityRelationshipLUTSequence'],\n '9443': ['SQ', '1', 'FramePixelDataPropertiesSequence'],\n '9444': ['CS', '1', 'GeometricalProperties'],\n '9445': ['FL', '1', 'GeometricMaximumDistortion'],\n '9446': ['CS', '1-n', 'ImageProcessingApplied'],\n '9454': ['CS', '1', 'MaskSelectionMode'],\n '9474': ['CS', '1', 'LUTFunction'],\n '9478': ['FL', '1', 'MaskVisibilityPercentage'],\n '9501': ['SQ', '1', 'PixelShiftSequence'],\n '9502': ['SQ', '1', 'RegionPixelShiftSequence'],\n '9503': ['SS', '2-2n', 'VerticesOfTheRegion'],\n '9505': ['SQ', '1', 'MultiFramePresentationSequence'],\n '9506': ['US', '2-2n', 'PixelShiftFrameRange'],\n '9507': ['US', '2-2n', 'LUTFrameRange'],\n '9520': ['DS', '16', 'ImageToEquipmentMappingMatrix'],\n '9537': ['CS', '1', 'EquipmentCoordinateSystemIdentification']\n },\n '0032': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '000A': ['CS', '1', 'StudyStatusID'],\n '000C': ['CS', '1', 'StudyPriorityID'],\n '0012': ['LO', '1', 'StudyIDIssuer'],\n '0032': ['DA', '1', 'StudyVerifiedDate'],\n '0033': ['TM', '1', 'StudyVerifiedTime'],\n '0034': ['DA', '1', 'StudyReadDate'],\n '0035': ['TM', '1', 'StudyReadTime'],\n '1000': ['DA', '1', 'ScheduledStudyStartDate'],\n '1001': ['TM', '1', 'ScheduledStudyStartTime'],\n '1010': ['DA', '1', 'ScheduledStudyStopDate'],\n '1011': ['TM', '1', 'ScheduledStudyStopTime'],\n '1020': ['LO', '1', 'ScheduledStudyLocation'],\n '1021': ['AE', '1-n', 'ScheduledStudyLocationAETitle'],\n '1030': ['LO', '1', 'ReasonForStudy'],\n '1031': ['SQ', '1', 'RequestingPhysicianIdentificationSequence'],\n '1032': ['PN', '1', 'RequestingPhysician'],\n '1033': ['LO', '1', 'RequestingService'],\n '1034': ['SQ', '1', 'RequestingServiceCodeSequence'],\n '1040': ['DA', '1', 'StudyArrivalDate'],\n '1041': ['TM', '1', 'StudyArrivalTime'],\n '1050': ['DA', '1', 'StudyCompletionDate'],\n '1051': ['TM', '1', 'StudyCompletionTime'],\n '1055': ['CS', '1', 'StudyComponentStatusID'],\n '1060': ['LO', '1', 'RequestedProcedureDescription'],\n '1064': ['SQ', '1', 'RequestedProcedureCodeSequence'],\n '1065': ['SQ', '1', 'RequestedLateralityCodeSequence'],\n '1066': ['UT', '1', 'ReasonForVisit'],\n '1067': ['SQ', '1', 'ReasonForVisitCodeSequence'],\n '1070': ['LO', '1', 'RequestedContrastAgent'],\n '4000': ['LT', '1', 'StudyComments']\n },\n '0034': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['SQ', '1', 'FlowIdentifierSequence'],\n '0002': ['OB', '1', 'FlowIdentifier'],\n '0003': ['UI', '1', 'FlowTransferSyntaxUID'],\n '0004': ['UL', '1', 'FlowRTPSamplingRate'],\n '0005': ['OB', '1', 'SourceIdentifier'],\n '0007': ['OB', '1', 'FrameOriginTimestamp'],\n '0008': ['CS', '1', 'IncludesImagingSubject'],\n '0009': ['SQ', '1', 'FrameUsefulnessGroupSequence'],\n '000A': ['SQ', '1', 'RealTimeBulkDataFlowSequence'],\n '000B': ['SQ', '1', 'CameraPositionGroupSequence'],\n '000C': ['CS', '1', 'IncludesInformation'],\n '000D': ['SQ', '1', 'TimeOfFrameGroupSequence']\n },\n '0038': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0004': ['SQ', '1', 'ReferencedPatientAliasSequence'],\n '0008': ['CS', '1', 'VisitStatusID'],\n '0010': ['LO', '1', 'AdmissionID'],\n '0011': ['LO', '1', 'IssuerOfAdmissionID'],\n '0014': ['SQ', '1', 'IssuerOfAdmissionIDSequence'],\n '0016': ['LO', '1', 'RouteOfAdmissions'],\n '001A': ['DA', '1', 'ScheduledAdmissionDate'],\n '001B': ['TM', '1', 'ScheduledAdmissionTime'],\n '001C': ['DA', '1', 'ScheduledDischargeDate'],\n '001D': ['TM', '1', 'ScheduledDischargeTime'],\n '001E': ['LO', '1', 'ScheduledPatientInstitutionResidence'],\n '0020': ['DA', '1', 'AdmittingDate'],\n '0021': ['TM', '1', 'AdmittingTime'],\n '0030': ['DA', '1', 'DischargeDate'],\n '0032': ['TM', '1', 'DischargeTime'],\n '0040': ['LO', '1', 'DischargeDiagnosisDescription'],\n '0044': ['SQ', '1', 'DischargeDiagnosisCodeSequence'],\n '0050': ['LO', '1', 'SpecialNeeds'],\n '0060': ['LO', '1', 'ServiceEpisodeID'],\n '0061': ['LO', '1', 'IssuerOfServiceEpisodeID'],\n '0062': ['LO', '1', 'ServiceEpisodeDescription'],\n '0064': ['SQ', '1', 'IssuerOfServiceEpisodeIDSequence'],\n '0100': ['SQ', '1', 'PertinentDocumentsSequence'],\n '0101': ['SQ', '1', 'PertinentResourcesSequence'],\n '0102': ['LO', '1', 'ResourceDescription'],\n '0300': ['LO', '1', 'CurrentPatientLocation'],\n '0400': ['LO', '1', 'PatientInstitutionResidence'],\n '0500': ['LO', '1', 'PatientState'],\n '0502': ['SQ', '1', 'PatientClinicalTrialParticipationSequence'],\n '4000': ['LT', '1', 'VisitComments']\n },\n '003A': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0004': ['CS', '1', 'WaveformOriginality'],\n '0005': ['US', '1', 'NumberOfWaveformChannels'],\n '0010': ['UL', '1', 'NumberOfWaveformSamples'],\n '001A': ['DS', '1', 'SamplingFrequency'],\n '0020': ['SH', '1', 'MultiplexGroupLabel'],\n '0200': ['SQ', '1', 'ChannelDefinitionSequence'],\n '0202': ['IS', '1', 'WaveformChannelNumber'],\n '0203': ['SH', '1', 'ChannelLabel'],\n '0205': ['CS', '1-n', 'ChannelStatus'],\n '0208': ['SQ', '1', 'ChannelSourceSequence'],\n '0209': ['SQ', '1', 'ChannelSourceModifiersSequence'],\n '020A': ['SQ', '1', 'SourceWaveformSequence'],\n '020C': ['LO', '1', 'ChannelDerivationDescription'],\n '0210': ['DS', '1', 'ChannelSensitivity'],\n '0211': ['SQ', '1', 'ChannelSensitivityUnitsSequence'],\n '0212': ['DS', '1', 'ChannelSensitivityCorrectionFactor'],\n '0213': ['DS', '1', 'ChannelBaseline'],\n '0214': ['DS', '1', 'ChannelTimeSkew'],\n '0215': ['DS', '1', 'ChannelSampleSkew'],\n '0218': ['DS', '1', 'ChannelOffset'],\n '021A': ['US', '1', 'WaveformBitsStored'],\n '0220': ['DS', '1', 'FilterLowFrequency'],\n '0221': ['DS', '1', 'FilterHighFrequency'],\n '0222': ['DS', '1', 'NotchFilterFrequency'],\n '0223': ['DS', '1', 'NotchFilterBandwidth'],\n '0230': ['FL', '1', 'WaveformDataDisplayScale'],\n '0231': ['US', '3', 'WaveformDisplayBackgroundCIELabValue'],\n '0240': ['SQ', '1', 'WaveformPresentationGroupSequence'],\n '0241': ['US', '1', 'PresentationGroupNumber'],\n '0242': ['SQ', '1', 'ChannelDisplaySequence'],\n '0244': ['US', '3', 'ChannelRecommendedDisplayCIELabValue'],\n '0245': ['FL', '1', 'ChannelPosition'],\n '0246': ['CS', '1', 'DisplayShadingFlag'],\n '0247': ['FL', '1', 'FractionalChannelDisplayScale'],\n '0248': ['FL', '1', 'AbsoluteChannelDisplayScale'],\n '0300': ['SQ', '1', 'MultiplexedAudioChannelsDescriptionCodeSequence'],\n '0301': ['IS', '1', 'ChannelIdentificationCode'],\n '0302': ['CS', '1', 'ChannelMode'],\n '0310': ['UI', '1', 'MultiplexGroupUID'],\n '0311': ['DS', '1', 'PowerlineFrequency'],\n '0312': ['SQ', '1', 'ChannelImpedanceSequence'],\n '0313': ['DS', '1', 'ImpedanceValue'],\n '0314': ['DT', '1', 'ImpedanceMeasurementDateTime'],\n '0315': ['DS', '1', 'ImpedanceMeasurementFrequency'],\n '0316': ['CS', '1', 'ImpedanceMeasurementCurrentType']\n },\n '0040': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['AE', '1-n', 'ScheduledStationAETitle'],\n '0002': ['DA', '1', 'ScheduledProcedureStepStartDate'],\n '0003': ['TM', '1', 'ScheduledProcedureStepStartTime'],\n '0004': ['DA', '1', 'ScheduledProcedureStepEndDate'],\n '0005': ['TM', '1', 'ScheduledProcedureStepEndTime'],\n '0006': ['PN', '1', 'ScheduledPerformingPhysicianName'],\n '0007': ['LO', '1', 'ScheduledProcedureStepDescription'],\n '0008': ['SQ', '1', 'ScheduledProtocolCodeSequence'],\n '0009': ['SH', '1', 'ScheduledProcedureStepID'],\n '000A': ['SQ', '1', 'StageCodeSequence'],\n '000B': ['SQ', '1', 'ScheduledPerformingPhysicianIdentificationSequence'],\n '0010': ['SH', '1-n', 'ScheduledStationName'],\n '0011': ['SH', '1', 'ScheduledProcedureStepLocation'],\n '0012': ['LO', '1', 'PreMedication'],\n '0020': ['CS', '1', 'ScheduledProcedureStepStatus'],\n '0026': ['SQ', '1', 'OrderPlacerIdentifierSequence'],\n '0027': ['SQ', '1', 'OrderFillerIdentifierSequence'],\n '0031': ['UT', '1', 'LocalNamespaceEntityID'],\n '0032': ['UT', '1', 'UniversalEntityID'],\n '0033': ['CS', '1', 'UniversalEntityIDType'],\n '0035': ['CS', '1', 'IdentifierTypeCode'],\n '0036': ['SQ', '1', 'AssigningFacilitySequence'],\n '0039': ['SQ', '1', 'AssigningJurisdictionCodeSequence'],\n '003A': ['SQ', '1', 'AssigningAgencyOrDepartmentCodeSequence'],\n '0100': ['SQ', '1', 'ScheduledProcedureStepSequence'],\n '0220': ['SQ', '1', 'ReferencedNonImageCompositeSOPInstanceSequence'],\n '0241': ['AE', '1', 'PerformedStationAETitle'],\n '0242': ['SH', '1', 'PerformedStationName'],\n '0243': ['SH', '1', 'PerformedLocation'],\n '0244': ['DA', '1', 'PerformedProcedureStepStartDate'],\n '0245': ['TM', '1', 'PerformedProcedureStepStartTime'],\n '0250': ['DA', '1', 'PerformedProcedureStepEndDate'],\n '0251': ['TM', '1', 'PerformedProcedureStepEndTime'],\n '0252': ['CS', '1', 'PerformedProcedureStepStatus'],\n '0253': ['SH', '1', 'PerformedProcedureStepID'],\n '0254': ['LO', '1', 'PerformedProcedureStepDescription'],\n '0255': ['LO', '1', 'PerformedProcedureTypeDescription'],\n '0260': ['SQ', '1', 'PerformedProtocolCodeSequence'],\n '0261': ['CS', '1', 'PerformedProtocolType'],\n '0270': ['SQ', '1', 'ScheduledStepAttributesSequence'],\n '0275': ['SQ', '1', 'RequestAttributesSequence'],\n '0280': ['ST', '1', 'CommentsOnThePerformedProcedureStep'],\n '0281': ['SQ', '1', 'PerformedProcedureStepDiscontinuationReasonCodeSequence'],\n '0293': ['SQ', '1', 'QuantitySequence'],\n '0294': ['DS', '1', 'Quantity'],\n '0295': ['SQ', '1', 'MeasuringUnitsSequence'],\n '0296': ['SQ', '1', 'BillingItemSequence'],\n '0300': ['US', '1', 'TotalTimeOfFluoroscopy'],\n '0301': ['US', '1', 'TotalNumberOfExposures'],\n '0302': ['US', '1', 'EntranceDose'],\n '0303': ['US', '1-2', 'ExposedArea'],\n '0306': ['DS', '1', 'DistanceSourceToEntrance'],\n '0307': ['DS', '1', 'DistanceSourceToSupport'],\n '030E': ['SQ', '1', 'ExposureDoseSequence'],\n '0310': ['ST', '1', 'CommentsOnRadiationDose'],\n '0312': ['DS', '1', 'XRayOutput'],\n '0314': ['DS', '1', 'HalfValueLayer'],\n '0316': ['DS', '1', 'OrganDose'],\n '0318': ['CS', '1', 'OrganExposed'],\n '0320': ['SQ', '1', 'BillingProcedureStepSequence'],\n '0321': ['SQ', '1', 'FilmConsumptionSequence'],\n '0324': ['SQ', '1', 'BillingSuppliesAndDevicesSequence'],\n '0330': ['SQ', '1', 'ReferencedProcedureStepSequence'],\n '0340': ['SQ', '1', 'PerformedSeriesSequence'],\n '0400': ['LT', '1', 'CommentsOnTheScheduledProcedureStep'],\n '0440': ['SQ', '1', 'ProtocolContextSequence'],\n '0441': ['SQ', '1', 'ContentItemModifierSequence'],\n '0500': ['SQ', '1', 'ScheduledSpecimenSequence'],\n '050A': ['LO', '1', 'SpecimenAccessionNumber'],\n '0512': ['LO', '1', 'ContainerIdentifier'],\n '0513': ['SQ', '1', 'IssuerOfTheContainerIdentifierSequence'],\n '0515': ['SQ', '1', 'AlternateContainerIdentifierSequence'],\n '0518': ['SQ', '1', 'ContainerTypeCodeSequence'],\n '051A': ['LO', '1', 'ContainerDescription'],\n '0520': ['SQ', '1', 'ContainerComponentSequence'],\n '0550': ['SQ', '1', 'SpecimenSequence'],\n '0551': ['LO', '1', 'SpecimenIdentifier'],\n '0552': ['SQ', '1', 'SpecimenDescriptionSequenceTrial'],\n '0553': ['ST', '1', 'SpecimenDescriptionTrial'],\n '0554': ['UI', '1', 'SpecimenUID'],\n '0555': ['SQ', '1', 'AcquisitionContextSequence'],\n '0556': ['ST', '1', 'AcquisitionContextDescription'],\n '0560': ['SQ', '1', 'SpecimenDescriptionSequence'],\n '0562': ['SQ', '1', 'IssuerOfTheSpecimenIdentifierSequence'],\n '059A': ['SQ', '1', 'SpecimenTypeCodeSequence'],\n '0600': ['LO', '1', 'SpecimenShortDescription'],\n '0602': ['UT', '1', 'SpecimenDetailedDescription'],\n '0610': ['SQ', '1', 'SpecimenPreparationSequence'],\n '0612': ['SQ', '1', 'SpecimenPreparationStepContentItemSequence'],\n '0620': ['SQ', '1', 'SpecimenLocalizationContentItemSequence'],\n '06FA': ['LO', '1', 'SlideIdentifier'],\n '0710': ['SQ', '1', 'WholeSlideMicroscopyImageFrameTypeSequence'],\n '071A': ['SQ', '1', 'ImageCenterPointCoordinatesSequence'],\n '072A': ['DS', '1', 'XOffsetInSlideCoordinateSystem'],\n '073A': ['DS', '1', 'YOffsetInSlideCoordinateSystem'],\n '074A': ['DS', '1', 'ZOffsetInSlideCoordinateSystem'],\n '08D8': ['SQ', '1', 'PixelSpacingSequence'],\n '08DA': ['SQ', '1', 'CoordinateSystemAxisCodeSequence'],\n '08EA': ['SQ', '1', 'MeasurementUnitsCodeSequence'],\n '09F8': ['SQ', '1', 'VitalStainCodeSequenceTrial'],\n '1001': ['SH', '1', 'RequestedProcedureID'],\n '1002': ['LO', '1', 'ReasonForTheRequestedProcedure'],\n '1003': ['SH', '1', 'RequestedProcedurePriority'],\n '1004': ['LO', '1', 'PatientTransportArrangements'],\n '1005': ['LO', '1', 'RequestedProcedureLocation'],\n '1006': ['SH', '1', 'PlacerOrderNumberProcedure'],\n '1007': ['SH', '1', 'FillerOrderNumberProcedure'],\n '1008': ['LO', '1', 'ConfidentialityCode'],\n '1009': ['SH', '1', 'ReportingPriority'],\n '100A': ['SQ', '1', 'ReasonForRequestedProcedureCodeSequence'],\n '1010': ['PN', '1-n', 'NamesOfIntendedRecipientsOfResults'],\n '1011': ['SQ', '1', 'IntendedRecipientsOfResultsIdentificationSequence'],\n '1012': ['SQ', '1', 'ReasonForPerformedProcedureCodeSequence'],\n '1060': ['LO', '1', 'RequestedProcedureDescriptionTrial'],\n '1101': ['SQ', '1', 'PersonIdentificationCodeSequence'],\n '1102': ['ST', '1', 'PersonAddress'],\n '1103': ['LO', '1-n', 'PersonTelephoneNumbers'],\n '1104': ['LT', '1', 'PersonTelecomInformation'],\n '1400': ['LT', '1', 'RequestedProcedureComments'],\n '2001': ['LO', '1', 'ReasonForTheImagingServiceRequest'],\n '2004': ['DA', '1', 'IssueDateOfImagingServiceRequest'],\n '2005': ['TM', '1', 'IssueTimeOfImagingServiceRequest'],\n '2006': ['SH', '1', 'PlacerOrderNumberImagingServiceRequestRetired'],\n '2007': ['SH', '1', 'FillerOrderNumberImagingServiceRequestRetired'],\n '2008': ['PN', '1', 'OrderEnteredBy'],\n '2009': ['SH', '1', 'OrderEntererLocation'],\n '2010': ['SH', '1', 'OrderCallbackPhoneNumber'],\n '2011': ['LT', '1', 'OrderCallbackTelecomInformation'],\n '2016': ['LO', '1', 'PlacerOrderNumberImagingServiceRequest'],\n '2017': ['LO', '1', 'FillerOrderNumberImagingServiceRequest'],\n '2400': ['LT', '1', 'ImagingServiceRequestComments'],\n '3001': ['LO', '1', 'ConfidentialityConstraintOnPatientDataDescription'],\n '4001': ['CS', '1', 'GeneralPurposeScheduledProcedureStepStatus'],\n '4002': ['CS', '1', 'GeneralPurposePerformedProcedureStepStatus'],\n '4003': ['CS', '1', 'GeneralPurposeScheduledProcedureStepPriority'],\n '4004': ['SQ', '1', 'ScheduledProcessingApplicationsCodeSequence'],\n '4005': ['DT', '1', 'ScheduledProcedureStepStartDateTime'],\n '4006': ['CS', '1', 'MultipleCopiesFlag'],\n '4007': ['SQ', '1', 'PerformedProcessingApplicationsCodeSequence'],\n '4008': ['DT', '1', 'ScheduledProcedureStepExpirationDateTime'],\n '4009': ['SQ', '1', 'HumanPerformerCodeSequence'],\n '4010': ['DT', '1', 'ScheduledProcedureStepModificationDateTime'],\n '4011': ['DT', '1', 'ExpectedCompletionDateTime'],\n '4015': ['SQ', '1', 'ResultingGeneralPurposePerformedProcedureStepsSequence'],\n '4016': ['SQ', '1', 'ReferencedGeneralPurposeScheduledProcedureStepSequence'],\n '4018': ['SQ', '1', 'ScheduledWorkitemCodeSequence'],\n '4019': ['SQ', '1', 'PerformedWorkitemCodeSequence'],\n '4020': ['CS', '1', 'InputAvailabilityFlag'],\n '4021': ['SQ', '1', 'InputInformationSequence'],\n '4022': ['SQ', '1', 'RelevantInformationSequence'],\n '4023': ['UI', '1', 'ReferencedGeneralPurposeScheduledProcedureStepTransactionUID'],\n '4025': ['SQ', '1', 'ScheduledStationNameCodeSequence'],\n '4026': ['SQ', '1', 'ScheduledStationClassCodeSequence'],\n '4027': ['SQ', '1', 'ScheduledStationGeographicLocationCodeSequence'],\n '4028': ['SQ', '1', 'PerformedStationNameCodeSequence'],\n '4029': ['SQ', '1', 'PerformedStationClassCodeSequence'],\n '4030': ['SQ', '1', 'PerformedStationGeographicLocationCodeSequence'],\n '4031': ['SQ', '1', 'RequestedSubsequentWorkitemCodeSequence'],\n '4032': ['SQ', '1', 'NonDICOMOutputCodeSequence'],\n '4033': ['SQ', '1', 'OutputInformationSequence'],\n '4034': ['SQ', '1', 'ScheduledHumanPerformersSequence'],\n '4035': ['SQ', '1', 'ActualHumanPerformersSequence'],\n '4036': ['LO', '1', 'HumanPerformerOrganization'],\n '4037': ['PN', '1', 'HumanPerformerName'],\n '4040': ['CS', '1', 'RawDataHandling'],\n '4041': ['CS', '1', 'InputReadinessState'],\n '4050': ['DT', '1', 'PerformedProcedureStepStartDateTime'],\n '4051': ['DT', '1', 'PerformedProcedureStepEndDateTime'],\n '4052': ['DT', '1', 'ProcedureStepCancellationDateTime'],\n '4070': ['SQ', '1', 'OutputDestinationSequence'],\n '4071': ['SQ', '1', 'DICOMStorageSequence'],\n '4072': ['SQ', '1', 'STOWRSStorageSequence'],\n '4073': ['UR', '1', 'StorageURL'],\n '4074': ['SQ', '1', 'XDSStorageSequence'],\n '8302': ['DS', '1', 'EntranceDoseInmGy'],\n '8303': ['CS', '1', 'EntranceDoseDerivation'],\n '9092': ['SQ', '1', 'ParametricMapFrameTypeSequence'],\n '9094': ['SQ', '1', 'ReferencedImageRealWorldValueMappingSequence'],\n '9096': ['SQ', '1', 'RealWorldValueMappingSequence'],\n '9098': ['SQ', '1', 'PixelValueMappingCodeSequence'],\n '9210': ['SH', '1', 'LUTLabel'],\n '9211': ['xs', '1', 'RealWorldValueLastValueMapped'],\n '9212': ['FD', '1-n', 'RealWorldValueLUTData'],\n '9213': ['FD', '1', 'DoubleFloatRealWorldValueLastValueMapped'],\n '9214': ['FD', '1', 'DoubleFloatRealWorldValueFirstValueMapped'],\n '9216': ['xs', '1', 'RealWorldValueFirstValueMapped'],\n '9220': ['SQ', '1', 'QuantityDefinitionSequence'],\n '9224': ['FD', '1', 'RealWorldValueIntercept'],\n '9225': ['FD', '1', 'RealWorldValueSlope'],\n 'A007': ['CS', '1', 'FindingsFlagTrial'],\n 'A010': ['CS', '1', 'RelationshipType'],\n 'A020': ['SQ', '1', 'FindingsSequenceTrial'],\n 'A021': ['UI', '1', 'FindingsGroupUIDTrial'],\n 'A022': ['UI', '1', 'ReferencedFindingsGroupUIDTrial'],\n 'A023': ['DA', '1', 'FindingsGroupRecordingDateTrial'],\n 'A024': ['TM', '1', 'FindingsGroupRecordingTimeTrial'],\n 'A026': ['SQ', '1', 'FindingsSourceCategoryCodeSequenceTrial'],\n 'A027': ['LO', '1', 'VerifyingOrganization'],\n 'A028': ['SQ', '1', 'DocumentingOrganizationIdentifierCodeSequenceTrial'],\n 'A030': ['DT', '1', 'VerificationDateTime'],\n 'A032': ['DT', '1', 'ObservationDateTime'],\n 'A033': ['DT', '1', 'ObservationStartDateTime'],\n 'A040': ['CS', '1', 'ValueType'],\n 'A043': ['SQ', '1', 'ConceptNameCodeSequence'],\n 'A047': ['LO', '1', 'MeasurementPrecisionDescriptionTrial'],\n 'A050': ['CS', '1', 'ContinuityOfContent'],\n 'A057': ['CS', '1-n', 'UrgencyOrPriorityAlertsTrial'],\n 'A060': ['LO', '1', 'SequencingIndicatorTrial'],\n 'A066': ['SQ', '1', 'DocumentIdentifierCodeSequenceTrial'],\n 'A067': ['PN', '1', 'DocumentAuthorTrial'],\n 'A068': ['SQ', '1', 'DocumentAuthorIdentifierCodeSequenceTrial'],\n 'A070': ['SQ', '1', 'IdentifierCodeSequenceTrial'],\n 'A073': ['SQ', '1', 'VerifyingObserverSequence'],\n 'A074': ['OB', '1', 'ObjectBinaryIdentifierTrial'],\n 'A075': ['PN', '1', 'VerifyingObserverName'],\n 'A076': ['SQ', '1', 'DocumentingObserverIdentifierCodeSequenceTrial'],\n 'A078': ['SQ', '1', 'AuthorObserverSequence'],\n 'A07A': ['SQ', '1', 'ParticipantSequence'],\n 'A07C': ['SQ', '1', 'CustodialOrganizationSequence'],\n 'A080': ['CS', '1', 'ParticipationType'],\n 'A082': ['DT', '1', 'ParticipationDateTime'],\n 'A084': ['CS', '1', 'ObserverType'],\n 'A085': ['SQ', '1', 'ProcedureIdentifierCodeSequenceTrial'],\n 'A088': ['SQ', '1', 'VerifyingObserverIdentificationCodeSequence'],\n 'A089': ['OB', '1', 'ObjectDirectoryBinaryIdentifierTrial'],\n 'A090': ['SQ', '1', 'EquivalentCDADocumentSequence'],\n 'A0B0': ['US', '2-2n', 'ReferencedWaveformChannels'],\n 'A110': ['DA', '1', 'DateOfDocumentOrVerbalTransactionTrial'],\n 'A112': ['TM', '1', 'TimeOfDocumentCreationOrVerbalTransactionTrial'],\n 'A120': ['DT', '1', 'DateTime'],\n 'A121': ['DA', '1', 'Date'],\n 'A122': ['TM', '1', 'Time'],\n 'A123': ['PN', '1', 'PersonName'],\n 'A124': ['UI', '1', 'UID'],\n 'A125': ['CS', '2', 'ReportStatusIDTrial'],\n 'A130': ['CS', '1', 'TemporalRangeType'],\n 'A132': ['UL', '1-n', 'ReferencedSamplePositions'],\n 'A136': ['US', '1-n', 'ReferencedFrameNumbers'],\n 'A138': ['DS', '1-n', 'ReferencedTimeOffsets'],\n 'A13A': ['DT', '1-n', 'ReferencedDateTime'],\n 'A160': ['UT', '1', 'TextValue'],\n 'A161': ['FD', '1-n', 'FloatingPointValue'],\n 'A162': ['SL', '1-n', 'RationalNumeratorValue'],\n 'A163': ['UL', '1-n', 'RationalDenominatorValue'],\n 'A167': ['SQ', '1', 'ObservationCategoryCodeSequenceTrial'],\n 'A168': ['SQ', '1', 'ConceptCodeSequence'],\n 'A16A': ['ST', '1', 'BibliographicCitationTrial'],\n 'A170': ['SQ', '1', 'PurposeOfReferenceCodeSequence'],\n 'A171': ['UI', '1', 'ObservationUID'],\n 'A172': ['UI', '1', 'ReferencedObservationUIDTrial'],\n 'A173': ['CS', '1', 'ReferencedObservationClassTrial'],\n 'A174': ['CS', '1', 'ReferencedObjectObservationClassTrial'],\n 'A180': ['US', '1', 'AnnotationGroupNumber'],\n 'A192': ['DA', '1', 'ObservationDateTrial'],\n 'A193': ['TM', '1', 'ObservationTimeTrial'],\n 'A194': ['CS', '1', 'MeasurementAutomationTrial'],\n 'A195': ['SQ', '1', 'ModifierCodeSequence'],\n 'A224': ['ST', '1', 'IdentificationDescriptionTrial'],\n 'A290': ['CS', '1', 'CoordinatesSetGeometricTypeTrial'],\n 'A296': ['SQ', '1', 'AlgorithmCodeSequenceTrial'],\n 'A297': ['ST', '1', 'AlgorithmDescriptionTrial'],\n 'A29A': ['SL', '2-2n', 'PixelCoordinatesSetTrial'],\n 'A300': ['SQ', '1', 'MeasuredValueSequence'],\n 'A301': ['SQ', '1', 'NumericValueQualifierCodeSequence'],\n 'A307': ['PN', '1', 'CurrentObserverTrial'],\n 'A30A': ['DS', '1-n', 'NumericValue'],\n 'A313': ['SQ', '1', 'ReferencedAccessionSequenceTrial'],\n 'A33A': ['ST', '1', 'ReportStatusCommentTrial'],\n 'A340': ['SQ', '1', 'ProcedureContextSequenceTrial'],\n 'A352': ['PN', '1', 'VerbalSourceTrial'],\n 'A353': ['ST', '1', 'AddressTrial'],\n 'A354': ['LO', '1', 'TelephoneNumberTrial'],\n 'A358': ['SQ', '1', 'VerbalSourceIdentifierCodeSequenceTrial'],\n 'A360': ['SQ', '1', 'PredecessorDocumentsSequence'],\n 'A370': ['SQ', '1', 'ReferencedRequestSequence'],\n 'A372': ['SQ', '1', 'PerformedProcedureCodeSequence'],\n 'A375': ['SQ', '1', 'CurrentRequestedProcedureEvidenceSequence'],\n 'A380': ['SQ', '1', 'ReportDetailSequenceTrial'],\n 'A385': ['SQ', '1', 'PertinentOtherEvidenceSequence'],\n 'A390': ['SQ', '1', 'HL7StructuredDocumentReferenceSequence'],\n 'A402': ['UI', '1', 'ObservationSubjectUIDTrial'],\n 'A403': ['CS', '1', 'ObservationSubjectClassTrial'],\n 'A404': ['SQ', '1', 'ObservationSubjectTypeCodeSequenceTrial'],\n 'A491': ['CS', '1', 'CompletionFlag'],\n 'A492': ['LO', '1', 'CompletionFlagDescription'],\n 'A493': ['CS', '1', 'VerificationFlag'],\n 'A494': ['CS', '1', 'ArchiveRequested'],\n 'A496': ['CS', '1', 'PreliminaryFlag'],\n 'A504': ['SQ', '1', 'ContentTemplateSequence'],\n 'A525': ['SQ', '1', 'IdenticalDocumentsSequence'],\n 'A600': ['CS', '1', 'ObservationSubjectContextFlagTrial'],\n 'A601': ['CS', '1', 'ObserverContextFlagTrial'],\n 'A603': ['CS', '1', 'ProcedureContextFlagTrial'],\n 'A730': ['SQ', '1', 'ContentSequence'],\n 'A731': ['SQ', '1', 'RelationshipSequenceTrial'],\n 'A732': ['SQ', '1', 'RelationshipTypeCodeSequenceTrial'],\n 'A744': ['SQ', '1', 'LanguageCodeSequenceTrial'],\n 'A801': ['SQ', '1', 'TabulatedValuesSequence'],\n 'A802': ['UL', '1', 'NumberOfTableRows'],\n 'A803': ['UL', '1', 'NumberOfTableColumns'],\n 'A804': ['UL', '1', 'TableRowNumber'],\n 'A805': ['UL', '1', 'TableColumnNumber'],\n 'A806': ['SQ', '1', 'TableRowDefinitionSequence'],\n 'A807': ['SQ', '1', 'TableColumnDefinitionSequence'],\n 'A808': ['SQ', '1', 'CellValuesSequence'],\n 'A992': ['ST', '1', 'UniformResourceLocatorTrial'],\n 'B020': ['SQ', '1', 'WaveformAnnotationSequence'],\n 'DB00': ['CS', '1', 'TemplateIdentifier'],\n 'DB06': ['DT', '1', 'TemplateVersion'],\n 'DB07': ['DT', '1', 'TemplateLocalVersion'],\n 'DB0B': ['CS', '1', 'TemplateExtensionFlag'],\n 'DB0C': ['UI', '1', 'TemplateExtensionOrganizationUID'],\n 'DB0D': ['UI', '1', 'TemplateExtensionCreatorUID'],\n 'DB73': ['UL', '1-n', 'ReferencedContentItemIdentifier'],\n 'E001': ['ST', '1', 'HL7InstanceIdentifier'],\n 'E004': ['DT', '1', 'HL7DocumentEffectiveTime'],\n 'E006': ['SQ', '1', 'HL7DocumentTypeCodeSequence'],\n 'E008': ['SQ', '1', 'DocumentClassCodeSequence'],\n 'E010': ['UR', '1', 'RetrieveURI'],\n 'E011': ['UI', '1', 'RetrieveLocationUID'],\n 'E020': ['CS', '1', 'TypeOfInstances'],\n 'E021': ['SQ', '1', 'DICOMRetrievalSequence'],\n 'E022': ['SQ', '1', 'DICOMMediaRetrievalSequence'],\n 'E023': ['SQ', '1', 'WADORetrievalSequence'],\n 'E024': ['SQ', '1', 'XDSRetrievalSequence'],\n 'E025': ['SQ', '1', 'WADORSRetrievalSequence'],\n 'E030': ['UI', '1', 'RepositoryUniqueID'],\n 'E031': ['UI', '1', 'HomeCommunityID']\n },\n '0042': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['ST', '1', 'DocumentTitle'],\n '0011': ['OB', '1', 'EncapsulatedDocument'],\n '0012': ['LO', '1', 'MIMETypeOfEncapsulatedDocument'],\n '0013': ['SQ', '1', 'SourceInstanceSequence'],\n '0014': ['LO', '1-n', 'ListOfMIMETypes'],\n '0015': ['UL', '1', 'EncapsulatedDocumentLength']\n },\n '0044': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['ST', '1', 'ProductPackageIdentifier'],\n '0002': ['CS', '1', 'SubstanceAdministrationApproval'],\n '0003': ['LT', '1', 'ApprovalStatusFurtherDescription'],\n '0004': ['DT', '1', 'ApprovalStatusDateTime'],\n '0007': ['SQ', '1', 'ProductTypeCodeSequence'],\n '0008': ['LO', '1-n', 'ProductName'],\n '0009': ['LT', '1', 'ProductDescription'],\n '000A': ['LO', '1', 'ProductLotIdentifier'],\n '000B': ['DT', '1', 'ProductExpirationDateTime'],\n '0010': ['DT', '1', 'SubstanceAdministrationDateTime'],\n '0011': ['LO', '1', 'SubstanceAdministrationNotes'],\n '0012': ['LO', '1', 'SubstanceAdministrationDeviceID'],\n '0013': ['SQ', '1', 'ProductParameterSequence'],\n '0019': ['SQ', '1', 'SubstanceAdministrationParameterSequence'],\n '0100': ['SQ', '1', 'ApprovalSequence'],\n '0101': ['SQ', '1', 'AssertionCodeSequence'],\n '0102': ['UI', '1', 'AssertionUID'],\n '0103': ['SQ', '1', 'AsserterIdentificationSequence'],\n '0104': ['DT', '1', 'AssertionDateTime'],\n '0105': ['DT', '1', 'AssertionExpirationDateTime'],\n '0106': ['UT', '1', 'AssertionComments'],\n '0107': ['SQ', '1', 'RelatedAssertionSequence'],\n '0108': ['UI', '1', 'ReferencedAssertionUID'],\n '0109': ['SQ', '1', 'ApprovalSubjectSequence'],\n '010A': ['SQ', '1', 'OrganizationalRoleCodeSequence']\n },\n '0046': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0012': ['LO', '1', 'LensDescription'],\n '0014': ['SQ', '1', 'RightLensSequence'],\n '0015': ['SQ', '1', 'LeftLensSequence'],\n '0016': ['SQ', '1', 'UnspecifiedLateralityLensSequence'],\n '0018': ['SQ', '1', 'CylinderSequence'],\n '0028': ['SQ', '1', 'PrismSequence'],\n '0030': ['FD', '1', 'HorizontalPrismPower'],\n '0032': ['CS', '1', 'HorizontalPrismBase'],\n '0034': ['FD', '1', 'VerticalPrismPower'],\n '0036': ['CS', '1', 'VerticalPrismBase'],\n '0038': ['CS', '1', 'LensSegmentType'],\n '0040': ['FD', '1', 'OpticalTransmittance'],\n '0042': ['FD', '1', 'ChannelWidth'],\n '0044': ['FD', '1', 'PupilSize'],\n '0046': ['FD', '1', 'CornealSize'],\n '0047': ['SQ', '1', 'CornealSizeSequence'],\n '0050': ['SQ', '1', 'AutorefractionRightEyeSequence'],\n '0052': ['SQ', '1', 'AutorefractionLeftEyeSequence'],\n '0060': ['FD', '1', 'DistancePupillaryDistance'],\n '0062': ['FD', '1', 'NearPupillaryDistance'],\n '0063': ['FD', '1', 'IntermediatePupillaryDistance'],\n '0064': ['FD', '1', 'OtherPupillaryDistance'],\n '0070': ['SQ', '1', 'KeratometryRightEyeSequence'],\n '0071': ['SQ', '1', 'KeratometryLeftEyeSequence'],\n '0074': ['SQ', '1', 'SteepKeratometricAxisSequence'],\n '0075': ['FD', '1', 'RadiusOfCurvature'],\n '0076': ['FD', '1', 'KeratometricPower'],\n '0077': ['FD', '1', 'KeratometricAxis'],\n '0080': ['SQ', '1', 'FlatKeratometricAxisSequence'],\n '0092': ['CS', '1', 'BackgroundColor'],\n '0094': ['CS', '1', 'Optotype'],\n '0095': ['CS', '1', 'OptotypePresentation'],\n '0097': ['SQ', '1', 'SubjectiveRefractionRightEyeSequence'],\n '0098': ['SQ', '1', 'SubjectiveRefractionLeftEyeSequence'],\n '0100': ['SQ', '1', 'AddNearSequence'],\n '0101': ['SQ', '1', 'AddIntermediateSequence'],\n '0102': ['SQ', '1', 'AddOtherSequence'],\n '0104': ['FD', '1', 'AddPower'],\n '0106': ['FD', '1', 'ViewingDistance'],\n '0110': ['SQ', '1', 'CorneaMeasurementsSequence'],\n '0111': ['SQ', '1', 'SourceOfCorneaMeasurementDataCodeSequence'],\n '0112': ['SQ', '1', 'SteepCornealAxisSequence'],\n '0113': ['SQ', '1', 'FlatCornealAxisSequence'],\n '0114': ['FD', '1', 'CornealPower'],\n '0115': ['FD', '1', 'CornealAxis'],\n '0116': ['SQ', '1', 'CorneaMeasurementMethodCodeSequence'],\n '0117': ['FL', '1', 'RefractiveIndexOfCornea'],\n '0118': ['FL', '1', 'RefractiveIndexOfAqueousHumor'],\n '0121': ['SQ', '1', 'VisualAcuityTypeCodeSequence'],\n '0122': ['SQ', '1', 'VisualAcuityRightEyeSequence'],\n '0123': ['SQ', '1', 'VisualAcuityLeftEyeSequence'],\n '0124': ['SQ', '1', 'VisualAcuityBothEyesOpenSequence'],\n '0125': ['CS', '1', 'ViewingDistanceType'],\n '0135': ['SS', '2', 'VisualAcuityModifiers'],\n '0137': ['FD', '1', 'DecimalVisualAcuity'],\n '0139': ['LO', '1', 'OptotypeDetailedDefinition'],\n '0145': ['SQ', '1', 'ReferencedRefractiveMeasurementsSequence'],\n '0146': ['FD', '1', 'SpherePower'],\n '0147': ['FD', '1', 'CylinderPower'],\n '0201': ['CS', '1', 'CornealTopographySurface'],\n '0202': ['FL', '2', 'CornealVertexLocation'],\n '0203': ['FL', '1', 'PupilCentroidXCoordinate'],\n '0204': ['FL', '1', 'PupilCentroidYCoordinate'],\n '0205': ['FL', '1', 'EquivalentPupilRadius'],\n '0207': ['SQ', '1', 'CornealTopographyMapTypeCodeSequence'],\n '0208': ['IS', '2-2n', 'VerticesOfTheOutlineOfPupil'],\n '0210': ['SQ', '1', 'CornealTopographyMappingNormalsSequence'],\n '0211': ['SQ', '1', 'MaximumCornealCurvatureSequence'],\n '0212': ['FL', '1', 'MaximumCornealCurvature'],\n '0213': ['FL', '2', 'MaximumCornealCurvatureLocation'],\n '0215': ['SQ', '1', 'MinimumKeratometricSequence'],\n '0218': ['SQ', '1', 'SimulatedKeratometricCylinderSequence'],\n '0220': ['FL', '1', 'AverageCornealPower'],\n '0224': ['FL', '1', 'CornealISValue'],\n '0227': ['FL', '1', 'AnalyzedArea'],\n '0230': ['FL', '1', 'SurfaceRegularityIndex'],\n '0232': ['FL', '1', 'SurfaceAsymmetryIndex'],\n '0234': ['FL', '1', 'CornealEccentricityIndex'],\n '0236': ['FL', '1', 'KeratoconusPredictionIndex'],\n '0238': ['FL', '1', 'DecimalPotentialVisualAcuity'],\n '0242': ['CS', '1', 'CornealTopographyMapQualityEvaluation'],\n '0244': ['SQ', '1', 'SourceImageCornealProcessedDataSequence'],\n '0247': ['FL', '3', 'CornealPointLocation'],\n '0248': ['CS', '1', 'CornealPointEstimated'],\n '0249': ['FL', '1', 'AxialPower'],\n '0250': ['FL', '1', 'TangentialPower'],\n '0251': ['FL', '1', 'RefractivePower'],\n '0252': ['FL', '1', 'RelativeElevation'],\n '0253': ['FL', '1', 'CornealWavefront']\n },\n '0048': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['FL', '1', 'ImagedVolumeWidth'],\n '0002': ['FL', '1', 'ImagedVolumeHeight'],\n '0003': ['FL', '1', 'ImagedVolumeDepth'],\n '0006': ['UL', '1', 'TotalPixelMatrixColumns'],\n '0007': ['UL', '1', 'TotalPixelMatrixRows'],\n '0008': ['SQ', '1', 'TotalPixelMatrixOriginSequence'],\n '0010': ['CS', '1', 'SpecimenLabelInImage'],\n '0011': ['CS', '1', 'FocusMethod'],\n '0012': ['CS', '1', 'ExtendedDepthOfField'],\n '0013': ['US', '1', 'NumberOfFocalPlanes'],\n '0014': ['FL', '1', 'DistanceBetweenFocalPlanes'],\n '0015': ['US', '3', 'RecommendedAbsentPixelCIELabValue'],\n '0100': ['SQ', '1', 'IlluminatorTypeCodeSequence'],\n '0102': ['DS', '6', 'ImageOrientationSlide'],\n '0105': ['SQ', '1', 'OpticalPathSequence'],\n '0106': ['SH', '1', 'OpticalPathIdentifier'],\n '0107': ['ST', '1', 'OpticalPathDescription'],\n '0108': ['SQ', '1', 'IlluminationColorCodeSequence'],\n '0110': ['SQ', '1', 'SpecimenReferenceSequence'],\n '0111': ['DS', '1', 'CondenserLensPower'],\n '0112': ['DS', '1', 'ObjectiveLensPower'],\n '0113': ['DS', '1', 'ObjectiveLensNumericalAperture'],\n '0120': ['SQ', '1', 'PaletteColorLookupTableSequence'],\n '0200': ['SQ', '1', 'ReferencedImageNavigationSequence'],\n '0201': ['US', '2', 'TopLeftHandCornerOfLocalizerArea'],\n '0202': ['US', '2', 'BottomRightHandCornerOfLocalizerArea'],\n '0207': ['SQ', '1', 'OpticalPathIdentificationSequence'],\n '021A': ['SQ', '1', 'PlanePositionSlideSequence'],\n '021E': ['SL', '1', 'ColumnPositionInTotalImagePixelMatrix'],\n '021F': ['SL', '1', 'RowPositionInTotalImagePixelMatrix'],\n '0301': ['CS', '1', 'PixelOriginInterpretation'],\n '0302': ['UL', '1', 'NumberOfOpticalPaths'],\n '0303': ['UL', '1', 'TotalPixelMatrixFocalPlanes']\n },\n '0050': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0004': ['CS', '1', 'CalibrationImage'],\n '0010': ['SQ', '1', 'DeviceSequence'],\n '0012': ['SQ', '1', 'ContainerComponentTypeCodeSequence'],\n '0013': ['FD', '1', 'ContainerComponentThickness'],\n '0014': ['DS', '1', 'DeviceLength'],\n '0015': ['FD', '1', 'ContainerComponentWidth'],\n '0016': ['DS', '1', 'DeviceDiameter'],\n '0017': ['CS', '1', 'DeviceDiameterUnits'],\n '0018': ['DS', '1', 'DeviceVolume'],\n '0019': ['DS', '1', 'InterMarkerDistance'],\n '001A': ['CS', '1', 'ContainerComponentMaterial'],\n '001B': ['LO', '1', 'ContainerComponentID'],\n '001C': ['FD', '1', 'ContainerComponentLength'],\n '001D': ['FD', '1', 'ContainerComponentDiameter'],\n '001E': ['LO', '1', 'ContainerComponentDescription'],\n '0020': ['LO', '1', 'DeviceDescription'],\n '0021': ['ST', '1', 'LongDeviceDescription']\n },\n '0052': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['FL', '1', 'ContrastBolusIngredientPercentByVolume'],\n '0002': ['FD', '1', 'OCTFocalDistance'],\n '0003': ['FD', '1', 'BeamSpotSize'],\n '0004': ['FD', '1', 'EffectiveRefractiveIndex'],\n '0006': ['CS', '1', 'OCTAcquisitionDomain'],\n '0007': ['FD', '1', 'OCTOpticalCenterWavelength'],\n '0008': ['FD', '1', 'AxialResolution'],\n '0009': ['FD', '1', 'RangingDepth'],\n '0011': ['FD', '1', 'ALineRate'],\n '0012': ['US', '1', 'ALinesPerFrame'],\n '0013': ['FD', '1', 'CatheterRotationalRate'],\n '0014': ['FD', '1', 'ALinePixelSpacing'],\n '0016': ['SQ', '1', 'ModeOfPercutaneousAccessSequence'],\n '0025': ['SQ', '1', 'IntravascularOCTFrameTypeSequence'],\n '0026': ['CS', '1', 'OCTZOffsetApplied'],\n '0027': ['SQ', '1', 'IntravascularFrameContentSequence'],\n '0028': ['FD', '1', 'IntravascularLongitudinalDistance'],\n '0029': ['SQ', '1', 'IntravascularOCTFrameContentSequence'],\n '0030': ['SS', '1', 'OCTZOffsetCorrection'],\n '0031': ['CS', '1', 'CatheterDirectionOfRotation'],\n '0033': ['FD', '1', 'SeamLineLocation'],\n '0034': ['FD', '1', 'FirstALineLocation'],\n '0036': ['US', '1', 'SeamLineIndex'],\n '0038': ['US', '1', 'NumberOfPaddedALines'],\n '0039': ['CS', '1', 'InterpolationType'],\n '003A': ['CS', '1', 'RefractiveIndexApplied']\n },\n '0054': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['US', '1-n', 'EnergyWindowVector'],\n '0011': ['US', '1', 'NumberOfEnergyWindows'],\n '0012': ['SQ', '1', 'EnergyWindowInformationSequence'],\n '0013': ['SQ', '1', 'EnergyWindowRangeSequence'],\n '0014': ['DS', '1', 'EnergyWindowLowerLimit'],\n '0015': ['DS', '1', 'EnergyWindowUpperLimit'],\n '0016': ['SQ', '1', 'RadiopharmaceuticalInformationSequence'],\n '0017': ['IS', '1', 'ResidualSyringeCounts'],\n '0018': ['SH', '1', 'EnergyWindowName'],\n '0020': ['US', '1-n', 'DetectorVector'],\n '0021': ['US', '1', 'NumberOfDetectors'],\n '0022': ['SQ', '1', 'DetectorInformationSequence'],\n '0030': ['US', '1-n', 'PhaseVector'],\n '0031': ['US', '1', 'NumberOfPhases'],\n '0032': ['SQ', '1', 'PhaseInformationSequence'],\n '0033': ['US', '1', 'NumberOfFramesInPhase'],\n '0036': ['IS', '1', 'PhaseDelay'],\n '0038': ['IS', '1', 'PauseBetweenFrames'],\n '0039': ['CS', '1', 'PhaseDescription'],\n '0050': ['US', '1-n', 'RotationVector'],\n '0051': ['US', '1', 'NumberOfRotations'],\n '0052': ['SQ', '1', 'RotationInformationSequence'],\n '0053': ['US', '1', 'NumberOfFramesInRotation'],\n '0060': ['US', '1-n', 'RRIntervalVector'],\n '0061': ['US', '1', 'NumberOfRRIntervals'],\n '0062': ['SQ', '1', 'GatedInformationSequence'],\n '0063': ['SQ', '1', 'DataInformationSequence'],\n '0070': ['US', '1-n', 'TimeSlotVector'],\n '0071': ['US', '1', 'NumberOfTimeSlots'],\n '0072': ['SQ', '1', 'TimeSlotInformationSequence'],\n '0073': ['DS', '1', 'TimeSlotTime'],\n '0080': ['US', '1-n', 'SliceVector'],\n '0081': ['US', '1', 'NumberOfSlices'],\n '0090': ['US', '1-n', 'AngularViewVector'],\n '0100': ['US', '1-n', 'TimeSliceVector'],\n '0101': ['US', '1', 'NumberOfTimeSlices'],\n '0200': ['DS', '1', 'StartAngle'],\n '0202': ['CS', '1', 'TypeOfDetectorMotion'],\n '0210': ['IS', '1-n', 'TriggerVector'],\n '0211': ['US', '1', 'NumberOfTriggersInPhase'],\n '0220': ['SQ', '1', 'ViewCodeSequence'],\n '0222': ['SQ', '1', 'ViewModifierCodeSequence'],\n '0300': ['SQ', '1', 'RadionuclideCodeSequence'],\n '0302': ['SQ', '1', 'AdministrationRouteCodeSequence'],\n '0304': ['SQ', '1', 'RadiopharmaceuticalCodeSequence'],\n '0306': ['SQ', '1', 'CalibrationDataSequence'],\n '0308': ['US', '1', 'EnergyWindowNumber'],\n '0400': ['SH', '1', 'ImageID'],\n '0410': ['SQ', '1', 'PatientOrientationCodeSequence'],\n '0412': ['SQ', '1', 'PatientOrientationModifierCodeSequence'],\n '0414': ['SQ', '1', 'PatientGantryRelationshipCodeSequence'],\n '0500': ['CS', '1', 'SliceProgressionDirection'],\n '0501': ['CS', '1', 'ScanProgressionDirection'],\n '1000': ['CS', '2', 'SeriesType'],\n '1001': ['CS', '1', 'Units'],\n '1002': ['CS', '1', 'CountsSource'],\n '1004': ['CS', '1', 'ReprojectionMethod'],\n '1006': ['CS', '1', 'SUVType'],\n '1100': ['CS', '1', 'RandomsCorrectionMethod'],\n '1101': ['LO', '1', 'AttenuationCorrectionMethod'],\n '1102': ['CS', '1', 'DecayCorrection'],\n '1103': ['LO', '1', 'ReconstructionMethod'],\n '1104': ['LO', '1', 'DetectorLinesOfResponseUsed'],\n '1105': ['LO', '1', 'ScatterCorrectionMethod'],\n '1200': ['DS', '1', 'AxialAcceptance'],\n '1201': ['IS', '2', 'AxialMash'],\n '1202': ['IS', '1', 'TransverseMash'],\n '1203': ['DS', '2', 'DetectorElementSize'],\n '1210': ['DS', '1', 'CoincidenceWindowWidth'],\n '1220': ['CS', '1-n', 'SecondaryCountsType'],\n '1300': ['DS', '1', 'FrameReferenceTime'],\n '1310': ['IS', '1', 'PrimaryPromptsCountsAccumulated'],\n '1311': ['IS', '1-n', 'SecondaryCountsAccumulated'],\n '1320': ['DS', '1', 'SliceSensitivityFactor'],\n '1321': ['DS', '1', 'DecayFactor'],\n '1322': ['DS', '1', 'DoseCalibrationFactor'],\n '1323': ['DS', '1', 'ScatterFractionFactor'],\n '1324': ['DS', '1', 'DeadTimeFactor'],\n '1330': ['US', '1', 'ImageIndex'],\n '1400': ['CS', '1-n', 'CountsIncluded'],\n '1401': ['CS', '1', 'DeadTimeCorrectionFlag']\n },\n '0060': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '3000': ['SQ', '1', 'HistogramSequence'],\n '3002': ['US', '1', 'HistogramNumberOfBins'],\n '3004': ['xs', '1', 'HistogramFirstBinValue'],\n '3006': ['xs', '1', 'HistogramLastBinValue'],\n '3008': ['US', '1', 'HistogramBinWidth'],\n '3010': ['LO', '1', 'HistogramExplanation'],\n '3020': ['UL', '1-n', 'HistogramData']\n },\n '0062': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['CS', '1', 'SegmentationType'],\n '0002': ['SQ', '1', 'SegmentSequence'],\n '0003': ['SQ', '1', 'SegmentedPropertyCategoryCodeSequence'],\n '0004': ['US', '1', 'SegmentNumber'],\n '0005': ['LO', '1', 'SegmentLabel'],\n '0006': ['ST', '1', 'SegmentDescription'],\n '0007': ['SQ', '1', 'SegmentationAlgorithmIdentificationSequence'],\n '0008': ['CS', '1', 'SegmentAlgorithmType'],\n '0009': ['LO', '1-n', 'SegmentAlgorithmName'],\n '000A': ['SQ', '1', 'SegmentIdentificationSequence'],\n '000B': ['US', '1-n', 'ReferencedSegmentNumber'],\n '000C': ['US', '1', 'RecommendedDisplayGrayscaleValue'],\n '000D': ['US', '3', 'RecommendedDisplayCIELabValue'],\n '000E': ['US', '1', 'MaximumFractionalValue'],\n '000F': ['SQ', '1', 'SegmentedPropertyTypeCodeSequence'],\n '0010': ['CS', '1', 'SegmentationFractionalType'],\n '0011': ['SQ', '1', 'SegmentedPropertyTypeModifierCodeSequence'],\n '0012': ['SQ', '1', 'UsedSegmentsSequence'],\n '0013': ['CS', '1', 'SegmentsOverlap'],\n '0020': ['UT', '1', 'TrackingID'],\n '0021': ['UI', '1', 'TrackingUID']\n },\n '0064': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['SQ', '1', 'DeformableRegistrationSequence'],\n '0003': ['UI', '1', 'SourceFrameOfReferenceUID'],\n '0005': ['SQ', '1', 'DeformableRegistrationGridSequence'],\n '0007': ['UL', '3', 'GridDimensions'],\n '0008': ['FD', '3', 'GridResolution'],\n '0009': ['OF', '1', 'VectorGridData'],\n '000F': ['SQ', '1', 'PreDeformationMatrixRegistrationSequence'],\n '0010': ['SQ', '1', 'PostDeformationMatrixRegistrationSequence']\n },\n '0066': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['UL', '1', 'NumberOfSurfaces'],\n '0002': ['SQ', '1', 'SurfaceSequence'],\n '0003': ['UL', '1', 'SurfaceNumber'],\n '0004': ['LT', '1', 'SurfaceComments'],\n '0009': ['CS', '1', 'SurfaceProcessing'],\n '000A': ['FL', '1', 'SurfaceProcessingRatio'],\n '000B': ['LO', '1', 'SurfaceProcessingDescription'],\n '000C': ['FL', '1', 'RecommendedPresentationOpacity'],\n '000D': ['CS', '1', 'RecommendedPresentationType'],\n '000E': ['CS', '1', 'FiniteVolume'],\n '0010': ['CS', '1', 'Manifold'],\n '0011': ['SQ', '1', 'SurfacePointsSequence'],\n '0012': ['SQ', '1', 'SurfacePointsNormalsSequence'],\n '0013': ['SQ', '1', 'SurfaceMeshPrimitivesSequence'],\n '0015': ['UL', '1', 'NumberOfSurfacePoints'],\n '0016': ['OF', '1', 'PointCoordinatesData'],\n '0017': ['FL', '3', 'PointPositionAccuracy'],\n '0018': ['FL', '1', 'MeanPointDistance'],\n '0019': ['FL', '1', 'MaximumPointDistance'],\n '001A': ['FL', '6', 'PointsBoundingBoxCoordinates'],\n '001B': ['FL', '3', 'AxisOfRotation'],\n '001C': ['FL', '3', 'CenterOfRotation'],\n '001E': ['UL', '1', 'NumberOfVectors'],\n '001F': ['US', '1', 'VectorDimensionality'],\n '0020': ['FL', '1-n', 'VectorAccuracy'],\n '0021': ['OF', '1', 'VectorCoordinateData'],\n '0022': ['OD', '1', 'DoublePointCoordinatesData'],\n '0023': ['OW', '1', 'TrianglePointIndexList'],\n '0024': ['OW', '1', 'EdgePointIndexList'],\n '0025': ['OW', '1', 'VertexPointIndexList'],\n '0026': ['SQ', '1', 'TriangleStripSequence'],\n '0027': ['SQ', '1', 'TriangleFanSequence'],\n '0028': ['SQ', '1', 'LineSequence'],\n '0029': ['OW', '1', 'PrimitivePointIndexList'],\n '002A': ['UL', '1', 'SurfaceCount'],\n '002B': ['SQ', '1', 'ReferencedSurfaceSequence'],\n '002C': ['UL', '1', 'ReferencedSurfaceNumber'],\n '002D': ['SQ', '1', 'SegmentSurfaceGenerationAlgorithmIdentificationSequence'],\n '002E': ['SQ', '1', 'SegmentSurfaceSourceInstanceSequence'],\n '002F': ['SQ', '1', 'AlgorithmFamilyCodeSequence'],\n '0030': ['SQ', '1', 'AlgorithmNameCodeSequence'],\n '0031': ['LO', '1', 'AlgorithmVersion'],\n '0032': ['LT', '1', 'AlgorithmParameters'],\n '0034': ['SQ', '1', 'FacetSequence'],\n '0035': ['SQ', '1', 'SurfaceProcessingAlgorithmIdentificationSequence'],\n '0036': ['LO', '1', 'AlgorithmName'],\n '0037': ['FL', '1', 'RecommendedPointRadius'],\n '0038': ['FL', '1', 'RecommendedLineThickness'],\n '0040': ['OL', '1', 'LongPrimitivePointIndexList'],\n '0041': ['OL', '1', 'LongTrianglePointIndexList'],\n '0042': ['OL', '1', 'LongEdgePointIndexList'],\n '0043': ['OL', '1', 'LongVertexPointIndexList'],\n '0101': ['SQ', '1', 'TrackSetSequence'],\n '0102': ['SQ', '1', 'TrackSequence'],\n '0103': ['OW', '1', 'RecommendedDisplayCIELabValueList'],\n '0104': ['SQ', '1', 'TrackingAlgorithmIdentificationSequence'],\n '0105': ['UL', '1', 'TrackSetNumber'],\n '0106': ['LO', '1', 'TrackSetLabel'],\n '0107': ['UT', '1', 'TrackSetDescription'],\n '0108': ['SQ', '1', 'TrackSetAnatomicalTypeCodeSequence'],\n '0121': ['SQ', '1', 'MeasurementsSequence'],\n '0124': ['SQ', '1', 'TrackSetStatisticsSequence'],\n '0125': ['OF', '1', 'FloatingPointValues'],\n '0129': ['OL', '1', 'TrackPointIndexList'],\n '0130': ['SQ', '1', 'TrackStatisticsSequence'],\n '0132': ['SQ', '1', 'MeasurementValuesSequence'],\n '0133': ['SQ', '1', 'DiffusionAcquisitionCodeSequence'],\n '0134': ['SQ', '1', 'DiffusionModelCodeSequence']\n },\n '0068': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '6210': ['LO', '1', 'ImplantSize'],\n '6221': ['LO', '1', 'ImplantTemplateVersion'],\n '6222': ['SQ', '1', 'ReplacedImplantTemplateSequence'],\n '6223': ['CS', '1', 'ImplantType'],\n '6224': ['SQ', '1', 'DerivationImplantTemplateSequence'],\n '6225': ['SQ', '1', 'OriginalImplantTemplateSequence'],\n '6226': ['DT', '1', 'EffectiveDateTime'],\n '6230': ['SQ', '1', 'ImplantTargetAnatomySequence'],\n '6260': ['SQ', '1', 'InformationFromManufacturerSequence'],\n '6265': ['SQ', '1', 'NotificationFromManufacturerSequence'],\n '6270': ['DT', '1', 'InformationIssueDateTime'],\n '6280': ['ST', '1', 'InformationSummary'],\n '62A0': ['SQ', '1', 'ImplantRegulatoryDisapprovalCodeSequence'],\n '62A5': ['FD', '1', 'OverallTemplateSpatialTolerance'],\n '62C0': ['SQ', '1', 'HPGLDocumentSequence'],\n '62D0': ['US', '1', 'HPGLDocumentID'],\n '62D5': ['LO', '1', 'HPGLDocumentLabel'],\n '62E0': ['SQ', '1', 'ViewOrientationCodeSequence'],\n '62F0': ['SQ', '1', 'ViewOrientationModifierCodeSequence'],\n '62F2': ['FD', '1', 'HPGLDocumentScaling'],\n '6300': ['OB', '1', 'HPGLDocument'],\n '6310': ['US', '1', 'HPGLContourPenNumber'],\n '6320': ['SQ', '1', 'HPGLPenSequence'],\n '6330': ['US', '1', 'HPGLPenNumber'],\n '6340': ['LO', '1', 'HPGLPenLabel'],\n '6345': ['ST', '1', 'HPGLPenDescription'],\n '6346': ['FD', '2', 'RecommendedRotationPoint'],\n '6347': ['FD', '4', 'BoundingRectangle'],\n '6350': ['US', '1-n', 'ImplantTemplate3DModelSurfaceNumber'],\n '6360': ['SQ', '1', 'SurfaceModelDescriptionSequence'],\n '6380': ['LO', '1', 'SurfaceModelLabel'],\n '6390': ['FD', '1', 'SurfaceModelScalingFactor'],\n '63A0': ['SQ', '1', 'MaterialsCodeSequence'],\n '63A4': ['SQ', '1', 'CoatingMaterialsCodeSequence'],\n '63A8': ['SQ', '1', 'ImplantTypeCodeSequence'],\n '63AC': ['SQ', '1', 'FixationMethodCodeSequence'],\n '63B0': ['SQ', '1', 'MatingFeatureSetsSequence'],\n '63C0': ['US', '1', 'MatingFeatureSetID'],\n '63D0': ['LO', '1', 'MatingFeatureSetLabel'],\n '63E0': ['SQ', '1', 'MatingFeatureSequence'],\n '63F0': ['US', '1', 'MatingFeatureID'],\n '6400': ['SQ', '1', 'MatingFeatureDegreeOfFreedomSequence'],\n '6410': ['US', '1', 'DegreeOfFreedomID'],\n '6420': ['CS', '1', 'DegreeOfFreedomType'],\n '6430': ['SQ', '1', 'TwoDMatingFeatureCoordinatesSequence'],\n '6440': ['US', '1', 'ReferencedHPGLDocumentID'],\n '6450': ['FD', '2', 'TwoDMatingPoint'],\n '6460': ['FD', '4', 'TwoDMatingAxes'],\n '6470': ['SQ', '1', 'TwoDDegreeOfFreedomSequence'],\n '6490': ['FD', '3', 'ThreeDDegreeOfFreedomAxis'],\n '64A0': ['FD', '2', 'RangeOfFreedom'],\n '64C0': ['FD', '3', 'ThreeDMatingPoint'],\n '64D0': ['FD', '9', 'ThreeDMatingAxes'],\n '64F0': ['FD', '3', 'TwoDDegreeOfFreedomAxis'],\n '6500': ['SQ', '1', 'PlanningLandmarkPointSequence'],\n '6510': ['SQ', '1', 'PlanningLandmarkLineSequence'],\n '6520': ['SQ', '1', 'PlanningLandmarkPlaneSequence'],\n '6530': ['US', '1', 'PlanningLandmarkID'],\n '6540': ['LO', '1', 'PlanningLandmarkDescription'],\n '6545': ['SQ', '1', 'PlanningLandmarkIdentificationCodeSequence'],\n '6550': ['SQ', '1', 'TwoDPointCoordinatesSequence'],\n '6560': ['FD', '2', 'TwoDPointCoordinates'],\n '6590': ['FD', '3', 'ThreeDPointCoordinates'],\n '65A0': ['SQ', '1', 'TwoDLineCoordinatesSequence'],\n '65B0': ['FD', '4', 'TwoDLineCoordinates'],\n '65D0': ['FD', '6', 'ThreeDLineCoordinates'],\n '65E0': ['SQ', '1', 'TwoDPlaneCoordinatesSequence'],\n '65F0': ['FD', '4', 'TwoDPlaneIntersection'],\n '6610': ['FD', '3', 'ThreeDPlaneOrigin'],\n '6620': ['FD', '3', 'ThreeDPlaneNormal'],\n '7001': ['CS', '1', 'ModelModification'],\n '7002': ['CS', '1', 'ModelMirroring'],\n '7003': ['SQ', '1', 'ModelUsageCodeSequence'],\n '7004': ['UI', '1', 'ModelGroupUID'],\n '7005': ['UR', '1', 'RelativeURIReferenceWithinEncapsulatedDocument']\n },\n '006A': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['CS', '1', 'AnnotationCoordinateType'],\n '0002': ['SQ', '1', 'AnnotationGroupSequence'],\n '0003': ['UI', '1', 'AnnotationGroupUID'],\n '0005': ['LO', '1', 'AnnotationGroupLabel'],\n '0006': ['UT', '1', 'AnnotationGroupDescription'],\n '0007': ['CS', '1', 'AnnotationGroupGenerationType'],\n '0008': ['SQ', '1', 'AnnotationGroupAlgorithmIdentificationSequence'],\n '0009': ['SQ', '1', 'AnnotationPropertyCategoryCodeSequence'],\n '000A': ['SQ', '1', 'AnnotationPropertyTypeCodeSequence'],\n '000B': ['SQ', '1', 'AnnotationPropertyTypeModifierCodeSequence'],\n '000C': ['UL', '1', 'NumberOfAnnotations'],\n '000D': ['CS', '1', 'AnnotationAppliesToAllOpticalPaths'],\n '000E': ['SH', '1-n', 'ReferencedOpticalPathIdentifier'],\n '000F': ['CS', '1', 'AnnotationAppliesToAllZPlanes'],\n '0010': ['FD', '1-n', 'CommonZCoordinateValue'],\n '0011': ['OL', '1', 'AnnotationIndexList']\n },\n '0070': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['SQ', '1', 'GraphicAnnotationSequence'],\n '0002': ['CS', '1', 'GraphicLayer'],\n '0003': ['CS', '1', 'BoundingBoxAnnotationUnits'],\n '0004': ['CS', '1', 'AnchorPointAnnotationUnits'],\n '0005': ['CS', '1', 'GraphicAnnotationUnits'],\n '0006': ['ST', '1', 'UnformattedTextValue'],\n '0008': ['SQ', '1', 'TextObjectSequence'],\n '0009': ['SQ', '1', 'GraphicObjectSequence'],\n '0010': ['FL', '2', 'BoundingBoxTopLeftHandCorner'],\n '0011': ['FL', '2', 'BoundingBoxBottomRightHandCorner'],\n '0012': ['CS', '1', 'BoundingBoxTextHorizontalJustification'],\n '0014': ['FL', '2', 'AnchorPoint'],\n '0015': ['CS', '1', 'AnchorPointVisibility'],\n '0020': ['US', '1', 'GraphicDimensions'],\n '0021': ['US', '1', 'NumberOfGraphicPoints'],\n '0022': ['FL', '2-n', 'GraphicData'],\n '0023': ['CS', '1', 'GraphicType'],\n '0024': ['CS', '1', 'GraphicFilled'],\n '0040': ['IS', '1', 'ImageRotationRetired'],\n '0041': ['CS', '1', 'ImageHorizontalFlip'],\n '0042': ['US', '1', 'ImageRotation'],\n '0050': ['US', '2', 'DisplayedAreaTopLeftHandCornerTrial'],\n '0051': ['US', '2', 'DisplayedAreaBottomRightHandCornerTrial'],\n '0052': ['SL', '2', 'DisplayedAreaTopLeftHandCorner'],\n '0053': ['SL', '2', 'DisplayedAreaBottomRightHandCorner'],\n '005A': ['SQ', '1', 'DisplayedAreaSelectionSequence'],\n '0060': ['SQ', '1', 'GraphicLayerSequence'],\n '0062': ['IS', '1', 'GraphicLayerOrder'],\n '0066': ['US', '1', 'GraphicLayerRecommendedDisplayGrayscaleValue'],\n '0067': ['US', '3', 'GraphicLayerRecommendedDisplayRGBValue'],\n '0068': ['LO', '1', 'GraphicLayerDescription'],\n '0080': ['CS', '1', 'ContentLabel'],\n '0081': ['LO', '1', 'ContentDescription'],\n '0082': ['DA', '1', 'PresentationCreationDate'],\n '0083': ['TM', '1', 'PresentationCreationTime'],\n '0084': ['PN', '1', 'ContentCreatorName'],\n '0086': ['SQ', '1', 'ContentCreatorIdentificationCodeSequence'],\n '0087': ['SQ', '1', 'AlternateContentDescriptionSequence'],\n '0100': ['CS', '1', 'PresentationSizeMode'],\n '0101': ['DS', '2', 'PresentationPixelSpacing'],\n '0102': ['IS', '2', 'PresentationPixelAspectRatio'],\n '0103': ['FL', '1', 'PresentationPixelMagnificationRatio'],\n '0207': ['LO', '1', 'GraphicGroupLabel'],\n '0208': ['ST', '1', 'GraphicGroupDescription'],\n '0209': ['SQ', '1', 'CompoundGraphicSequence'],\n '0226': ['UL', '1', 'CompoundGraphicInstanceID'],\n '0227': ['LO', '1', 'FontName'],\n '0228': ['CS', '1', 'FontNameType'],\n '0229': ['LO', '1', 'CSSFontName'],\n '0230': ['FD', '1', 'RotationAngle'],\n '0231': ['SQ', '1', 'TextStyleSequence'],\n '0232': ['SQ', '1', 'LineStyleSequence'],\n '0233': ['SQ', '1', 'FillStyleSequence'],\n '0234': ['SQ', '1', 'GraphicGroupSequence'],\n '0241': ['US', '3', 'TextColorCIELabValue'],\n '0242': ['CS', '1', 'HorizontalAlignment'],\n '0243': ['CS', '1', 'VerticalAlignment'],\n '0244': ['CS', '1', 'ShadowStyle'],\n '0245': ['FL', '1', 'ShadowOffsetX'],\n '0246': ['FL', '1', 'ShadowOffsetY'],\n '0247': ['US', '3', 'ShadowColorCIELabValue'],\n '0248': ['CS', '1', 'Underlined'],\n '0249': ['CS', '1', 'Bold'],\n '0250': ['CS', '1', 'Italic'],\n '0251': ['US', '3', 'PatternOnColorCIELabValue'],\n '0252': ['US', '3', 'PatternOffColorCIELabValue'],\n '0253': ['FL', '1', 'LineThickness'],\n '0254': ['CS', '1', 'LineDashingStyle'],\n '0255': ['UL', '1', 'LinePattern'],\n '0256': ['OB', '1', 'FillPattern'],\n '0257': ['CS', '1', 'FillMode'],\n '0258': ['FL', '1', 'ShadowOpacity'],\n '0261': ['FL', '1', 'GapLength'],\n '0262': ['FL', '1', 'DiameterOfVisibility'],\n '0273': ['FL', '2', 'RotationPoint'],\n '0274': ['CS', '1', 'TickAlignment'],\n '0278': ['CS', '1', 'ShowTickLabel'],\n '0279': ['CS', '1', 'TickLabelAlignment'],\n '0282': ['CS', '1', 'CompoundGraphicUnits'],\n '0284': ['FL', '1', 'PatternOnOpacity'],\n '0285': ['FL', '1', 'PatternOffOpacity'],\n '0287': ['SQ', '1', 'MajorTicksSequence'],\n '0288': ['FL', '1', 'TickPosition'],\n '0289': ['SH', '1', 'TickLabel'],\n '0294': ['CS', '1', 'CompoundGraphicType'],\n '0295': ['UL', '1', 'GraphicGroupID'],\n '0306': ['CS', '1', 'ShapeType'],\n '0308': ['SQ', '1', 'RegistrationSequence'],\n '0309': ['SQ', '1', 'MatrixRegistrationSequence'],\n '030A': ['SQ', '1', 'MatrixSequence'],\n '030B': ['FD', '16', 'FrameOfReferenceToDisplayedCoordinateSystemTransformationMatrix'],\n '030C': ['CS', '1', 'FrameOfReferenceTransformationMatrixType'],\n '030D': ['SQ', '1', 'RegistrationTypeCodeSequence'],\n '030F': ['ST', '1', 'FiducialDescription'],\n '0310': ['SH', '1', 'FiducialIdentifier'],\n '0311': ['SQ', '1', 'FiducialIdentifierCodeSequence'],\n '0312': ['FD', '1', 'ContourUncertaintyRadius'],\n '0314': ['SQ', '1', 'UsedFiducialsSequence'],\n '0318': ['SQ', '1', 'GraphicCoordinatesDataSequence'],\n '031A': ['UI', '1', 'FiducialUID'],\n '031B': ['UI', '1', 'ReferencedFiducialUID'],\n '031C': ['SQ', '1', 'FiducialSetSequence'],\n '031E': ['SQ', '1', 'FiducialSequence'],\n '031F': ['SQ', '1', 'FiducialsPropertyCategoryCodeSequence'],\n '0401': ['US', '3', 'GraphicLayerRecommendedDisplayCIELabValue'],\n '0402': ['SQ', '1', 'BlendingSequence'],\n '0403': ['FL', '1', 'RelativeOpacity'],\n '0404': ['SQ', '1', 'ReferencedSpatialRegistrationSequence'],\n '0405': ['CS', '1', 'BlendingPosition'],\n '1101': ['UI', '1', 'PresentationDisplayCollectionUID'],\n '1102': ['UI', '1', 'PresentationSequenceCollectionUID'],\n '1103': ['US', '1', 'PresentationSequencePositionIndex'],\n '1104': ['SQ', '1', 'RenderedImageReferenceSequence'],\n '1201': ['SQ', '1', 'VolumetricPresentationStateInputSequence'],\n '1202': ['CS', '1', 'PresentationInputType'],\n '1203': ['US', '1', 'InputSequencePositionIndex'],\n '1204': ['CS', '1', 'Crop'],\n '1205': ['US', '1-n', 'CroppingSpecificationIndex'],\n '1206': ['CS', '1', 'CompositingMethod'],\n '1207': ['US', '1', 'VolumetricPresentationInputNumber'],\n '1208': ['CS', '1', 'ImageVolumeGeometry'],\n '1209': ['UI', '1', 'VolumetricPresentationInputSetUID'],\n '120A': ['SQ', '1', 'VolumetricPresentationInputSetSequence'],\n '120B': ['CS', '1', 'GlobalCrop'],\n '120C': ['US', '1-n', 'GlobalCroppingSpecificationIndex'],\n '120D': ['CS', '1', 'RenderingMethod'],\n '1301': ['SQ', '1', 'VolumeCroppingSequence'],\n '1302': ['CS', '1', 'VolumeCroppingMethod'],\n '1303': ['FD', '6', 'BoundingBoxCrop'],\n '1304': ['SQ', '1', 'ObliqueCroppingPlaneSequence'],\n '1305': ['FD', '4', 'Plane'],\n '1306': ['FD', '3', 'PlaneNormal'],\n '1309': ['US', '1', 'CroppingSpecificationNumber'],\n '1501': ['CS', '1', 'MultiPlanarReconstructionStyle'],\n '1502': ['CS', '1', 'MPRThicknessType'],\n '1503': ['FD', '1', 'MPRSlabThickness'],\n '1505': ['FD', '3', 'MPRTopLeftHandCorner'],\n '1507': ['FD', '3', 'MPRViewWidthDirection'],\n '1508': ['FD', '1', 'MPRViewWidth'],\n '150C': ['UL', '1', 'NumberOfVolumetricCurvePoints'],\n '150D': ['OD', '1', 'VolumetricCurvePoints'],\n '1511': ['FD', '3', 'MPRViewHeightDirection'],\n '1512': ['FD', '1', 'MPRViewHeight'],\n '1602': ['CS', '1', 'RenderProjection'],\n '1603': ['FD', '3', 'ViewpointPosition'],\n '1604': ['FD', '3', 'ViewpointLookAtPoint'],\n '1605': ['FD', '3', 'ViewpointUpDirection'],\n '1606': ['FD', '6', 'RenderFieldOfView'],\n '1607': ['FD', '1', 'SamplingStepSize'],\n '1701': ['CS', '1', 'ShadingStyle'],\n '1702': ['FD', '1', 'AmbientReflectionIntensity'],\n '1703': ['FD', '3', 'LightDirection'],\n '1704': ['FD', '1', 'DiffuseReflectionIntensity'],\n '1705': ['FD', '1', 'SpecularReflectionIntensity'],\n '1706': ['FD', '1', 'Shininess'],\n '1801': ['SQ', '1', 'PresentationStateClassificationComponentSequence'],\n '1802': ['CS', '1', 'ComponentType'],\n '1803': ['SQ', '1', 'ComponentInputSequence'],\n '1804': ['US', '1', 'VolumetricPresentationInputIndex'],\n '1805': ['SQ', '1', 'PresentationStateCompositorComponentSequence'],\n '1806': ['SQ', '1', 'WeightingTransferFunctionSequence'],\n '1807': ['US', '3', 'WeightingLookupTableDescriptor'],\n '1808': ['OB', '1', 'WeightingLookupTableData'],\n '1901': ['SQ', '1', 'VolumetricAnnotationSequence'],\n '1903': ['SQ', '1', 'ReferencedStructuredContextSequence'],\n '1904': ['UI', '1', 'ReferencedContentItem'],\n '1905': ['SQ', '1', 'VolumetricPresentationInputAnnotationSequence'],\n '1907': ['CS', '1', 'AnnotationClipping'],\n '1A01': ['CS', '1', 'PresentationAnimationStyle'],\n '1A03': ['FD', '1', 'RecommendedAnimationRate'],\n '1A04': ['SQ', '1', 'AnimationCurveSequence'],\n '1A05': ['FD', '1', 'AnimationStepSize'],\n '1A06': ['FD', '1', 'SwivelRange'],\n '1A07': ['OD', '1', 'VolumetricCurveUpDirections'],\n '1A08': ['SQ', '1', 'VolumeStreamSequence'],\n '1A09': ['LO', '1', 'RGBATransferFunctionDescription'],\n '1B01': ['SQ', '1', 'AdvancedBlendingSequence'],\n '1B02': ['US', '1', 'BlendingInputNumber'],\n '1B03': ['SQ', '1', 'BlendingDisplayInputSequence'],\n '1B04': ['SQ', '1', 'BlendingDisplaySequence'],\n '1B06': ['CS', '1', 'BlendingMode'],\n '1B07': ['CS', '1', 'TimeSeriesBlending'],\n '1B08': ['CS', '1', 'GeometryForDisplay'],\n '1B11': ['SQ', '1', 'ThresholdSequence'],\n '1B12': ['SQ', '1', 'ThresholdValueSequence'],\n '1B13': ['CS', '1', 'ThresholdType'],\n '1B14': ['FD', '1', 'ThresholdValue']\n },\n '0072': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['SH', '1', 'HangingProtocolName'],\n '0004': ['LO', '1', 'HangingProtocolDescription'],\n '0006': ['CS', '1', 'HangingProtocolLevel'],\n '0008': ['LO', '1', 'HangingProtocolCreator'],\n '000A': ['DT', '1', 'HangingProtocolCreationDateTime'],\n '000C': ['SQ', '1', 'HangingProtocolDefinitionSequence'],\n '000E': ['SQ', '1', 'HangingProtocolUserIdentificationCodeSequence'],\n '0010': ['LO', '1', 'HangingProtocolUserGroupName'],\n '0012': ['SQ', '1', 'SourceHangingProtocolSequence'],\n '0014': ['US', '1', 'NumberOfPriorsReferenced'],\n '0020': ['SQ', '1', 'ImageSetsSequence'],\n '0022': ['SQ', '1', 'ImageSetSelectorSequence'],\n '0024': ['CS', '1', 'ImageSetSelectorUsageFlag'],\n '0026': ['AT', '1', 'SelectorAttribute'],\n '0028': ['US', '1', 'SelectorValueNumber'],\n '0030': ['SQ', '1', 'TimeBasedImageSetsSequence'],\n '0032': ['US', '1', 'ImageSetNumber'],\n '0034': ['CS', '1', 'ImageSetSelectorCategory'],\n '0038': ['US', '2', 'RelativeTime'],\n '003A': ['CS', '1', 'RelativeTimeUnits'],\n '003C': ['SS', '2', 'AbstractPriorValue'],\n '003E': ['SQ', '1', 'AbstractPriorCodeSequence'],\n '0040': ['LO', '1', 'ImageSetLabel'],\n '0050': ['CS', '1', 'SelectorAttributeVR'],\n '0052': ['AT', '1-n', 'SelectorSequencePointer'],\n '0054': ['LO', '1-n', 'SelectorSequencePointerPrivateCreator'],\n '0056': ['LO', '1', 'SelectorAttributePrivateCreator'],\n '005E': ['AE', '1-n', 'SelectorAEValue'],\n '005F': ['AS', '1-n', 'SelectorASValue'],\n '0060': ['AT', '1-n', 'SelectorATValue'],\n '0061': ['DA', '1-n', 'SelectorDAValue'],\n '0062': ['CS', '1-n', 'SelectorCSValue'],\n '0063': ['DT', '1-n', 'SelectorDTValue'],\n '0064': ['IS', '1-n', 'SelectorISValue'],\n '0065': ['OB', '1', 'SelectorOBValue'],\n '0066': ['LO', '1-n', 'SelectorLOValue'],\n '0067': ['OF', '1', 'SelectorOFValue'],\n '0068': ['LT', '1', 'SelectorLTValue'],\n '0069': ['OW', '1', 'SelectorOWValue'],\n '006A': ['PN', '1-n', 'SelectorPNValue'],\n '006B': ['TM', '1-n', 'SelectorTMValue'],\n '006C': ['SH', '1-n', 'SelectorSHValue'],\n '006D': ['UN', '1', 'SelectorUNValue'],\n '006E': ['ST', '1', 'SelectorSTValue'],\n '006F': ['UC', '1-n', 'SelectorUCValue'],\n '0070': ['UT', '1', 'SelectorUTValue'],\n '0071': ['UR', '1', 'SelectorURValue'],\n '0072': ['DS', '1-n', 'SelectorDSValue'],\n '0073': ['OD', '1', 'SelectorODValue'],\n '0074': ['FD', '1-n', 'SelectorFDValue'],\n '0075': ['OL', '1', 'SelectorOLValue'],\n '0076': ['FL', '1-n', 'SelectorFLValue'],\n '0078': ['UL', '1-n', 'SelectorULValue'],\n '007A': ['US', '1-n', 'SelectorUSValue'],\n '007C': ['SL', '1-n', 'SelectorSLValue'],\n '007E': ['SS', '1-n', 'SelectorSSValue'],\n '007F': ['UI', '1-n', 'SelectorUIValue'],\n '0080': ['SQ', '1', 'SelectorCodeSequenceValue'],\n '0081': ['OV', '1', 'SelectorOVValue'],\n '0082': ['SV', '1-n', 'SelectorSVValue'],\n '0083': ['UV', '1-n', 'SelectorUVValue'],\n '0100': ['US', '1', 'NumberOfScreens'],\n '0102': ['SQ', '1', 'NominalScreenDefinitionSequence'],\n '0104': ['US', '1', 'NumberOfVerticalPixels'],\n '0106': ['US', '1', 'NumberOfHorizontalPixels'],\n '0108': ['FD', '4', 'DisplayEnvironmentSpatialPosition'],\n '010A': ['US', '1', 'ScreenMinimumGrayscaleBitDepth'],\n '010C': ['US', '1', 'ScreenMinimumColorBitDepth'],\n '010E': ['US', '1', 'ApplicationMaximumRepaintTime'],\n '0200': ['SQ', '1', 'DisplaySetsSequence'],\n '0202': ['US', '1', 'DisplaySetNumber'],\n '0203': ['LO', '1', 'DisplaySetLabel'],\n '0204': ['US', '1', 'DisplaySetPresentationGroup'],\n '0206': ['LO', '1', 'DisplaySetPresentationGroupDescription'],\n '0208': ['CS', '1', 'PartialDataDisplayHandling'],\n '0210': ['SQ', '1', 'SynchronizedScrollingSequence'],\n '0212': ['US', '2-n', 'DisplaySetScrollingGroup'],\n '0214': ['SQ', '1', 'NavigationIndicatorSequence'],\n '0216': ['US', '1', 'NavigationDisplaySet'],\n '0218': ['US', '1-n', 'ReferenceDisplaySets'],\n '0300': ['SQ', '1', 'ImageBoxesSequence'],\n '0302': ['US', '1', 'ImageBoxNumber'],\n '0304': ['CS', '1', 'ImageBoxLayoutType'],\n '0306': ['US', '1', 'ImageBoxTileHorizontalDimension'],\n '0308': ['US', '1', 'ImageBoxTileVerticalDimension'],\n '0310': ['CS', '1', 'ImageBoxScrollDirection'],\n '0312': ['CS', '1', 'ImageBoxSmallScrollType'],\n '0314': ['US', '1', 'ImageBoxSmallScrollAmount'],\n '0316': ['CS', '1', 'ImageBoxLargeScrollType'],\n '0318': ['US', '1', 'ImageBoxLargeScrollAmount'],\n '0320': ['US', '1', 'ImageBoxOverlapPriority'],\n '0330': ['FD', '1', 'CineRelativeToRealTime'],\n '0400': ['SQ', '1', 'FilterOperationsSequence'],\n '0402': ['CS', '1', 'FilterByCategory'],\n '0404': ['CS', '1', 'FilterByAttributePresence'],\n '0406': ['CS', '1', 'FilterByOperator'],\n '0420': ['US', '3', 'StructuredDisplayBackgroundCIELabValue'],\n '0421': ['US', '3', 'EmptyImageBoxCIELabValue'],\n '0422': ['SQ', '1', 'StructuredDisplayImageBoxSequence'],\n '0424': ['SQ', '1', 'StructuredDisplayTextBoxSequence'],\n '0427': ['SQ', '1', 'ReferencedFirstFrameSequence'],\n '0430': ['SQ', '1', 'ImageBoxSynchronizationSequence'],\n '0432': ['US', '2-n', 'SynchronizedImageBoxList'],\n '0434': ['CS', '1', 'TypeOfSynchronization'],\n '0500': ['CS', '1', 'BlendingOperationType'],\n '0510': ['CS', '1', 'ReformattingOperationType'],\n '0512': ['FD', '1', 'ReformattingThickness'],\n '0514': ['FD', '1', 'ReformattingInterval'],\n '0516': ['CS', '1', 'ReformattingOperationInitialViewDirection'],\n '0520': ['CS', '1-n', 'ThreeDRenderingType'],\n '0600': ['SQ', '1', 'SortingOperationsSequence'],\n '0602': ['CS', '1', 'SortByCategory'],\n '0604': ['CS', '1', 'SortingDirection'],\n '0700': ['CS', '2', 'DisplaySetPatientOrientation'],\n '0702': ['CS', '1', 'VOIType'],\n '0704': ['CS', '1', 'PseudoColorType'],\n '0705': ['SQ', '1', 'PseudoColorPaletteInstanceReferenceSequence'],\n '0706': ['CS', '1', 'ShowGrayscaleInverted'],\n '0710': ['CS', '1', 'ShowImageTrueSizeFlag'],\n '0712': ['CS', '1', 'ShowGraphicAnnotationFlag'],\n '0714': ['CS', '1', 'ShowPatientDemographicsFlag'],\n '0716': ['CS', '1', 'ShowAcquisitionTechniquesFlag'],\n '0717': ['CS', '1', 'DisplaySetHorizontalJustification'],\n '0718': ['CS', '1', 'DisplaySetVerticalJustification']\n },\n '0074': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0120': ['FD', '1', 'ContinuationStartMeterset'],\n '0121': ['FD', '1', 'ContinuationEndMeterset'],\n '1000': ['CS', '1', 'ProcedureStepState'],\n '1002': ['SQ', '1', 'ProcedureStepProgressInformationSequence'],\n '1004': ['DS', '1', 'ProcedureStepProgress'],\n '1006': ['ST', '1', 'ProcedureStepProgressDescription'],\n '1007': ['SQ', '1', 'ProcedureStepProgressParametersSequence'],\n '1008': ['SQ', '1', 'ProcedureStepCommunicationsURISequence'],\n '100A': ['UR', '1', 'ContactURI'],\n '100C': ['LO', '1', 'ContactDisplayName'],\n '100E': ['SQ', '1', 'ProcedureStepDiscontinuationReasonCodeSequence'],\n '1020': ['SQ', '1', 'BeamTaskSequence'],\n '1022': ['CS', '1', 'BeamTaskType'],\n '1024': ['IS', '1', 'BeamOrderIndexTrial'],\n '1025': ['CS', '1', 'AutosequenceFlag'],\n '1026': ['FD', '1', 'TableTopVerticalAdjustedPosition'],\n '1027': ['FD', '1', 'TableTopLongitudinalAdjustedPosition'],\n '1028': ['FD', '1', 'TableTopLateralAdjustedPosition'],\n '102A': ['FD', '1', 'PatientSupportAdjustedAngle'],\n '102B': ['FD', '1', 'TableTopEccentricAdjustedAngle'],\n '102C': ['FD', '1', 'TableTopPitchAdjustedAngle'],\n '102D': ['FD', '1', 'TableTopRollAdjustedAngle'],\n '1030': ['SQ', '1', 'DeliveryVerificationImageSequence'],\n '1032': ['CS', '1', 'VerificationImageTiming'],\n '1034': ['CS', '1', 'DoubleExposureFlag'],\n '1036': ['CS', '1', 'DoubleExposureOrdering'],\n '1038': ['DS', '1', 'DoubleExposureMetersetTrial'],\n '103A': ['DS', '4', 'DoubleExposureFieldDeltaTrial'],\n '1040': ['SQ', '1', 'RelatedReferenceRTImageSequence'],\n '1042': ['SQ', '1', 'GeneralMachineVerificationSequence'],\n '1044': ['SQ', '1', 'ConventionalMachineVerificationSequence'],\n '1046': ['SQ', '1', 'IonMachineVerificationSequence'],\n '1048': ['SQ', '1', 'FailedAttributesSequence'],\n '104A': ['SQ', '1', 'OverriddenAttributesSequence'],\n '104C': ['SQ', '1', 'ConventionalControlPointVerificationSequence'],\n '104E': ['SQ', '1', 'IonControlPointVerificationSequence'],\n '1050': ['SQ', '1', 'AttributeOccurrenceSequence'],\n '1052': ['AT', '1', 'AttributeOccurrencePointer'],\n '1054': ['UL', '1', 'AttributeItemSelector'],\n '1056': ['LO', '1', 'AttributeOccurrencePrivateCreator'],\n '1057': ['IS', '1-n', 'SelectorSequencePointerItems'],\n '1200': ['CS', '1', 'ScheduledProcedureStepPriority'],\n '1202': ['LO', '1', 'WorklistLabel'],\n '1204': ['LO', '1', 'ProcedureStepLabel'],\n '1210': ['SQ', '1', 'ScheduledProcessingParametersSequence'],\n '1212': ['SQ', '1', 'PerformedProcessingParametersSequence'],\n '1216': ['SQ', '1', 'UnifiedProcedureStepPerformedProcedureSequence'],\n '1220': ['SQ', '1', 'RelatedProcedureStepSequence'],\n '1222': ['LO', '1', 'ProcedureStepRelationshipType'],\n '1224': ['SQ', '1', 'ReplacedProcedureStepSequence'],\n '1230': ['LO', '1', 'DeletionLock'],\n '1234': ['AE', '1', 'ReceivingAE'],\n '1236': ['AE', '1', 'RequestingAE'],\n '1238': ['LT', '1', 'ReasonForCancellation'],\n '1242': ['CS', '1', 'SCPStatus'],\n '1244': ['CS', '1', 'SubscriptionListStatus'],\n '1246': ['CS', '1', 'UnifiedProcedureStepListStatus'],\n '1324': ['UL', '1', 'BeamOrderIndex'],\n '1338': ['FD', '1', 'DoubleExposureMeterset'],\n '133A': ['FD', '4', 'DoubleExposureFieldDelta'],\n '1401': ['SQ', '1', 'BrachyTaskSequence'],\n '1402': ['DS', '1', 'ContinuationStartTotalReferenceAirKerma'],\n '1403': ['DS', '1', 'ContinuationEndTotalReferenceAirKerma'],\n '1404': ['IS', '1', 'ContinuationPulseNumber'],\n '1405': ['SQ', '1', 'ChannelDeliveryOrderSequence'],\n '1406': ['IS', '1', 'ReferencedChannelNumber'],\n '1407': ['DS', '1', 'StartCumulativeTimeWeight'],\n '1408': ['DS', '1', 'EndCumulativeTimeWeight'],\n '1409': ['SQ', '1', 'OmittedChannelSequence'],\n '140A': ['CS', '1', 'ReasonForChannelOmission'],\n '140B': ['LO', '1', 'ReasonForChannelOmissionDescription'],\n '140C': ['IS', '1', 'ChannelDeliveryOrderIndex'],\n '140D': ['SQ', '1', 'ChannelDeliveryContinuationSequence'],\n '140E': ['SQ', '1', 'OmittedApplicationSetupSequence']\n },\n '0076': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['LO', '1', 'ImplantAssemblyTemplateName'],\n '0003': ['LO', '1', 'ImplantAssemblyTemplateIssuer'],\n '0006': ['LO', '1', 'ImplantAssemblyTemplateVersion'],\n '0008': ['SQ', '1', 'ReplacedImplantAssemblyTemplateSequence'],\n '000A': ['CS', '1', 'ImplantAssemblyTemplateType'],\n '000C': ['SQ', '1', 'OriginalImplantAssemblyTemplateSequence'],\n '000E': ['SQ', '1', 'DerivationImplantAssemblyTemplateSequence'],\n '0010': ['SQ', '1', 'ImplantAssemblyTemplateTargetAnatomySequence'],\n '0020': ['SQ', '1', 'ProcedureTypeCodeSequence'],\n '0030': ['LO', '1', 'SurgicalTechnique'],\n '0032': ['SQ', '1', 'ComponentTypesSequence'],\n '0034': ['SQ', '1', 'ComponentTypeCodeSequence'],\n '0036': ['CS', '1', 'ExclusiveComponentType'],\n '0038': ['CS', '1', 'MandatoryComponentType'],\n '0040': ['SQ', '1', 'ComponentSequence'],\n '0055': ['US', '1', 'ComponentID'],\n '0060': ['SQ', '1', 'ComponentAssemblySequence'],\n '0070': ['US', '1', 'Component1ReferencedID'],\n '0080': ['US', '1', 'Component1ReferencedMatingFeatureSetID'],\n '0090': ['US', '1', 'Component1ReferencedMatingFeatureID'],\n '00A0': ['US', '1', 'Component2ReferencedID'],\n '00B0': ['US', '1', 'Component2ReferencedMatingFeatureSetID'],\n '00C0': ['US', '1', 'Component2ReferencedMatingFeatureID']\n },\n '0078': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['LO', '1', 'ImplantTemplateGroupName'],\n '0010': ['ST', '1', 'ImplantTemplateGroupDescription'],\n '0020': ['LO', '1', 'ImplantTemplateGroupIssuer'],\n '0024': ['LO', '1', 'ImplantTemplateGroupVersion'],\n '0026': ['SQ', '1', 'ReplacedImplantTemplateGroupSequence'],\n '0028': ['SQ', '1', 'ImplantTemplateGroupTargetAnatomySequence'],\n '002A': ['SQ', '1', 'ImplantTemplateGroupMembersSequence'],\n '002E': ['US', '1', 'ImplantTemplateGroupMemberID'],\n '0050': ['FD', '3', 'ThreeDImplantTemplateGroupMemberMatchingPoint'],\n '0060': ['FD', '9', 'ThreeDImplantTemplateGroupMemberMatchingAxes'],\n '0070': ['SQ', '1', 'ImplantTemplateGroupMemberMatching2DCoordinatesSequence'],\n '0090': ['FD', '2', 'TwoDImplantTemplateGroupMemberMatchingPoint'],\n '00A0': ['FD', '4', 'TwoDImplantTemplateGroupMemberMatchingAxes'],\n '00B0': ['SQ', '1', 'ImplantTemplateGroupVariationDimensionSequence'],\n '00B2': ['LO', '1', 'ImplantTemplateGroupVariationDimensionName'],\n '00B4': ['SQ', '1', 'ImplantTemplateGroupVariationDimensionRankSequence'],\n '00B6': ['US', '1', 'ReferencedImplantTemplateGroupMemberID'],\n '00B8': ['US', '1', 'ImplantTemplateGroupVariationDimensionRank']\n },\n '0080': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['SQ', '1', 'SurfaceScanAcquisitionTypeCodeSequence'],\n '0002': ['SQ', '1', 'SurfaceScanModeCodeSequence'],\n '0003': ['SQ', '1', 'RegistrationMethodCodeSequence'],\n '0004': ['FD', '1', 'ShotDurationTime'],\n '0005': ['FD', '1', 'ShotOffsetTime'],\n '0006': ['US', '1-n', 'SurfacePointPresentationValueData'],\n '0007': ['US', '3-3n', 'SurfacePointColorCIELabValueData'],\n '0008': ['SQ', '1', 'UVMappingSequence'],\n '0009': ['SH', '1', 'TextureLabel'],\n '0010': ['OF', '1', 'UValueData'],\n '0011': ['OF', '1', 'VValueData'],\n '0012': ['SQ', '1', 'ReferencedTextureSequence'],\n '0013': ['SQ', '1', 'ReferencedSurfaceDataSequence']\n },\n '0082': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['CS', '1', 'AssessmentSummary'],\n '0003': ['UT', '1', 'AssessmentSummaryDescription'],\n '0004': ['SQ', '1', 'AssessedSOPInstanceSequence'],\n '0005': ['SQ', '1', 'ReferencedComparisonSOPInstanceSequence'],\n '0006': ['UL', '1', 'NumberOfAssessmentObservations'],\n '0007': ['SQ', '1', 'AssessmentObservationsSequence'],\n '0008': ['CS', '1', 'ObservationSignificance'],\n '000A': ['UT', '1', 'ObservationDescription'],\n '000C': ['SQ', '1', 'StructuredConstraintObservationSequence'],\n '0010': ['SQ', '1', 'AssessedAttributeValueSequence'],\n '0016': ['LO', '1', 'AssessmentSetID'],\n '0017': ['SQ', '1', 'AssessmentRequesterSequence'],\n '0018': ['LO', '1', 'SelectorAttributeName'],\n '0019': ['LO', '1', 'SelectorAttributeKeyword'],\n '0021': ['SQ', '1', 'AssessmentTypeCodeSequence'],\n '0022': ['SQ', '1', 'ObservationBasisCodeSequence'],\n '0023': ['LO', '1', 'AssessmentLabel'],\n '0032': ['CS', '1', 'ConstraintType'],\n '0033': ['UT', '1', 'SpecificationSelectionGuidance'],\n '0034': ['SQ', '1', 'ConstraintValueSequence'],\n '0035': ['SQ', '1', 'RecommendedDefaultValueSequence'],\n '0036': ['CS', '1', 'ConstraintViolationSignificance'],\n '0037': ['UT', '1', 'ConstraintViolationCondition'],\n '0038': ['CS', '1', 'ModifiableConstraintFlag']\n },\n '0088': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0130': ['SH', '1', 'StorageMediaFileSetID'],\n '0140': ['UI', '1', 'StorageMediaFileSetUID'],\n '0200': ['SQ', '1', 'IconImageSequence'],\n '0904': ['LO', '1', 'TopicTitle'],\n '0906': ['ST', '1', 'TopicSubject'],\n '0910': ['LO', '1', 'TopicAuthor'],\n '0912': ['LO', '1-32', 'TopicKeywords']\n },\n '0100': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0410': ['CS', '1', 'SOPInstanceStatus'],\n '0420': ['DT', '1', 'SOPAuthorizationDateTime'],\n '0424': ['LT', '1', 'SOPAuthorizationComment'],\n '0426': ['LO', '1', 'AuthorizationEquipmentCertificationNumber']\n },\n '0400': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0005': ['US', '1', 'MACIDNumber'],\n '0010': ['UI', '1', 'MACCalculationTransferSyntaxUID'],\n '0015': ['CS', '1', 'MACAlgorithm'],\n '0020': ['AT', '1-n', 'DataElementsSigned'],\n '0100': ['UI', '1', 'DigitalSignatureUID'],\n '0105': ['DT', '1', 'DigitalSignatureDateTime'],\n '0110': ['CS', '1', 'CertificateType'],\n '0115': ['OB', '1', 'CertificateOfSigner'],\n '0120': ['OB', '1', 'Signature'],\n '0305': ['CS', '1', 'CertifiedTimestampType'],\n '0310': ['OB', '1', 'CertifiedTimestamp'],\n '0315': ['FL', '1', ''],\n '0401': ['SQ', '1', 'DigitalSignaturePurposeCodeSequence'],\n '0402': ['SQ', '1', 'ReferencedDigitalSignatureSequence'],\n '0403': ['SQ', '1', 'ReferencedSOPInstanceMACSequence'],\n '0404': ['OB', '1', 'MAC'],\n '0500': ['SQ', '1', 'EncryptedAttributesSequence'],\n '0510': ['UI', '1', 'EncryptedContentTransferSyntaxUID'],\n '0520': ['OB', '1', 'EncryptedContent'],\n '0550': ['SQ', '1', 'ModifiedAttributesSequence'],\n '0551': ['SQ', '1', 'NonconformingModifiedAttributesSequence'],\n '0552': ['OB', '1', 'NonconformingDataElementValue'],\n '0561': ['SQ', '1', 'OriginalAttributesSequence'],\n '0562': ['DT', '1', 'AttributeModificationDateTime'],\n '0563': ['LO', '1', 'ModifyingSystem'],\n '0564': ['LO', '1', 'SourceOfPreviousValues'],\n '0565': ['CS', '1', 'ReasonForTheAttributeModification'],\n '0600': ['CS', '1', 'InstanceOriginStatus']\n },\n '1000': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['US', '3', 'EscapeTriplet'],\n '0011': ['US', '3', 'RunLengthTriplet'],\n '0012': ['US', '1', 'HuffmanTableSize'],\n '0013': ['US', '3', 'HuffmanTableTriplet'],\n '0014': ['US', '1', 'ShiftTableSize'],\n '0015': ['US', '3', 'ShiftTableTriplet']\n },\n '1010': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0004': ['US', '1-n', 'ZonalMap']\n },\n '2000': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['IS', '1', 'NumberOfCopies'],\n '001E': ['SQ', '1', 'PrinterConfigurationSequence'],\n '0020': ['CS', '1', 'PrintPriority'],\n '0030': ['CS', '1', 'MediumType'],\n '0040': ['CS', '1', 'FilmDestination'],\n '0050': ['LO', '1', 'FilmSessionLabel'],\n '0060': ['IS', '1', 'MemoryAllocation'],\n '0061': ['IS', '1', 'MaximumMemoryAllocation'],\n '0062': ['CS', '1', 'ColorImagePrintingFlag'],\n '0063': ['CS', '1', 'CollationFlag'],\n '0065': ['CS', '1', 'AnnotationFlag'],\n '0067': ['CS', '1', 'ImageOverlayFlag'],\n '0069': ['CS', '1', 'PresentationLUTFlag'],\n '006A': ['CS', '1', 'ImageBoxPresentationLUTFlag'],\n '00A0': ['US', '1', 'MemoryBitDepth'],\n '00A1': ['US', '1', 'PrintingBitDepth'],\n '00A2': ['SQ', '1', 'MediaInstalledSequence'],\n '00A4': ['SQ', '1', 'OtherMediaAvailableSequence'],\n '00A8': ['SQ', '1', 'SupportedImageDisplayFormatsSequence'],\n '0500': ['SQ', '1', 'ReferencedFilmBoxSequence'],\n '0510': ['SQ', '1', 'ReferencedStoredPrintSequence']\n },\n '2010': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['ST', '1', 'ImageDisplayFormat'],\n '0030': ['CS', '1', 'AnnotationDisplayFormatID'],\n '0040': ['CS', '1', 'FilmOrientation'],\n '0050': ['CS', '1', 'FilmSizeID'],\n '0052': ['CS', '1', 'PrinterResolutionID'],\n '0054': ['CS', '1', 'DefaultPrinterResolutionID'],\n '0060': ['CS', '1', 'MagnificationType'],\n '0080': ['CS', '1', 'SmoothingType'],\n '00A6': ['CS', '1', 'DefaultMagnificationType'],\n '00A7': ['CS', '1-n', 'OtherMagnificationTypesAvailable'],\n '00A8': ['CS', '1', 'DefaultSmoothingType'],\n '00A9': ['CS', '1-n', 'OtherSmoothingTypesAvailable'],\n '0100': ['CS', '1', 'BorderDensity'],\n '0110': ['CS', '1', 'EmptyImageDensity'],\n '0120': ['US', '1', 'MinDensity'],\n '0130': ['US', '1', 'MaxDensity'],\n '0140': ['CS', '1', 'Trim'],\n '0150': ['ST', '1', 'ConfigurationInformation'],\n '0152': ['LT', '1', 'ConfigurationInformationDescription'],\n '0154': ['IS', '1', 'MaximumCollatedFilms'],\n '015E': ['US', '1', 'Illumination'],\n '0160': ['US', '1', 'ReflectedAmbientLight'],\n '0376': ['DS', '2', 'PrinterPixelSpacing'],\n '0500': ['SQ', '1', 'ReferencedFilmSessionSequence'],\n '0510': ['SQ', '1', 'ReferencedImageBoxSequence'],\n '0520': ['SQ', '1', 'ReferencedBasicAnnotationBoxSequence']\n },\n '2020': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['US', '1', 'ImageBoxPosition'],\n '0020': ['CS', '1', 'Polarity'],\n '0030': ['DS', '1', 'RequestedImageSize'],\n '0040': ['CS', '1', 'RequestedDecimateCropBehavior'],\n '0050': ['CS', '1', 'RequestedResolutionID'],\n '00A0': ['CS', '1', 'RequestedImageSizeFlag'],\n '00A2': ['CS', '1', 'DecimateCropResult'],\n '0110': ['SQ', '1', 'BasicGrayscaleImageSequence'],\n '0111': ['SQ', '1', 'BasicColorImageSequence'],\n '0130': ['SQ', '1', 'ReferencedImageOverlayBoxSequence'],\n '0140': ['SQ', '1', 'ReferencedVOILUTBoxSequence']\n },\n '2030': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['US', '1', 'AnnotationPosition'],\n '0020': ['LO', '1', 'TextString']\n },\n '2040': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['SQ', '1', 'ReferencedOverlayPlaneSequence'],\n '0011': ['US', '1-99', 'ReferencedOverlayPlaneGroups'],\n '0020': ['SQ', '1', 'OverlayPixelDataSequence'],\n '0060': ['CS', '1', 'OverlayMagnificationType'],\n '0070': ['CS', '1', 'OverlaySmoothingType'],\n '0072': ['CS', '1', 'OverlayOrImageMagnification'],\n '0074': ['US', '1', 'MagnifyToNumberOfColumns'],\n '0080': ['CS', '1', 'OverlayForegroundDensity'],\n '0082': ['CS', '1', 'OverlayBackgroundDensity'],\n '0090': ['CS', '1', 'OverlayMode'],\n '0100': ['CS', '1', 'ThresholdDensity'],\n '0500': ['SQ', '1', 'ReferencedImageBoxSequenceRetired']\n },\n '2050': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['SQ', '1', 'PresentationLUTSequence'],\n '0020': ['CS', '1', 'PresentationLUTShape'],\n '0500': ['SQ', '1', 'ReferencedPresentationLUTSequence']\n },\n '2100': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['SH', '1', 'PrintJobID'],\n '0020': ['CS', '1', 'ExecutionStatus'],\n '0030': ['CS', '1', 'ExecutionStatusInfo'],\n '0040': ['DA', '1', 'CreationDate'],\n '0050': ['TM', '1', 'CreationTime'],\n '0070': ['AE', '1', 'Originator'],\n '0140': ['AE', '1', 'DestinationAE'],\n '0160': ['SH', '1', 'OwnerID'],\n '0170': ['IS', '1', 'NumberOfFilms'],\n '0500': ['SQ', '1', 'ReferencedPrintJobSequencePullStoredPrint']\n },\n '2110': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['CS', '1', 'PrinterStatus'],\n '0020': ['CS', '1', 'PrinterStatusInfo'],\n '0030': ['LO', '1', 'PrinterName'],\n '0099': ['SH', '1', 'PrintQueueID']\n },\n '2120': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['CS', '1', 'QueueStatus'],\n '0050': ['SQ', '1', 'PrintJobDescriptionSequence'],\n '0070': ['SQ', '1', 'ReferencedPrintJobSequence']\n },\n '2130': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['SQ', '1', 'PrintManagementCapabilitiesSequence'],\n '0015': ['SQ', '1', 'PrinterCharacteristicsSequence'],\n '0030': ['SQ', '1', 'FilmBoxContentSequence'],\n '0040': ['SQ', '1', 'ImageBoxContentSequence'],\n '0050': ['SQ', '1', 'AnnotationContentSequence'],\n '0060': ['SQ', '1', 'ImageOverlayBoxContentSequence'],\n '0080': ['SQ', '1', 'PresentationLUTContentSequence'],\n '00A0': ['SQ', '1', 'ProposedStudySequence'],\n '00C0': ['SQ', '1', 'OriginalImageSequence']\n },\n '2200': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['CS', '1', 'LabelUsingInformationExtractedFromInstances'],\n '0002': ['UT', '1', 'LabelText'],\n '0003': ['CS', '1', 'LabelStyleSelection'],\n '0004': ['LT', '1', 'MediaDisposition'],\n '0005': ['LT', '1', 'BarcodeValue'],\n '0006': ['CS', '1', 'BarcodeSymbology'],\n '0007': ['CS', '1', 'AllowMediaSplitting'],\n '0008': ['CS', '1', 'IncludeNonDICOMObjects'],\n '0009': ['CS', '1', 'IncludeDisplayApplication'],\n '000A': ['CS', '1', 'PreserveCompositeInstancesAfterMediaCreation'],\n '000B': ['US', '1', 'TotalNumberOfPiecesOfMediaCreated'],\n '000C': ['LO', '1', 'RequestedMediaApplicationProfile'],\n '000D': ['SQ', '1', 'ReferencedStorageMediaSequence'],\n '000E': ['AT', '1-n', 'FailureAttributes'],\n '000F': ['CS', '1', 'AllowLossyCompression'],\n '0020': ['CS', '1', 'RequestPriority']\n },\n '3002': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['SH', '1', 'RTImageLabel'],\n '0003': ['LO', '1', 'RTImageName'],\n '0004': ['ST', '1', 'RTImageDescription'],\n '000A': ['CS', '1', 'ReportedValuesOrigin'],\n '000C': ['CS', '1', 'RTImagePlane'],\n '000D': ['DS', '3', 'XRayImageReceptorTranslation'],\n '000E': ['DS', '1', 'XRayImageReceptorAngle'],\n '0010': ['DS', '6', 'RTImageOrientation'],\n '0011': ['DS', '2', 'ImagePlanePixelSpacing'],\n '0012': ['DS', '2', 'RTImagePosition'],\n '0020': ['SH', '1', 'RadiationMachineName'],\n '0022': ['DS', '1', 'RadiationMachineSAD'],\n '0024': ['DS', '1', 'RadiationMachineSSD'],\n '0026': ['DS', '1', 'RTImageSID'],\n '0028': ['DS', '1', 'SourceToReferenceObjectDistance'],\n '0029': ['IS', '1', 'FractionNumber'],\n '0030': ['SQ', '1', 'ExposureSequence'],\n '0032': ['DS', '1', 'MetersetExposure'],\n '0034': ['DS', '4', 'DiaphragmPosition'],\n '0040': ['SQ', '1', 'FluenceMapSequence'],\n '0041': ['CS', '1', 'FluenceDataSource'],\n '0042': ['DS', '1', 'FluenceDataScale'],\n '0050': ['SQ', '1', 'PrimaryFluenceModeSequence'],\n '0051': ['CS', '1', 'FluenceMode'],\n '0052': ['SH', '1', 'FluenceModeID']\n },\n '3004': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['CS', '1', 'DVHType'],\n '0002': ['CS', '1', 'DoseUnits'],\n '0004': ['CS', '1', 'DoseType'],\n '0005': ['CS', '1', 'SpatialTransformOfDose'],\n '0006': ['LO', '1', 'DoseComment'],\n '0008': ['DS', '3', 'NormalizationPoint'],\n '000A': ['CS', '1', 'DoseSummationType'],\n '000C': ['DS', '2-n', 'GridFrameOffsetVector'],\n '000E': ['DS', '1', 'DoseGridScaling'],\n '0010': ['SQ', '1', 'RTDoseROISequence'],\n '0012': ['DS', '1', 'DoseValue'],\n '0014': ['CS', '1-3', 'TissueHeterogeneityCorrection'],\n '0040': ['DS', '3', 'DVHNormalizationPoint'],\n '0042': ['DS', '1', 'DVHNormalizationDoseValue'],\n '0050': ['SQ', '1', 'DVHSequence'],\n '0052': ['DS', '1', 'DVHDoseScaling'],\n '0054': ['CS', '1', 'DVHVolumeUnits'],\n '0056': ['IS', '1', 'DVHNumberOfBins'],\n '0058': ['DS', '2-2n', 'DVHData'],\n '0060': ['SQ', '1', 'DVHReferencedROISequence'],\n '0062': ['CS', '1', 'DVHROIContributionType'],\n '0070': ['DS', '1', 'DVHMinimumDose'],\n '0072': ['DS', '1', 'DVHMaximumDose'],\n '0074': ['DS', '1', 'DVHMeanDose']\n },\n '3006': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['SH', '1', 'StructureSetLabel'],\n '0004': ['LO', '1', 'StructureSetName'],\n '0006': ['ST', '1', 'StructureSetDescription'],\n '0008': ['DA', '1', 'StructureSetDate'],\n '0009': ['TM', '1', 'StructureSetTime'],\n '0010': ['SQ', '1', 'ReferencedFrameOfReferenceSequence'],\n '0012': ['SQ', '1', 'RTReferencedStudySequence'],\n '0014': ['SQ', '1', 'RTReferencedSeriesSequence'],\n '0016': ['SQ', '1', 'ContourImageSequence'],\n '0018': ['SQ', '1', 'PredecessorStructureSetSequence'],\n '0020': ['SQ', '1', 'StructureSetROISequence'],\n '0022': ['IS', '1', 'ROINumber'],\n '0024': ['UI', '1', 'ReferencedFrameOfReferenceUID'],\n '0026': ['LO', '1', 'ROIName'],\n '0028': ['ST', '1', 'ROIDescription'],\n '002A': ['IS', '3', 'ROIDisplayColor'],\n '002C': ['DS', '1', 'ROIVolume'],\n '0030': ['SQ', '1', 'RTRelatedROISequence'],\n '0033': ['CS', '1', 'RTROIRelationship'],\n '0036': ['CS', '1', 'ROIGenerationAlgorithm'],\n '0037': ['SQ', '1', 'ROIDerivationAlgorithmIdentificationSequence'],\n '0038': ['LO', '1', 'ROIGenerationDescription'],\n '0039': ['SQ', '1', 'ROIContourSequence'],\n '0040': ['SQ', '1', 'ContourSequence'],\n '0042': ['CS', '1', 'ContourGeometricType'],\n '0044': ['DS', '1', 'ContourSlabThickness'],\n '0045': ['DS', '3', 'ContourOffsetVector'],\n '0046': ['IS', '1', 'NumberOfContourPoints'],\n '0048': ['IS', '1', 'ContourNumber'],\n '0049': ['IS', '1-n', 'AttachedContours'],\n '004A': ['SQ', '1', 'SourcePixelPlanesCharacteristicsSequence'],\n '0050': ['DS', '3-3n', 'ContourData'],\n '0080': ['SQ', '1', 'RTROIObservationsSequence'],\n '0082': ['IS', '1', 'ObservationNumber'],\n '0084': ['IS', '1', 'ReferencedROINumber'],\n '0085': ['SH', '1', 'ROIObservationLabel'],\n '0086': ['SQ', '1', 'RTROIIdentificationCodeSequence'],\n '0088': ['ST', '1', 'ROIObservationDescription'],\n '00A0': ['SQ', '1', 'RelatedRTROIObservationsSequence'],\n '00A4': ['CS', '1', 'RTROIInterpretedType'],\n '00A6': ['PN', '1', 'ROIInterpreter'],\n '00B0': ['SQ', '1', 'ROIPhysicalPropertiesSequence'],\n '00B2': ['CS', '1', 'ROIPhysicalProperty'],\n '00B4': ['DS', '1', 'ROIPhysicalPropertyValue'],\n '00B6': ['SQ', '1', 'ROIElementalCompositionSequence'],\n '00B7': ['US', '1', 'ROIElementalCompositionAtomicNumber'],\n '00B8': ['FL', '1', 'ROIElementalCompositionAtomicMassFraction'],\n '00B9': ['SQ', '1', 'AdditionalRTROIIdentificationCodeSequence'],\n '00C0': ['SQ', '1', 'FrameOfReferenceRelationshipSequence'],\n '00C2': ['UI', '1', 'RelatedFrameOfReferenceUID'],\n '00C4': ['CS', '1', 'FrameOfReferenceTransformationType'],\n '00C6': ['DS', '16', 'FrameOfReferenceTransformationMatrix'],\n '00C8': ['LO', '1', 'FrameOfReferenceTransformationComment'],\n '00C9': ['SQ', '1', 'PatientLocationCoordinatesSequence'],\n '00CA': ['SQ', '1', 'PatientLocationCoordinatesCodeSequence'],\n '00CB': ['SQ', '1', 'PatientSupportPositionSequence']\n },\n '3008': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['SQ', '1', 'MeasuredDoseReferenceSequence'],\n '0012': ['ST', '1', 'MeasuredDoseDescription'],\n '0014': ['CS', '1', 'MeasuredDoseType'],\n '0016': ['DS', '1', 'MeasuredDoseValue'],\n '0020': ['SQ', '1', 'TreatmentSessionBeamSequence'],\n '0021': ['SQ', '1', 'TreatmentSessionIonBeamSequence'],\n '0022': ['IS', '1', 'CurrentFractionNumber'],\n '0024': ['DA', '1', 'TreatmentControlPointDate'],\n '0025': ['TM', '1', 'TreatmentControlPointTime'],\n '002A': ['CS', '1', 'TreatmentTerminationStatus'],\n '002B': ['SH', '1', 'TreatmentTerminationCode'],\n '002C': ['CS', '1', 'TreatmentVerificationStatus'],\n '0030': ['SQ', '1', 'ReferencedTreatmentRecordSequence'],\n '0032': ['DS', '1', 'SpecifiedPrimaryMeterset'],\n '0033': ['DS', '1', 'SpecifiedSecondaryMeterset'],\n '0036': ['DS', '1', 'DeliveredPrimaryMeterset'],\n '0037': ['DS', '1', 'DeliveredSecondaryMeterset'],\n '003A': ['DS', '1', 'SpecifiedTreatmentTime'],\n '003B': ['DS', '1', 'DeliveredTreatmentTime'],\n '0040': ['SQ', '1', 'ControlPointDeliverySequence'],\n '0041': ['SQ', '1', 'IonControlPointDeliverySequence'],\n '0042': ['DS', '1', 'SpecifiedMeterset'],\n '0044': ['DS', '1', 'DeliveredMeterset'],\n '0045': ['FL', '1', 'MetersetRateSet'],\n '0046': ['FL', '1', 'MetersetRateDelivered'],\n '0047': ['FL', '1-n', 'ScanSpotMetersetsDelivered'],\n '0048': ['DS', '1', 'DoseRateDelivered'],\n '0050': ['SQ', '1', 'TreatmentSummaryCalculatedDoseReferenceSequence'],\n '0052': ['DS', '1', 'CumulativeDoseToDoseReference'],\n '0054': ['DA', '1', 'FirstTreatmentDate'],\n '0056': ['DA', '1', 'MostRecentTreatmentDate'],\n '005A': ['IS', '1', 'NumberOfFractionsDelivered'],\n '0060': ['SQ', '1', 'OverrideSequence'],\n '0061': ['AT', '1', 'ParameterSequencePointer'],\n '0062': ['AT', '1', 'OverrideParameterPointer'],\n '0063': ['IS', '1', 'ParameterItemIndex'],\n '0064': ['IS', '1', 'MeasuredDoseReferenceNumber'],\n '0065': ['AT', '1', 'ParameterPointer'],\n '0066': ['ST', '1', 'OverrideReason'],\n '0067': ['US', '1', 'ParameterValueNumber'],\n '0068': ['SQ', '1', 'CorrectedParameterSequence'],\n '006A': ['FL', '1', 'CorrectionValue'],\n '0070': ['SQ', '1', 'CalculatedDoseReferenceSequence'],\n '0072': ['IS', '1', 'CalculatedDoseReferenceNumber'],\n '0074': ['ST', '1', 'CalculatedDoseReferenceDescription'],\n '0076': ['DS', '1', 'CalculatedDoseReferenceDoseValue'],\n '0078': ['DS', '1', 'StartMeterset'],\n '007A': ['DS', '1', 'EndMeterset'],\n '0080': ['SQ', '1', 'ReferencedMeasuredDoseReferenceSequence'],\n '0082': ['IS', '1', 'ReferencedMeasuredDoseReferenceNumber'],\n '0090': ['SQ', '1', 'ReferencedCalculatedDoseReferenceSequence'],\n '0092': ['IS', '1', 'ReferencedCalculatedDoseReferenceNumber'],\n '00A0': ['SQ', '1', 'BeamLimitingDeviceLeafPairsSequence'],\n '00B0': ['SQ', '1', 'RecordedWedgeSequence'],\n '00C0': ['SQ', '1', 'RecordedCompensatorSequence'],\n '00D0': ['SQ', '1', 'RecordedBlockSequence'],\n '00D1': ['SQ', '1', 'RecordedBlockSlabSequence'],\n '00E0': ['SQ', '1', 'TreatmentSummaryMeasuredDoseReferenceSequence'],\n '00F0': ['SQ', '1', 'RecordedSnoutSequence'],\n '00F2': ['SQ', '1', 'RecordedRangeShifterSequence'],\n '00F4': ['SQ', '1', 'RecordedLateralSpreadingDeviceSequence'],\n '00F6': ['SQ', '1', 'RecordedRangeModulatorSequence'],\n '0100': ['SQ', '1', 'RecordedSourceSequence'],\n '0105': ['LO', '1', 'SourceSerialNumber'],\n '0110': ['SQ', '1', 'TreatmentSessionApplicationSetupSequence'],\n '0116': ['CS', '1', 'ApplicationSetupCheck'],\n '0120': ['SQ', '1', 'RecordedBrachyAccessoryDeviceSequence'],\n '0122': ['IS', '1', 'ReferencedBrachyAccessoryDeviceNumber'],\n '0130': ['SQ', '1', 'RecordedChannelSequence'],\n '0132': ['DS', '1', 'SpecifiedChannelTotalTime'],\n '0134': ['DS', '1', 'DeliveredChannelTotalTime'],\n '0136': ['IS', '1', 'SpecifiedNumberOfPulses'],\n '0138': ['IS', '1', 'DeliveredNumberOfPulses'],\n '013A': ['DS', '1', 'SpecifiedPulseRepetitionInterval'],\n '013C': ['DS', '1', 'DeliveredPulseRepetitionInterval'],\n '0140': ['SQ', '1', 'RecordedSourceApplicatorSequence'],\n '0142': ['IS', '1', 'ReferencedSourceApplicatorNumber'],\n '0150': ['SQ', '1', 'RecordedChannelShieldSequence'],\n '0152': ['IS', '1', 'ReferencedChannelShieldNumber'],\n '0160': ['SQ', '1', 'BrachyControlPointDeliveredSequence'],\n '0162': ['DA', '1', 'SafePositionExitDate'],\n '0164': ['TM', '1', 'SafePositionExitTime'],\n '0166': ['DA', '1', 'SafePositionReturnDate'],\n '0168': ['TM', '1', 'SafePositionReturnTime'],\n '0171': ['SQ', '1', 'PulseSpecificBrachyControlPointDeliveredSequence'],\n '0172': ['US', '1', 'PulseNumber'],\n '0173': ['SQ', '1', 'BrachyPulseControlPointDeliveredSequence'],\n '0200': ['CS', '1', 'CurrentTreatmentStatus'],\n '0202': ['ST', '1', 'TreatmentStatusComment'],\n '0220': ['SQ', '1', 'FractionGroupSummarySequence'],\n '0223': ['IS', '1', 'ReferencedFractionNumber'],\n '0224': ['CS', '1', 'FractionGroupType'],\n '0230': ['CS', '1', 'BeamStopperPosition'],\n '0240': ['SQ', '1', 'FractionStatusSummarySequence'],\n '0250': ['DA', '1', 'TreatmentDate'],\n '0251': ['TM', '1', 'TreatmentTime']\n },\n '300A': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['SH', '1', 'RTPlanLabel'],\n '0003': ['LO', '1', 'RTPlanName'],\n '0004': ['ST', '1', 'RTPlanDescription'],\n '0006': ['DA', '1', 'RTPlanDate'],\n '0007': ['TM', '1', 'RTPlanTime'],\n '0009': ['LO', '1-n', 'TreatmentProtocols'],\n '000A': ['CS', '1', 'PlanIntent'],\n '000B': ['LO', '1-n', 'TreatmentSites'],\n '000C': ['CS', '1', 'RTPlanGeometry'],\n '000E': ['ST', '1', 'PrescriptionDescription'],\n '0010': ['SQ', '1', 'DoseReferenceSequence'],\n '0012': ['IS', '1', 'DoseReferenceNumber'],\n '0013': ['UI', '1', 'DoseReferenceUID'],\n '0014': ['CS', '1', 'DoseReferenceStructureType'],\n '0015': ['CS', '1', 'NominalBeamEnergyUnit'],\n '0016': ['LO', '1', 'DoseReferenceDescription'],\n '0018': ['DS', '3', 'DoseReferencePointCoordinates'],\n '001A': ['DS', '1', 'NominalPriorDose'],\n '0020': ['CS', '1', 'DoseReferenceType'],\n '0021': ['DS', '1', 'ConstraintWeight'],\n '0022': ['DS', '1', 'DeliveryWarningDose'],\n '0023': ['DS', '1', 'DeliveryMaximumDose'],\n '0025': ['DS', '1', 'TargetMinimumDose'],\n '0026': ['DS', '1', 'TargetPrescriptionDose'],\n '0027': ['DS', '1', 'TargetMaximumDose'],\n '0028': ['DS', '1', 'TargetUnderdoseVolumeFraction'],\n '002A': ['DS', '1', 'OrganAtRiskFullVolumeDose'],\n '002B': ['DS', '1', 'OrganAtRiskLimitDose'],\n '002C': ['DS', '1', 'OrganAtRiskMaximumDose'],\n '002D': ['DS', '1', 'OrganAtRiskOverdoseVolumeFraction'],\n '0040': ['SQ', '1', 'ToleranceTableSequence'],\n '0042': ['IS', '1', 'ToleranceTableNumber'],\n '0043': ['SH', '1', 'ToleranceTableLabel'],\n '0044': ['DS', '1', 'GantryAngleTolerance'],\n '0046': ['DS', '1', 'BeamLimitingDeviceAngleTolerance'],\n '0048': ['SQ', '1', 'BeamLimitingDeviceToleranceSequence'],\n '004A': ['DS', '1', 'BeamLimitingDevicePositionTolerance'],\n '004B': ['FL', '1', 'SnoutPositionTolerance'],\n '004C': ['DS', '1', 'PatientSupportAngleTolerance'],\n '004E': ['DS', '1', 'TableTopEccentricAngleTolerance'],\n '004F': ['FL', '1', 'TableTopPitchAngleTolerance'],\n '0050': ['FL', '1', 'TableTopRollAngleTolerance'],\n '0051': ['DS', '1', 'TableTopVerticalPositionTolerance'],\n '0052': ['DS', '1', 'TableTopLongitudinalPositionTolerance'],\n '0053': ['DS', '1', 'TableTopLateralPositionTolerance'],\n '0055': ['CS', '1', 'RTPlanRelationship'],\n '0070': ['SQ', '1', 'FractionGroupSequence'],\n '0071': ['IS', '1', 'FractionGroupNumber'],\n '0072': ['LO', '1', 'FractionGroupDescription'],\n '0078': ['IS', '1', 'NumberOfFractionsPlanned'],\n '0079': ['IS', '1', 'NumberOfFractionPatternDigitsPerDay'],\n '007A': ['IS', '1', 'RepeatFractionCycleLength'],\n '007B': ['LT', '1', 'FractionPattern'],\n '0080': ['IS', '1', 'NumberOfBeams'],\n '0082': ['DS', '3', 'BeamDoseSpecificationPoint'],\n '0083': ['UI', '1', 'ReferencedDoseReferenceUID'],\n '0084': ['DS', '1', 'BeamDose'],\n '0086': ['DS', '1', 'BeamMeterset'],\n '0088': ['FL', '1', 'BeamDosePointDepth'],\n '0089': ['FL', '1', 'BeamDosePointEquivalentDepth'],\n '008A': ['FL', '1', 'BeamDosePointSSD'],\n '008B': ['CS', '1', 'BeamDoseMeaning'],\n '008C': ['SQ', '1', 'BeamDoseVerificationControlPointSequence'],\n '008D': ['FL', '1', 'AverageBeamDosePointDepth'],\n '008E': ['FL', '1', 'AverageBeamDosePointEquivalentDepth'],\n '008F': ['FL', '1', 'AverageBeamDosePointSSD'],\n '0090': ['CS', '1', 'BeamDoseType'],\n '0091': ['DS', '1', 'AlternateBeamDose'],\n '0092': ['CS', '1', 'AlternateBeamDoseType'],\n '0093': ['CS', '1', 'DepthValueAveragingFlag'],\n '0094': ['DS', '1', 'BeamDosePointSourceToExternalContourDistance'],\n '00A0': ['IS', '1', 'NumberOfBrachyApplicationSetups'],\n '00A2': ['DS', '3', 'BrachyApplicationSetupDoseSpecificationPoint'],\n '00A4': ['DS', '1', 'BrachyApplicationSetupDose'],\n '00B0': ['SQ', '1', 'BeamSequence'],\n '00B2': ['SH', '1', 'TreatmentMachineName'],\n '00B3': ['CS', '1', 'PrimaryDosimeterUnit'],\n '00B4': ['DS', '1', 'SourceAxisDistance'],\n '00B6': ['SQ', '1', 'BeamLimitingDeviceSequence'],\n '00B8': ['CS', '1', 'RTBeamLimitingDeviceType'],\n '00BA': ['DS', '1', 'SourceToBeamLimitingDeviceDistance'],\n '00BB': ['FL', '1', 'IsocenterToBeamLimitingDeviceDistance'],\n '00BC': ['IS', '1', 'NumberOfLeafJawPairs'],\n '00BE': ['DS', '3-n', 'LeafPositionBoundaries'],\n '00C0': ['IS', '1', 'BeamNumber'],\n '00C2': ['LO', '1', 'BeamName'],\n '00C3': ['ST', '1', 'BeamDescription'],\n '00C4': ['CS', '1', 'BeamType'],\n '00C5': ['FD', '1', 'BeamDeliveryDurationLimit'],\n '00C6': ['CS', '1', 'RadiationType'],\n '00C7': ['CS', '1', 'HighDoseTechniqueType'],\n '00C8': ['IS', '1', 'ReferenceImageNumber'],\n '00CA': ['SQ', '1', 'PlannedVerificationImageSequence'],\n '00CC': ['LO', '1-n', 'ImagingDeviceSpecificAcquisitionParameters'],\n '00CE': ['CS', '1', 'TreatmentDeliveryType'],\n '00D0': ['IS', '1', 'NumberOfWedges'],\n '00D1': ['SQ', '1', 'WedgeSequence'],\n '00D2': ['IS', '1', 'WedgeNumber'],\n '00D3': ['CS', '1', 'WedgeType'],\n '00D4': ['SH', '1', 'WedgeID'],\n '00D5': ['IS', '1', 'WedgeAngle'],\n '00D6': ['DS', '1', 'WedgeFactor'],\n '00D7': ['FL', '1', 'TotalWedgeTrayWaterEquivalentThickness'],\n '00D8': ['DS', '1', 'WedgeOrientation'],\n '00D9': ['FL', '1', 'IsocenterToWedgeTrayDistance'],\n '00DA': ['DS', '1', 'SourceToWedgeTrayDistance'],\n '00DB': ['FL', '1', 'WedgeThinEdgePosition'],\n '00DC': ['SH', '1', 'BolusID'],\n '00DD': ['ST', '1', 'BolusDescription'],\n '00DE': ['DS', '1', 'EffectiveWedgeAngle'],\n '00E0': ['IS', '1', 'NumberOfCompensators'],\n '00E1': ['SH', '1', 'MaterialID'],\n '00E2': ['DS', '1', 'TotalCompensatorTrayFactor'],\n '00E3': ['SQ', '1', 'CompensatorSequence'],\n '00E4': ['IS', '1', 'CompensatorNumber'],\n '00E5': ['SH', '1', 'CompensatorID'],\n '00E6': ['DS', '1', 'SourceToCompensatorTrayDistance'],\n '00E7': ['IS', '1', 'CompensatorRows'],\n '00E8': ['IS', '1', 'CompensatorColumns'],\n '00E9': ['DS', '2', 'CompensatorPixelSpacing'],\n '00EA': ['DS', '2', 'CompensatorPosition'],\n '00EB': ['DS', '1-n', 'CompensatorTransmissionData'],\n '00EC': ['DS', '1-n', 'CompensatorThicknessData'],\n '00ED': ['IS', '1', 'NumberOfBoli'],\n '00EE': ['CS', '1', 'CompensatorType'],\n '00EF': ['SH', '1', 'CompensatorTrayID'],\n '00F0': ['IS', '1', 'NumberOfBlocks'],\n '00F2': ['DS', '1', 'TotalBlockTrayFactor'],\n '00F3': ['FL', '1', 'TotalBlockTrayWaterEquivalentThickness'],\n '00F4': ['SQ', '1', 'BlockSequence'],\n '00F5': ['SH', '1', 'BlockTrayID'],\n '00F6': ['DS', '1', 'SourceToBlockTrayDistance'],\n '00F7': ['FL', '1', 'IsocenterToBlockTrayDistance'],\n '00F8': ['CS', '1', 'BlockType'],\n '00F9': ['LO', '1', 'AccessoryCode'],\n '00FA': ['CS', '1', 'BlockDivergence'],\n '00FB': ['CS', '1', 'BlockMountingPosition'],\n '00FC': ['IS', '1', 'BlockNumber'],\n '00FE': ['LO', '1', 'BlockName'],\n '0100': ['DS', '1', 'BlockThickness'],\n '0102': ['DS', '1', 'BlockTransmission'],\n '0104': ['IS', '1', 'BlockNumberOfPoints'],\n '0106': ['DS', '2-2n', 'BlockData'],\n '0107': ['SQ', '1', 'ApplicatorSequence'],\n '0108': ['SH', '1', 'ApplicatorID'],\n '0109': ['CS', '1', 'ApplicatorType'],\n '010A': ['LO', '1', 'ApplicatorDescription'],\n '010C': ['DS', '1', 'CumulativeDoseReferenceCoefficient'],\n '010E': ['DS', '1', 'FinalCumulativeMetersetWeight'],\n '0110': ['IS', '1', 'NumberOfControlPoints'],\n '0111': ['SQ', '1', 'ControlPointSequence'],\n '0112': ['IS', '1', 'ControlPointIndex'],\n '0114': ['DS', '1', 'NominalBeamEnergy'],\n '0115': ['DS', '1', 'DoseRateSet'],\n '0116': ['SQ', '1', 'WedgePositionSequence'],\n '0118': ['CS', '1', 'WedgePosition'],\n '011A': ['SQ', '1', 'BeamLimitingDevicePositionSequence'],\n '011C': ['DS', '2-2n', 'LeafJawPositions'],\n '011E': ['DS', '1', 'GantryAngle'],\n '011F': ['CS', '1', 'GantryRotationDirection'],\n '0120': ['DS', '1', 'BeamLimitingDeviceAngle'],\n '0121': ['CS', '1', 'BeamLimitingDeviceRotationDirection'],\n '0122': ['DS', '1', 'PatientSupportAngle'],\n '0123': ['CS', '1', 'PatientSupportRotationDirection'],\n '0124': ['DS', '1', 'TableTopEccentricAxisDistance'],\n '0125': ['DS', '1', 'TableTopEccentricAngle'],\n '0126': ['CS', '1', 'TableTopEccentricRotationDirection'],\n '0128': ['DS', '1', 'TableTopVerticalPosition'],\n '0129': ['DS', '1', 'TableTopLongitudinalPosition'],\n '012A': ['DS', '1', 'TableTopLateralPosition'],\n '012C': ['DS', '3', 'IsocenterPosition'],\n '012E': ['DS', '3', 'SurfaceEntryPoint'],\n '0130': ['DS', '1', 'SourceToSurfaceDistance'],\n '0131': ['FL', '1', 'AverageBeamDosePointSourceToExternalContourDistance'],\n '0132': ['FL', '1', 'SourceToExternalContourDistance'],\n '0133': ['FL', '3', 'ExternalContourEntryPoint'],\n '0134': ['DS', '1', 'CumulativeMetersetWeight'],\n '0140': ['FL', '1', 'TableTopPitchAngle'],\n '0142': ['CS', '1', 'TableTopPitchRotationDirection'],\n '0144': ['FL', '1', 'TableTopRollAngle'],\n '0146': ['CS', '1', 'TableTopRollRotationDirection'],\n '0148': ['FL', '1', 'HeadFixationAngle'],\n '014A': ['FL', '1', 'GantryPitchAngle'],\n '014C': ['CS', '1', 'GantryPitchRotationDirection'],\n '014E': ['FL', '1', 'GantryPitchAngleTolerance'],\n '0150': ['CS', '1', 'FixationEye'],\n '0151': ['DS', '1', 'ChairHeadFramePosition'],\n '0152': ['DS', '1', 'HeadFixationAngleTolerance'],\n '0153': ['DS', '1', 'ChairHeadFramePositionTolerance'],\n '0154': ['DS', '1', 'FixationLightAzimuthalAngleTolerance'],\n '0155': ['DS', '1', 'FixationLightPolarAngleTolerance'],\n '0180': ['SQ', '1', 'PatientSetupSequence'],\n '0182': ['IS', '1', 'PatientSetupNumber'],\n '0183': ['LO', '1', 'PatientSetupLabel'],\n '0184': ['LO', '1', 'PatientAdditionalPosition'],\n '0190': ['SQ', '1', 'FixationDeviceSequence'],\n '0192': ['CS', '1', 'FixationDeviceType'],\n '0194': ['SH', '1', 'FixationDeviceLabel'],\n '0196': ['ST', '1', 'FixationDeviceDescription'],\n '0198': ['SH', '1', 'FixationDevicePosition'],\n '0199': ['FL', '1', 'FixationDevicePitchAngle'],\n '019A': ['FL', '1', 'FixationDeviceRollAngle'],\n '01A0': ['SQ', '1', 'ShieldingDeviceSequence'],\n '01A2': ['CS', '1', 'ShieldingDeviceType'],\n '01A4': ['SH', '1', 'ShieldingDeviceLabel'],\n '01A6': ['ST', '1', 'ShieldingDeviceDescription'],\n '01A8': ['SH', '1', 'ShieldingDevicePosition'],\n '01B0': ['CS', '1', 'SetupTechnique'],\n '01B2': ['ST', '1', 'SetupTechniqueDescription'],\n '01B4': ['SQ', '1', 'SetupDeviceSequence'],\n '01B6': ['CS', '1', 'SetupDeviceType'],\n '01B8': ['SH', '1', 'SetupDeviceLabel'],\n '01BA': ['ST', '1', 'SetupDeviceDescription'],\n '01BC': ['DS', '1', 'SetupDeviceParameter'],\n '01D0': ['ST', '1', 'SetupReferenceDescription'],\n '01D2': ['DS', '1', 'TableTopVerticalSetupDisplacement'],\n '01D4': ['DS', '1', 'TableTopLongitudinalSetupDisplacement'],\n '01D6': ['DS', '1', 'TableTopLateralSetupDisplacement'],\n '0200': ['CS', '1', 'BrachyTreatmentTechnique'],\n '0202': ['CS', '1', 'BrachyTreatmentType'],\n '0206': ['SQ', '1', 'TreatmentMachineSequence'],\n '0210': ['SQ', '1', 'SourceSequence'],\n '0212': ['IS', '1', 'SourceNumber'],\n '0214': ['CS', '1', 'SourceType'],\n '0216': ['LO', '1', 'SourceManufacturer'],\n '0218': ['DS', '1', 'ActiveSourceDiameter'],\n '021A': ['DS', '1', 'ActiveSourceLength'],\n '021B': ['SH', '1', 'SourceModelID'],\n '021C': ['LO', '1', 'SourceDescription'],\n '0222': ['DS', '1', 'SourceEncapsulationNominalThickness'],\n '0224': ['DS', '1', 'SourceEncapsulationNominalTransmission'],\n '0226': ['LO', '1', 'SourceIsotopeName'],\n '0228': ['DS', '1', 'SourceIsotopeHalfLife'],\n '0229': ['CS', '1', 'SourceStrengthUnits'],\n '022A': ['DS', '1', 'ReferenceAirKermaRate'],\n '022B': ['DS', '1', 'SourceStrength'],\n '022C': ['DA', '1', 'SourceStrengthReferenceDate'],\n '022E': ['TM', '1', 'SourceStrengthReferenceTime'],\n '0230': ['SQ', '1', 'ApplicationSetupSequence'],\n '0232': ['CS', '1', 'ApplicationSetupType'],\n '0234': ['IS', '1', 'ApplicationSetupNumber'],\n '0236': ['LO', '1', 'ApplicationSetupName'],\n '0238': ['LO', '1', 'ApplicationSetupManufacturer'],\n '0240': ['IS', '1', 'TemplateNumber'],\n '0242': ['SH', '1', 'TemplateType'],\n '0244': ['LO', '1', 'TemplateName'],\n '0250': ['DS', '1', 'TotalReferenceAirKerma'],\n '0260': ['SQ', '1', 'BrachyAccessoryDeviceSequence'],\n '0262': ['IS', '1', 'BrachyAccessoryDeviceNumber'],\n '0263': ['SH', '1', 'BrachyAccessoryDeviceID'],\n '0264': ['CS', '1', 'BrachyAccessoryDeviceType'],\n '0266': ['LO', '1', 'BrachyAccessoryDeviceName'],\n '026A': ['DS', '1', 'BrachyAccessoryDeviceNominalThickness'],\n '026C': ['DS', '1', 'BrachyAccessoryDeviceNominalTransmission'],\n '0271': ['DS', '1', 'ChannelEffectiveLength'],\n '0272': ['DS', '1', 'ChannelInnerLength'],\n '0273': ['SH', '1', 'AfterloaderChannelID'],\n '0274': ['DS', '1', 'SourceApplicatorTipLength'],\n '0280': ['SQ', '1', 'ChannelSequence'],\n '0282': ['IS', '1', 'ChannelNumber'],\n '0284': ['DS', '1', 'ChannelLength'],\n '0286': ['DS', '1', 'ChannelTotalTime'],\n '0288': ['CS', '1', 'SourceMovementType'],\n '028A': ['IS', '1', 'NumberOfPulses'],\n '028C': ['DS', '1', 'PulseRepetitionInterval'],\n '0290': ['IS', '1', 'SourceApplicatorNumber'],\n '0291': ['SH', '1', 'SourceApplicatorID'],\n '0292': ['CS', '1', 'SourceApplicatorType'],\n '0294': ['LO', '1', 'SourceApplicatorName'],\n '0296': ['DS', '1', 'SourceApplicatorLength'],\n '0298': ['LO', '1', 'SourceApplicatorManufacturer'],\n '029C': ['DS', '1', 'SourceApplicatorWallNominalThickness'],\n '029E': ['DS', '1', 'SourceApplicatorWallNominalTransmission'],\n '02A0': ['DS', '1', 'SourceApplicatorStepSize'],\n '02A1': ['IS', '1', 'ApplicatorShapeReferencedROINumber'],\n '02A2': ['IS', '1', 'TransferTubeNumber'],\n '02A4': ['DS', '1', 'TransferTubeLength'],\n '02B0': ['SQ', '1', 'ChannelShieldSequence'],\n '02B2': ['IS', '1', 'ChannelShieldNumber'],\n '02B3': ['SH', '1', 'ChannelShieldID'],\n '02B4': ['LO', '1', 'ChannelShieldName'],\n '02B8': ['DS', '1', 'ChannelShieldNominalThickness'],\n '02BA': ['DS', '1', 'ChannelShieldNominalTransmission'],\n '02C8': ['DS', '1', 'FinalCumulativeTimeWeight'],\n '02D0': ['SQ', '1', 'BrachyControlPointSequence'],\n '02D2': ['DS', '1', 'ControlPointRelativePosition'],\n '02D4': ['DS', '3', 'ControlPoint3DPosition'],\n '02D6': ['DS', '1', 'CumulativeTimeWeight'],\n '02E0': ['CS', '1', 'CompensatorDivergence'],\n '02E1': ['CS', '1', 'CompensatorMountingPosition'],\n '02E2': ['DS', '1-n', 'SourceToCompensatorDistance'],\n '02E3': ['FL', '1', 'TotalCompensatorTrayWaterEquivalentThickness'],\n '02E4': ['FL', '1', 'IsocenterToCompensatorTrayDistance'],\n '02E5': ['FL', '1', 'CompensatorColumnOffset'],\n '02E6': ['FL', '1-n', 'IsocenterToCompensatorDistances'],\n '02E7': ['FL', '1', 'CompensatorRelativeStoppingPowerRatio'],\n '02E8': ['FL', '1', 'CompensatorMillingToolDiameter'],\n '02EA': ['SQ', '1', 'IonRangeCompensatorSequence'],\n '02EB': ['LT', '1', 'CompensatorDescription'],\n '0302': ['IS', '1', 'RadiationMassNumber'],\n '0304': ['IS', '1', 'RadiationAtomicNumber'],\n '0306': ['SS', '1', 'RadiationChargeState'],\n '0308': ['CS', '1', 'ScanMode'],\n '0309': ['CS', '1', 'ModulatedScanModeType'],\n '030A': ['FL', '2', 'VirtualSourceAxisDistances'],\n '030C': ['SQ', '1', 'SnoutSequence'],\n '030D': ['FL', '1', 'SnoutPosition'],\n '030F': ['SH', '1', 'SnoutID'],\n '0312': ['IS', '1', 'NumberOfRangeShifters'],\n '0314': ['SQ', '1', 'RangeShifterSequence'],\n '0316': ['IS', '1', 'RangeShifterNumber'],\n '0318': ['SH', '1', 'RangeShifterID'],\n '0320': ['CS', '1', 'RangeShifterType'],\n '0322': ['LO', '1', 'RangeShifterDescription'],\n '0330': ['IS', '1', 'NumberOfLateralSpreadingDevices'],\n '0332': ['SQ', '1', 'LateralSpreadingDeviceSequence'],\n '0334': ['IS', '1', 'LateralSpreadingDeviceNumber'],\n '0336': ['SH', '1', 'LateralSpreadingDeviceID'],\n '0338': ['CS', '1', 'LateralSpreadingDeviceType'],\n '033A': ['LO', '1', 'LateralSpreadingDeviceDescription'],\n '033C': ['FL', '1', 'LateralSpreadingDeviceWaterEquivalentThickness'],\n '0340': ['IS', '1', 'NumberOfRangeModulators'],\n '0342': ['SQ', '1', 'RangeModulatorSequence'],\n '0344': ['IS', '1', 'RangeModulatorNumber'],\n '0346': ['SH', '1', 'RangeModulatorID'],\n '0348': ['CS', '1', 'RangeModulatorType'],\n '034A': ['LO', '1', 'RangeModulatorDescription'],\n '034C': ['SH', '1', 'BeamCurrentModulationID'],\n '0350': ['CS', '1', 'PatientSupportType'],\n '0352': ['SH', '1', 'PatientSupportID'],\n '0354': ['LO', '1', 'PatientSupportAccessoryCode'],\n '0355': ['LO', '1', 'TrayAccessoryCode'],\n '0356': ['FL', '1', 'FixationLightAzimuthalAngle'],\n '0358': ['FL', '1', 'FixationLightPolarAngle'],\n '035A': ['FL', '1', 'MetersetRate'],\n '0360': ['SQ', '1', 'RangeShifterSettingsSequence'],\n '0362': ['LO', '1', 'RangeShifterSetting'],\n '0364': ['FL', '1', 'IsocenterToRangeShifterDistance'],\n '0366': ['FL', '1', 'RangeShifterWaterEquivalentThickness'],\n '0370': ['SQ', '1', 'LateralSpreadingDeviceSettingsSequence'],\n '0372': ['LO', '1', 'LateralSpreadingDeviceSetting'],\n '0374': ['FL', '1', 'IsocenterToLateralSpreadingDeviceDistance'],\n '0380': ['SQ', '1', 'RangeModulatorSettingsSequence'],\n '0382': ['FL', '1', 'RangeModulatorGatingStartValue'],\n '0384': ['FL', '1', 'RangeModulatorGatingStopValue'],\n '0386': ['FL', '1', 'RangeModulatorGatingStartWaterEquivalentThickness'],\n '0388': ['FL', '1', 'RangeModulatorGatingStopWaterEquivalentThickness'],\n '038A': ['FL', '1', 'IsocenterToRangeModulatorDistance'],\n '038F': ['FL', '1-n', 'ScanSpotTimeOffset'],\n '0390': ['SH', '1', 'ScanSpotTuneID'],\n '0391': ['IS', '1-n', 'ScanSpotPrescribedIndices'],\n '0392': ['IS', '1', 'NumberOfScanSpotPositions'],\n '0393': ['CS', '1', 'ScanSpotReordered'],\n '0394': ['FL', '1-n', 'ScanSpotPositionMap'],\n '0395': ['CS', '1', 'ScanSpotReorderingAllowed'],\n '0396': ['FL', '1-n', 'ScanSpotMetersetWeights'],\n '0398': ['FL', '2', 'ScanningSpotSize'],\n '0399': ['FL', '2-2n', 'ScanSpotSizesDelivered'],\n '039A': ['IS', '1', 'NumberOfPaintings'],\n '03A0': ['SQ', '1', 'IonToleranceTableSequence'],\n '03A2': ['SQ', '1', 'IonBeamSequence'],\n '03A4': ['SQ', '1', 'IonBeamLimitingDeviceSequence'],\n '03A6': ['SQ', '1', 'IonBlockSequence'],\n '03A8': ['SQ', '1', 'IonControlPointSequence'],\n '03AA': ['SQ', '1', 'IonWedgeSequence'],\n '03AC': ['SQ', '1', 'IonWedgePositionSequence'],\n '0401': ['SQ', '1', 'ReferencedSetupImageSequence'],\n '0402': ['ST', '1', 'SetupImageComment'],\n '0410': ['SQ', '1', 'MotionSynchronizationSequence'],\n '0412': ['FL', '3', 'ControlPointOrientation'],\n '0420': ['SQ', '1', 'GeneralAccessorySequence'],\n '0421': ['SH', '1', 'GeneralAccessoryID'],\n '0422': ['ST', '1', 'GeneralAccessoryDescription'],\n '0423': ['CS', '1', 'GeneralAccessoryType'],\n '0424': ['IS', '1', 'GeneralAccessoryNumber'],\n '0425': ['FL', '1', 'SourceToGeneralAccessoryDistance'],\n '0426': ['DS', '1', 'IsocenterToGeneralAccessoryDistance'],\n '0431': ['SQ', '1', 'ApplicatorGeometrySequence'],\n '0432': ['CS', '1', 'ApplicatorApertureShape'],\n '0433': ['FL', '1', 'ApplicatorOpening'],\n '0434': ['FL', '1', 'ApplicatorOpeningX'],\n '0435': ['FL', '1', 'ApplicatorOpeningY'],\n '0436': ['FL', '1', 'SourceToApplicatorMountingPositionDistance'],\n '0440': ['IS', '1', 'NumberOfBlockSlabItems'],\n '0441': ['SQ', '1', 'BlockSlabSequence'],\n '0442': ['DS', '1', 'BlockSlabThickness'],\n '0443': ['US', '1', 'BlockSlabNumber'],\n '0450': ['SQ', '1', 'DeviceMotionControlSequence'],\n '0451': ['CS', '1', 'DeviceMotionExecutionMode'],\n '0452': ['CS', '1', 'DeviceMotionObservationMode'],\n '0453': ['SQ', '1', 'DeviceMotionParameterCodeSequence'],\n '0501': ['FL', '1', 'DistalDepthFraction'],\n '0502': ['FL', '1', 'DistalDepth'],\n '0503': ['FL', '2', 'NominalRangeModulationFractions'],\n '0504': ['FL', '2', 'NominalRangeModulatedRegionDepths'],\n '0505': ['SQ', '1', 'DepthDoseParametersSequence'],\n '0506': ['SQ', '1', 'DeliveredDepthDoseParametersSequence'],\n '0507': ['FL', '1', 'DeliveredDistalDepthFraction'],\n '0508': ['FL', '1', 'DeliveredDistalDepth'],\n '0509': ['FL', '2', 'DeliveredNominalRangeModulationFractions'],\n '0510': ['FL', '2', 'DeliveredNominalRangeModulatedRegionDepths'],\n '0511': ['CS', '1', 'DeliveredReferenceDoseDefinition'],\n '0512': ['CS', '1', 'ReferenceDoseDefinition'],\n '0600': ['US', '1', 'RTControlPointIndex'],\n '0601': ['US', '1', 'RadiationGenerationModeIndex'],\n '0602': ['US', '1', 'ReferencedDefinedDeviceIndex'],\n '0603': ['US', '1', 'RadiationDoseIdentificationIndex'],\n '0604': ['US', '1', 'NumberOfRTControlPoints'],\n '0605': ['US', '1', 'ReferencedRadiationGenerationModeIndex'],\n '0606': ['US', '1', 'TreatmentPositionIndex'],\n '0607': ['US', '1', 'ReferencedDeviceIndex'],\n '0608': ['LO', '1', 'TreatmentPositionGroupLabel'],\n '0609': ['UI', '1', 'TreatmentPositionGroupUID'],\n '060A': ['SQ', '1', 'TreatmentPositionGroupSequence'],\n '060B': ['US', '1', 'ReferencedTreatmentPositionIndex'],\n '060C': ['US', '1', 'ReferencedRadiationDoseIdentificationIndex'],\n '060D': ['FD', '1', 'RTAccessoryHolderWaterEquivalentThickness'],\n '060E': ['US', '1', 'ReferencedRTAccessoryHolderDeviceIndex'],\n '060F': ['CS', '1', 'RTAccessoryHolderSlotExistenceFlag'],\n '0610': ['SQ', '1', 'RTAccessoryHolderSlotSequence'],\n '0611': ['LO', '1', 'RTAccessoryHolderSlotID'],\n '0612': ['FD', '1', 'RTAccessoryHolderSlotDistance'],\n '0613': ['FD', '1', 'RTAccessorySlotDistance'],\n '0614': ['SQ', '1', 'RTAccessoryHolderDefinitionSequence'],\n '0615': ['LO', '1', 'RTAccessoryDeviceSlotID'],\n '0616': ['SQ', '1', 'RTRadiationSequence'],\n '0617': ['SQ', '1', 'RadiationDoseSequence'],\n '0618': ['SQ', '1', 'RadiationDoseIdentificationSequence'],\n '0619': ['LO', '1', 'RadiationDoseIdentificationLabel'],\n '061A': ['CS', '1', 'ReferenceDoseType'],\n '061B': ['CS', '1', 'PrimaryDoseValueIndicator'],\n '061C': ['SQ', '1', 'DoseValuesSequence'],\n '061D': ['CS', '1-n', 'DoseValuePurpose'],\n '061E': ['FD', '3', 'ReferenceDosePointCoordinates'],\n '061F': ['SQ', '1', 'RadiationDoseValuesParametersSequence'],\n '0620': ['SQ', '1', 'MetersetToDoseMappingSequence'],\n '0621': ['SQ', '1', 'ExpectedInVivoMeasurementValuesSequence'],\n '0622': ['US', '1', 'ExpectedInVivoMeasurementValueIndex'],\n '0623': ['LO', '1', 'RadiationDoseInVivoMeasurementLabel'],\n '0624': ['FD', '2', 'RadiationDoseCentralAxisDisplacement'],\n '0625': ['FD', '1', 'RadiationDoseValue'],\n '0626': ['FD', '1', 'RadiationDoseSourceToSkinDistance'],\n '0627': ['FD', '3', 'RadiationDoseMeasurementPointCoordinates'],\n '0628': ['FD', '1', 'RadiationDoseSourceToExternalContourDistance'],\n '0629': ['SQ', '1', 'RTToleranceSetSequence'],\n '062A': ['LO', '1', 'RTToleranceSetLabel'],\n '062B': ['SQ', '1', 'AttributeToleranceValuesSequence'],\n '062C': ['FD', '1', 'ToleranceValue'],\n '062D': ['SQ', '1', 'PatientSupportPositionToleranceSequence'],\n '062E': ['FD', '1', 'TreatmentTimeLimit'],\n '062F': ['SQ', '1', 'CArmPhotonElectronControlPointSequence'],\n '0630': ['SQ', '1', 'ReferencedRTRadiationSequence'],\n '0631': ['SQ', '1', 'ReferencedRTInstanceSequence'],\n '0632': ['SQ', '1', 'ReferencedRTPatientSetupSequence'],\n '0634': ['FD', '1', 'SourceToPatientSurfaceDistance'],\n '0635': ['SQ', '1', 'TreatmentMachineSpecialModeCodeSequence'],\n '0636': ['US', '1', 'IntendedNumberOfFractions'],\n '0637': ['CS', '1', 'RTRadiationSetIntent'],\n '0638': ['CS', '1', 'RTRadiationPhysicalAndGeometricContentDetailFlag'],\n '0639': ['CS', '1', 'RTRecordFlag'],\n '063A': ['SQ', '1', 'TreatmentDeviceIdentificationSequence'],\n '063B': ['SQ', '1', 'ReferencedRTPhysicianIntentSequence'],\n '063C': ['FD', '1', 'CumulativeMeterset'],\n '063D': ['FD', '1', 'DeliveryRate'],\n '063E': ['SQ', '1', 'DeliveryRateUnitSequence'],\n '063F': ['SQ', '1', 'TreatmentPositionSequence'],\n '0640': ['FD', '1', 'RadiationSourceAxisDistance'],\n '0641': ['US', '1', 'NumberOfRTBeamLimitingDevices'],\n '0642': ['FD', '1', 'RTBeamLimitingDeviceProximalDistance'],\n '0643': ['FD', '1', 'RTBeamLimitingDeviceDistalDistance'],\n '0644': ['SQ', '1', 'ParallelRTBeamDelimiterDeviceOrientationLabelCodeSequence'],\n '0645': ['FD', '1', 'BeamModifierOrientationAngle'],\n '0646': ['SQ', '1', 'FixedRTBeamDelimiterDeviceSequence'],\n '0647': ['SQ', '1', 'ParallelRTBeamDelimiterDeviceSequence'],\n '0648': ['US', '1', 'NumberOfParallelRTBeamDelimiters'],\n '0649': ['FD', '2-n', 'ParallelRTBeamDelimiterBoundaries'],\n '064A': ['FD', '2-n', 'ParallelRTBeamDelimiterPositions'],\n '064B': ['FD', '2', 'RTBeamLimitingDeviceOffset'],\n '064C': ['SQ', '1', 'RTBeamDelimiterGeometrySequence'],\n '064D': ['SQ', '1', 'RTBeamLimitingDeviceDefinitionSequence'],\n '064E': ['CS', '1', 'ParallelRTBeamDelimiterOpeningMode'],\n '064F': ['CS', '1-n', 'ParallelRTBeamDelimiterLeafMountingSide'],\n '0650': ['UI', '1', 'PatientSetupUID'],\n '0651': ['SQ', '1', 'WedgeDefinitionSequence'],\n '0652': ['FD', '1', 'RadiationBeamWedgeAngle'],\n '0653': ['FD', '1', 'RadiationBeamWedgeThinEdgeDistance'],\n '0654': ['FD', '1', 'RadiationBeamEffectiveWedgeAngle'],\n '0655': ['US', '1', 'NumberOfWedgePositions'],\n '0656': ['SQ', '1', 'RTBeamLimitingDeviceOpeningSequence'],\n '0657': ['US', '1', 'NumberOfRTBeamLimitingDeviceOpenings'],\n '0658': ['SQ', '1', 'RadiationDosimeterUnitSequence'],\n '0659': ['SQ', '1', 'RTDeviceDistanceReferenceLocationCodeSequence'],\n '065A': ['SQ', '1', 'RadiationDeviceConfigurationAndCommissioningKeySequence'],\n '065B': ['SQ', '1', 'PatientSupportPositionParameterSequence'],\n '065C': ['CS', '1', 'PatientSupportPositionSpecificationMethod'],\n '065D': ['SQ', '1', 'PatientSupportPositionDeviceParameterSequence'],\n '065E': ['US', '1', 'DeviceOrderIndex'],\n '065F': ['US', '1', 'PatientSupportPositionParameterOrderIndex'],\n '0660': ['SQ', '1', 'PatientSupportPositionDeviceToleranceSequence'],\n '0661': ['US', '1', 'PatientSupportPositionToleranceOrderIndex'],\n '0662': ['SQ', '1', 'CompensatorDefinitionSequence'],\n '0663': ['CS', '1', 'CompensatorMapOrientation'],\n '0664': ['OF', '1', 'CompensatorProximalThicknessMap'],\n '0665': ['OF', '1', 'CompensatorDistalThicknessMap'],\n '0666': ['FD', '1', 'CompensatorBasePlaneOffset'],\n '0667': ['SQ', '1', 'CompensatorShapeFabricationCodeSequence'],\n '0668': ['SQ', '1', 'CompensatorShapeSequence'],\n '0669': ['FD', '1', 'RadiationBeamCompensatorMillingToolDiameter'],\n '066A': ['SQ', '1', 'BlockDefinitionSequence'],\n '066B': ['OF', '1', 'BlockEdgeData'],\n '066C': ['CS', '1', 'BlockOrientation'],\n '066D': ['FD', '1', 'RadiationBeamBlockThickness'],\n '066E': ['FD', '1', 'RadiationBeamBlockSlabThickness'],\n '066F': ['SQ', '1', 'BlockEdgeDataSequence'],\n '0670': ['US', '1', 'NumberOfRTAccessoryHolders'],\n '0671': ['SQ', '1', 'GeneralAccessoryDefinitionSequence'],\n '0672': ['US', '1', 'NumberOfGeneralAccessories'],\n '0673': ['SQ', '1', 'BolusDefinitionSequence'],\n '0674': ['US', '1', 'NumberOfBoluses'],\n '0675': ['UI', '1', 'EquipmentFrameOfReferenceUID'],\n '0676': ['ST', '1', 'EquipmentFrameOfReferenceDescription'],\n '0677': ['SQ', '1', 'EquipmentReferencePointCoordinatesSequence'],\n '0678': ['SQ', '1', 'EquipmentReferencePointCodeSequence'],\n '0679': ['FD', '1', 'RTBeamLimitingDeviceAngle'],\n '067A': ['FD', '1', 'SourceRollAngle'],\n '067B': ['SQ', '1', 'RadiationGenerationModeSequence'],\n '067C': ['SH', '1', 'RadiationGenerationModeLabel'],\n '067D': ['ST', '1', 'RadiationGenerationModeDescription'],\n '067E': ['SQ', '1', 'RadiationGenerationModeMachineCodeSequence'],\n '067F': ['SQ', '1', 'RadiationTypeCodeSequence'],\n '0680': ['DS', '1', 'NominalEnergy'],\n '0681': ['DS', '1', 'MinimumNominalEnergy'],\n '0682': ['DS', '1', 'MaximumNominalEnergy'],\n '0683': ['SQ', '1', 'RadiationFluenceModifierCodeSequence'],\n '0684': ['SQ', '1', 'EnergyUnitCodeSequence'],\n '0685': ['US', '1', 'NumberOfRadiationGenerationModes'],\n '0686': ['SQ', '1', 'PatientSupportDevicesSequence'],\n '0687': ['US', '1', 'NumberOfPatientSupportDevices'],\n '0688': ['FD', '1', 'RTBeamModifierDefinitionDistance'],\n '0689': ['SQ', '1', 'BeamAreaLimitSequence'],\n '068A': ['SQ', '1', 'ReferencedRTPrescriptionSequence'],\n '0700': ['UI', '1', 'TreatmentSessionUID'],\n '0701': ['CS', '1', 'RTRadiationUsage'],\n '0702': ['SQ', '1', 'ReferencedRTRadiationSetSequence'],\n '0703': ['SQ', '1', 'ReferencedRTRadiationRecordSequence'],\n '0704': ['US', '1', 'RTRadiationSetDeliveryNumber'],\n '0705': ['US', '1', 'ClinicalFractionNumber'],\n '0706': ['CS', '1', 'RTTreatmentFractionCompletionStatus'],\n '0707': ['CS', '1', 'RTRadiationSetUsage'],\n '0708': ['CS', '1', 'TreatmentDeliveryContinuationFlag'],\n '0709': ['CS', '1', 'TreatmentRecordContentOrigin'],\n '0714': ['CS', '1', 'RTTreatmentTerminationStatus'],\n '0715': ['SQ', '1', 'RTTreatmentTerminationReasonCodeSequence'],\n '0716': ['SQ', '1', 'MachineSpecificTreatmentTerminationCodeSequence'],\n '0722': ['SQ', '1', 'RTRadiationSalvageRecordControlPointSequence'],\n '0723': ['CS', '1', 'StartingMetersetValueKnownFlag'],\n '0730': ['ST', '1', 'TreatmentTerminationDescription'],\n '0731': ['SQ', '1', 'TreatmentToleranceViolationSequence'],\n '0732': ['CS', '1', 'TreatmentToleranceViolationCategory'],\n '0733': ['SQ', '1', 'TreatmentToleranceViolationAttributeSequence'],\n '0734': ['ST', '1', 'TreatmentToleranceViolationDescription'],\n '0735': ['ST', '1', 'TreatmentToleranceViolationIdentification'],\n '0736': ['DT', '1', 'TreatmentToleranceViolationDateTime'],\n '073A': ['DT', '1', 'RecordedRTControlPointDateTime'],\n '073B': ['US', '1', 'ReferencedRadiationRTControlPointIndex'],\n '073E': ['SQ', '1', 'AlternateValueSequence'],\n '073F': ['SQ', '1', 'ConfirmationSequence'],\n '0740': ['SQ', '1', 'InterlockSequence'],\n '0741': ['DT', '1', 'InterlockDateTime'],\n '0742': ['ST', '1', 'InterlockDescription'],\n '0743': ['SQ', '1', 'InterlockOriginatingDeviceSequence'],\n '0744': ['SQ', '1', 'InterlockCodeSequence'],\n '0745': ['SQ', '1', 'InterlockResolutionCodeSequence'],\n '0746': ['SQ', '1', 'InterlockResolutionUserSequence'],\n '0760': ['DT', '1', 'OverrideDateTime'],\n '0761': ['SQ', '1', 'TreatmentToleranceViolationTypeCodeSequence'],\n '0762': ['SQ', '1', 'TreatmentToleranceViolationCauseCodeSequence'],\n '0772': ['SQ', '1', 'MeasuredMetersetToDoseMappingSequence'],\n '0773': ['US', '1', 'ReferencedExpectedInVivoMeasurementValueIndex'],\n '0774': ['SQ', '1', 'DoseMeasurementDeviceCodeSequence'],\n '0780': ['SQ', '1', 'AdditionalParameterRecordingInstanceSequence'],\n '0782': ['US', '1', ''],\n '0783': ['ST', '1', 'InterlockOriginDescription'],\n '0784': ['SQ', '1', 'RTPatientPositionScopeSequence'],\n '0785': ['UI', '1', 'ReferencedTreatmentPositionGroupUID'],\n '0786': ['US', '1', 'RadiationOrderIndex'],\n '0787': ['SQ', '1', 'OmittedRadiationSequence'],\n '0788': ['SQ', '1', 'ReasonForOmissionCodeSequence'],\n '0789': ['SQ', '1', 'RTDeliveryStartPatientPositionSequence'],\n '078A': ['SQ', '1', 'RTTreatmentPreparationPatientPositionSequence'],\n '078B': ['SQ', '1', 'ReferencedRTTreatmentPreparationSequence'],\n '078C': ['SQ', '1', 'ReferencedPatientSetupPhotoSequence'],\n '078D': ['SQ', '1', 'PatientTreatmentPreparationMethodCodeSequence'],\n '078E': ['LT', '1', 'PatientTreatmentPreparationProcedureParameterDescription'],\n '078F': ['SQ', '1', 'PatientTreatmentPreparationDeviceSequence'],\n '0790': ['SQ', '1', 'PatientTreatmentPreparationProcedureSequence'],\n '0791': ['SQ', '1', 'PatientTreatmentPreparationProcedureCodeSequence'],\n '0792': ['LT', '1', 'PatientTreatmentPreparationMethodDescription'],\n '0793': ['SQ', '1', 'PatientTreatmentPreparationProcedureParameterSequence'],\n '0794': ['LT', '1', 'PatientSetupPhotoDescription'],\n '0795': ['US', '1', 'PatientTreatmentPreparationProcedureIndex'],\n '0796': ['US', '1', 'ReferencedPatientSetupProcedureIndex'],\n '0797': ['SQ', '1', 'RTRadiationTaskSequence'],\n '0798': ['SQ', '1', 'RTPatientPositionDisplacementSequence'],\n '0799': ['SQ', '1', 'RTPatientPositionSequence'],\n '079A': ['LO', '1', 'DisplacementReferenceLabel'],\n '079B': ['FD', '16', 'DisplacementMatrix'],\n '079C': ['SQ', '1', 'PatientSupportDisplacementSequence'],\n '079D': ['SQ', '1', 'DisplacementReferenceLocationCodeSequence'],\n '079E': ['CS', '1', 'RTRadiationSetDeliveryUsage']\n },\n '300C': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['SQ', '1', 'ReferencedRTPlanSequence'],\n '0004': ['SQ', '1', 'ReferencedBeamSequence'],\n '0006': ['IS', '1', 'ReferencedBeamNumber'],\n '0007': ['IS', '1', 'ReferencedReferenceImageNumber'],\n '0008': ['DS', '1', 'StartCumulativeMetersetWeight'],\n '0009': ['DS', '1', 'EndCumulativeMetersetWeight'],\n '000A': ['SQ', '1', 'ReferencedBrachyApplicationSetupSequence'],\n '000C': ['IS', '1', 'ReferencedBrachyApplicationSetupNumber'],\n '000E': ['IS', '1', 'ReferencedSourceNumber'],\n '0020': ['SQ', '1', 'ReferencedFractionGroupSequence'],\n '0022': ['IS', '1', 'ReferencedFractionGroupNumber'],\n '0040': ['SQ', '1', 'ReferencedVerificationImageSequence'],\n '0042': ['SQ', '1', 'ReferencedReferenceImageSequence'],\n '0050': ['SQ', '1', 'ReferencedDoseReferenceSequence'],\n '0051': ['IS', '1', 'ReferencedDoseReferenceNumber'],\n '0055': ['SQ', '1', 'BrachyReferencedDoseReferenceSequence'],\n '0060': ['SQ', '1', 'ReferencedStructureSetSequence'],\n '006A': ['IS', '1', 'ReferencedPatientSetupNumber'],\n '0080': ['SQ', '1', 'ReferencedDoseSequence'],\n '00A0': ['IS', '1', 'ReferencedToleranceTableNumber'],\n '00B0': ['SQ', '1', 'ReferencedBolusSequence'],\n '00C0': ['IS', '1', 'ReferencedWedgeNumber'],\n '00D0': ['IS', '1', 'ReferencedCompensatorNumber'],\n '00E0': ['IS', '1', 'ReferencedBlockNumber'],\n '00F0': ['IS', '1', 'ReferencedControlPointIndex'],\n '00F2': ['SQ', '1', 'ReferencedControlPointSequence'],\n '00F4': ['IS', '1', 'ReferencedStartControlPointIndex'],\n '00F6': ['IS', '1', 'ReferencedStopControlPointIndex'],\n '0100': ['IS', '1', 'ReferencedRangeShifterNumber'],\n '0102': ['IS', '1', 'ReferencedLateralSpreadingDeviceNumber'],\n '0104': ['IS', '1', 'ReferencedRangeModulatorNumber'],\n '0111': ['SQ', '1', 'OmittedBeamTaskSequence'],\n '0112': ['CS', '1', 'ReasonForOmission'],\n '0113': ['LO', '1', 'ReasonForOmissionDescription'],\n '0114': ['SQ', '1', 'PrescriptionOverviewSequence'],\n '0115': ['FL', '1', 'TotalPrescriptionDose'],\n '0116': ['SQ', '1', 'PlanOverviewSequence'],\n '0117': ['US', '1', 'PlanOverviewIndex'],\n '0118': ['US', '1', 'ReferencedPlanOverviewIndex'],\n '0119': ['US', '1', 'NumberOfFractionsIncluded'],\n '0120': ['SQ', '1', 'DoseCalibrationConditionsSequence'],\n '0121': ['FD', '1', 'AbsorbedDoseToMetersetRatio'],\n '0122': ['FD', '2', 'DelineatedRadiationFieldSize'],\n '0123': ['CS', '1', 'DoseCalibrationConditionsVerifiedFlag'],\n '0124': ['FD', '1', 'CalibrationReferencePointDepth'],\n '0125': ['SQ', '1', 'GatingBeamHoldTransitionSequence'],\n '0126': ['CS', '1', 'BeamHoldTransition'],\n '0127': ['DT', '1', 'BeamHoldTransitionDateTime'],\n '0128': ['SQ', '1', 'BeamHoldOriginatingDeviceSequence']\n },\n '300E': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0002': ['CS', '1', 'ApprovalStatus'],\n '0004': ['DA', '1', 'ReviewDate'],\n '0005': ['TM', '1', 'ReviewTime'],\n '0008': ['PN', '1', 'ReviewerName']\n },\n '3010': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['SQ', '1', 'RadiobiologicalDoseEffectSequence'],\n '0002': ['CS', '1', 'RadiobiologicalDoseEffectFlag'],\n '0003': ['SQ', '1', 'EffectiveDoseCalculationMethodCategoryCodeSequence'],\n '0004': ['SQ', '1', 'EffectiveDoseCalculationMethodCodeSequence'],\n '0005': ['LO', '1', 'EffectiveDoseCalculationMethodDescription'],\n '0006': ['UI', '1', 'ConceptualVolumeUID'],\n '0007': ['SQ', '1', 'OriginatingSOPInstanceReferenceSequence'],\n '0008': ['SQ', '1', 'ConceptualVolumeConstituentSequence'],\n '0009': ['SQ', '1', 'EquivalentConceptualVolumeInstanceReferenceSequence'],\n '000A': ['SQ', '1', 'EquivalentConceptualVolumesSequence'],\n '000B': ['UI', '1', 'ReferencedConceptualVolumeUID'],\n '000C': ['UT', '1', 'ConceptualVolumeCombinationExpression'],\n '000D': ['US', '1', 'ConceptualVolumeConstituentIndex'],\n '000E': ['CS', '1', 'ConceptualVolumeCombinationFlag'],\n '000F': ['ST', '1', 'ConceptualVolumeCombinationDescription'],\n '0010': ['CS', '1', 'ConceptualVolumeSegmentationDefinedFlag'],\n '0011': ['SQ', '1', 'ConceptualVolumeSegmentationReferenceSequence'],\n '0012': ['SQ', '1', 'ConceptualVolumeConstituentSegmentationReferenceSequence'],\n '0013': ['UI', '1', 'ConstituentConceptualVolumeUID'],\n '0014': ['SQ', '1', 'DerivationConceptualVolumeSequence'],\n '0015': ['UI', '1', 'SourceConceptualVolumeUID'],\n '0016': ['SQ', '1', 'ConceptualVolumeDerivationAlgorithmSequence'],\n '0017': ['ST', '1', 'ConceptualVolumeDescription'],\n '0018': ['SQ', '1', 'SourceConceptualVolumeSequence'],\n '0019': ['SQ', '1', 'AuthorIdentificationSequence'],\n '001A': ['LO', '1', 'ManufacturerModelVersion'],\n '001B': ['UC', '1', 'DeviceAlternateIdentifier'],\n '001C': ['CS', '1', 'DeviceAlternateIdentifierType'],\n '001D': ['LT', '1', 'DeviceAlternateIdentifierFormat'],\n '001E': ['LO', '1', 'SegmentationCreationTemplateLabel'],\n '001F': ['UI', '1', 'SegmentationTemplateUID'],\n '0020': ['US', '1', 'ReferencedSegmentReferenceIndex'],\n '0021': ['SQ', '1', 'SegmentReferenceSequence'],\n '0022': ['US', '1', 'SegmentReferenceIndex'],\n '0023': ['SQ', '1', 'DirectSegmentReferenceSequence'],\n '0024': ['SQ', '1', 'CombinationSegmentReferenceSequence'],\n '0025': ['SQ', '1', 'ConceptualVolumeSequence'],\n '0026': ['SQ', '1', 'SegmentedRTAccessoryDeviceSequence'],\n '0027': ['SQ', '1', 'SegmentCharacteristicsSequence'],\n '0028': ['SQ', '1', 'RelatedSegmentCharacteristicsSequence'],\n '0029': ['US', '1', 'SegmentCharacteristicsPrecedence'],\n '002A': ['SQ', '1', 'RTSegmentAnnotationSequence'],\n '002B': ['SQ', '1', 'SegmentAnnotationCategoryCodeSequence'],\n '002C': ['SQ', '1', 'SegmentAnnotationTypeCodeSequence'],\n '002D': ['LO', '1', 'DeviceLabel'],\n '002E': ['SQ', '1', 'DeviceTypeCodeSequence'],\n '002F': ['SQ', '1', 'SegmentAnnotationTypeModifierCodeSequence'],\n '0030': ['SQ', '1', 'PatientEquipmentRelationshipCodeSequence'],\n '0031': ['UI', '1', 'ReferencedFiducialsUID'],\n '0032': ['SQ', '1', 'PatientTreatmentOrientationSequence'],\n '0033': ['SH', '1', 'UserContentLabel'],\n '0034': ['LO', '1', 'UserContentLongLabel'],\n '0035': ['SH', '1', 'EntityLabel'],\n '0036': ['LO', '1', 'EntityName'],\n '0037': ['ST', '1', 'EntityDescription'],\n '0038': ['LO', '1', 'EntityLongLabel'],\n '0039': ['US', '1', 'DeviceIndex'],\n '003A': ['US', '1', 'RTTreatmentPhaseIndex'],\n '003B': ['UI', '1', 'RTTreatmentPhaseUID'],\n '003C': ['US', '1', 'RTPrescriptionIndex'],\n '003D': ['US', '1', 'RTSegmentAnnotationIndex'],\n '003E': ['US', '1', 'BasisRTTreatmentPhaseIndex'],\n '003F': ['US', '1', 'RelatedRTTreatmentPhaseIndex'],\n '0040': ['US', '1', 'ReferencedRTTreatmentPhaseIndex'],\n '0041': ['US', '1', 'ReferencedRTPrescriptionIndex'],\n '0042': ['US', '1', 'ReferencedParentRTPrescriptionIndex'],\n '0043': ['ST', '1', 'ManufacturerDeviceIdentifier'],\n '0044': ['SQ', '1', 'InstanceLevelReferencedPerformedProcedureStepSequence'],\n '0045': ['CS', '1', 'RTTreatmentPhaseIntentPresenceFlag'],\n '0046': ['CS', '1', 'RadiotherapyTreatmentType'],\n '0047': ['CS', '1-n', 'TeletherapyRadiationType'],\n '0048': ['CS', '1-n', 'BrachytherapySourceType'],\n '0049': ['SQ', '1', 'ReferencedRTTreatmentPhaseSequence'],\n '004A': ['SQ', '1', 'ReferencedDirectSegmentInstanceSequence'],\n '004B': ['SQ', '1', 'IntendedRTTreatmentPhaseSequence'],\n '004C': ['DA', '1', 'IntendedPhaseStartDate'],\n '004D': ['DA', '1', 'IntendedPhaseEndDate'],\n '004E': ['SQ', '1', 'RTTreatmentPhaseIntervalSequence'],\n '004F': ['CS', '1', 'TemporalRelationshipIntervalAnchor'],\n '0050': ['FD', '1', 'MinimumNumberOfIntervalDays'],\n '0051': ['FD', '1', 'MaximumNumberOfIntervalDays'],\n '0052': ['UI', '1-n', 'PertinentSOPClassesInStudy'],\n '0053': ['UI', '1-n', 'PertinentSOPClassesInSeries'],\n '0054': ['LO', '1', 'RTPrescriptionLabel'],\n '0055': ['SQ', '1', 'RTPhysicianIntentPredecessorSequence'],\n '0056': ['LO', '1', 'RTTreatmentApproachLabel'],\n '0057': ['SQ', '1', 'RTPhysicianIntentSequence'],\n '0058': ['US', '1', 'RTPhysicianIntentIndex'],\n '0059': ['CS', '1', 'RTTreatmentIntentType'],\n '005A': ['UT', '1', 'RTPhysicianIntentNarrative'],\n '005B': ['SQ', '1', 'RTProtocolCodeSequence'],\n '005C': ['ST', '1', 'ReasonForSuperseding'],\n '005D': ['SQ', '1', 'RTDiagnosisCodeSequence'],\n '005E': ['US', '1', 'ReferencedRTPhysicianIntentIndex'],\n '005F': ['SQ', '1', 'RTPhysicianIntentInputInstanceSequence'],\n '0060': ['SQ', '1', 'RTAnatomicPrescriptionSequence'],\n '0061': ['UT', '1', 'PriorTreatmentDoseDescription'],\n '0062': ['SQ', '1', 'PriorTreatmentReferenceSequence'],\n '0063': ['CS', '1', 'DosimetricObjectiveEvaluationScope'],\n '0064': ['SQ', '1', 'TherapeuticRoleCategoryCodeSequence'],\n '0065': ['SQ', '1', 'TherapeuticRoleTypeCodeSequence'],\n '0066': ['US', '1', 'ConceptualVolumeOptimizationPrecedence'],\n '0067': ['SQ', '1', 'ConceptualVolumeCategoryCodeSequence'],\n '0068': ['CS', '1', 'ConceptualVolumeBlockingConstraint'],\n '0069': ['SQ', '1', 'ConceptualVolumeTypeCodeSequence'],\n '006A': ['SQ', '1', 'ConceptualVolumeTypeModifierCodeSequence'],\n '006B': ['SQ', '1', 'RTPrescriptionSequence'],\n '006C': ['SQ', '1', 'DosimetricObjectiveSequence'],\n '006D': ['SQ', '1', 'DosimetricObjectiveTypeCodeSequence'],\n '006E': ['UI', '1', 'DosimetricObjectiveUID'],\n '006F': ['UI', '1', 'ReferencedDosimetricObjectiveUID'],\n '0070': ['SQ', '1', 'DosimetricObjectiveParameterSequence'],\n '0071': ['SQ', '1', 'ReferencedDosimetricObjectivesSequence'],\n '0073': ['CS', '1', 'AbsoluteDosimetricObjectiveFlag'],\n '0074': ['FD', '1', 'DosimetricObjectiveWeight'],\n '0075': ['CS', '1', 'DosimetricObjectivePurpose'],\n '0076': ['SQ', '1', 'PlanningInputInformationSequence'],\n '0077': ['LO', '1', 'TreatmentSite'],\n '0078': ['SQ', '1', 'TreatmentSiteCodeSequence'],\n '0079': ['SQ', '1', 'FractionPatternSequence'],\n '007A': ['UT', '1', 'TreatmentTechniqueNotes'],\n '007B': ['UT', '1', 'PrescriptionNotes'],\n '007C': ['IS', '1', 'NumberOfIntervalFractions'],\n '007D': ['US', '1', 'NumberOfFractions'],\n '007E': ['US', '1', 'IntendedDeliveryDuration'],\n '007F': ['UT', '1', 'FractionationNotes'],\n '0080': ['SQ', '1', 'RTTreatmentTechniqueCodeSequence'],\n '0081': ['SQ', '1', 'PrescriptionNotesSequence'],\n '0082': ['SQ', '1', 'FractionBasedRelationshipSequence'],\n '0083': ['CS', '1', 'FractionBasedRelationshipIntervalAnchor'],\n '0084': ['FD', '1', 'MinimumHoursBetweenFractions'],\n '0085': ['TM', '1-n', 'IntendedFractionStartTime'],\n '0086': ['LT', '1', 'IntendedStartDayOfWeek'],\n '0087': ['SQ', '1', 'WeekdayFractionPatternSequence'],\n '0088': ['SQ', '1', 'DeliveryTimeStructureCodeSequence'],\n '0089': ['SQ', '1', 'TreatmentSiteModifierCodeSequence'],\n '0090': ['CS', '1', 'RoboticBaseLocationIndicator'],\n '0091': ['SQ', '1', 'RoboticPathNodeSetCodeSequence'],\n '0092': ['UL', '1', 'RoboticNodeIdentifier'],\n '0093': ['FD', '3', 'RTTreatmentSourceCoordinates'],\n '0094': ['FD', '1', 'RadiationSourceCoordinateSystemYawAngle'],\n '0095': ['FD', '1', 'RadiationSourceCoordinateSystemRollAngle'],\n '0096': ['FD', '1', 'RadiationSourceCoordinateSystemPitchAngle'],\n '0097': ['SQ', '1', 'RoboticPathControlPointSequence'],\n '0098': ['SQ', '1', 'TomotherapeuticControlPointSequence'],\n '0099': ['FD', '1-n', 'TomotherapeuticLeafOpenDurations'],\n '009A': ['FD', '1-n', 'TomotherapeuticLeafInitialClosedDurations']\n },\n '4000': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['LT', '1', 'Arbitrary'],\n '4000': ['LT', '1', 'TextComments']\n },\n '4008': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0040': ['SH', '1', 'ResultsID'],\n '0042': ['LO', '1', 'ResultsIDIssuer'],\n '0050': ['SQ', '1', 'ReferencedInterpretationSequence'],\n '00FF': ['CS', '1', 'ReportProductionStatusTrial'],\n '0100': ['DA', '1', 'InterpretationRecordedDate'],\n '0101': ['TM', '1', 'InterpretationRecordedTime'],\n '0102': ['PN', '1', 'InterpretationRecorder'],\n '0103': ['LO', '1', 'ReferenceToRecordedSound'],\n '0108': ['DA', '1', 'InterpretationTranscriptionDate'],\n '0109': ['TM', '1', 'InterpretationTranscriptionTime'],\n '010A': ['PN', '1', 'InterpretationTranscriber'],\n '010B': ['ST', '1', 'InterpretationText'],\n '010C': ['PN', '1', 'InterpretationAuthor'],\n '0111': ['SQ', '1', 'InterpretationApproverSequence'],\n '0112': ['DA', '1', 'InterpretationApprovalDate'],\n '0113': ['TM', '1', 'InterpretationApprovalTime'],\n '0114': ['PN', '1', 'PhysicianApprovingInterpretation'],\n '0115': ['LT', '1', 'InterpretationDiagnosisDescription'],\n '0117': ['SQ', '1', 'InterpretationDiagnosisCodeSequence'],\n '0118': ['SQ', '1', 'ResultsDistributionListSequence'],\n '0119': ['PN', '1', 'DistributionName'],\n '011A': ['LO', '1', 'DistributionAddress'],\n '0200': ['SH', '1', 'InterpretationID'],\n '0202': ['LO', '1', 'InterpretationIDIssuer'],\n '0210': ['CS', '1', 'InterpretationTypeID'],\n '0212': ['CS', '1', 'InterpretationStatusID'],\n '0300': ['ST', '1', 'Impressions'],\n '4000': ['ST', '1', 'ResultsComments']\n },\n '4010': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['CS', '1', 'LowEnergyDetectors'],\n '0002': ['CS', '1', 'HighEnergyDetectors'],\n '0004': ['SQ', '1', 'DetectorGeometrySequence'],\n '1001': ['SQ', '1', 'ThreatROIVoxelSequence'],\n '1004': ['FL', '3', 'ThreatROIBase'],\n '1005': ['FL', '3', 'ThreatROIExtents'],\n '1006': ['OB', '1', 'ThreatROIBitmap'],\n '1007': ['SH', '1', 'RouteSegmentID'],\n '1008': ['CS', '1', 'GantryType'],\n '1009': ['CS', '1', 'OOIOwnerType'],\n '100A': ['SQ', '1', 'RouteSegmentSequence'],\n '1010': ['US', '1', 'PotentialThreatObjectID'],\n '1011': ['SQ', '1', 'ThreatSequence'],\n '1012': ['CS', '1', 'ThreatCategory'],\n '1013': ['LT', '1', 'ThreatCategoryDescription'],\n '1014': ['CS', '1', 'ATDAbilityAssessment'],\n '1015': ['CS', '1', 'ATDAssessmentFlag'],\n '1016': ['FL', '1', 'ATDAssessmentProbability'],\n '1017': ['FL', '1', 'Mass'],\n '1018': ['FL', '1', 'Density'],\n '1019': ['FL', '1', 'ZEffective'],\n '101A': ['SH', '1', 'BoardingPassID'],\n '101B': ['FL', '3', 'CenterOfMass'],\n '101C': ['FL', '3', 'CenterOfPTO'],\n '101D': ['FL', '6-n', 'BoundingPolygon'],\n '101E': ['SH', '1', 'RouteSegmentStartLocationID'],\n '101F': ['SH', '1', 'RouteSegmentEndLocationID'],\n '1020': ['CS', '1', 'RouteSegmentLocationIDType'],\n '1021': ['CS', '1-n', 'AbortReason'],\n '1023': ['FL', '1', 'VolumeOfPTO'],\n '1024': ['CS', '1', 'AbortFlag'],\n '1025': ['DT', '1', 'RouteSegmentStartTime'],\n '1026': ['DT', '1', 'RouteSegmentEndTime'],\n '1027': ['CS', '1', 'TDRType'],\n '1028': ['CS', '1', 'InternationalRouteSegment'],\n '1029': ['LO', '1-n', 'ThreatDetectionAlgorithmAndVersion'],\n '102A': ['SH', '1', 'AssignedLocation'],\n '102B': ['DT', '1', 'AlarmDecisionTime'],\n '1031': ['CS', '1', 'AlarmDecision'],\n '1033': ['US', '1', 'NumberOfTotalObjects'],\n '1034': ['US', '1', 'NumberOfAlarmObjects'],\n '1037': ['SQ', '1', 'PTORepresentationSequence'],\n '1038': ['SQ', '1', 'ATDAssessmentSequence'],\n '1039': ['CS', '1', 'TIPType'],\n '103A': ['CS', '1', 'DICOSVersion'],\n '1041': ['DT', '1', 'OOIOwnerCreationTime'],\n '1042': ['CS', '1', 'OOIType'],\n '1043': ['FL', '3', 'OOISize'],\n '1044': ['CS', '1', 'AcquisitionStatus'],\n '1045': ['SQ', '1', 'BasisMaterialsCodeSequence'],\n '1046': ['CS', '1', 'PhantomType'],\n '1047': ['SQ', '1', 'OOIOwnerSequence'],\n '1048': ['CS', '1', 'ScanType'],\n '1051': ['LO', '1', 'ItineraryID'],\n '1052': ['SH', '1', 'ItineraryIDType'],\n '1053': ['LO', '1', 'ItineraryIDAssigningAuthority'],\n '1054': ['SH', '1', 'RouteID'],\n '1055': ['SH', '1', 'RouteIDAssigningAuthority'],\n '1056': ['CS', '1', 'InboundArrivalType'],\n '1058': ['SH', '1', 'CarrierID'],\n '1059': ['CS', '1', 'CarrierIDAssigningAuthority'],\n '1060': ['FL', '3', 'SourceOrientation'],\n '1061': ['FL', '3', 'SourcePosition'],\n '1062': ['FL', '1', 'BeltHeight'],\n '1064': ['SQ', '1', 'AlgorithmRoutingCodeSequence'],\n '1067': ['CS', '1', 'TransportClassification'],\n '1068': ['LT', '1', 'OOITypeDescriptor'],\n '1069': ['FL', '1', 'TotalProcessingTime'],\n '106C': ['OB', '1', 'DetectorCalibrationData'],\n '106D': ['CS', '1', 'AdditionalScreeningPerformed'],\n '106E': ['CS', '1', 'AdditionalInspectionSelectionCriteria'],\n '106F': ['SQ', '1', 'AdditionalInspectionMethodSequence'],\n '1070': ['CS', '1', 'AITDeviceType'],\n '1071': ['SQ', '1', 'QRMeasurementsSequence'],\n '1072': ['SQ', '1', 'TargetMaterialSequence'],\n '1073': ['FD', '1', 'SNRThreshold'],\n '1075': ['DS', '1', 'ImageScaleRepresentation'],\n '1076': ['SQ', '1', 'ReferencedPTOSequence'],\n '1077': ['SQ', '1', 'ReferencedTDRInstanceSequence'],\n '1078': ['ST', '1', 'PTOLocationDescription'],\n '1079': ['SQ', '1', 'AnomalyLocatorIndicatorSequence'],\n '107A': ['FL', '3', 'AnomalyLocatorIndicator'],\n '107B': ['SQ', '1', 'PTORegionSequence'],\n '107C': ['CS', '1', 'InspectionSelectionCriteria'],\n '107D': ['SQ', '1', 'SecondaryInspectionMethodSequence'],\n '107E': ['DS', '6', 'PRCSToRCSOrientation']\n },\n '4FFE': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['SQ', '1', 'MACParametersSequence']\n },\n '5000': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0005': ['US', '1', 'CurveDimensions'],\n '0010': ['US', '1', 'NumberOfPoints'],\n '0020': ['CS', '1', 'TypeOfData'],\n '0022': ['LO', '1', 'CurveDescription'],\n '0030': ['SH', '1-n', 'AxisUnits'],\n '0040': ['SH', '1-n', 'AxisLabels'],\n '0103': ['US', '1', 'DataValueRepresentation'],\n '0104': ['US', '1-n', 'MinimumCoordinateValue'],\n '0105': ['US', '1-n', 'MaximumCoordinateValue'],\n '0106': ['SH', '1-n', 'CurveRange'],\n '0110': ['US', '1-n', 'CurveDataDescriptor'],\n '0112': ['US', '1-n', 'CoordinateStartValue'],\n '0114': ['US', '1-n', 'CoordinateStepValue'],\n '1001': ['CS', '1', 'CurveActivationLayer'],\n '2000': ['US', '1', 'AudioType'],\n '2002': ['US', '1', 'AudioSampleFormat'],\n '2004': ['US', '1', 'NumberOfChannels'],\n '2006': ['UL', '1', 'NumberOfSamples'],\n '2008': ['UL', '1', 'SampleRate'],\n '200A': ['UL', '1', 'TotalTime'],\n '200C': ['ox', '1', 'AudioSampleData'],\n '200E': ['LT', '1', 'AudioComments'],\n '2500': ['LO', '1', 'CurveLabel'],\n '2600': ['SQ', '1', 'CurveReferencedOverlaySequence'],\n '2610': ['US', '1', 'CurveReferencedOverlayGroup'],\n '3000': ['ox', '1', 'CurveData']\n },\n '5200': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '9229': ['SQ', '1', 'SharedFunctionalGroupsSequence'],\n '9230': ['SQ', '1', 'PerFrameFunctionalGroupsSequence']\n },\n '5400': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0100': ['SQ', '1', 'WaveformSequence'],\n '0110': ['ox', '1', 'ChannelMinimumValue'],\n '0112': ['ox', '1', 'ChannelMaximumValue'],\n '1004': ['US', '1', 'WaveformBitsAllocated'],\n '1006': ['CS', '1', 'WaveformSampleInterpretation'],\n '100A': ['ox', '1', 'WaveformPaddingValue'],\n '1010': ['ox', '1', 'WaveformData']\n },\n '5600': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['OF', '1', 'FirstOrderPhaseCorrectionAngle'],\n '0020': ['OF', '1', 'SpectroscopyData']\n },\n '6000': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['US', '1', 'OverlayRows'],\n '0011': ['US', '1', 'OverlayColumns'],\n '0012': ['US', '1', 'OverlayPlanes'],\n '0015': ['IS', '1', 'NumberOfFramesInOverlay'],\n '0022': ['LO', '1', 'OverlayDescription'],\n '0040': ['CS', '1', 'OverlayType'],\n '0045': ['LO', '1', 'OverlaySubtype'],\n '0050': ['SS', '2', 'OverlayOrigin'],\n '0051': ['US', '1', 'ImageFrameOrigin'],\n '0052': ['US', '1', 'OverlayPlaneOrigin'],\n '0060': ['CS', '1', 'OverlayCompressionCode'],\n '0061': ['SH', '1', 'OverlayCompressionOriginator'],\n '0062': ['SH', '1', 'OverlayCompressionLabel'],\n '0063': ['CS', '1', 'OverlayCompressionDescription'],\n '0066': ['AT', '1-n', 'OverlayCompressionStepPointers'],\n '0068': ['US', '1', 'OverlayRepeatInterval'],\n '0069': ['US', '1', 'OverlayBitsGrouped'],\n '0100': ['US', '1', 'OverlayBitsAllocated'],\n '0102': ['US', '1', 'OverlayBitPosition'],\n '0110': ['CS', '1', 'OverlayFormat'],\n '0200': ['US', '1', 'OverlayLocation'],\n '0800': ['CS', '1-n', 'OverlayCodeLabel'],\n '0802': ['US', '1', 'OverlayNumberOfTables'],\n '0803': ['AT', '1-n', 'OverlayCodeTableLocation'],\n '0804': ['US', '1', 'OverlayBitsForCodeWord'],\n '1001': ['CS', '1', 'OverlayActivationLayer'],\n '1100': ['US', '1', 'OverlayDescriptorGray'],\n '1101': ['US', '1', 'OverlayDescriptorRed'],\n '1102': ['US', '1', 'OverlayDescriptorGreen'],\n '1103': ['US', '1', 'OverlayDescriptorBlue'],\n '1200': ['US', '1-n', 'OverlaysGray'],\n '1201': ['US', '1-n', 'OverlaysRed'],\n '1202': ['US', '1-n', 'OverlaysGreen'],\n '1203': ['US', '1-n', 'OverlaysBlue'],\n '1301': ['IS', '1', 'ROIArea'],\n '1302': ['DS', '1', 'ROIMean'],\n '1303': ['DS', '1', 'ROIStandardDeviation'],\n '1500': ['LO', '1', 'OverlayLabel'],\n '3000': ['ox', '1', 'OverlayData'],\n '4000': ['LT', '1', 'OverlayComments']\n },\n '7F00': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0010': ['ox', '1', 'VariablePixelData'],\n '0011': ['US', '1', 'VariableNextDataGroup'],\n '0020': ['OW', '1', 'VariableCoefficientsSDVN'],\n '0030': ['OW', '1', 'VariableCoefficientsSDHN'],\n '0040': ['OW', '1', 'VariableCoefficientsSDDN']\n },\n '7FE0': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n '0001': ['OV', '1', 'ExtendedOffsetTable'],\n '0002': ['OV', '1', 'ExtendedOffsetTableLengths'],\n '0008': ['OF', '1', 'FloatPixelData'],\n '0009': ['OD', '1', 'DoubleFloatPixelData'],\n '0010': ['ox', '1', 'PixelData'],\n '0020': ['OW', '1', 'CoefficientsSDVN'],\n '0030': ['OW', '1', 'CoefficientsSDHN'],\n '0040': ['OW', '1', 'CoefficientsSDDN']\n },\n 'FFFA': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n 'FFFA': ['SQ', '1', 'DigitalSignaturesSequence']\n },\n 'FFFC': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n 'FFFC': ['OB', '1', 'DataSetTrailingPadding']\n },\n 'FFFE': {\n '0000': ['UL', '1', 'GenericGroupLength'],\n 'E000': ['NONE', '1', 'Item'],\n 'E00D': ['NONE', '1', 'ItemDelimitationItem'],\n 'E0DD': ['NONE', '1', 'SequenceDelimitationItem']\n }\n}; // Dictionary\n\n/**\n * Add tags to the dictionary.\n *\n * @param {string} group The group key.\n * @param {Object} tags The tags to add as an\n * object indexed by element key with values as:\n * [VR, multiplicity, TagName] (all strings).\n */\nexport function addTagsToDictionary(group, tags) {\n // TODO: add checks!\n dictionary[group] = tags;\n}\n\n/**\n * Tag groups: key to name pairs.\n * Copied from gdcm-2.6.1\\Source\\DataDictionary\\GroupName.dic\n * -> removed duplicates (commented).\n *\n * @type {Object}\n */\nexport const tagGroups = {\n '0000': 'Command',\n '0002': 'Meta Element',\n '0004': 'File Set',\n //'0004': 'Directory',\n '0008': 'Identifying',\n '0009': 'SPI Identifying',\n '0010': 'Patient',\n '0012': 'Clinical Trial',\n '0018': 'Acquisition',\n '0019': 'SPI Acquisition',\n '0020': 'Image',\n '0021': 'SPI Image',\n '0022': 'Ophtalmology',\n '0028': 'Image Presentation',\n '0032': 'Study',\n '0038': 'Visit',\n '003A': 'Waveform',\n '0040': 'Procedure',\n //'0040': ''Modality Worklist',\n '0042': 'Encapsulated Document',\n '0050': 'Device Informations',\n //'0050': 'XRay Angio Device',\n '0054': 'Nuclear Medicine',\n '0060': 'Histogram',\n '0070': 'Presentation State',\n '0072': 'Hanging Protocol',\n '0088': 'Storage',\n //'0088': 'Medicine',\n '0100': 'Authorization',\n '0400': 'Digital Signature',\n '1000': 'Code Table',\n '1010': 'Zonal Map',\n '2000': 'Film Session',\n '2010': 'Film Box',\n '2020': 'Image Box',\n '2030': 'Annotation',\n '2040': 'Overlay Box',\n '2050': 'Presentation LUT',\n '2100': 'Print Job',\n '2110': 'Printer',\n '2120': 'Queue',\n '2130': 'Print Content',\n '2200': 'Media Creation',\n '3002': 'RT Image',\n '3004': 'RT Dose',\n '3006': 'RT StructureSet',\n '3008': 'RT Treatment',\n '300A': 'RT Plan',\n '300C': 'RT Relationship',\n '300E': 'RT Approval',\n '4000': 'Text',\n '4008': 'Results',\n '4FFE': 'MAC Parameters',\n '5000': 'Curve',\n '5002': 'Curve',\n '5004': 'Curve',\n '5006': 'Curve',\n '5008': 'Curve',\n '500A': 'Curve',\n '500C': 'Curve',\n '500E': 'Curve',\n '5400': 'Waveform Data',\n '6000': 'Overlays',\n '6002': 'Overlays',\n '6004': 'Overlays',\n '6008': 'Overlays',\n '600A': 'Overlays',\n '600C': 'Overlays',\n '600E': 'Overlays',\n 'FFFC': 'Generic',\n '7FE0': 'Pixel Data',\n 'FFFF': 'Unknown'\n};\n\n/**\n * List of Value Representation (VR) with 32bit Value Length (VL).\n *\n * Added locally used 'ox'.\n * See {@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/chapter_7.html#table_7.1-1}.\n *\n * @type {Object}\n */\nconst vr32bitVL = {\n OB: true,\n OD: true,\n OF: true,\n OL: true,\n OV: true,\n OW: true,\n SQ: true,\n SV: true,\n UC: true,\n UN: true,\n UR: true,\n UT: true,\n UV: true,\n ox: true\n};\n\n/**\n * Does the input Value Representation (VR) have a 32bit Value Length (VL).\n *\n * @param {string} vr The data Value Representation (VR).\n * @returns {boolean} True if this VR has a 32-bit VL.\n */\nexport function is32bitVLVR(vr) {\n return typeof vr32bitVL[vr] !== 'undefined';\n}\n\n/**\n * List of string VR with extended or replaced default character repertoire defined in\n * Specific Character Set (0008,0005).\n *\n * See {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/chapter_6.html#sect_6.1.2.2}.\n *\n * @type {Object}\n */\nconst vrCharSetString = {\n SH: true,\n LO: true,\n UC: true,\n ST: true,\n LT: true,\n UT: true,\n PN: true\n};\n\n/**\n * Does the input Value Representation (VR) have an special character repertoire.\n *\n * @param {string} vr The data VR.\n * @returns {boolean} True if this VR has a special char set.\n */\nexport function isCharSetStringVR(vr) {\n return typeof vrCharSetString[vr] !== 'undefined';\n}\n\n/**\n * VR equivalent javascript types.\n *\n * See {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_6.2.html#table_6.2-1}.\n *\n * @type {Object}\n */\nexport const vrTypes = {\n AE: 'string',\n AS: 'string',\n AT: undefined,\n CS: 'string',\n DA: 'string',\n DS: 'string',\n DT: 'string',\n FL: 'Float32',\n FD: 'Float64',\n IS: 'string',\n LO: 'string',\n LT: 'string',\n OB: 'Uint8',\n OD: 'Uint64',\n OF: 'Uint32',\n OL: 'Uint32',\n OV: 'Uint64',\n OW: 'Uint16',\n PN: 'string',\n SH: 'string',\n SL: 'Int32',\n SQ: undefined,\n SS: 'Int16',\n ST: 'string',\n SV: 'Int64',\n TM: 'string',\n UC: 'string',\n UI: 'string',\n UL: 'Uint32',\n UN: 'Uint8',\n UR: 'string',\n US: 'Uint16',\n UT: 'string',\n UV: 'Uint64'\n};\n\n/**\n * Transfer syntaxes.\n *\n * See {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part06/chapter_A.html#table_A-1}.\n *\n * @type {Object}\n */\nexport const transferSyntaxes = {\n '1.2.840.10008.1.2': 'Implicit VR Little Endian',\n '1.2.840.10008.1.2.1': 'Explicit VR Little Endian',\n '1.2.840.10008.1.2.1.98': 'Encapsulated Uncompressed Explicit VR Little Endian',\n '1.2.840.10008.1.2.1.99': 'Deflated Explicit VR Little Endian',\n '1.2.840.10008.1.2.2': 'Explicit VR Big Endian (Retired)',\n '1.2.840.10008.1.2.4.50': 'JPEG Baseline (Process 1)',\n '1.2.840.10008.1.2.4.51': 'JPEG Extended (Process 2 & 4)',\n '1.2.840.10008.1.2.4.52': 'JPEG Extended (Process 3 & 5) (Retired)',\n '1.2.840.10008.1.2.4.53': 'JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8) (Retired)',\n '1.2.840.10008.1.2.4.54': 'JPEG Spectral Selection, Non-Hierarchical (Process 7 & 9) (Retired)',\n '1.2.840.10008.1.2.4.55': 'JPEG Full Progression, Non-Hierarchical (Process 10 & 12) (Retired)',\n '1.2.840.10008.1.2.4.56': 'JPEG Full Progression, Non-Hierarchical (Process 11 & 13) (Retired)',\n '1.2.840.10008.1.2.4.57': 'JPEG Lossless, Non-Hierarchical (Process 14)',\n '1.2.840.10008.1.2.4.58': 'JPEG Lossless, Non-Hierarchical (Process 15) (Retired)',\n '1.2.840.10008.1.2.4.59': 'JPEG Extended, Hierarchical (Process 16 & 18) (Retired)',\n '1.2.840.10008.1.2.4.60': 'JPEG Extended, Hierarchical (Process 17 & 19) (Retired)',\n '1.2.840.10008.1.2.4.61': 'JPEG Spectral Selection, Hierarchical (Process 20 & 22) (Retired)',\n '1.2.840.10008.1.2.4.62': 'JPEG Spectral Selection, Hierarchical (Process 21 & 23) (Retired)',\n '1.2.840.10008.1.2.4.63': 'JPEG Full Progression, Hierarchical (Process 24 & 26) (Retired)',\n '1.2.840.10008.1.2.4.64': 'JPEG Full Progression, Hierarchical (Process 25 & 27) (Retired)',\n '1.2.840.10008.1.2.4.65': 'JPEG Lossless, Hierarchical (Process 28) (Retired)',\n '1.2.840.10008.1.2.4.66': 'JPEG Lossless, Hierarchical (Process 29) (Retired)',\n '1.2.840.10008.1.2.4.70': 'JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14 [Selection Value 1])',\n '1.2.840.10008.1.2.4.80': 'JPEG-LS Lossless Image Compression',\n '1.2.840.10008.1.2.4.81': 'JPEG-LS Lossy (Near-Lossless) Image Compression',\n '1.2.840.10008.1.2.4.90': 'JPEG 2000 Image Compression (Lossless Only)',\n '1.2.840.10008.1.2.4.91': 'JPEG 2000 Image Compression',\n '1.2.840.10008.1.2.4.92': 'JPEG 2000 Part 2 Multi-component Image Compression (Lossless Only)',\n '1.2.840.10008.1.2.4.93': 'JPEG 2000 Part 2 Multi-component Image Compression',\n '1.2.840.10008.1.2.4.94': 'JPIP Referenced',\n '1.2.840.10008.1.2.4.95': 'JPIP Referenced Deflate',\n '1.2.840.10008.1.2.4.100': 'MPEG2 Main Profile / Main Level',\n '1.2.840.10008.1.2.4.101': 'MPEG2 Main Profile / High Level',\n '1.2.840.10008.1.2.4.102': 'MPEG-4 AVC/H.264 High Profile / Level 4.1',\n '1.2.840.10008.1.2.4.103': 'MPEG-4 AVC/H.264 BD-compatible High Profile / Level 4.1',\n '1.2.840.10008.1.2.4.104': 'MPEG-4 AVC/H.264 High Profile / Level 4.2 For 2D Video',\n '1.2.840.10008.1.2.4.105': 'MPEG-4 AVC/H.264 High Profile / Level 4.2 For 3D Video',\n '1.2.840.10008.1.2.4.106': 'MPEG-4 AVC/H.264 Stereo High Profile / Level 4.2',\n '1.2.840.10008.1.2.4.107': 'HEVC/H.265 Main Profile / Level 5.1',\n '1.2.840.10008.1.2.4.108': 'HEVC/H.265 Main 10 Profile / Level 5.1',\n '1.2.840.10008.1.2.5': 'RLE Lossless',\n '1.2.840.10008.1.2.6.1': 'RFC 2557 MIME encapsulation (Retired)',\n '1.2.840.10008.1.2.6.2': 'XML Encoding (Retired)',\n '1.2.840.10008.1.2.7.1': 'SMPTE ST 2110-20 Uncompressed Progressive Active Video',\n '1.2.840.10008.1.2.7.2': 'SMPTE ST 2110-20 Uncompressed Interlaced Active Video',\n '1.2.840.10008.1.2.7.3': 'SMPTE ST 2110-30 PCM Digital Audio',\n '1.2.840.10008.1.20': 'Papyrus 3 Implicit VR Little Endian (Retired)'\n};\n\n/**\n * Transfer syntaxes indexed by keyword.\n *\n * @type {Object}\n */\nexport const transferSyntaxKeywords = {\n ImplicitVRLittleEndian: '1.2.840.10008.1.2',\n ExplicitVRLittleEndian: '1.2.840.10008.1.2.1',\n EncapsulatedUncompressedExplicitVRLittleEndian: '1.2.840.10008.1.2.1.98',\n DeflatedExplicitVRLittleEndian: '1.2.840.10008.1.2.1.99',\n ExplicitVRBigEndian: '1.2.840.10008.1.2.2',\n JPEGBaseline8Bit: '1.2.840.10008.1.2.4.50',\n JPEGExtended12Bit: '1.2.840.10008.1.2.4.51',\n JPEGExtended35: '1.2.840.10008.1.2.4.52',\n JPEGSpectralSelectionNonHierarchical68: '1.2.840.10008.1.2.4.53',\n JPEGSpectralSelectionNonHierarchical79: '1.2.840.10008.1.2.4.54',\n JPEGFullProgressionNonHierarchical1012: '1.2.840.10008.1.2.4.55',\n JPEGFullProgressionNonHierarchical1113: '1.2.840.10008.1.2.4.56',\n JPEGLossless: '1.2.840.10008.1.2.4.57',\n JPEGLosslessNonHierarchical15: '1.2.840.10008.1.2.4.58',\n JPEGExtendedHierarchical1618: '1.2.840.10008.1.2.4.59',\n JPEGExtendedHierarchical1719: '1.2.840.10008.1.2.4.60',\n JPEGSpectralSelectionHierarchical2022: '1.2.840.10008.1.2.4.61',\n JPEGSpectralSelectionHierarchical2123: '1.2.840.10008.1.2.4.62',\n JPEGFullProgressionHierarchical2426: '1.2.840.10008.1.2.4.63',\n JPEGFullProgressionHierarchical2527: '1.2.840.10008.1.2.4.64',\n JPEGLosslessHierarchical28: '1.2.840.10008.1.2.4.65',\n JPEGLosslessHierarchical29: '1.2.840.10008.1.2.4.66',\n JPEGLosslessSV1: '1.2.840.10008.1.2.4.70',\n JPEGLSLossless: '1.2.840.10008.1.2.4.80',\n JPEGLSNearLossless: '1.2.840.10008.1.2.4.81',\n JPEG2000Lossless: '1.2.840.10008.1.2.4.90',\n JPEG2000: '1.2.840.10008.1.2.4.91',\n JPEG2000MCLossless: '1.2.840.10008.1.2.4.92',\n JPEG2000MC: '1.2.840.10008.1.2.4.93',\n JPIPReferenced: '1.2.840.10008.1.2.4.94',\n JPIPReferencedDeflate: '1.2.840.10008.1.2.4.95',\n MPEG2MPML: '1.2.840.10008.1.2.4.100',\n MPEG2MPHL: '1.2.840.10008.1.2.4.101',\n MPEG4HP41: '1.2.840.10008.1.2.4.102',\n MPEG4HP41BD: '1.2.840.10008.1.2.4.103',\n MPEG4HP422D: '1.2.840.10008.1.2.4.104',\n MPEG4HP423D: '1.2.840.10008.1.2.4.105',\n MPEG4HP42STEREO: '1.2.840.10008.1.2.4.106',\n HEVCMP51: '1.2.840.10008.1.2.4.107',\n HEVCM10P51: '1.2.840.10008.1.2.4.108',\n RLELossless: '1.2.840.10008.1.2.5',\n RFC2557MIMEEncapsulation: '1.2.840.10008.1.2.6.1',\n XMLEncoding: '1.2.840.10008.1.2.6.2',\n SMPTEST211020UncompressedProgressiveActiveVideo: '1.2.840.10008.1.2.7.1',\n SMPTEST211020UncompressedInterlacedActiveVideo: '1.2.840.10008.1.2.7.2',\n SMPTEST211030PCMDigitalAudio: '1.2.840.10008.1.2.7.3',\n Papyrus3ImplicitVRLittleEndian: '1.2.840.10008.1.20'\n};\n","import {\n dictionary,\n tagGroups\n} from './dictionary';\n\n/**\n * Immutable tag.\n */\nexport class Tag {\n\n /**\n * The tag group.\n *\n * @type {string}\n */\n #group;\n\n /**\n * The tag element.\n *\n * @type {string}\n */\n #element;\n\n /**\n * @param {string} group The tag group as '####'.\n * @param {string} element The tag element as '####'.\n */\n constructor(group, element) {\n if (!group || typeof group === 'undefined') {\n throw new Error('Cannot create tag with no group.');\n }\n if (group.length !== 4) {\n throw new Error('Cannot create tag with badly sized group: ' + group);\n }\n if (!element || typeof element === 'undefined') {\n throw new Error('Cannot create tag with no element.');\n }\n if (element.length !== 4) {\n throw new Error('Cannot create tag with badly sized element: ' + element);\n }\n this.#group = group;\n this.#element = element;\n }\n\n /**\n * Get the tag group.\n *\n * @returns {string} The tag group.\n */\n getGroup() {\n return this.#group;\n }\n\n /**\n * Get the tag element.\n *\n * @returns {string} The tag element.\n */\n getElement() {\n return this.#element;\n }\n\n /**\n * Get as string representation of the tag: 'key: name'.\n *\n * @returns {string} A string representing the tag.\n */\n toString() {\n return this.getKey() + ': ' + this.getNameFromDictionary();\n }\n\n /**\n * Check for Tag equality.\n *\n * @param {Tag} rhs The other tag to compare to.\n * @returns {boolean} True if both tags are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n typeof rhs !== 'undefined' &&\n this.#group === rhs.getGroup() &&\n this.#element === rhs.getElement();\n }\n\n /**\n * Get the group-element key used to store DICOM elements.\n *\n * @returns {string} The key as '########'.\n */\n getKey() {\n return this.#group + this.#element;\n }\n\n /**\n * Get the group name as defined in TagGroups.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return tagGroups[this.#group];\n }\n\n /**\n * Does this tag have a VR.\n * Basically not the Item, ItemDelimitationItem nor\n * SequenceDelimitationItem tags.\n *\n * @returns {boolean} True if this tag has a VR.\n */\n isWithVR() {\n return !(this.#group === 'FFFE' &&\n (this.#element === 'E000' ||\n this.#element === 'E00D' ||\n this.#element === 'E0DD')\n );\n }\n\n /**\n * Is the tag group a private tag group ?\n *\n * See: {@link http://dicom.nema.org/medical/dicom/2022a/output/html/part05.html#sect_7.8}.\n *\n * @returns {boolean} True if the tag group is private,\n * ie if its group is an odd number.\n */\n isPrivate() {\n return parseInt(this.#group, 16) % 2 === 1;\n }\n\n /**\n * Get the tag info from the dicom dictionary.\n *\n * @returns {string[]|undefined} The info as [vr, multiplicity, name].\n */\n #getInfoFromDictionary() {\n let info;\n if (typeof dictionary[this.#group] !== 'undefined' &&\n typeof dictionary[this.#group][this.#element] !==\n 'undefined') {\n info = dictionary[this.#group][this.#element];\n }\n return info;\n }\n\n /**\n * Get the tag Value Representation (VR) from the dicom dictionary.\n *\n * @returns {string|undefined} The VR.\n */\n getVrFromDictionary() {\n let vr;\n const info = this.#getInfoFromDictionary();\n if (typeof info !== 'undefined') {\n vr = info[0];\n }\n return vr;\n }\n\n /**\n * Get the tag name from the dicom dictionary.\n *\n * @returns {string|undefined} The VR.\n */\n getNameFromDictionary() {\n let name;\n const info = this.#getInfoFromDictionary();\n if (typeof info !== 'undefined') {\n name = info[2];\n }\n return name;\n }\n\n} // Tag class\n\n/**\n * Tag compare function.\n *\n * @param {Tag} a The first tag.\n * @param {Tag} b The second tag.\n * @returns {number} The result of the tag comparison,\n * positive for b before a, negative for a before b and\n * zero to keep same order.\n */\nexport function tagCompareFunction(a, b) {\n // first by group\n let res = parseInt(a.getGroup(), 16) - parseInt(b.getGroup(), 16);\n if (res === 0) {\n // by element if same group\n res = parseInt(a.getElement(), 16) - parseInt(b.getElement(), 16);\n }\n return res;\n}\n\n/**\n * Split a group-element key used to store DICOM elements.\n *\n * @param {string} key The key in form \"00280102\" as generated by tag::getKey.\n * @returns {Tag} The DICOM tag.\n */\nexport function getTagFromKey(key) {\n if (!key || typeof key === 'undefined') {\n throw new Error('Cannot create tag with no key.');\n }\n if (key.length !== 8) {\n throw new Error('Cannot create tag with badly sized key: ' + key);\n }\n return new Tag(key.substring(0, 4), key.substring(4, 8));\n}\n\n/**\n * Get the TransferSyntaxUID Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getTransferSyntaxUIDTag() {\n return new Tag('0002', '0010');\n}\n\n/**\n * Get the FileMetaInformationGroupLength Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getFileMetaInformationGroupLengthTag() {\n return new Tag('0002', '0000');\n}\n\n/**\n * Is the input tag the FileMetaInformationGroupLength Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isFileMetaInformationGroupLengthTag(tag) {\n return tag.equals(getFileMetaInformationGroupLengthTag());\n}\n\n/**\n * Get the Item Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getItemTag() {\n return new Tag('FFFE', 'E000');\n}\n\n/**\n * Is the input tag the Item Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isItemTag(tag) {\n // faster than tag.equals(getItemTag());\n return tag.getKey() === 'FFFEE000';\n}\n\n/**\n * Get the ItemDelimitationItem Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getItemDelimitationItemTag() {\n return new Tag('FFFE', 'E00D');\n}\n\n/**\n * Is the input tag the ItemDelimitationItem Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isItemDelimitationItemTag(tag) {\n // faster than tag.equals(getItemDelimitationItemTag());\n return tag.getKey() === 'FFFEE00D';\n}\n\n/**\n * Get the SequenceDelimitationItem Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getSequenceDelimitationItemTag() {\n return new Tag('FFFE', 'E0DD');\n}\n\n/**\n * Is the input tag the SequenceDelimitationItem Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isSequenceDelimitationItemTag(tag) {\n // faster than tag.equals(getSequenceDelimitationItemTag());\n return tag.getKey() === 'FFFEE0DD';\n}\n\n/**\n * Get the PixelData Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getPixelDataTag() {\n return new Tag('7FE0', '0010');\n}\n\n/**\n * Is the input tag the PixelData Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isPixelDataTag(tag) {\n // faster than tag.equals(getPixelDataTag());\n return tag.getKey() === '7FE00010';\n}\n\n/**\n * Get a tag from the dictionary using a tag string name.\n *\n * @param {string} tagName The tag string name.\n * @returns {Tag|undefined} The tag object or null if not found.\n */\nexport function getTagFromDictionary(tagName) {\n if (typeof tagName === 'undefined' || tagName === null) {\n return null;\n }\n let group = null;\n let element = null;\n const dict = dictionary;\n const keys0 = Object.keys(dict);\n let keys1 = null;\n let foundTag = false;\n // search through dictionary\n for (let k0 = 0, lenK0 = keys0.length; k0 < lenK0; ++k0) {\n group = keys0[k0];\n keys1 = Object.keys(dict[group]);\n for (let k1 = 0, lenK1 = keys1.length; k1 < lenK1; ++k1) {\n element = keys1[k1];\n if (dict[group][element][2] === tagName) {\n foundTag = true;\n break;\n }\n }\n if (foundTag) {\n break;\n }\n }\n let tag;\n if (foundTag) {\n tag = new Tag(group, element);\n }\n return tag;\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Tag} from './dicomTag';\n/* eslint-enable no-unused-vars */\n\n/**\n * DICOM data element.\n */\nexport class DataElement {\n /**\n * The element Value Representation.\n *\n * @type {string}\n */\n vr;\n /**\n * The element value.\n *\n * @type {Array}\n */\n value;\n\n // [start] internal values\n // only present during parsing or writing otherwise not set\n\n /**\n * The element dicom tag.\n *\n * @type {Tag}\n */\n tag;\n\n /**\n * The element Value Length.\n *\n * @type {number}\n */\n vl;\n\n /**\n * Flag to know if defined or undefined sequence length.\n *\n * @type {boolean}\n */\n undefinedLength;\n\n /**\n * The element start offset.\n *\n * @type {number}\n */\n startOffset;\n\n /**\n * The element end offset.\n *\n * @type {number}\n */\n endOffset;\n\n /**\n * The sequence items.\n *\n * @type {Array}\n */\n items;\n\n // [end] internal values\n\n /**\n * @param {string} vr The element VR (Value Representation).\n */\n constructor(vr) {\n this.vr = vr;\n }\n}","/**\n * Is the Native endianness Little Endian.\n *\n * @returns {boolean} True if little endian.\n */\nexport function isNativeLittleEndian() {\n return new Int8Array(new Int16Array([1]).buffer)[0] > 0;\n}\n\n/**\n * Flip an array's endianness.\n * Inspired from [DataStream.js]{@link https://github.com/kig/DataStream.js}.\n *\n * @param {object} array The array to flip (modified).\n */\nfunction flipArrayEndianness(array) {\n const blen = array.byteLength;\n const u8 = new Uint8Array(array.buffer, array.byteOffset, blen);\n const bpe = array.BYTES_PER_ELEMENT;\n let tmp;\n for (let i = 0; i < blen; i += bpe) {\n for (let j = i + bpe - 1, k = i; j > k; j--, k++) {\n tmp = u8[k];\n u8[k] = u8[j];\n u8[j] = tmp;\n }\n }\n}\n\n/**\n * Data reader.\n */\nexport class DataReader {\n\n /**\n * The input buffer.\n *\n * @type {ArrayBuffer}\n */\n #buffer;\n\n /**\n * Is the endianness Little Endian.\n *\n * @type {boolean}\n */\n #isLittleEndian = true;\n\n /**\n * Is the Native endianness Little Endian.\n *\n * @type {boolean}\n */\n #isNativeLittleEndian = isNativeLittleEndian();\n\n /**\n * Flag to know if the TypedArray data needs flipping.\n *\n * @type {boolean}\n */\n #needFlip;\n\n /**\n * The main data view.\n *\n * @type {DataView}\n */\n #view;\n\n /**\n * @param {ArrayBuffer} buffer The input array buffer.\n * @param {boolean} [isLittleEndian] Flag to tell if the data is little\n * or big endian (default: true).\n */\n constructor(buffer, isLittleEndian) {\n this.#buffer = buffer;\n // Set endian flag if not defined.\n if (typeof isLittleEndian !== 'undefined') {\n this.#isLittleEndian = isLittleEndian;\n }\n this.#needFlip = (this.#isLittleEndian !== this.#isNativeLittleEndian);\n this.#view = new DataView(buffer);\n }\n\n /**\n * Read Uint16 (2 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {number} The read data.\n */\n readUint16(byteOffset) {\n return this.#view.getUint16(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read Int16 (2 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {number} The read data.\n */\n readInt16(byteOffset) {\n return this.#view.getInt16(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read Uint32 (4 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {number} The read data.\n */\n readUint32(byteOffset) {\n return this.#view.getUint32(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read BigUint64 (8 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {bigint} The read data.\n */\n readBigUint64(byteOffset) {\n return this.#view.getBigUint64(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read Int32 (4 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {number} The read data.\n */\n readInt32(byteOffset) {\n return this.#view.getInt32(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read BigInt64 (8 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {bigint} The read data.\n */\n readBigInt64(byteOffset) {\n return this.#view.getBigInt64(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read Float32 (4 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {number} The read data.\n */\n readFloat32(byteOffset) {\n return this.#view.getFloat32(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read Float64 (8 bytes) data.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {number} The read data.\n */\n readFloat64(byteOffset) {\n return this.#view.getFloat64(byteOffset, this.#isLittleEndian);\n }\n\n /**\n * Read binary (0/1) array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Uint8Array} The read data.\n */\n readBinaryArray(byteOffset, size) {\n // input\n const bitArray = new Uint8Array(this.#buffer, byteOffset, size);\n // result\n const byteArrayLength = 8 * bitArray.length;\n const data = new Uint8Array(byteArrayLength);\n let bitNumber = 0;\n let bitIndex = 0;\n for (let i = 0; i < byteArrayLength; ++i) {\n bitNumber = i % 8;\n bitIndex = Math.floor(i / 8);\n // see https://stackoverflow.com/questions/4854207/get-a-specific-bit-from-byte/4854257\n // @ts-ignore\n data[i] = 255 * ((bitArray[bitIndex] & (1 << bitNumber)) !== 0);\n }\n return data;\n }\n\n /**\n * Read Uint8 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Uint8Array} The read data.\n */\n readUint8Array(byteOffset, size) {\n return new Uint8Array(this.#buffer, byteOffset, size);\n }\n\n /**\n * Read Int8 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Int8Array} The read data.\n */\n readInt8Array(byteOffset, size) {\n return new Int8Array(this.#buffer, byteOffset, size);\n }\n\n /**\n * Read Uint16 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Uint16Array} The read data.\n */\n readUint16Array(byteOffset, size) {\n const bpe = Uint16Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of Uint16Array.BYTES_PER_ELEMENT (=2)\n if (byteOffset % bpe === 0) {\n data = new Uint16Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new Uint16Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readUint16(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Int16 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Int16Array} The read data.\n */\n readInt16Array(byteOffset, size) {\n const bpe = Int16Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of Int16Array.BYTES_PER_ELEMENT (=2)\n if (byteOffset % bpe === 0) {\n data = new Int16Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new Int16Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readInt16(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Uint32 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Uint32Array} The read data.\n */\n readUint32Array(byteOffset, size) {\n const bpe = Uint32Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of Uint32Array.BYTES_PER_ELEMENT (=4)\n if (byteOffset % bpe === 0) {\n data = new Uint32Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new Uint32Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readUint32(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Uint64 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {BigUint64Array} The read data.\n */\n readUint64Array(byteOffset, size) {\n const bpe = BigUint64Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of BigUint64Array.BYTES_PER_ELEMENT (=8)\n if (byteOffset % bpe === 0) {\n data = new BigUint64Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new BigUint64Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readBigUint64(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Int32 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Int32Array} The read data.\n */\n readInt32Array(byteOffset, size) {\n const bpe = Int32Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of Int32Array.BYTES_PER_ELEMENT (=4)\n if (byteOffset % bpe === 0) {\n data = new Int32Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new Int32Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readInt32(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Int64 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {BigInt64Array} The read data.\n */\n readInt64Array(byteOffset, size) {\n const bpe = BigInt64Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of BigInt64Array.BYTES_PER_ELEMENT (=8)\n if (byteOffset % bpe === 0) {\n data = new BigInt64Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new BigInt64Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readBigInt64(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Float32 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Float32Array} The read data.\n */\n readFloat32Array(byteOffset, size) {\n const bpe = Float32Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of Float32Array.BYTES_PER_ELEMENT (=4)\n if (byteOffset % bpe === 0) {\n data = new Float32Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new Float32Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readFloat32(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read Float64 array.\n *\n * @param {number} byteOffset The offset to start reading from.\n * @param {number} size The size of the array.\n * @returns {Float64Array} The read data.\n */\n readFloat64Array(byteOffset, size) {\n const bpe = Float64Array.BYTES_PER_ELEMENT;\n const arraySize = size / bpe;\n let data = null;\n // byteOffset should be a multiple of Float64Array.BYTES_PER_ELEMENT (=8)\n if (byteOffset % bpe === 0) {\n data = new Float64Array(this.#buffer, byteOffset, arraySize);\n if (this.#needFlip) {\n flipArrayEndianness(data);\n }\n } else {\n data = new Float64Array(arraySize);\n let index = byteOffset;\n for (let i = 0; i < arraySize; ++i) {\n data[i] = this.readFloat64(index);\n index += bpe;\n }\n }\n return data;\n }\n\n /**\n * Read data as an hexadecimal string of length 4 (no '0x' prefix).\n *\n * @param {number} byteOffset The offset to start reading from.\n * @returns {string} The read data ('####').\n */\n readHex(byteOffset) {\n // read and convert to hex string\n const str = this.readUint16(byteOffset).toString(16);\n // return padded\n return '0000'.substring(0, 4 - str.length) + str.toUpperCase();\n }\n\n} // class DataReader\n","import {\n Tag,\n getTransferSyntaxUIDTag,\n isSequenceDelimitationItemTag,\n isItemDelimitationItemTag,\n isPixelDataTag\n} from './dicomTag';\nimport {\n is32bitVLVR,\n isCharSetStringVR,\n transferSyntaxes,\n transferSyntaxKeywords,\n vrTypes,\n} from './dictionary';\nimport {DataElement} from './dataElement';\nimport {DataReader} from './dataReader';\nimport {logger} from '../utils/logger';\n\n/**\n * List of DICOM data elements indexed via a 8 character string formed from\n * the group and element numbers.\n *\n * @typedef {Object} DataElements\n */\n\n/**\n * Get the version of the library.\n *\n * @returns {string} The version of the library.\n */\nexport function getDwvVersion() {\n return '0.35.0-beta.3';\n}\n\n/**\n * Check that an input buffer includes the DICOM prefix 'DICM'\n * after the 128 bytes preamble.\n *\n * Ref: [DICOM File Meta]{@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part10/chapter_7.html#sect_7.1}.\n *\n * @param {ArrayBuffer} buffer The buffer to check.\n * @returns {boolean} True if the buffer includes the prefix.\n */\nexport function hasDicomPrefix(buffer) {\n // check size: typed array constructor will throw RangeError if\n // byteOffset + length * TypedArray.BYTES_PER_ELEMENT > buffer.byteLength\n if (buffer.byteLength < 132) {\n return false;\n }\n const prefixArray = new Uint8Array(buffer, 128, 4);\n const stringReducer = function (previous, current) {\n return previous += String.fromCharCode(current);\n };\n return prefixArray.reduce(stringReducer, '') === 'DICM';\n}\n\n// Zero-width space (u200B)\n// @ts-ignore\nconst ZWS = String.fromCharCode('u200B');\n\n/**\n * Clean string: remove zero-width space ending and trim.\n * Warning: no tests are done on the input, will fail if\n * null or undefined or not string.\n * Exported for tests only.\n *\n * @param {string} inputStr The string to clean.\n * @returns {string} The cleaned string.\n */\nexport function cleanString(inputStr) {\n let res = inputStr;\n // get rid of ending zero-width space\n const lastIndex = inputStr.length - 1;\n if (inputStr[lastIndex] === ZWS) {\n res = inputStr.substring(0, lastIndex);\n }\n // trim spaces\n res = res.trim();\n // return\n return res;\n}\n\n/**\n * Get the utfLabel (used by the TextDecoder) from a character set term.\n *\n * References:\n * - DICOM [Value Encoding]{@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/chapter_6.html},\n * - DICOM [Specific Character Set]{@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.12.html#sect_C.12.1.1.2},\n * - [TextDecoder#Parameters]{@link https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder/TextDecoder#Parameters}.\n *\n * @param {string} charSetTerm The DICOM character set.\n * @returns {string} The corresponding UTF label.\n */\nfunction getUtfLabel(charSetTerm) {\n let label = 'utf-8';\n if (charSetTerm === 'ISO_IR 100') {\n label = 'iso-8859-1';\n } else if (charSetTerm === 'ISO_IR 101') {\n label = 'iso-8859-2';\n } else if (charSetTerm === 'ISO_IR 109') {\n label = 'iso-8859-3';\n } else if (charSetTerm === 'ISO_IR 110') {\n label = 'iso-8859-4';\n } else if (charSetTerm === 'ISO_IR 144') {\n label = 'iso-8859-5';\n } else if (charSetTerm === 'ISO_IR 127') {\n label = 'iso-8859-6';\n } else if (charSetTerm === 'ISO_IR 126') {\n label = 'iso-8859-7';\n } else if (charSetTerm === 'ISO_IR 138') {\n label = 'iso-8859-8';\n } else if (charSetTerm === 'ISO_IR 148') {\n label = 'iso-8859-9';\n } else if (charSetTerm === 'ISO_IR 13') {\n label = 'shift-jis';\n } else if (charSetTerm === 'ISO_IR 166') {\n label = 'iso-8859-11';\n } else if (charSetTerm === 'ISO 2022 IR 87') {\n label = 'iso-2022-jp';\n } else if (charSetTerm === 'ISO 2022 IR 149') {\n // not supported by TextDecoder when it says it should...\n //label = \"iso-2022-kr\";\n } else if (charSetTerm === 'ISO 2022 IR 58') {\n // not supported by TextDecoder...\n //label = \"iso-2022-cn\";\n } else if (charSetTerm === 'ISO_IR 192') {\n label = 'utf-8';\n } else if (charSetTerm === 'GB18030') {\n label = 'gb18030';\n } else if (charSetTerm === 'GB2312') {\n label = 'gb2312';\n } else if (charSetTerm === 'GBK') {\n label = 'chinese';\n }\n return label;\n}\n\n/**\n * Default text decoder.\n */\nclass DefaultTextDecoder {\n /**\n * Decode an input string buffer.\n *\n * @param {Uint8Array} buffer The buffer to decode.\n * @returns {string} The decoded string.\n */\n decode(buffer) {\n let result = '';\n for (let i = 0, leni = buffer.length; i < leni; ++i) {\n result += String.fromCharCode(buffer[i]);\n }\n return result;\n }\n}\n\n/**\n * Get patient orientation label in the reverse direction.\n *\n * @param {string} ori Patient Orientation value.\n * @returns {string} Reverse Orientation Label.\n */\nexport function getReverseOrientation(ori) {\n if (!ori) {\n return null;\n }\n // reverse labels\n const rlabels = {\n L: 'R',\n R: 'L',\n A: 'P',\n P: 'A',\n H: 'F',\n F: 'H'\n };\n\n let rori = '';\n for (let n = 0; n < ori.length; n++) {\n const o = ori.substring(n, n + 1);\n const r = rlabels[o];\n if (r) {\n rori += r;\n }\n }\n // return\n return rori;\n}\n\n/**\n * Tell if a given syntax is an implicit one (element with no VR).\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if an implicit syntax.\n */\nexport function isImplicitTransferSyntax(syntax) {\n return syntax === transferSyntaxKeywords.ImplicitVRLittleEndian;\n}\n\n/**\n * Tell if a given syntax is a big endian syntax.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a big endian syntax.\n */\nexport function isBigEndianTransferSyntax(syntax) {\n return syntax === transferSyntaxKeywords.ExplicitVRBigEndian;\n}\n\n/**\n * Tell if a given syntax is a JPEG baseline one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a jpeg baseline syntax.\n */\nexport function isJpegBaselineTransferSyntax(syntax) {\n return syntax === transferSyntaxKeywords.JPEGBaseline8Bit ||\n syntax === transferSyntaxKeywords.JPEGExtended12Bit;\n}\n\n/**\n * Tell if a given syntax is a JPEG Lossless one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a jpeg lossless syntax.\n */\nexport function isJpegLosslessTransferSyntax(syntax) {\n return syntax === transferSyntaxKeywords.JPEGLossless ||\n syntax === transferSyntaxKeywords.JPEGLosslessSV1;\n}\n\n/**\n * Tell if a given syntax is a JPEG 2000 one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a jpeg 2000 syntax.\n */\nexport function isJpeg2000TransferSyntax(syntax) {\n return syntax.match(/1.2.840.10008.1.2.4.9/) !== null;\n}\n\n/**\n * Tell if a given syntax is a RLE (Run-length encoding) one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a RLE syntax.\n */\nfunction isRleTransferSyntax(syntax) {\n return syntax === transferSyntaxKeywords.RLELossless;\n}\n\n/**\n * Tell if a given syntax needs decompression.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {string|undefined} The name of the decompression algorithm.\n */\nexport function getSyntaxDecompressionName(syntax) {\n let algo;\n if (isJpeg2000TransferSyntax(syntax)) {\n algo = 'jpeg2000';\n } else if (isJpegBaselineTransferSyntax(syntax)) {\n algo = 'jpeg-baseline';\n } else if (isJpegLosslessTransferSyntax(syntax)) {\n algo = 'jpeg-lossless';\n } else if (isRleTransferSyntax(syntax)) {\n algo = 'rle';\n }\n return algo;\n}\n\n/**\n * Tell if a given syntax is supported for reading.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a supported syntax.\n */\nfunction isReadSupportedTransferSyntax(syntax) {\n return (syntax === transferSyntaxKeywords.ImplicitVRLittleEndian ||\n syntax === transferSyntaxKeywords.ExplicitVRLittleEndian ||\n syntax === transferSyntaxKeywords.ExplicitVRBigEndian ||\n isJpegBaselineTransferSyntax(syntax) ||\n isJpegLosslessTransferSyntax(syntax) ||\n isJpeg2000TransferSyntax(syntax) ||\n isRleTransferSyntax(syntax));\n}\n\n/**\n * Get a transfer syntax name from its UID.\n *\n * @param {string} syntax The transfer syntax UID value.\n * @returns {string} The transfer syntax name.\n */\nexport function getTransferSyntaxName(syntax) {\n let name = 'Unknown';\n if (typeof transferSyntaxes[syntax] !== 'undefined') {\n name = transferSyntaxes[syntax];\n }\n return name;\n}\n\n/**\n * Guess the transfer syntax from the first data element.\n *\n * See {@link https://github.com/ivmartel/dwv/issues/188}\n * (Allow to load DICOM with no DICM preamble) for more details.\n *\n * @param {DataElement} firstDataElement The first data element\n * of the DICOM header.\n * @returns {DataElement} The transfer syntax data element.\n */\nfunction guessTransferSyntax(firstDataElement) {\n const oEightGroupBigEndian = '0800';\n const oEightGroupLittleEndian = '0008';\n // check that group is 0008\n const group = firstDataElement.tag.getGroup();\n if (group !== oEightGroupBigEndian &&\n group !== oEightGroupLittleEndian) {\n throw new Error(\n 'Not a valid DICOM file (no magic DICM word found' +\n ' and first element not in 0008 group)'\n );\n }\n // reasonable assumption: 2 uppercase characters => explicit vr\n const vr = firstDataElement.vr;\n const vr0 = vr.charCodeAt(0);\n const vr1 = vr.charCodeAt(1);\n const implicit = (vr0 >= 65 && vr0 <= 90 && vr1 >= 65 && vr1 <= 90)\n ? false : true;\n // guess transfer syntax\n let syntax = null;\n if (group === oEightGroupLittleEndian) {\n if (implicit) {\n syntax = transferSyntaxKeywords.ImplicitVRLittleEndian;\n } else {\n syntax = transferSyntaxKeywords.ExplicitVRLittleEndian;\n }\n } else {\n if (implicit) {\n // ImplicitVRBigEndian: impossible\n throw new Error(\n 'Not a valid DICOM file (no magic DICM word found' +\n 'and implicit VR big endian detected)'\n );\n } else {\n syntax = transferSyntaxKeywords.ExplicitVRBigEndian;\n }\n }\n // set transfer syntax data element\n const dataElement = new DataElement('UI');\n dataElement.tag = getTransferSyntaxUIDTag();\n dataElement.value = [syntax];\n dataElement.vl = dataElement.value[0].length;\n dataElement.startOffset = firstDataElement.startOffset;\n dataElement.endOffset = dataElement.startOffset + dataElement.vl;\n\n return dataElement;\n}\n\n/**\n * Get the appropriate TypedArray in function of arguments.\n *\n * @param {number} bitsAllocated The number of bites used to store\n * the data: [8, 16, 32].\n * @param {number} pixelRepresentation The pixel representation,\n * 0:unsigned;1:signed.\n * @param {number} size The size of the new array.\n * @returns {Uint8Array|Int8Array|Uint16Array|Int16Array|Uint32Array|Int32Array}\n * The good typed array.\n */\nexport function getTypedArray(bitsAllocated, pixelRepresentation, size) {\n let res = null;\n try {\n if (bitsAllocated === 1 || bitsAllocated === 8) {\n if (pixelRepresentation === 0) {\n res = new Uint8Array(size);\n } else {\n res = new Int8Array(size);\n }\n } else if (bitsAllocated === 16) {\n if (pixelRepresentation === 0) {\n res = new Uint16Array(size);\n } else {\n res = new Int16Array(size);\n }\n } else if (bitsAllocated === 32) {\n if (pixelRepresentation === 0) {\n res = new Uint32Array(size);\n } else {\n res = new Int32Array(size);\n }\n }\n } catch (error) {\n if (error instanceof RangeError) {\n const powerOf2 = Math.floor(Math.log(size) / Math.log(2));\n logger.error('Cannot allocate array of size: ' +\n size + ' (>2^' + powerOf2 + ').');\n }\n }\n return res;\n}\n\n/**\n * Get the number of bytes occupied by a data element prefix,\n * (without its value).\n *\n * WARNING: this is valid for tags with a VR, if not sure use\n * the 'isTagWithVR' function first.\n *\n * Reference:\n * - [Data Element explicit]{@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/chapter_7.html#table_7.1-1},\n * - [Data Element implicit]{@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_7.5.2.html#table_7.5-1}.\n *\n * ```\n * | Tag | VR | VL | Value |\n * | 4 | 2 | 2 | X | -> regular explicit: 8 + X\n * | 4 | 2+2 | 4 | X | -> 32bit VL: 12 + X\n *\n * | Tag | VL | Value |\n * | 4 | 4 | X | -> implicit (32bit VL): 8 + X\n *\n * | Tag | Len | Value |\n * | 4 | 4 | X | -> item: 8 + X\n * ```\n *\n * @param {string} vr The Value Representation of the element.\n * @param {boolean} isImplicit Does the data use implicit VR?\n * @returns {number} The size of the element prefix.\n */\nexport function getDataElementPrefixByteSize(vr, isImplicit) {\n return isImplicit ? 8 : is32bitVLVR(vr) ? 12 : 8;\n}\n\n/**\n * Is the input VR a known VR.\n *\n * @param {string} vr The vr to test.\n * @returns {boolean} True if known.\n */\nfunction isKnownVR(vr) {\n const extraVrTypes = ['NONE', 'ox', 'xx', 'xs'];\n const knownTypes = Object.keys(vrTypes).concat(extraVrTypes);\n return knownTypes.includes(vr);\n}\n\n/**\n * Small list of used tag keys.\n */\nconst TagKeys = {\n TransferSyntax: '00020010',\n SpecificCharacterSet: '00080005',\n NumberOfFrames: '00280008',\n BitsAllocated: '00280100',\n PixelRepresentation: '00280103',\n PixelData: '7FE00010'\n};\n\n/**\n * DicomParser class.\n *\n * @example\n * // XMLHttpRequest onload callback\n * const onload = function (event) {\n * // setup the dicom parser\n * const dicomParser = new dwv.DicomParser();\n * // parse the buffer\n * dicomParser.parse(event.target.response);\n * // get the dicom tags\n * const tags = dicomParser.getDicomElements();\n * // display the modality\n * const div = document.getElementById('dwv');\n * div.appendChild(document.createTextNode(\n * 'Modality: ' + tags['00080060'].value[0]\n * ));\n * };\n * // DICOM file request\n * const request = new XMLHttpRequest();\n * const url = 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm';\n * request.open('GET', url);\n * request.responseType = 'arraybuffer';\n * request.onload = onload;\n * request.send();\n */\nexport class DicomParser {\n\n /**\n * The list of DICOM elements.\n *\n * @type {DataElements}\n */\n #dataElements = {};\n\n /**\n * Default character set (optional).\n *\n * @type {string}\n */\n #defaultCharacterSet;\n\n /**\n * Default text decoder.\n *\n * @type {DefaultTextDecoder}\n */\n #defaultTextDecoder = new DefaultTextDecoder();\n\n /**\n * Special text decoder.\n *\n * @type {DefaultTextDecoder|TextDecoder}\n */\n #textDecoder = this.#defaultTextDecoder;\n\n /**\n * Decode an input string buffer using the default text decoder.\n *\n * @param {Uint8Array} buffer The buffer to decode.\n * @returns {string} The decoded string.\n */\n #decodeString(buffer) {\n return this.#defaultTextDecoder.decode(buffer);\n }\n\n /**\n * Decode an input string buffer using the 'special' text decoder.\n *\n * @param {Uint8Array} buffer The buffer to decode.\n * @returns {string} The decoded string.\n */\n #decodeSpecialString(buffer) {\n return this.#textDecoder.decode(buffer);\n }\n\n /**\n * Get the default character set.\n *\n * @returns {string} The default character set.\n */\n getDefaultCharacterSet() {\n return this.#defaultCharacterSet;\n }\n\n /**\n * Set the default character set.\n *\n * @param {string} characterSet The input character set.\n */\n setDefaultCharacterSet(characterSet) {\n this.#defaultCharacterSet = characterSet;\n }\n\n /**\n * Set the text decoder character set.\n *\n * @param {string} characterSet The input character set.\n */\n setDecoderCharacterSet(characterSet) {\n /**\n * The text decoder.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder}.\n *\n * @external TextDecoder\n */\n this.#textDecoder = new TextDecoder(characterSet);\n }\n\n // not using type DataElements since the typedef is not exported with the API\n\n /**\n * Get the DICOM data elements.\n *\n * @returns {Object} The data elements.\n */\n getDicomElements() {\n return this.#dataElements;\n }\n\n /**\n * Read a DICOM tag.\n *\n * @param {DataReader} reader The raw data reader.\n * @param {number} offset The offset where to start to read.\n * @returns {object} An object containing the tag and the end offset.\n */\n #readTag(reader, offset) {\n // group\n const group = reader.readHex(offset);\n offset += Uint16Array.BYTES_PER_ELEMENT;\n // element\n const element = reader.readHex(offset);\n offset += Uint16Array.BYTES_PER_ELEMENT;\n // return\n return {\n tag: new Tag(group, element),\n endOffset: offset\n };\n }\n\n /**\n * Read an item data element.\n *\n * @param {DataReader} reader The raw data reader.\n * @param {number} offset The offset where to start to read.\n * @param {boolean} implicit Is the DICOM VR implicit?\n * @returns {object} The item data as a list of data elements.\n */\n #readItemDataElement(reader, offset, implicit) {\n const itemData = {};\n\n // read the first item\n let item = this.#readDataElement(reader, offset, implicit);\n offset = item.endOffset;\n\n // exit if it is a sequence delimitation item\n if (isSequenceDelimitationItemTag(item.tag)) {\n return {\n data: itemData,\n endOffset: item.endOffset,\n isSeqDelim: true\n };\n }\n\n // store item (mainly to keep vl)\n itemData[item.tag.getKey()] = {\n tag: item.tag,\n vr: 'NONE',\n vl: item.vl,\n undefinedLength: item.undefinedLength\n };\n\n if (!item.undefinedLength) {\n // explicit VR item: read until the end offset\n const endOffset = offset;\n offset -= item.vl;\n while (offset < endOffset) {\n item = this.#readDataElement(reader, offset, implicit);\n offset = item.endOffset;\n itemData[item.tag.getKey()] = item;\n }\n } else {\n // implicit VR item: read until the item delimitation item\n let isItemDelim = false;\n while (!isItemDelim) {\n item = this.#readDataElement(reader, offset, implicit);\n offset = item.endOffset;\n isItemDelim = isItemDelimitationItemTag(item.tag);\n if (!isItemDelim) {\n itemData[item.tag.getKey()] = item;\n }\n }\n }\n\n return {\n data: itemData,\n endOffset: offset,\n isSeqDelim: false\n };\n }\n\n /**\n * Read the pixel item data element.\n * Ref: [Single frame fragments]{@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_A.4.html#table_A.4-1}.\n *\n * @param {DataReader} reader The raw data reader.\n * @param {number} offset The offset where to start to read.\n * @param {boolean} implicit Is the DICOM VR implicit?\n * @returns {object} The item data as an array of data elements.\n */\n #readPixelItemDataElement(\n reader, offset, implicit) {\n const itemData = [];\n\n // first item: basic offset table\n let item = this.#readDataElement(reader, offset, implicit);\n const offsetTableVl = item.vl;\n offset = item.endOffset;\n\n // read until the sequence delimitation item\n let isSeqDelim = false;\n while (!isSeqDelim) {\n item = this.#readDataElement(reader, offset, implicit);\n offset = item.endOffset;\n isSeqDelim = isSequenceDelimitationItemTag(item.tag);\n if (!isSeqDelim) {\n // force pixel item vr to OB\n item.vr = 'OB';\n itemData.push(item);\n }\n }\n\n return {\n data: itemData,\n endOffset: offset,\n offsetTableVl: offsetTableVl\n };\n }\n\n /**\n * Read a DICOM data element.\n *\n * Reference: [DICOM VRs]{@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_6.2.html#table_6.2-1}.\n *\n * @param {DataReader} reader The raw data reader.\n * @param {number} offset The offset where to start to read.\n * @param {boolean} implicit Is the DICOM VR implicit?\n * @returns {DataElement} The data element.\n */\n #readDataElement(reader, offset, implicit) {\n // Tag: group, element\n const readTagRes = this.#readTag(reader, offset);\n const tag = readTagRes.tag;\n offset = readTagRes.endOffset;\n\n // Value Representation (VR)\n let vr = null;\n let is32bitVL = false;\n if (tag.isWithVR()) {\n // implicit VR\n if (implicit) {\n vr = tag.getVrFromDictionary();\n if (typeof vr === 'undefined') {\n vr = 'UN';\n }\n is32bitVL = true;\n } else {\n vr = this.#decodeString(reader.readUint8Array(offset, 2));\n offset += 2 * Uint8Array.BYTES_PER_ELEMENT;\n is32bitVL = is32bitVLVR(vr);\n // reserved 2 bytes\n if (is32bitVL) {\n offset += 2 * Uint8Array.BYTES_PER_ELEMENT;\n }\n }\n } else {\n vr = 'NONE';\n is32bitVL = true;\n }\n\n // check vr\n if (!isKnownVR(vr)) {\n logger.warn('Unknown VR: ' + vr +\n ' (for tag ' + tag.getKey() + '), treating as \\'UN\\'');\n vr = 'UN';\n }\n\n // Value Length (VL)\n let vl = 0;\n if (is32bitVL) {\n vl = reader.readUint32(offset);\n offset += Uint32Array.BYTES_PER_ELEMENT;\n } else {\n vl = reader.readUint16(offset);\n offset += Uint16Array.BYTES_PER_ELEMENT;\n }\n\n // check the value of VL\n let undefinedLength = false;\n if (vl === 0xffffffff) {\n undefinedLength = true;\n vl = 0;\n }\n\n // treat private tag with unknown VR and zero VL as a sequence (see #799)\n if (tag.isPrivate() && vr === 'UN' && vl === 0) {\n vr = 'SQ';\n }\n\n let startOffset = offset;\n let endOffset = startOffset + vl;\n\n // read sequence elements\n let data;\n if (isPixelDataTag(tag) && undefinedLength) {\n // pixel data sequence (implicit)\n const pixItemData =\n this.#readPixelItemDataElement(reader, offset, implicit);\n offset = pixItemData.endOffset;\n startOffset += pixItemData.offsetTableVl;\n data = pixItemData.data;\n endOffset = offset;\n vl = offset - startOffset;\n } else if (vr === 'SQ') {\n // sequence\n data = [];\n let itemData;\n if (!undefinedLength) {\n if (vl !== 0) {\n // explicit VR sequence: read until the end offset\n const sqEndOffset = offset + vl;\n while (offset < sqEndOffset) {\n itemData = this.#readItemDataElement(reader, offset, implicit);\n data.push(itemData.data);\n offset = itemData.endOffset;\n }\n endOffset = offset;\n vl = offset - startOffset;\n }\n } else {\n // implicit VR sequence: read until the sequence delimitation item\n let isSeqDelim = false;\n while (!isSeqDelim) {\n itemData = this.#readItemDataElement(reader, offset, implicit);\n isSeqDelim = itemData.isSeqDelim;\n offset = itemData.endOffset;\n // do not store the delimitation item\n if (!isSeqDelim) {\n data.push(itemData.data);\n }\n }\n endOffset = offset;\n vl = offset - startOffset;\n }\n }\n\n // return\n const element = new DataElement(vr);\n element.tag = tag;\n element.vl = vl;\n element.startOffset = startOffset;\n element.endOffset = endOffset;\n // only set if true (only for sequences and items)\n if (undefinedLength) {\n element.undefinedLength = undefinedLength;\n }\n if (data) {\n element.items = data;\n }\n return element;\n }\n\n /**\n * Interpret the data of an element.\n *\n * @param {DataElement} element The data element.\n * @param {DataReader} reader The raw data reader.\n * @param {number} [pixelRepresentation] PixelRepresentation 0->unsigned,\n * 1->signed (needed for pixel data or VR=xs).\n * @param {number} [bitsAllocated] Bits allocated (needed for pixel data).\n * @returns {object} The interpreted data.\n */\n #interpretElement(\n element, reader, pixelRepresentation, bitsAllocated) {\n\n const tag = element.tag;\n const vl = element.vl;\n const vr = element.vr;\n const offset = element.startOffset;\n\n // data\n let data = null;\n const vrType = vrTypes[vr];\n if (isPixelDataTag(tag)) {\n if (element.undefinedLength) {\n // implicit pixel data sequence\n data = [];\n for (let j = 0; j < element.items.length; ++j) {\n data.push(this.#interpretElement(\n element.items[j], reader,\n pixelRepresentation, bitsAllocated));\n }\n // remove non parsed items\n delete element.items;\n } else {\n // check bits allocated and VR\n // https://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_A.2.html\n if (bitsAllocated > 8 && vr === 'OB') {\n logger.warn(\n 'Reading DICOM pixel data with bitsAllocated>8 and OB VR' +\n ', treating as OW'\n );\n element.vr = 'OW';\n }\n // read\n data = [];\n if (bitsAllocated === 1) {\n data.push(reader.readBinaryArray(offset, vl));\n } else if (bitsAllocated === 8) {\n if (pixelRepresentation === 0) {\n data.push(reader.readUint8Array(offset, vl));\n } else {\n data.push(reader.readInt8Array(offset, vl));\n }\n } else if (bitsAllocated === 16) {\n if (pixelRepresentation === 0) {\n data.push(reader.readUint16Array(offset, vl));\n } else {\n data.push(reader.readInt16Array(offset, vl));\n }\n } else {\n throw new Error('Unsupported bits allocated: ' + bitsAllocated);\n }\n }\n } else if (typeof vrType !== 'undefined') {\n if (vrType === 'Uint8') {\n data = reader.readUint8Array(offset, vl);\n } else if (vrType === 'Uint16') {\n data = reader.readUint16Array(offset, vl);\n // keep as binary for 'O*' VR\n if (vr[0] !== 'O') {\n data = Array.from(data);\n }\n } else if (vrType === 'Uint32') {\n data = reader.readUint32Array(offset, vl);\n // keep as binary for 'O*' VR\n if (vr[0] !== 'O') {\n data = Array.from(data);\n }\n } else if (vrType === 'Uint64') {\n data = reader.readUint64Array(offset, vl);\n } else if (vrType === 'Int16') {\n data = Array.from(reader.readInt16Array(offset, vl));\n } else if (vrType === 'Int32') {\n data = Array.from(reader.readInt32Array(offset, vl));\n } else if (vrType === 'Int64') {\n data = reader.readInt64Array(offset, vl);\n } else if (vrType === 'Float32') {\n data = Array.from(reader.readFloat32Array(offset, vl));\n } else if (vrType === 'Float64') {\n data = Array.from(reader.readFloat64Array(offset, vl));\n } else if (vrType === 'string') {\n const stream = reader.readUint8Array(offset, vl);\n if (isCharSetStringVR(vr)) {\n data = this.#decodeSpecialString(stream);\n } else {\n data = this.#decodeString(stream);\n }\n data = cleanString(data).split('\\\\');\n } else {\n throw new Error('Unknown VR type: ' + vrType);\n }\n } else if (vr === 'xx') {\n // US or OW\n data = Array.from(reader.readUint16Array(offset, vl));\n } else if (vr === 'ox') {\n // OB or OW\n if (bitsAllocated === 8) {\n if (pixelRepresentation === 0) {\n data = Array.from(reader.readUint8Array(offset, vl));\n } else {\n data = Array.from(reader.readInt8Array(offset, vl));\n }\n } else {\n if (pixelRepresentation === 0) {\n data = Array.from(reader.readUint16Array(offset, vl));\n } else {\n data = Array.from(reader.readInt16Array(offset, vl));\n }\n }\n } else if (vr === 'xs') {\n // (US or SS) or (US or SS or OW)\n if (pixelRepresentation === 0) {\n data = Array.from(reader.readUint16Array(offset, vl));\n } else {\n data = Array.from(reader.readInt16Array(offset, vl));\n }\n } else if (vr === 'AT') {\n // attribute\n const raw = reader.readUint16Array(offset, vl);\n data = [];\n for (let i = 0, leni = raw.length; i < leni; i += 2) {\n const stri = raw[i].toString(16);\n const stri1 = raw[i + 1].toString(16);\n let str = '(';\n str += '0000'.substring(0, 4 - stri.length) + stri.toUpperCase();\n str += ',';\n str += '0000'.substring(0, 4 - stri1.length) + stri1.toUpperCase();\n str += ')';\n data.push(str);\n }\n } else if (vr === 'SQ') {\n // sequence\n data = [];\n for (let k = 0; k < element.items.length; ++k) {\n const item = element.items[k];\n const itemData = {};\n const keys = Object.keys(item);\n let sqBitsAllocated = bitsAllocated;\n let sqPixelRepresentation = pixelRepresentation;\n for (let l = 0; l < keys.length; ++l) {\n // check if local bitsAllocated\n // (inside item loop to get interpreted value)\n let dataElement = item[TagKeys.BitsAllocated];\n if (typeof dataElement !== 'undefined' &&\n typeof dataElement.value !== 'undefined') {\n sqBitsAllocated = dataElement.value[0];\n }\n // check if local pixelRepresentation\n // (inside item loop to get interpreted value)\n dataElement = item[TagKeys.PixelRepresentation];\n if (typeof dataElement !== 'undefined' &&\n typeof dataElement.value !== 'undefined') {\n sqPixelRepresentation = dataElement.value[0];\n }\n const subElement = item[keys[l]];\n subElement.value = this.#interpretElement(\n subElement, reader,\n sqPixelRepresentation, sqBitsAllocated);\n delete subElement.tag;\n delete subElement.vl;\n delete subElement.startOffset;\n delete subElement.endOffset;\n itemData[keys[l]] = subElement;\n }\n data.push(itemData);\n }\n // remove non parsed elements\n delete element.items;\n } else if (vr === 'NONE') {\n // no VR -> no data\n data = [];\n } else {\n logger.warn('Unknown VR: ' + vr +\n ' (for tag ' + element.tag.getKey() + ')');\n // empty data...\n data = [];\n }\n\n return data;\n }\n\n /**\n * Interpret the data of a list of elements.\n *\n * @param {DataElements} elements A list of data elements.\n * @param {DataReader} reader The raw data reader.\n * @param {number} pixelRepresentation PixelRepresentation 0->unsigned,\n * 1->signed.\n * @param {number} bitsAllocated Bits allocated.\n */\n #interpret(\n elements, reader,\n pixelRepresentation, bitsAllocated) {\n\n const keys = Object.keys(elements);\n for (let i = 0; i < keys.length; ++i) {\n const element = elements[keys[i]];\n if (typeof element.value === 'undefined') {\n element.value = this.#interpretElement(\n element, reader, pixelRepresentation, bitsAllocated);\n }\n // delete interpretation specific properties\n delete element.tag;\n delete element.vl;\n delete element.startOffset;\n delete element.endOffset;\n }\n }\n\n /**\n * Parse the complete DICOM file (given as input to the class).\n * Fills in the member object 'dataElements'.\n *\n * @param {ArrayBuffer} buffer The input array buffer.\n */\n parse(buffer) {\n let offset = 0;\n let syntax = '';\n let dataElement = null;\n // default readers\n const metaReader = new DataReader(buffer);\n let dataReader = new DataReader(buffer);\n\n // 128 -> 132: magic word\n offset = 128;\n const magicword = this.#decodeString(metaReader.readUint8Array(offset, 4));\n offset += 4 * Uint8Array.BYTES_PER_ELEMENT;\n if (magicword === 'DICM') {\n // 0002, 0000: FileMetaInformationGroupLength (vr='UL')\n dataElement = this.#readDataElement(metaReader, offset, false);\n dataElement.value = this.#interpretElement(dataElement, metaReader);\n // increment offset\n offset = dataElement.endOffset;\n // store the data element\n this.#dataElements[dataElement.tag.getKey()] = dataElement;\n // get meta length\n const metaLength = dataElement.value[0];\n\n // meta elements\n const metaEnd = offset + metaLength;\n while (offset < metaEnd) {\n // get the data element\n dataElement = this.#readDataElement(metaReader, offset, false);\n offset = dataElement.endOffset;\n // store the data element\n this.#dataElements[dataElement.tag.getKey()] = dataElement;\n }\n\n // check the TransferSyntaxUID (has to be there!)\n dataElement = this.#dataElements[TagKeys.TransferSyntax];\n if (typeof dataElement === 'undefined') {\n throw new Error('Not a valid DICOM file (no TransferSyntaxUID found)');\n }\n dataElement.value = this.#interpretElement(dataElement, metaReader);\n syntax = dataElement.value[0];\n\n } else {\n logger.warn('No DICM prefix, trying to guess tansfer syntax.');\n // read first element\n dataElement = this.#readDataElement(dataReader, 0, false);\n // guess transfer syntax\n const tsElement = guessTransferSyntax(dataElement);\n // store\n this.#dataElements[tsElement.tag.getKey()] = tsElement;\n syntax = tsElement.value[0];\n // reset offset\n offset = 0;\n }\n\n // check transfer syntax support\n if (!isReadSupportedTransferSyntax(syntax)) {\n throw new Error('Unsupported DICOM transfer syntax: \\'' + syntax +\n '\\' (' + getTransferSyntaxName(syntax) + ')');\n }\n\n // set implicit flag\n let implicit = false;\n if (isImplicitTransferSyntax(syntax)) {\n implicit = true;\n }\n\n // Big Endian\n if (isBigEndianTransferSyntax(syntax)) {\n dataReader = new DataReader(buffer, false);\n }\n\n // DICOM data elements\n while (offset < buffer.byteLength) {\n // get the data element\n dataElement = this.#readDataElement(dataReader, offset, implicit);\n // increment offset\n offset = dataElement.endOffset;\n // store the data element\n const key = dataElement.tag.getKey();\n if (typeof this.#dataElements[key] === 'undefined') {\n this.#dataElements[key] = dataElement;\n } else {\n logger.warn('Not saving duplicate tag: ' + key);\n }\n }\n\n // safety checks...\n if (isNaN(offset)) {\n throw new Error('Problem while parsing, bad offset');\n }\n if (buffer.byteLength !== offset) {\n logger.warn('Did not reach the end of the buffer: ' +\n offset + ' != ' + buffer.byteLength);\n }\n\n //-------------------------------------------------\n // values needed for data interpretation\n\n // pixel specific\n let pixelRepresentation = 0;\n let bitsAllocated = 16;\n if (typeof this.#dataElements[TagKeys.PixelData] !== 'undefined') {\n // PixelRepresentation 0->unsigned, 1->signed\n dataElement = this.#dataElements[TagKeys.PixelRepresentation];\n if (typeof dataElement !== 'undefined') {\n dataElement.value = this.#interpretElement(dataElement, dataReader);\n pixelRepresentation = dataElement.value[0];\n } else {\n logger.warn(\n 'Reading DICOM pixel data with default pixelRepresentation.');\n }\n\n // BitsAllocated\n dataElement = this.#dataElements[TagKeys.BitsAllocated];\n if (typeof dataElement !== 'undefined') {\n dataElement.value = this.#interpretElement(dataElement, dataReader);\n bitsAllocated = dataElement.value[0];\n } else {\n logger.warn('Reading DICOM pixel data with default bitsAllocated.');\n }\n }\n\n // default character set\n if (typeof this.#defaultCharacterSet !== 'undefined') {\n this.setDecoderCharacterSet(this.#defaultCharacterSet);\n }\n\n // SpecificCharacterSet\n dataElement = this.#dataElements[TagKeys.SpecificCharacterSet];\n if (typeof dataElement !== 'undefined') {\n dataElement.value = this.#interpretElement(dataElement, dataReader);\n let charSetTerm;\n if (dataElement.value.length === 1) {\n charSetTerm = dataElement.value[0];\n } else {\n charSetTerm = dataElement.value[1];\n logger.warn('Unsupported character set with code extensions: \\'' +\n charSetTerm + '\\'.');\n }\n this.setDecoderCharacterSet(getUtfLabel(charSetTerm));\n }\n\n // interpret the dicom elements\n this.#interpret(\n this.#dataElements, dataReader,\n pixelRepresentation, bitsAllocated\n );\n\n // handle fragmented pixel buffer\n // Reference: http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_8.2.html\n // (third note, \"Depending on the transfer syntax...\")\n dataElement = this.#dataElements[TagKeys.PixelData];\n if (typeof dataElement !== 'undefined') {\n if (dataElement.undefinedLength) {\n let numberOfFrames = 1;\n if (typeof this.#dataElements[TagKeys.NumberOfFrames] !== 'undefined') {\n numberOfFrames = Number(\n this.#dataElements[TagKeys.NumberOfFrames].value[0]\n );\n }\n const pixItems = dataElement.value;\n if (pixItems.length > 1 && pixItems.length > numberOfFrames) {\n // concatenate pixel data items\n // concat does not work on typed arrays\n //this.pixelBuffer = this.pixelBuffer.concat( dataElement.data );\n // manual concat...\n const nItemPerFrame = pixItems.length / numberOfFrames;\n const newPixItems = [];\n let index = 0;\n for (let f = 0; f < numberOfFrames; ++f) {\n index = f * nItemPerFrame;\n // calculate the size of a frame\n let size = 0;\n for (let i = 0; i < nItemPerFrame; ++i) {\n size += pixItems[index + i].length;\n }\n // create new buffer\n const newBuffer = new pixItems[0].constructor(size);\n // fill new buffer\n let fragOffset = 0;\n for (let j = 0; j < nItemPerFrame; ++j) {\n newBuffer.set(pixItems[index + j], fragOffset);\n fragOffset += pixItems[index + j].length;\n }\n newPixItems[f] = newBuffer;\n }\n // store as pixel data\n dataElement.value = newPixItems;\n }\n }\n }\n }\n\n} // class DicomParser\n","import {logger} from './logger';\n\n/**\n * ListenerHandler class: handles add/removing and firing listeners.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget#example}.\n */\nexport class ListenerHandler {\n /**\n * Listeners.\n *\n * @type {object}\n */\n #listeners = {};\n\n /**\n * Add an event listener.\n *\n * @param {string} type The event type.\n * @param {object} callback The method associated with the provided\n * event type, will be called with the fired event.\n */\n add(type, callback) {\n // create array if not present\n if (typeof this.#listeners[type] === 'undefined') {\n this.#listeners[type] = [];\n }\n // add callback to listeners array\n this.#listeners[type].push(callback);\n }\n\n /**\n * Remove an event listener.\n *\n * @param {string} type The event type.\n * @param {object} callback The method associated with the provided\n * event type.\n */\n remove(type, callback) {\n // check if the type is present\n if (typeof this.#listeners[type] === 'undefined') {\n return;\n }\n // remove from listeners array\n let nFound = 0;\n for (let i = 0; i < this.#listeners[type].length; ++i) {\n if (this.#listeners[type][i] === callback) {\n ++nFound;\n this.#listeners[type].splice(i, 1);\n }\n }\n if (nFound === 0) {\n logger.debug('No callback found on remove listener for type ' + type);\n }\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n fireEvent = (event) => {\n // check if they are listeners for the event type\n if (typeof this.#listeners[event.type] === 'undefined') {\n return;\n }\n // fire events from a copy of the listeners array\n // to avoid interference from possible add/remove\n const stack = this.#listeners[event.type].slice();\n for (let i = 0; i < stack.length; ++i) {\n stack[i](event);\n }\n };\n}\n","import {Index} from '../math/index';\nimport {Point2D} from '../math/point';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {Point} from '../math/point';\nimport {Matrix33} from '../math/matrix';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get an simple iterator for a given range for a one component data.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols}.\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start The start of the range (included).\n * @param {number} end The end of the range (excluded).\n * @param {number} [increment] The increment between indicies (default=1).\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function simpleRange(dataAccessor, start, end, increment) {\n if (typeof increment === 'undefined') {\n increment = 1;\n }\n let nextIndex = start;\n // result\n return {\n next: function () {\n if (nextIndex < end) {\n const result = {\n value: dataAccessor(nextIndex),\n done: false,\n index: nextIndex\n };\n nextIndex += increment;\n return result;\n }\n return {\n done: true,\n index: end\n };\n }\n };\n}\n\n/**\n * Get an iterator for a given range for a one component data.\n *\n * Using 'maxIter' and not an 'end' index since it fails in some edge cases\n * (for ex coronal2, ie zxy).\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start Zero-based index at which to start the iteration.\n * @param {number} maxIter The maximum number of iterations.\n * @param {number} increment Increment between indicies.\n * @param {number} blockMaxIter Number of applied increment after which\n * blockIncrement is applied.\n * @param {number} blockIncrement Increment after blockMaxIter is reached,\n * the value is from block start to the next block start.\n * @param {boolean} reverse1 If true, loop from end to start.\n * WARN: don't forget to set the value of start as the last index!\n * @param {boolean} reverse2 If true, loop from block end to block start.\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function range(dataAccessor, start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2) {\n if (typeof reverse1 === 'undefined') {\n reverse1 = false;\n }\n if (typeof reverse2 === 'undefined') {\n reverse2 = false;\n }\n\n // first index of the iteration\n let nextIndex = start;\n // adapt first index and increments to reverse values\n if (reverse1) {\n blockIncrement *= -1;\n if (reverse2) {\n // start at end of line\n nextIndex -= (blockMaxIter - 1) * increment;\n } else {\n increment *= -1;\n }\n } else {\n if (reverse2) {\n // start at end of line\n nextIndex += (blockMaxIter - 1) * increment;\n increment *= -1;\n }\n }\n const finalBlockIncrement = blockIncrement - blockMaxIter * increment;\n\n // counters\n let mainCount = 0;\n let blockCount = 0;\n // result\n return {\n next: function () {\n if (mainCount < maxIter) {\n const result = {\n value: dataAccessor(nextIndex),\n done: false,\n index: nextIndex\n };\n nextIndex += increment;\n ++mainCount;\n ++blockCount;\n if (blockCount === blockMaxIter) {\n blockCount = 0;\n nextIndex += finalBlockIncrement;\n }\n return result;\n }\n return {\n done: true,\n index: nextIndex\n };\n }\n };\n}\n\n/**\n * Get an iterator for a given range with bounds (for a one component data).\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols}.\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start The start of the range (included).\n * @param {number} end The end of the range (excluded).\n * @param {number} increment The increment between indicies.\n * @param {number} regionSize The size of the region to iterate through.\n * @param {number} regionOffset The offset between regions.\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function rangeRegion(\n dataAccessor, start, end, increment, regionSize, regionOffset) {\n let nextIndex = start;\n let regionElementCount = 0;\n // result\n return {\n next: function () {\n if (nextIndex < end) {\n const result = {\n value: dataAccessor(nextIndex),\n done: false,\n index: nextIndex\n };\n regionElementCount += 1;\n nextIndex += increment;\n if (regionElementCount === regionSize) {\n regionElementCount = 0;\n nextIndex += regionOffset;\n }\n return result;\n }\n return {\n done: true,\n index: end\n };\n }\n };\n}\n\n/**\n * Get an iterator for a given range with bounds (for a one component data).\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols}.\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start The start of the range (included).\n * @param {number} end The end of the range (excluded).\n * @param {number} increment The increment between indicies.\n * @param {number[][]} regions An array of regions: [off0, size, off1].\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function rangeRegions(\n dataAccessor, start, end, increment, regions) {\n let nextIndex = start;\n let regionCount = 0;\n let regionElementCount = 0;\n // result\n return {\n next: function () {\n if (nextIndex < end) {\n const result = {\n value: dataAccessor(nextIndex),\n done: false,\n index: nextIndex\n };\n regionElementCount += 1;\n nextIndex += increment;\n if (regionElementCount === regions[regionCount][1]) {\n regionElementCount = 0;\n // off1 of current group\n nextIndex += regions[regionCount][2];\n regionCount += 1;\n // off0 of next group\n if (regionCount < regions.length) {\n nextIndex += regions[regionCount][0];\n }\n }\n return result;\n }\n return {\n done: true,\n index: end\n };\n }\n };\n}\n\n/**\n * Get an iterator for a given range for a 3 components data.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols}.\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start The start of the range (included).\n * @param {number} end The end of the range (excluded).\n * (end - start) needs to be a multiple of 3...\n * @param {number} increment The increment between indicies (default=1).\n * @param {boolean} isPlanar A flag to know if the data is planar\n * (RRRR...GGGG...BBBB...) or not (RGBRGBRGBRGB...), defaults to false.\n * @returns {object} A 3 components iterator folowing the iterator and iterable\n * protocol, the value is an array of size 3 with each component.\n */\nexport function simpleRange3d(\n dataAccessor, start, end, increment, isPlanar) {\n if (typeof increment === 'undefined') {\n increment = 1;\n }\n if (typeof isPlanar === 'undefined') {\n isPlanar = false;\n }\n let nextIndex = start;\n let componentIncrement = 1;\n if (isPlanar) {\n componentIncrement = (end - start) / 3;\n } else {\n increment *= 3;\n }\n let nextIndex1 = nextIndex + componentIncrement;\n let nextIndex2 = nextIndex + 2 * componentIncrement;\n\n // result\n return {\n next: function () {\n if (nextIndex < end) {\n const result = {\n value: [\n dataAccessor(nextIndex),\n dataAccessor(nextIndex1),\n dataAccessor(nextIndex2)\n ],\n done: false,\n index: [nextIndex, nextIndex1, nextIndex2]\n };\n nextIndex += increment;\n nextIndex1 += increment;\n nextIndex2 += increment;\n return result;\n }\n return {\n done: true,\n index: [end]\n };\n }\n };\n}\n\n/**\n * Get an iterator for a given range for a 3 components data.\n *\n * Using 'maxIter' and not an 'end' index since it fails in some edge cases\n * (for ex coronal2, ie zxy).\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start Zero-based index at which to start the iteration.\n * @param {number} maxIter The maximum number of iterations.\n * @param {number} increment Increment between indicies.\n * @param {number} blockMaxIter Number of applied increment after which\n * blockIncrement is applied.\n * @param {number} blockIncrement Increment after blockMaxIter is reached,\n * the value is from block start to the next block start.\n * @param {boolean} reverse1 If true, loop from end to start.\n * WARN: don't forget to set the value of start as the last index!\n * @param {boolean} reverse2 If true, loop from block end to block start.\n * @param {boolean} isPlanar A flag to know if the data is planar\n * (RRRR...GGGG...BBBB...) or not (RGBRGBRGBRGB...), defaults to false.\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function range3d(dataAccessor, start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2, isPlanar) {\n const iters = [];\n if (isPlanar) {\n iters.push(range(\n dataAccessor, start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2\n ));\n iters.push(range(\n dataAccessor, start + maxIter * increment, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2\n ));\n iters.push(range(\n dataAccessor, start + 2 * maxIter * increment, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2\n ));\n } else {\n increment *= 3;\n blockIncrement *= 3;\n iters.push(range(\n dataAccessor, start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2\n ));\n iters.push(range(\n dataAccessor, start + 1, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2\n ));\n iters.push(range(\n dataAccessor, start + 2, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2\n ));\n }\n\n // result\n return {\n next: function () {\n const r0 = iters[0].next();\n const r1 = iters[1].next();\n const r2 = iters[2].next();\n if (!r0.done) {\n return {\n value: [\n r0.value,\n r1.value,\n r2.value\n ],\n done: false,\n index: [\n r0.index,\n r1.index,\n r2.index\n ]\n };\n }\n return {\n done: true,\n index: r2.index\n };\n }\n };\n}\n\n/**\n * Get a list of values for a given iterator.\n *\n * @param {object} iterator The iterator to use to loop through data.\n * @returns {Array} The list of values.\n */\nexport function getIteratorValues(iterator) {\n const values = [];\n let ival = iterator.next();\n while (!ival.done) {\n values.push(ival.value);\n ival = iterator.next();\n }\n return values;\n}\n\n/**\n * Get a slice index iterator.\n *\n * @param {Image} image The image to parse.\n * @param {Index} position The current position.\n * @param {boolean} isRescaled Flag for rescaled values (default false).\n * @param {Matrix33} viewOrientation The view orientation.\n * @returns {object} The slice iterator.\n */\nexport function getSliceIterator(\n image, position, isRescaled, viewOrientation) {\n const size = image.getGeometry().getSize();\n // zero-ify non direction index\n let dirMax2Index = 2;\n if (viewOrientation && typeof viewOrientation !== 'undefined') {\n dirMax2Index = viewOrientation.getColAbsMax(2).index;\n }\n const posValues = position.getValues();\n // keep the main direction and any other than 3D\n const indexFilter = function (element, index) {\n return (index === dirMax2Index || index > 2) ? element : 0;\n };\n const posStart = new Index(posValues.map(indexFilter));\n let start = size.indexToOffset(posStart);\n\n // default to non rescaled data\n if (typeof isRescaled === 'undefined') {\n isRescaled = false;\n }\n let dataAccessor = null;\n if (isRescaled) {\n dataAccessor = function (offset) {\n return image.getRescaledValueAtOffset(offset);\n };\n } else {\n dataAccessor = function (offset) {\n return image.getValueAtOffset(offset);\n };\n }\n\n const ncols = size.get(0);\n const nrows = size.get(1);\n const nslices = size.get(2);\n let sliceSize = size.getDimSize(2);\n\n const ncomp = image.getNumberOfComponents();\n const isPlanar = image.getPlanarConfiguration() === 1;\n const getRange = function (\n dataAccessor, start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2) {\n if (ncomp === 1) {\n return range(dataAccessor, start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2);\n } else if (ncomp === 3) {\n return range3d(dataAccessor, 3 * start, maxIter, increment,\n blockMaxIter, blockIncrement, reverse1, reverse2, isPlanar);\n }\n };\n\n let rangeObj = null;\n if (viewOrientation && typeof viewOrientation !== 'undefined') {\n const dirMax0 = viewOrientation.getColAbsMax(0);\n const dirMax2 = viewOrientation.getColAbsMax(2);\n\n // default reverse\n const reverse1 = false;\n const reverse2 = false;\n\n let maxIter = null;\n if (dirMax2.index === 2) {\n // axial\n maxIter = ncols * nrows;\n if (dirMax0.index === 0) {\n // xyz\n rangeObj = getRange(dataAccessor,\n start, maxIter, 1, ncols, ncols, reverse1, reverse2);\n } else {\n // yxz\n rangeObj = getRange(dataAccessor,\n start, maxIter, ncols, nrows, 1, reverse1, reverse2);\n }\n } else if (dirMax2.index === 0) {\n // sagittal\n maxIter = nslices * nrows;\n if (dirMax0.index === 1) {\n // yzx\n rangeObj = getRange(dataAccessor,\n start, maxIter, ncols, nrows, sliceSize, reverse1, reverse2);\n } else {\n // zyx\n rangeObj = getRange(dataAccessor,\n start, maxIter, sliceSize, nslices, ncols, reverse1, reverse2);\n }\n } else if (dirMax2.index === 1) {\n // coronal\n maxIter = nslices * ncols;\n if (dirMax0.index === 0) {\n // xzy\n rangeObj = getRange(dataAccessor,\n start, maxIter, 1, ncols, sliceSize, reverse1, reverse2);\n } else {\n // zxy\n rangeObj = getRange(dataAccessor,\n start, maxIter, sliceSize, nslices, 1, reverse1, reverse2);\n }\n } else {\n throw new Error('Unknown direction: ' + dirMax2.index);\n }\n } else {\n if (image.getNumberOfComponents() === 1) {\n rangeObj = simpleRange(dataAccessor, start, start + sliceSize);\n } else if (image.getNumberOfComponents() === 3) {\n // 3 times bigger...\n start *= 3;\n sliceSize *= 3;\n rangeObj = simpleRange3d(\n dataAccessor, start, start + sliceSize, 1, isPlanar);\n } else {\n throw new Error('Unsupported number of components: ' +\n image.getNumberOfComponents());\n }\n }\n\n return rangeObj;\n}\n\n/**\n * Get a slice index iterator for a rectangular region.\n *\n * @param {Image} image The image to parse.\n * @param {Index} index The current position.\n * @param {boolean} isRescaled Flag for rescaled values (default false).\n * @param {Point2D} min The minimum position (optional).\n * @param {Point2D} max The maximum position (optional).\n * @returns {object} The slice iterator.\n */\nexport function getRegionSliceIterator(\n image, index, isRescaled, min, max) {\n if (image.getNumberOfComponents() !== 1) {\n throw new Error('Unsupported number of components for region iterator: ' +\n image.getNumberOfComponents());\n }\n\n // default to non rescaled data\n if (typeof isRescaled === 'undefined') {\n isRescaled = false;\n }\n let dataAccessor = null;\n if (isRescaled) {\n dataAccessor = function (offset) {\n return image.getRescaledValueAtOffset(offset);\n };\n } else {\n dataAccessor = function (offset) {\n return image.getValueAtOffset(offset);\n };\n }\n\n const size = image.getGeometry().getSize();\n if (typeof min === 'undefined') {\n min = new Point2D(0, 0);\n }\n if (typeof max === 'undefined') {\n max = new Point2D(\n size.get(0) - 1,\n size.get(1)\n );\n }\n // position to pixel for max: extra X is ok, remove extra Y\n const startOffset = size.indexToOffset(index.getWithNew2D(\n min.getX(), min.getY()\n ));\n const endOffset = size.indexToOffset(index.getWithNew2D(\n max.getX(), max.getY() - 1\n ));\n\n // minimum 1 column\n const rangeNumberOfColumns = Math.max(1, max.getX() - min.getX());\n const rowIncrement = size.get(0) - rangeNumberOfColumns;\n\n return rangeRegion(\n dataAccessor, startOffset, endOffset + 1,\n 1, rangeNumberOfColumns, rowIncrement);\n}\n\n/**\n * Get a slice index iterator for a rectangular region.\n *\n * @param {Image} image The image to parse.\n * @param {Index} index The current position.\n * @param {boolean} isRescaled Flag for rescaled values (default false).\n * @param {number[][][]} regions An array of [x, y] pairs (min, max).\n * @returns {object|undefined} The slice iterator.\n */\nexport function getVariableRegionSliceIterator(\n image, index, isRescaled, regions) {\n if (image.getNumberOfComponents() !== 1) {\n throw new Error('Unsupported number of components for region iterator: ' +\n image.getNumberOfComponents());\n }\n\n // default to non rescaled data\n if (typeof isRescaled === 'undefined') {\n isRescaled = false;\n }\n let dataAccessor = null;\n if (isRescaled) {\n dataAccessor = function (offset) {\n return image.getRescaledValueAtOffset(offset);\n };\n } else {\n dataAccessor = function (offset) {\n return image.getValueAtOffset(offset);\n };\n }\n\n const size = image.getGeometry().getSize();\n\n const offsetRegions = [];\n let region;\n let min = null;\n let max = null;\n let regionIndex = null;\n for (let i = 0; i < regions.length; ++i) {\n region = regions[i];\n const width = region[1][0] - region[0][0];\n if (width !== 0) {\n regionIndex = i;\n if (!min) {\n min = region[0];\n }\n offsetRegions.push([\n region[0][0],\n width,\n size.get(0) - region[1][0]\n ]);\n }\n }\n if (regionIndex !== null) {\n max = regions[regionIndex][1];\n }\n\n // exit if no offsets\n if (offsetRegions.length === 0) {\n return undefined;\n }\n\n const startOffset = size.indexToOffset(index.getWithNew2D(\n min[0], min[1]\n ));\n const endOffset = size.indexToOffset(index.getWithNew2D(\n max[0], max[1]\n ));\n\n return rangeRegions(\n dataAccessor, startOffset, endOffset + 1,\n 1, offsetRegions);\n}\n\n/**\n * Get a multiple value iterator. The input array defines the values and\n * their start index.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols}.\n *\n * @param {Array} values An array of {index, value} pairs.\n * @param {number} end The end of the range (excluded).\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function valueRange(values, end) {\n let nextIndex = 0;\n let nextValueIndex = 0;\n // result\n return {\n next: function () {\n if (nextIndex < end) {\n if (nextValueIndex + 1 < values.length &&\n nextIndex >= values[nextValueIndex + 1].index) {\n ++nextValueIndex;\n }\n const result = {\n value: values[nextValueIndex].value,\n done: false,\n index: nextIndex\n };\n ++nextIndex;\n return result;\n }\n return {\n done: true,\n index: end\n };\n }\n };\n}\n","/**\n * Rescale Slope and Intercept.\n */\nexport class RescaleSlopeAndIntercept {\n\n /**\n * The slope.\n *\n * @type {number}\n */\n #slope;\n\n /**\n * The intercept.\n *\n * @type {number}\n */\n #intercept;\n\n /**\n * @param {number} slope The slope of the RSI.\n * @param {number} intercept The intercept of the RSI.\n */\n constructor(slope, intercept) {\n /*// Check the rescale slope.\n if(typeof(slope) === 'undefined') {\n slope = 1;\n }\n // Check the rescale intercept.\n if(typeof(intercept) === 'undefined') {\n intercept = 0;\n }*/\n this.#slope = slope;\n this.#intercept = intercept;\n }\n\n /**\n * Get the slope of the RSI.\n *\n * @returns {number} The slope of the RSI.\n */\n getSlope() {\n return this.#slope;\n }\n\n /**\n * Get the intercept of the RSI.\n *\n * @returns {number} The intercept of the RSI.\n */\n getIntercept() {\n return this.#intercept;\n }\n\n /**\n * Apply the RSI on an input value.\n *\n * @param {number} value The input value.\n * @returns {number} The value to rescale.\n */\n apply(value) {\n return value * this.#slope + this.#intercept;\n }\n\n /**\n * Check for RSI equality.\n *\n * @param {RescaleSlopeAndIntercept} rhs The other RSI to compare to.\n * @returns {boolean} True if both RSI are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n typeof rhs !== 'undefined' &&\n this.getSlope() === rhs.getSlope() &&\n this.getIntercept() === rhs.getIntercept();\n }\n\n /**\n * Is this RSI an ID RSI.\n *\n * @returns {boolean} True if the RSI has a slope of 1 and no intercept.\n */\n isID() {\n return (this.getSlope() === 1 && this.getIntercept() === 0);\n }\n\n} // class RescaleSlopeAndIntercept\n","import {Index} from '../math/index';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Matrix33} from '../math/matrix';\nimport {Scalar2D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Immutable Size class.\n * Warning: the input array is NOT cloned, modifying it will\n * modify the index values.\n */\nexport class Size {\n\n /**\n * The size values.\n *\n * @type {number[]}\n */\n #values;\n\n /**\n * @param {number[]} values The size values.\n */\n constructor(values) {\n if (!values || typeof values === 'undefined') {\n throw new Error('Cannot create size with no values.');\n }\n if (values.length === 0) {\n throw new Error('Cannot create size with empty values.');\n }\n const valueCheck = function (val) {\n return !isNaN(val) && val !== 0;\n };\n if (!values.every(valueCheck)) {\n throw new Error('Cannot create size with non number or zero values.');\n }\n this.#values = values;\n }\n\n /**\n * Get the size value at the given array index.\n *\n * @param {number} i The index to get.\n * @returns {number} The value.\n */\n get(i) {\n return this.#values[i];\n }\n\n /**\n * Get the length of the index.\n *\n * @returns {number} The length.\n */\n length() {\n return this.#values.length;\n }\n\n /**\n * Get a string representation of the size.\n *\n * @returns {string} The Size as a string.\n */\n toString() {\n return '(' + this.#values.toString() + ')';\n }\n\n /**\n * Get the values of this index.\n *\n * @returns {number[]} The array of values.\n */\n getValues() {\n return this.#values.slice();\n }\n\n /**\n * Check if a dimension exists and has more than one element.\n *\n * @param {number} dimension The dimension to check.\n * @returns {boolean} True if the size is more than one.\n */\n moreThanOne(dimension) {\n return this.length() >= dimension + 1 && this.get(dimension) !== 1;\n }\n\n /**\n * Check if the associated data is scrollable in 3D.\n *\n * @param {Matrix33} [viewOrientation] The orientation matrix.\n * @returns {boolean} True if scrollable.\n */\n canScroll3D(viewOrientation) {\n let dimension = 2;\n if (typeof viewOrientation !== 'undefined') {\n dimension = viewOrientation.getThirdColMajorDirection();\n }\n return this.moreThanOne(dimension);\n }\n\n /**\n * Check if the associated data is scrollable: either in 3D or\n * in other directions.\n *\n * @param {Matrix33} viewOrientation The orientation matrix.\n * @returns {boolean} True if scrollable.\n */\n canScroll(viewOrientation) {\n let canScroll = this.canScroll3D(viewOrientation);\n // check possible other dimensions\n for (let i = 3; i < this.length(); ++i) {\n canScroll = canScroll || this.moreThanOne(i);\n }\n return canScroll;\n }\n\n /**\n * Get the size of a given dimension.\n *\n * @param {number} dimension The dimension.\n * @param {number} [start] Optional start dimension to start counting from.\n * @returns {number} The size.\n */\n getDimSize(dimension, start) {\n if (dimension > this.length()) {\n return null;\n }\n if (typeof start === 'undefined') {\n start = 0;\n } else {\n if (start < 0 || start > dimension) {\n throw new Error('Invalid start value for getDimSize');\n }\n }\n let size = 1;\n for (let i = start; i < dimension; ++i) {\n size *= this.get(i);\n }\n return size;\n }\n\n /**\n * Get the total size.\n *\n * @param {number} [start] Optional start dimension to base the offset on.\n * @returns {number} The total size.\n */\n getTotalSize(start) {\n return this.getDimSize(this.length(), start);\n }\n\n /**\n * Check for equality.\n *\n * @param {Size} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n // check input\n if (!rhs) {\n return false;\n }\n // check length\n const length = this.length();\n if (length !== rhs.length()) {\n return false;\n }\n // check values\n for (let i = 0; i < length; ++i) {\n if (this.get(i) !== rhs.get(i)) {\n return false;\n }\n }\n // seems ok!\n return true;\n }\n\n /**\n * Check that an index is within bounds.\n *\n * @param {Index} index The index to check.\n * @param {number[]} dirs Optional list of directions to check.\n * @returns {boolean} True if the given coordinates are within bounds.\n */\n isInBounds(index, dirs) {\n // check input\n if (!index) {\n return false;\n }\n // check length\n const length = this.length();\n if (length !== index.length()) {\n return false;\n }\n // create dirs if not there\n if (typeof dirs === 'undefined') {\n dirs = [];\n for (let j = 0; j < length; ++j) {\n dirs.push(j);\n }\n } else {\n for (let k = 0; k < length; ++k) {\n if (dirs[k] > length - 1) {\n throw new Error('Wrong input dir value: ' + dirs[k]);\n }\n }\n }\n // check values is 0 <= v < size\n const inBound = function (value, size) {\n return value >= 0 && value < size;\n };\n // check\n for (let i = 0; i < dirs.length; ++i) {\n if (!inBound(index.get(dirs[i]), this.get(dirs[i]))) {\n return false;\n }\n }\n // seems ok!\n return true;\n }\n\n /**\n * Convert an index to an offset in memory.\n *\n * @param {Index} index The index to convert.\n * @param {number} [start] Optional start dimension to base the offset on.\n * @returns {number} The offset.\n */\n indexToOffset(index, start) {\n // TODO check for equality\n if (index.length() < this.length()) {\n throw new Error('Incompatible index and size length');\n }\n if (typeof start === 'undefined') {\n start = 0;\n } else {\n if (start < 0 || start > this.length() - 1) {\n throw new Error('Invalid start value for indexToOffset');\n }\n }\n let offset = 0;\n for (let i = start; i < this.length(); ++i) {\n offset += index.get(i) * this.getDimSize(i, start);\n }\n return offset;\n }\n\n /**\n * Convert an offset in memory to an index.\n *\n * @param {number} offset The offset to convert.\n * @returns {Index} The index.\n */\n offsetToIndex(offset) {\n const values = new Array(this.length());\n let off = offset;\n let dimSize = 0;\n for (let i = this.length() - 1; i > 0; --i) {\n dimSize = this.getDimSize(i);\n values[i] = Math.floor(off / dimSize);\n off = off - values[i] * dimSize;\n }\n values[0] = off;\n return new Index(values);\n }\n\n /**\n * Get the 2D base of this size.\n *\n * @returns {Scalar2D} The 2D base [0,1] as {x,y}.\n */\n get2D() {\n return {\n x: this.get(0),\n y: this.get(1)\n };\n }\n\n} // Size class\n","/**\n * Statistics storage class.\n * 'simple' statistics do not include median, p25 nor p75.\n */\nexport class Statistics {\n /**\n * Minimum.\n *\n * @type {number}\n */\n min;\n /**\n * Maximum.\n *\n * @type {number}\n */\n max;\n /**\n * Mean.\n *\n * @type {number}\n */\n mean;\n /**\n * Standard deviation.\n *\n * @type {number}\n */\n stdDev;\n /**\n * Median.\n *\n * @type {number|undefined}\n */\n median;\n /**\n * 25th percentile.\n *\n * @type {number|undefined}\n */\n p25;\n /**\n * 75th percentile.\n *\n * @type {number|undefined}\n */\n p75;\n\n /**\n * @param {number} min The minimum.\n * @param {number} max The maxnimum.\n * @param {number} mean The mean.\n * @param {number} stdDev The standard deviation.\n */\n constructor(min, max, mean, stdDev) {\n this.min = min;\n this.max = max;\n this.mean = mean;\n this.stdDev = stdDev;\n }\n}\n\n/**\n * Get statistics on an input array of number.\n * Note: could use {@link https://github.com/tmcw/simple-statistics}.\n *\n * @param {number[]} values The array of values to extract stats from.\n * @param {string[]} flags A list of stat value names to calculate.\n * @returns {Statistics} A statistics object.\n */\nexport function getStats(values, flags) {\n if (includesFullStatsFlags(flags)) {\n return getFullStats(values);\n } else {\n return getBasicStats(values);\n }\n}\n\n/**\n * Does the input flag list contain a full stat element?\n *\n * @param {string[]} flags A list of stat values to calculate.\n * @returns {boolean} True if one of the flags is a full stat flag.\n */\nfunction includesFullStatsFlags(flags) {\n return typeof flags !== 'undefined' &&\n flags !== null &&\n (flags.includes('median') ||\n flags.includes('p25') ||\n flags.includes('p75'));\n}\n\n/**\n * Get simple stats: minimum, maximum, mean and standard deviation\n * of an array of values.\n *\n * @param {number[]} values The array of values to extract stats from.\n * @returns {Statistics} Simple statistics (no median, p25 nor p75).\n */\nexport function getBasicStats(values) {\n let min = values[0];\n let max = min;\n let sum = 0;\n let sumSqr = 0;\n let val = 0;\n const length = values.length;\n for (let i = 0; i < length; ++i) {\n val = values[i];\n if (val < min) {\n min = val;\n } else if (val > max) {\n max = val;\n }\n sum += val;\n sumSqr += val * val;\n }\n\n const mean = sum / length;\n // see http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance\n let variance = sumSqr / length - mean * mean;\n if (variance < 0) {\n variance = 0;\n }\n const stdDev = Math.sqrt(variance);\n\n return new Statistics(min, max, mean, stdDev);\n}\n\n/**\n * Get full stats: minimum, maximum, mean, standard deviation, median, 25%\n * and 75% percentile of an array of values.\n *\n * @param {number[]} values The array of values to extract stats from.\n * @returns {Statistics} Complete statistics (includes median, p25 and p75).\n */\nfunction getFullStats(values) {\n // get basic stats\n const stats = getBasicStats(values);\n\n // sort array... can get slow...\n values.sort(function (a, b) {\n return a - b;\n });\n\n stats.median = getPercentile(values, 0.5);\n stats.p25 = getPercentile(values, 0.25);\n stats.p75 = getPercentile(values, 0.75);\n\n return stats;\n}\n\n/**\n * Get an arrays' percentile. Uses linear interpolation for percentiles\n * that lie between data points.\n * See: {@link https://en.wikipedia.org/wiki/Percentile} (second variant interpolation).\n *\n * @param {number[]} values The sorted array of values.\n * @param {number} ratio The percentile ratio [0-1].\n * @returns {number} The percentile.\n */\nfunction getPercentile(values, ratio) {\n // check input\n if (values.length === 0) {\n throw new Error('Empty array provided for percentile calculation.');\n }\n if (ratio < 0 || ratio > 1) {\n throw new Error(\n 'Invalid ratio provided for percentile calculation: ' + ratio);\n }\n // return min for ratio=0 amd max for ratio=1\n if (ratio === 0) {\n return values[0];\n } else if (ratio === 1) {\n return values[values.length - 1];\n }\n // general case: interpolate between indices if needed\n const i = (values.length - 1) * ratio;\n const i0 = Math.floor(i);\n const v0 = values[i0];\n const v1 = values[i0 + 1];\n return v0 + (v1 - v0) * (i - i0);\n}\n\n/**\n * Unique ID generator.\n *\n * See {@link http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript}\n * and this {@link http://stackoverflow.com/a/13403498 answer}.\n *\n * @returns {string} A unique ID.\n */\nexport function guid() {\n return Math.random().toString(36).substring(2, 15);\n}\n\n/**\n * Number range.\n */\nexport class NumberRange {\n /**\n * @type {number}\n */\n min;\n /**\n * @type {number}\n */\n max;\n /**\n * @param {number} min The minimum.\n * @param {number} max The maximum.\n */\n constructor(min, max) {\n this.min = min;\n this.max = max;\n }\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Scalar2D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Immutable Spacing class.\n * Warning: the input array is NOT cloned, modifying it will\n * modify the index values.\n */\nexport class Spacing {\n\n /**\n * The spacing values.\n *\n * @type {number[]}\n */\n #values;\n\n /**\n * @param {number[]} values The spacing values.\n */\n constructor(values) {\n if (!values || typeof values === 'undefined') {\n throw new Error('Cannot create spacing with no values.');\n }\n if (values.length === 0) {\n throw new Error('Cannot create spacing with empty values.');\n }\n const valueCheck = function (val) {\n return !isNaN(val) && val !== 0;\n };\n if (!values.every(valueCheck)) {\n throw new Error('Cannot create spacing with non number or zero values.');\n }\n this.#values = values;\n }\n\n /**\n * Get the spacing value at the given array index.\n *\n * @param {number} i The index to get.\n * @returns {number} The value.\n */\n get(i) {\n return this.#values[i];\n }\n\n /**\n * Get the length of the spacing.\n *\n * @returns {number} The length.\n */\n length() {\n return this.#values.length;\n }\n\n /**\n * Get a string representation of the spacing.\n *\n * @returns {string} The spacing as a string.\n */\n toString() {\n return '(' + this.#values.toString() + ')';\n }\n\n /**\n * Get the values of this spacing.\n *\n * @returns {number[]} The array of values.\n */\n getValues() {\n return this.#values.slice();\n }\n\n /**\n * Check for equality.\n *\n * @param {Spacing} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n // check input\n if (!rhs) {\n return false;\n }\n // check length\n const length = this.length();\n if (length !== rhs.length()) {\n return false;\n }\n // check values\n for (let i = 0; i < length; ++i) {\n if (this.get(i) !== rhs.get(i)) {\n return false;\n }\n }\n // seems ok!\n return true;\n }\n\n /**\n * Get the 2D base of this size.\n *\n * @returns {Scalar2D} The 2D base [col,row] as {x,y}.\n */\n get2D() {\n return {\n x: this.get(0),\n y: this.get(1)\n };\n }\n\n} // Spacing class\n","import {\n getIdentityMat33,\n REAL_WORLD_EPSILON\n} from '../math/matrix';\nimport {Point3D, Point} from '../math/point';\nimport {Vector3D} from '../math/vector';\nimport {Index} from '../math/index';\nimport {getBasicStats} from '../math/stats';\nimport {precisionRound} from '../utils/string';\nimport {logger} from '../utils/logger';\nimport {Size} from './size';\nimport {Spacing} from './spacing';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Matrix33} from '../math/matrix';\n/* eslint-enable no-unused-vars */\n\n/**\n * 2D/3D Geometry class.\n */\nexport class Geometry {\n\n /**\n * Array of origins.\n *\n * @type {Point3D[]}\n */\n #origins;\n\n /**\n * Data size.\n *\n * @type {Size}\n */\n #size;\n\n /**\n * Data spacing.\n *\n * @type {Spacing}\n */\n #spacing;\n\n /**\n * Local helper object for time points.\n *\n * @type {Object}\n */\n #timeOrigins = {};\n\n /**\n * Initial time index.\n *\n * @type {number}\n */\n #initialTime;\n\n /**\n * Data orientation.\n *\n * @type {Matrix33}\n */\n #orientation = getIdentityMat33();\n\n /**\n * Flag to know if new origins were added.\n *\n * @type {boolean}\n */\n #newOrigins = false;\n\n /**\n * @param {Point3D} origin The object origin (a 3D point).\n * @param {Size} size The object size.\n * @param {Spacing} spacing The object spacing.\n * @param {Matrix33} [orientation] The object orientation (3*3 matrix,\n * default to 3*3 identity).\n * @param {number} [time] Optional time index.\n */\n constructor(origin, size, spacing, orientation, time) {\n this.#origins = [origin];\n this.#size = size;\n this.#spacing = spacing;\n if (typeof time !== 'undefined') {\n this.#initialTime = time;\n this.#timeOrigins[time] = [origin];\n }\n // check input orientation\n if (typeof orientation !== 'undefined') {\n this.#orientation = orientation;\n }\n }\n\n /**\n * Get the time value that was passed at construction.\n *\n * @returns {number} The time value.\n */\n getInitialTime() {\n return this.#initialTime;\n }\n\n /**\n * Get the total number of slices.\n * Can be different from what is stored in the size object\n * during a volume with time points creation process.\n *\n * @returns {number} The total count.\n */\n getCurrentTotalNumberOfSlices() {\n const keys = Object.keys(this.#timeOrigins);\n if (keys.length === 0) {\n return this.#origins.length;\n }\n let count = 0;\n for (let i = 0; i < keys.length; ++i) {\n count += this.#timeOrigins[keys[i]].length;\n }\n return count;\n }\n\n /**\n * Check if a time point has associated slices.\n *\n * @param {number} time The time point to check.\n * @returns {boolean} True if slices are present.\n */\n hasSlicesAtTime(time) {\n return typeof this.#timeOrigins[time] !== 'undefined';\n }\n\n /**\n * Get the number of slices stored for time points preceding\n * the input one.\n *\n * @param {number} time The time point to check.\n * @returns {number|undefined} The count.\n */\n getCurrentNumberOfSlicesBeforeTime(time) {\n const keys = Object.keys(this.#timeOrigins);\n if (keys.length === 0) {\n return undefined;\n }\n let count = 0;\n for (let i = 0; i < keys.length; ++i) {\n const key = keys[i];\n if (parseInt(key, 10) === time) {\n break;\n }\n count += this.#timeOrigins[key].length;\n }\n return count;\n }\n\n /**\n * Get the object origin.\n * This should be the lowest origin to ease calculations (?).\n *\n * @returns {Point3D} The object origin.\n */\n getOrigin() {\n return this.#origins[0];\n }\n\n /**\n * Get the object origins.\n *\n * @returns {Point3D[]} The object origins.\n */\n getOrigins() {\n return this.#origins;\n }\n\n /**\n * Check if a point is in the origin list.\n *\n * @param {Point3D} point3D The point to check.\n * @param {number} tol The comparison tolerance\n * default to Number.EPSILON.\n * @returns {boolean} True if in list.\n */\n includesOrigin(point3D, tol) {\n for (let i = 0; i < this.#origins.length; ++i) {\n if (this.#origins[i].isSimilar(point3D, tol)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get the object size.\n * Warning: the size comes as stored in DICOM, meaning that it could\n * be oriented.\n *\n * @param {Matrix33} [viewOrientation] The view orientation (optional).\n * @returns {Size} The object size.\n */\n getSize(viewOrientation) {\n let res = this.#size;\n if (viewOrientation && typeof viewOrientation !== 'undefined') {\n let values = getOrientedArray3D(\n [\n this.#size.get(0),\n this.#size.get(1),\n this.#size.get(2)\n ],\n viewOrientation);\n values = values.map(Math.abs);\n res = new Size(values.concat(this.#size.getValues().slice(3)));\n }\n return res;\n }\n\n /**\n * Calculate slice spacing from origins and replace current\n * if needed.\n */\n #updateSliceSpacing() {\n const geoSliceSpacing = getSliceGeometrySpacing(this.#origins);\n // update local if needed\n if (typeof geoSliceSpacing !== 'undefined' &&\n this.#spacing.get(2) !== geoSliceSpacing) {\n logger.trace('Using geometric spacing ' + geoSliceSpacing +\n ' instead of tag spacing ' + this.#spacing.get(2));\n const values = this.#spacing.getValues();\n values[2] = geoSliceSpacing;\n this.#spacing = new Spacing(values);\n }\n }\n\n /**\n * Get the object spacing.\n * Warning: the spacing comes as stored in DICOM, meaning that it could\n * be oriented.\n *\n * @param {Matrix33} [viewOrientation] The view orientation (optional).\n * @returns {Spacing} The object spacing.\n */\n getSpacing(viewOrientation) {\n // update slice spacing after appendSlice\n if (this.#newOrigins) {\n this.#updateSliceSpacing();\n this.#newOrigins = false;\n }\n let res = this.#spacing;\n if (viewOrientation && typeof viewOrientation !== 'undefined') {\n let orientedValues = getOrientedArray3D(\n [\n this.#spacing.get(0),\n this.#spacing.get(1),\n this.#spacing.get(2)\n ],\n viewOrientation);\n orientedValues = orientedValues.map(Math.abs);\n res = new Spacing(orientedValues);\n }\n return res;\n }\n\n /**\n * Get the image spacing in real world.\n *\n * @returns {Spacing} The object spacing.\n */\n getRealSpacing() {\n // asOneAndZeros to not change spacing values...\n return this.getSpacing(\n this.#orientation.getInverse().asOneAndZeros()\n );\n }\n\n /**\n * Get the object orientation.\n *\n * @returns {Matrix33} The object orientation.\n */\n getOrientation() {\n return this.#orientation;\n }\n\n /**\n * Get the slice position of a point in the current slice layout.\n * Slice indices increase with decreasing origins (high index -> low origin),\n * this simplified the handling of reconstruction since it means\n * the displayed data is in the same 'direction' as the extracted data.\n * As seen in the getOrigin method, the main origin is the lowest one.\n * This implies that the index to world and reverse method do some flipping\n * magic...\n *\n * @param {Point3D} point The point to evaluate.\n * @param {number} time Optional time index.\n * @returns {number} The slice index.\n */\n getSliceIndex(point, time) {\n // cannot use this.worldToIndex(point).getK() since\n // we cannot guaranty consecutive slices...\n\n let localOrigins = this.#origins;\n if (typeof time !== 'undefined') {\n localOrigins = this.#timeOrigins[time];\n }\n\n // find the closest origin\n const closestOriginIndex = point.getClosest(localOrigins);\n const closestOrigin = localOrigins[closestOriginIndex];\n\n // direction between the input point and the closest origin\n const pointDir = point.minus(closestOrigin);\n\n // use third orientation matrix column as plane normal vector\n const normal = new Vector3D(\n this.#orientation.get(0, 2),\n this.#orientation.get(1, 2),\n this.#orientation.get(2, 2)\n );\n\n // codirectional vectors: above slice index\n // oposite vectors: below slice index\n const isCodirectional = normal.isCodirectional(pointDir);\n const sliceIndex = isCodirectional\n ? closestOriginIndex + 1 : closestOriginIndex;\n\n return sliceIndex;\n }\n\n /**\n * Append an origin to the geometry.\n *\n * @param {Point3D} origin The origin to append.\n * @param {number} index The index at which to append.\n * @param {number} [time] Optional time index.\n */\n appendOrigin(origin, index, time) {\n // equal callback\n const equalToOrigin = function (element) {\n return element.equals(origin);\n };\n if (typeof time !== 'undefined') {\n // check if not already in list\n const found = this.#timeOrigins[time].find(equalToOrigin);\n if (typeof found !== 'undefined') {\n throw new Error('Cannot append same time origin twice');\n }\n // add in origin array\n this.#timeOrigins[time].splice(index, 0, origin);\n }\n if (typeof time === 'undefined' || time === this.#initialTime) {\n // check if not already in list\n const found = this.#origins.find(equalToOrigin);\n if (typeof found !== 'undefined') {\n throw new Error('Cannot append same origin twice');\n }\n // update flag\n this.#newOrigins = true;\n // add in origin array\n this.#origins.splice(index, 0, origin);\n // increment second dimension\n const values = this.#size.getValues();\n values[2] += 1;\n this.#size = new Size(values);\n }\n }\n\n /**\n * Append a frame to the geometry.\n *\n * @param {Point3D} origin The origin to append.\n * @param {number} time Optional time index.\n */\n appendFrame(origin, time) {\n // add origin to list\n this.#timeOrigins[time] = [origin];\n // increment third dimension\n const sizeValues = this.#size.getValues();\n const spacingValues = this.#spacing.getValues();\n if (sizeValues.length === 4) {\n sizeValues[3] += 1;\n } else {\n sizeValues.push(2);\n spacingValues.push(1);\n }\n this.#size = new Size(sizeValues);\n this.#spacing = new Spacing(spacingValues);\n }\n\n /**\n * Get a string representation of the geometry.\n *\n * @returns {string} The geometry as a string.\n */\n toString() {\n return 'Origin: ' + this.getOrigin() +\n ', Size: ' + this.getSize() +\n ', Spacing: ' + this.getSpacing() +\n ', Orientation: ' + this.getOrientation();\n }\n\n /**\n * Check for equality.\n *\n * @param {Geometry} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.getOrigin().equals(rhs.getOrigin()) &&\n this.getSize().equals(rhs.getSize()) &&\n this.getSpacing().equals(rhs.getSpacing());\n }\n\n /**\n * Check that a point is within bounds.\n *\n * @param {Point} point The point to check.\n * @returns {boolean} True if the given coordinates are within bounds.\n */\n isInBounds(point) {\n return this.isIndexInBounds(this.worldToIndex(point));\n }\n\n /**\n * Check that a index is within bounds.\n *\n * @param {Index} index The index to check.\n * @param {number[]} [dirs] Optional list of directions to check.\n * @returns {boolean} True if the given coordinates are within bounds.\n */\n isIndexInBounds(index, dirs) {\n return this.getSize().isInBounds(index, dirs);\n }\n\n /**\n * Convert an index into world coordinates.\n *\n * @param {Index} index The index to convert.\n * @returns {Point} The corresponding point.\n */\n indexToWorld(index) {\n // apply spacing\n // (spacing is oriented, apply before orientation)\n const spacing = this.getSpacing();\n const orientedPoint3D = new Point3D(\n index.get(0) * spacing.get(0),\n index.get(1) * spacing.get(1),\n index.get(2) * spacing.get(2)\n );\n // de-orient\n const point3D = this.getOrientation().multiplyPoint3D(orientedPoint3D);\n // keep >3d values\n const values = index.getValues();\n const origin = this.getOrigin();\n values[0] = origin.getX() + point3D.getX();\n values[1] = origin.getY() + point3D.getY();\n values[2] = origin.getZ() + point3D.getZ();\n // return point\n return new Point(values);\n }\n\n /**\n * Convert a 3D point into world coordinates.\n *\n * @param {Point3D} point The 3D point to convert.\n * @returns {Point3D} The corresponding world 3D point.\n */\n pointToWorld(point) {\n // apply spacing\n // (spacing is oriented, apply before orientation)\n const spacing = this.getSpacing();\n const orientedPoint3D = new Point3D(\n point.getX() * spacing.get(0),\n point.getY() * spacing.get(1),\n point.getZ() * spacing.get(2)\n );\n // de-orient\n const point3D = this.getOrientation().multiplyPoint3D(orientedPoint3D);\n // return point3D\n const origin = this.getOrigin();\n return new Point3D(\n origin.getX() + point3D.getX(),\n origin.getY() + point3D.getY(),\n origin.getZ() + point3D.getZ()\n );\n }\n\n /**\n * Convert world coordinates into an index.\n *\n * @param {Point} point The point to convert.\n * @returns {Index} The corresponding index.\n */\n worldToIndex(point) {\n // compensate for origin\n // (origin is not oriented, compensate before orientation)\n // TODO: use slice origin...\n const origin = this.getOrigin();\n const point3D = new Point3D(\n point.get(0) - origin.getX(),\n point.get(1) - origin.getY(),\n point.get(2) - origin.getZ()\n );\n // orient\n const orientedPoint3D =\n this.getOrientation().getInverse().multiplyPoint3D(point3D);\n // keep >3d values\n const values = point.getValues();\n // apply spacing and round\n const spacing = this.getSpacing();\n values[0] = Math.round(orientedPoint3D.getX() / spacing.get(0));\n values[1] = Math.round(orientedPoint3D.getY() / spacing.get(1));\n values[2] = Math.round(orientedPoint3D.getZ() / spacing.get(2));\n\n // return index\n return new Index(values);\n }\n\n /**\n * Convert world coordinates into an point.\n *\n * @param {Point} point The world point to convert.\n * @returns {Point3D} The corresponding point.\n */\n worldToPoint(point) {\n // compensate for origin\n // (origin is not oriented, compensate before orientation)\n const origin = this.getOrigin();\n const point3D = new Point3D(\n point.get(0) - origin.getX(),\n point.get(1) - origin.getY(),\n point.get(2) - origin.getZ()\n );\n // orient\n const orientedPoint3D =\n this.getOrientation().getInverse().multiplyPoint3D(point3D);\n // keep >3d values\n const values = point.getValues();\n // apply spacing and round\n const spacing = this.getSpacing();\n values[0] = orientedPoint3D.getX() / spacing.get(0);\n values[1] = orientedPoint3D.getY() / spacing.get(1);\n values[2] = orientedPoint3D.getZ() / spacing.get(2);\n\n // return index\n return new Point3D(values[0], values[1], values[2]);\n }\n\n} // class Geometry\n\n/**\n * Get the oriented values of an input 3D array.\n *\n * @param {number[]} array3D The 3D array.\n * @param {Matrix33} orientation The orientation 3D matrix.\n * @returns {number[]} The values reordered according to the orientation.\n */\nexport function getOrientedArray3D(array3D, orientation) {\n // values = orientation * orientedValues\n // -> inv(orientation) * values = orientedValues\n return orientation.getInverse().multiplyArray3D(array3D);\n}\n\n/**\n * Get the raw values of an oriented input 3D array.\n *\n * @param {number[]} array3D The 3D array.\n * @param {Matrix33} orientation The orientation 3D matrix.\n * @returns {number[]} The values reordered to compensate the orientation.\n */\nexport function getDeOrientedArray3D(array3D, orientation) {\n // values = orientation * orientedValues\n return orientation.multiplyArray3D(array3D);\n}\n\n/**\n * Get the slice spacing from the difference in the Z directions\n * of input origins.\n *\n * @param {Point3D[]} origins An array of Point3D.\n * @returns {number|undefined} The spacing.\n */\nexport function getSliceGeometrySpacing(origins) {\n // check origins\n if (origins.length <= 1) {\n return;\n }\n\n const spacings = [];\n for (let i = 0; i < origins.length - 1; ++i) {\n const origin1 = origins[i];\n const origin2 = origins[i + 1];\n const sliceSpacing = origin1.getDistance(origin2);\n if (sliceSpacing === 0) {\n throw new Error('Zero slice spacing ' +\n origin1.toString() + ' ' + origin2.toString());\n }\n spacings.push(sliceSpacing);\n }\n\n // use rounded mean value as spacing\n const stats = getBasicStats(spacings);\n const spacing = precisionRound(stats.mean, 4);\n\n // warn if non constant\n if (stats.stdDev > REAL_WORLD_EPSILON) {\n logger.warn('Varying slice spacing, value: ' + spacing +\n ' (mean: ' + stats.mean +\n ', min: ' + stats.min +\n ', max: ' + stats.max +\n ', stdDev: ' + stats.stdDev + ')');\n }\n\n return spacing;\n}\n","import {DataElement} from './dataElement';\n\n/**\n * Pad an input string with a '0' to form a 2 digit one.\n *\n * @param {string} str The string to pad.\n * @returns {string} The padded string.\n */\nfunction padZeroTwoDigit(str) {\n return ('0' + str).slice(-2);\n}\n\n/**\n * Get a 'date' object with {year, monthIndex, day} ready for the\n * Date constructor from a DICOM element with vr=DA.\n *\n * @param {DataElement} element The DICOM element with date information.\n * @returns {{year, monthIndex, day}|undefined} The 'date' object.\n */\nexport function getDate(element) {\n if (typeof element === 'undefined') {\n return undefined;\n }\n if (element.value.length !== 1) {\n return undefined;\n }\n const daValue = element.value[0];\n // Two possible formats:\n // - standard 'YYYYMMDD'\n // - non-standard 'YYYY.MM.DD' (previous ACR-NEMA)\n let monthBeginIndex = 4;\n let dayBeginIndex = 6;\n if (daValue.length === 10) {\n monthBeginIndex = 5;\n dayBeginIndex = 8;\n }\n const daYears = parseInt(daValue.substring(0, 4), 10);\n // 0-11 range\n const daMonthIndex = daValue.length >= monthBeginIndex + 2\n ? parseInt(daValue.substring(\n monthBeginIndex, monthBeginIndex + 2), 10) - 1 : 0;\n const daDay = daValue.length === dayBeginIndex + 2\n ? parseInt(daValue.substring(\n dayBeginIndex, dayBeginIndex + 2), 10) : 0;\n return {\n year: daYears,\n monthIndex: daMonthIndex,\n day: daDay\n };\n}\n\n/**\n * Get a time object with {hours, minutes, seconds} ready for the\n * Date constructor from a DICOM element with vr=TM.\n *\n * @param {DataElement} element The DICOM element with date information.\n * @returns {{hours, minutes, seconds, milliseconds}|undefined} The time object.\n */\nexport function getTime(element) {\n if (typeof element === 'undefined') {\n return undefined;\n }\n if (element.value.length !== 1) {\n return undefined;\n }\n // format: HH[MMSS.FFFFFF]\n const tmValue = element.value[0];\n const tmHours = parseInt(tmValue.substring(0, 2), 10);\n const tmMinutes = tmValue.length >= 4\n ? parseInt(tmValue.substring(2, 4), 10) : 0;\n const tmSeconds = tmValue.length >= 6\n ? parseInt(tmValue.substring(4, 6), 10) : 0;\n const tmFracSecondsStr = tmValue.length >= 8\n ? tmValue.substring(7, 10) : 0;\n const tmMilliSeconds = tmFracSecondsStr === 0 ? 0\n : parseInt(tmFracSecondsStr, 10) *\n Math.pow(10, 3 - tmFracSecondsStr.length);\n return {\n hours: tmHours,\n minutes: tmMinutes,\n seconds: tmSeconds,\n milliseconds: tmMilliSeconds\n };\n}\n\n/**\n * Get a 'dateTime' object with {date, time} ready for the\n * Date constructor from a DICOM element with vr=DT.\n *\n * @param {DataElement} element The DICOM element with date-time information.\n * @returns {{date, time}|undefined} The time object.\n */\nexport function getDateTime(element) {\n if (typeof element === 'undefined') {\n return undefined;\n }\n if (element.value.length !== 1) {\n return undefined;\n }\n // format: YYYYMMDDHHMMSS.FFFFFF&ZZXX\n const dtFullValue = element.value[0];\n // remove offset (&ZZXX)\n const dtValue = dtFullValue.split('&')[0];\n const dateDataElement = new DataElement('DA');\n dateDataElement.value = [dtValue.substring(0, 8)];\n const dtDate = getDate(dateDataElement);\n const timeDataElement = new DataElement('TM');\n timeDataElement.value = [dtValue.substring(8)];\n const dtTime = dtValue.length >= 9\n ? getTime(timeDataElement) : undefined;\n return {\n date: dtDate,\n time: dtTime\n };\n}\n\n/**\n * Extract date values from a Date object.\n *\n * @param {Date} date The input date.\n * @returns {{year, monthIndex, day}} A 'date' object.\n */\nexport function dateToDateObj(date) {\n return {\n year: date.getFullYear().toString(),\n monthIndex: padZeroTwoDigit((date.getMonth() + 1).toString()),\n day: padZeroTwoDigit(date.getDate().toString())\n };\n}\n\n/**\n * Extract time values from a Date object.\n *\n * @param {Date} date The input date.\n * @returns {{hours, minutes, seconds}} A 'time' object.\n */\nexport function dateToTimeObj(date) {\n return {\n hours: padZeroTwoDigit(date.getHours().toString()),\n minutes: padZeroTwoDigit(date.getMinutes().toString()),\n seconds: padZeroTwoDigit(date.getSeconds().toString())\n };\n}\n\n/**\n * Get a DICOM formated date string.\n *\n * @param {{year, monthIndex, day}} dateObj The date to format.\n * @returns {string} The formated date.\n */\nexport function getDicomDate(dateObj) {\n // YYYYMMDD\n return (\n dateObj.year +\n dateObj.monthIndex +\n dateObj.day\n );\n}\n\n/**\n * Get a DICOM formated time string.\n *\n * @param {{hours, minutes, seconds}} dateObj The date to format.\n * @returns {string} The formated time.\n */\nexport function getDicomTime(dateObj) {\n // HHMMSS\n return (\n dateObj.hours +\n dateObj.minutes +\n dateObj.seconds\n );\n}\n\n/**\n * Get a DICOM formated datetime string.\n *\n * @param {{date, time}} datetime The datetime to format.\n * @returns {string} The formated datetime.\n */\nexport function getDicomDateTime(datetime) {\n // HHMMSS\n let res = getDicomDate(datetime.date);\n if (typeof datetime.time !== 'undefined') {\n res += getDicomTime(datetime.time);\n }\n return res;\n}\n","import {Vector3D} from './vector';\nimport {\n Matrix33,\n getIdentityMat33\n} from './matrix';\n\n/**\n * Create a 3x3 coronal (xzy) matrix.\n *\n * @returns {Matrix33} The coronal matrix.\n */\nexport function getCoronalMat33() {\n /* eslint-disable @stylistic/js/array-element-newline */\n return new Matrix33([\n 1, 0, 0,\n 0, 0, 1,\n 0, -1, 0\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n}\n\n/**\n * Create a 3x3 sagittal (yzx) matrix.\n *\n * @returns {Matrix33} The sagittal matrix.\n */\nexport function getSagittalMat33() {\n /* eslint-disable @stylistic/js/array-element-newline */\n return new Matrix33([\n 0, 0, -1,\n 1, 0, 0,\n 0, -1, 0\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n}\n\n/**\n * Default anatomical plane orientations.\n */\nexport const Orientation = {\n /**\n * Axial, also known as transverse.\n */\n Axial: 'axial',\n /**\n * Coronal, also known as frontal.\n */\n Coronal: 'coronal',\n /**\n * Sagittal, also known as anteroposterior.\n */\n Sagittal: 'sagittal'\n};\n\n/**\n * Get an orientation matrix from a name.\n *\n * @param {string} name The orientation name.\n * @returns {Matrix33|undefined} The orientation matrix.\n */\nexport function getMatrixFromName(name) {\n let matrix;\n if (name === Orientation.Axial) {\n matrix = getIdentityMat33();\n } else if (name === Orientation.Coronal) {\n matrix = getCoronalMat33();\n } else if (name === Orientation.Sagittal) {\n matrix = getSagittalMat33();\n }\n return matrix;\n}\n\n/**\n * Get the orientation code of an orientation matrix. Each letter defines\n * the towards direction. Letters are: R (right), L (left),\n * A (anterior), P (posterior), I (inferior) and S (superior).\n *\n * @param {Matrix33} matrix The orientation matrix.\n * @returns {string} The orientation code.\n */\nexport function getOrientationStringLPS(matrix) {\n const v0 = new Vector3D(\n matrix.get(0, 0),\n matrix.get(1, 0),\n matrix.get(2, 0)\n );\n const v1 = new Vector3D(\n matrix.get(0, 1),\n matrix.get(1, 1),\n matrix.get(2, 1)\n );\n const v2 = new Vector3D(\n matrix.get(0, 2),\n matrix.get(1, 2),\n matrix.get(2, 2)\n );\n return getVectorStringLPS(v0) +\n getVectorStringLPS(v1) +\n getVectorStringLPS(v2);\n}\n\n/**\n * Get the orientation code of an orientation vector.\n * Credits: David Clunie, {@link https://www.dclunie.com/medical-image-faq/html/part2.html}.\n *\n * @param {Vector3D} vector The orientation vector.\n * @returns {string} The orientation code.\n */\nfunction getVectorStringLPS(vector) {\n let abs = new Vector3D(\n Math.abs(vector.getX()),\n Math.abs(vector.getY()),\n Math.abs(vector.getZ())\n );\n\n let orientation = '';\n const orientationX = vector.getX() < 0 ? 'R' : 'L';\n const orientationY = vector.getY() < 0 ? 'A' : 'P';\n // as defined in DICOM\n //const orientationZ = vector.getZ() < 0 ? 'F' : 'H';\n const orientationZ = vector.getZ() < 0 ? 'I' : 'S';\n\n const threshold = 0.0001;\n\n for (let i = 0; i < 3; i++) {\n if (abs.getX() > threshold &&\n abs.getX() > abs.getY() &&\n abs.getX() > abs.getZ()) {\n orientation += orientationX;\n abs = new Vector3D(0, abs.getY(), abs.getZ());\n } else if (abs.getY() > threshold &&\n abs.getY() > abs.getX() &&\n abs.getY() > abs.getZ()) {\n orientation += orientationY;\n abs = new Vector3D(abs.getX(), 0, abs.getZ());\n } else if (abs.getZ() > threshold &&\n abs.getZ() > abs.getX() &&\n abs.getZ() > abs.getY()) {\n orientation += orientationZ;\n abs = new Vector3D(abs.getX(), abs.getY(), 0);\n } else {\n break;\n }\n }\n\n return orientation;\n}\n\n/**\n * Get the LPS 'group' (axial, coronal or sagittal) from a LPS code.\n *\n * @param {string} code The LPS code string.\n * @returns {string|undefined} The group.\n */\nfunction getLPSGroup(code) {\n let orientStr;\n const axialCodes =\n ['LPS', 'LAI', 'RPI', 'RAS', 'ALS', 'ARI', 'PLI', 'PRS'];\n const coronalCodes =\n ['LSA', 'LIP', 'RSP', 'RIA', 'ILA', 'IRP', 'SLP', 'SRA'];\n const sagittalCodes =\n ['PSL', 'PIR', 'ASR', 'AIL', 'IAR', 'IPL', 'SAL', 'SPR'];\n if (axialCodes.includes(code)) {\n orientStr = Orientation.Axial;\n } else if (coronalCodes.includes(code)) {\n orientStr = Orientation.Coronal;\n } else if (sagittalCodes.includes(code)) {\n orientStr = Orientation.Sagittal;\n }\n return orientStr;\n}\n\n/**\n * Get the name of an image orientation patient.\n *\n * @param {number[]} cosines The image orientation\n * patient cosines (6 values).\n * @returns {string|undefined} The orientation\n * name: axial, coronal or sagittal.\n */\nexport function getOrientationName(cosines) {\n let name;\n const orientMatrix = getOrientationFromCosines(cosines);\n if (typeof orientMatrix !== 'undefined') {\n const lpsStr = getOrientationStringLPS(orientMatrix.asOneAndZeros());\n name = getLPSGroup(lpsStr);\n }\n return name;\n}\n\n/**\n * Get the orientation matrix associated to the direction cosines.\n *\n * @param {number[]} cosines The image orientation\n * patient cosines (6 values).\n * @returns {Matrix33|undefined} The orientation matrix.\n */\nexport function getOrientationFromCosines(cosines) {\n let orientationMatrix;\n if (typeof cosines !== 'undefined' && cosines.length === 6) {\n const rowCosines = new Vector3D(cosines[0], cosines[1], cosines[2]);\n const colCosines = new Vector3D(cosines[3], cosines[4], cosines[5]);\n const normal = rowCosines.crossProduct(colCosines);\n /* eslint-disable @stylistic/js/array-element-newline */\n orientationMatrix = new Matrix33([\n rowCosines.getX(), colCosines.getX(), normal.getX(),\n rowCosines.getY(), colCosines.getY(), normal.getY(),\n rowCosines.getZ(), colCosines.getZ(), normal.getZ()\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n }\n return orientationMatrix;\n}\n\n/**\n * Get the direction cosines from an orientation matrix.\n *\n * @param {Matrix33} matrix The input matrix.\n * @returns {number[]} The image orientation\n * patient cosines (6 values).\n */\nexport function getCosinesFromOrientation(matrix) {\n return [\n matrix.get(0, 0),\n matrix.get(1, 0),\n matrix.get(2, 0),\n matrix.get(0, 1),\n matrix.get(1, 1),\n matrix.get(2, 1)\n ];\n}\n\n/**\n * Get the view orientation according to an image and target orientation.\n * The view orientation is used to go from target to image space.\n *\n * @param {Matrix33} imageOrientation The image geometry.\n * @param {Matrix33} targetOrientation The target orientation.\n * @returns {Matrix33} The view orientation.\n */\nexport function getViewOrientation(imageOrientation, targetOrientation) {\n let viewOrientation = getIdentityMat33();\n if (typeof targetOrientation !== 'undefined') {\n // i: image, v: view, t: target, O: orientation, P: point\n // [Img] -- Oi --> [Real] <-- Ot -- [Target]\n // Pi = (Oi)-1 * Ot * Pt = Ov * Pt\n // -> Ov = (Oi)-1 * Ot\n // TODO: asOneAndZeros simplifies but not nice...\n viewOrientation =\n imageOrientation.asOneAndZeros().getInverse().multiply(targetOrientation);\n }\n // TODO: why abs???\n return viewOrientation.getAbs();\n}\n\n/**\n * Get the target orientation according to an image and view orientation.\n * The target orientation is used to go from target to real space.\n *\n * @param {Matrix33} imageOrientation The image geometry.\n * @param {Matrix33} viewOrientation The view orientation.\n * @returns {Matrix33} The target orientation.\n */\nexport function getTargetOrientation(imageOrientation, viewOrientation) {\n // i: image, v: view, t: target, O: orientation, P: point\n // [Img] -- Oi --> [Real] <-- Ot -- [Target]\n // Pi = (Oi)-1 * Ot * Pt = Ov * Pt\n // -> Ot = Oi * Ov\n // note: asOneAndZeros as in getViewOrientation...\n let targetOrientation =\n imageOrientation.asOneAndZeros().multiply(viewOrientation);\n\n // TODO: why abs???\n const simpleImageOrientation = imageOrientation.asOneAndZeros().getAbs();\n if (simpleImageOrientation.equals(getCoronalMat33().getAbs())) {\n targetOrientation = targetOrientation.getAbs();\n }\n\n return targetOrientation;\n}\n","import {\n DicomParser,\n getTransferSyntaxName,\n isJpeg2000TransferSyntax,\n isJpegBaselineTransferSyntax,\n isJpegLosslessTransferSyntax\n} from './dicomParser';\nimport {\n getDate,\n getTime,\n getDateTime\n} from './dicomDate';\nimport {\n isPixelDataTag,\n isItemDelimitationItemTag,\n isSequenceDelimitationItemTag,\n getItemTag,\n getItemDelimitationItemTag,\n getSequenceDelimitationItemTag,\n getPixelDataTag,\n getTagFromKey\n} from './dicomTag';\nimport {isNativeLittleEndian} from './dataReader';\nimport {getOrientationFromCosines} from '../math/orientation';\nimport {Spacing} from '../image/spacing';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Tag} from './dicomTag';\nimport {DataElement} from './dataElement';\nimport {Matrix33} from '../math/matrix';\n/* eslint-enable no-unused-vars */\n\n/**\n * @typedef {Object} DataElements\n */\n\n/**\n * Dump the DICOM tags to a string in the same way as the\n * DCMTK `dcmdump` command (https://support.dcmtk.org/docs-dcmrt/dcmdump.html).\n *\n * @param {Object} dicomElements The dicom elements.\n * @returns {string} The dumped file.\n */\nexport function dcmdump(dicomElements) {\n const keys = Object.keys(dicomElements);\n let result = '\\n';\n result += '# Dicom-File-Format\\n';\n result += '\\n';\n result += '# Dicom-Meta-Information-Header\\n';\n result += '# Used TransferSyntax: ';\n if (isNativeLittleEndian()) {\n result += 'Little Endian Explicit\\n';\n } else {\n result += 'NOT Little Endian Explicit\\n';\n }\n let dicomElement = null;\n let tag = null;\n let checkHeader = true;\n for (let i = 0, leni = keys.length; i < leni; ++i) {\n dicomElement = dicomElements[keys[i]];\n tag = getTagFromKey(keys[i]);\n if (checkHeader && tag.getGroup() !== '0002') {\n result += '\\n';\n result += '# Dicom-Data-Set\\n';\n result += '# Used TransferSyntax: ';\n const syntax = dicomElements['00020010'].value[0];\n result += getTransferSyntaxName(syntax);\n result += '\\n';\n checkHeader = false;\n }\n result += getElementAsString(tag, dicomElement) + '\\n';\n }\n return result;\n}\n\n/**\n * Get a data element value as a string.\n *\n * @param {Tag} tag The DICOM tag.\n * @param {object} dicomElement The DICOM element.\n * @param {boolean} [pretty] When set to true, returns a 'pretified' content.\n * @returns {string} A string representation of the DICOM element.\n */\nfunction getElementValueAsString(tag, dicomElement, pretty) {\n let str = '';\n const strLenLimit = 65;\n\n // dafault to pretty output\n if (typeof pretty === 'undefined') {\n pretty = true;\n }\n // check dicom element input\n if (typeof dicomElement === 'undefined' || dicomElement === null) {\n return str;\n }\n\n // Polyfill for Number.isInteger.\n const isInteger = Number.isInteger || function (value) {\n return typeof value === 'number' &&\n isFinite(value) &&\n Math.floor(value) === value;\n };\n\n // TODO Support sequences.\n\n if (dicomElement.vr !== 'SQ' &&\n dicomElement.value.length === 1 && dicomElement.value[0] === '') {\n str += '(no value available)';\n } else if (isPixelDataTag(tag) &&\n dicomElement.undefinedLength) {\n str = '(PixelSequence)';\n } else if (dicomElement.vr === 'DA' && pretty) {\n const daObj = getDate(dicomElement);\n const da = new Date(daObj.year, daObj.monthIndex, daObj.day);\n str = da.toLocaleDateString();\n } else if (dicomElement.vr === 'TM' && pretty) {\n const tmObj = getTime(dicomElement);\n str = tmObj.hours + ':' + tmObj.minutes + ':' + tmObj.seconds;\n } else {\n let isOtherVR = false;\n if (dicomElement.vr.length !== 0) {\n isOtherVR = (dicomElement.vr[0].toUpperCase() === 'O');\n }\n const isFloatNumberVR = (dicomElement.vr === 'FL' ||\n dicomElement.vr === 'FD' ||\n dicomElement.vr === 'DS');\n let valueStr = '';\n for (let k = 0, lenk = dicomElement.value.length; k < lenk; ++k) {\n valueStr = '';\n if (k !== 0) {\n valueStr += '\\\\';\n }\n if (isFloatNumberVR) {\n const num = Number(dicomElement.value[k]);\n if (!isInteger(num) && pretty) {\n valueStr += num.toPrecision(4);\n } else {\n valueStr += num.toString();\n }\n } else if (isOtherVR) {\n let tmp = dicomElement.value[k].toString(16);\n if (dicomElement.vr === 'OB') {\n tmp = '00'.substring(0, 2 - tmp.length) + tmp;\n } else {\n tmp = '0000'.substring(0, 4 - tmp.length) + tmp;\n }\n valueStr += tmp;\n } else {\n valueStr += dicomElement.value[k];\n }\n // check length\n if (str.length + valueStr.length <= strLenLimit) {\n str += valueStr;\n } else {\n str += '...';\n break;\n }\n }\n }\n return str;\n}\n\n/**\n * Get a data element as a string.\n *\n * @param {Tag} tag The DICOM tag.\n * @param {object} dicomElement The DICOM element.\n * @param {string} [prefix] A string to prepend this one.\n * @returns {string} The element as a string.\n */\nfunction getElementAsString(tag, dicomElement, prefix) {\n // default prefix\n prefix = prefix || '';\n\n // get tag anme from dictionary\n const tagName = tag.getNameFromDictionary();\n\n let deSize = dicomElement.value.length;\n let isOtherVR = false;\n if (dicomElement.vr.length !== 0) {\n isOtherVR = (dicomElement.vr[0].toUpperCase() === 'O');\n }\n\n // no size for delimitations\n if (isItemDelimitationItemTag(tag) ||\n isSequenceDelimitationItemTag(tag)) {\n deSize = 0;\n } else if (isOtherVR) {\n deSize = 1;\n }\n\n const isPixSequence = (isPixelDataTag(tag) &&\n dicomElement.undefinedLength);\n\n let line = null;\n\n // (group,element)\n line = '(';\n line += tag.getGroup().toLowerCase();\n line += ',';\n line += tag.getElement().toLowerCase();\n line += ') ';\n // value representation\n line += dicomElement.vr;\n // value\n if (dicomElement.vr !== 'SQ' &&\n dicomElement.value.length === 1 &&\n dicomElement.value[0] === '') {\n line += ' (no value available)';\n deSize = 0;\n } else {\n // simple number display\n if (dicomElement.vr === 'na') {\n line += ' ';\n line += dicomElement.value[0];\n } else if (isPixSequence) {\n // pixel sequence\n line += ' (PixelSequence #=' + deSize + ')';\n } else if (dicomElement.vr === 'SQ') {\n line += ' (Sequence with';\n if (dicomElement.undefinedLength) {\n line += ' undefined';\n } else {\n line += ' explicit';\n }\n line += ' length #=';\n line += dicomElement.value.length;\n line += ')';\n } else if (isOtherVR ||\n dicomElement.vr === 'pi' ||\n dicomElement.vr === 'UL' ||\n dicomElement.vr === 'US' ||\n dicomElement.vr === 'SL' ||\n dicomElement.vr === 'SS' ||\n dicomElement.vr === 'FL' ||\n dicomElement.vr === 'FD' ||\n dicomElement.vr === 'AT') {\n // 'O'ther array, limited display length\n line += ' ';\n line += getElementValueAsString(tag, dicomElement, false);\n } else {\n // default\n line += ' [';\n line += getElementValueAsString(tag, dicomElement, false);\n line += ']';\n }\n }\n\n // align #\n const nSpaces = 55 - line.length;\n if (nSpaces > 0) {\n for (let s = 0; s < nSpaces; ++s) {\n line += ' ';\n }\n }\n line += ' # ';\n if (dicomElement.vl < 100) {\n line += ' ';\n }\n if (dicomElement.vl < 10) {\n line += ' ';\n }\n line += dicomElement.vl;\n line += ', ';\n line += deSize; //dictElement[1];\n line += ' ';\n if (tagName !== null) {\n line += tagName;\n } else {\n line += 'Unknown Tag & Data';\n }\n\n let message = null;\n\n // continue for sequence\n if (dicomElement.vr === 'SQ') {\n let item = null;\n for (let l = 0, lenl = dicomElement.value.length; l < lenl; ++l) {\n item = dicomElement.value[l];\n const itemKeys = Object.keys(item);\n if (itemKeys.length === 0) {\n continue;\n }\n\n // get the item element\n const itemTag = getItemTag();\n const itemElement = item['FFFEE000'];\n message = '(Item with';\n if (itemElement.undefinedLength) {\n message += ' undefined';\n } else {\n message += ' explicit';\n }\n message += ' length #=' + (itemKeys.length - 1) + ')';\n itemElement.value = [message];\n itemElement.vr = 'na';\n\n line += '\\n';\n line += getElementAsString(itemTag, itemElement, prefix + ' ');\n\n for (let m = 0, lenm = itemKeys.length; m < lenm; ++m) {\n const itemTag = getTagFromKey(itemKeys[m]);\n if (itemKeys[m] !== 'xFFFEE000') {\n line += '\\n';\n line += getElementAsString(itemTag, item[itemKeys[m]],\n prefix + ' ');\n }\n }\n\n message = '(ItemDelimitationItem';\n if (!itemElement.undefinedLength) {\n message += ' for re-encoding';\n }\n message += ')';\n const itemDelimTag = getItemDelimitationItemTag();\n const itemDelimElement = {\n vr: 'na',\n vl: '0',\n value: [message]\n };\n line += '\\n';\n line += getElementAsString(\n itemDelimTag, itemDelimElement, prefix + ' ');\n\n }\n\n message = '(SequenceDelimitationItem';\n if (!dicomElement.undefinedLength) {\n message += ' for re-encod.';\n }\n message += ')';\n const sqDelimTag = getSequenceDelimitationItemTag();\n const sqDelimElement = {\n vr: 'na',\n vl: '0',\n value: [message]\n };\n line += '\\n';\n line += getElementAsString(sqDelimTag, sqDelimElement, prefix);\n } else if (isPixSequence) {\n // pixel sequence\n let pixItem = null;\n for (let n = 0, lenn = dicomElement.value.length; n < lenn; ++n) {\n pixItem = dicomElement.value[n];\n line += '\\n';\n pixItem.vr = 'pi';\n line += getElementAsString(\n getPixelDataTag(), pixItem, prefix + ' ');\n }\n\n const pixDelimTag = getSequenceDelimitationItemTag();\n const pixDelimElement = {\n vr: 'na',\n vl: '0',\n value: ['(SequenceDelimitationItem)']\n };\n line += '\\n';\n line += getElementAsString(pixDelimTag, pixDelimElement, prefix);\n }\n\n return prefix + line;\n}\n\n/**\n * Extract the 2D size from dicom elements.\n *\n * @param {DataElements} elements The DICOM elements.\n * @returns {number[]} The size.\n */\nexport function getImage2DSize(elements) {\n // rows\n const rows = elements['00280010'];\n if (typeof rows === 'undefined') {\n throw new Error('Missing DICOM image number of rows');\n }\n if (rows.value.length === 0) {\n throw new Error('Empty DICOM image number of rows');\n }\n // columns\n const columns = elements['00280011'];\n if (typeof columns === 'undefined') {\n throw new Error('Missing DICOM image number of columns');\n }\n if (columns.value.length === 0) {\n throw new Error('Empty DICOM image number of columns');\n }\n return [columns.value[0], rows.value[0]];\n}\n\n/**\n * Get the pixel spacing from the different spacing tags.\n *\n * @param {DataElements} elements The DICOM elements.\n * @returns {Spacing} The read spacing or the default [1,1].\n */\nexport function getPixelSpacing(elements) {\n // default\n let rowSpacing = 1;\n let columnSpacing = 1;\n\n // 1. PixelSpacing\n // 2. ImagerPixelSpacing\n // 3. NominalScannedPixelSpacing\n // 4. PixelAspectRatio\n const keys = ['00280030', '00181164', '00182010', '00280034'];\n for (let k = 0; k < keys.length; ++k) {\n const spacing = elements[keys[k]];\n if (spacing && spacing.value.length === 2) {\n // spacing order: [row, column]\n rowSpacing = parseFloat(spacing.value[0]);\n columnSpacing = parseFloat(spacing.value[1]);\n break;\n }\n }\n\n // check\n if (columnSpacing === 0) {\n logger.warn('Zero column spacing.');\n columnSpacing = 1;\n }\n if (rowSpacing === 0) {\n logger.warn('Zero row spacing.');\n rowSpacing = 1;\n }\n\n // return\n // (slice spacing will be calculated using the image position patient)\n return new Spacing([columnSpacing, rowSpacing, 1]);\n}\n\n/**\n * Get the pixel data unit.\n *\n * @param {DataElements} elements The DICOM elements.\n * @returns {string|null} The unit value if available.\n */\nexport function getPixelUnit(elements) {\n let unit;\n // 1. RescaleType\n // 2. Units (for PET)\n const keys = ['00281054', '00541001'];\n for (let i = 0; i < keys.length; ++i) {\n const element = elements[keys[i]];\n if (typeof element !== 'undefined') {\n unit = element.value[0];\n break;\n }\n }\n // default rescale type for CT\n if (typeof unit === 'undefined') {\n const element = elements['00080060'];\n if (typeof element !== 'undefined') {\n const modality = element.value[0];\n if (modality === 'CT') {\n unit = 'HU';\n }\n }\n }\n return unit;\n}\n\n/**\n * Check the dimension organization from a dicom element.\n *\n * @param {DataElements} dataElements The root dicom element.\n * @returns {object} The dimension organizations and indices.\n */\nexport function getDimensionOrganization(dataElements) {\n // Dimension Organization Sequence (required)\n const orgSq = dataElements['00209221'];\n if (typeof orgSq === 'undefined' || orgSq.value.length !== 1) {\n throw new Error('Unsupported dimension organization sequence length');\n }\n // Dimension Organization UID\n const orgUID = orgSq.value[0]['00209164'].value[0];\n\n // Dimension Index Sequence (conditionally required)\n const indices = [];\n const indexSqElem = dataElements['00209222'];\n if (typeof indexSqElem !== 'undefined') {\n const indexSq = indexSqElem.value;\n // expecting 2D index\n if (indexSq.length !== 2) {\n throw new Error('Unsupported dimension index sequence length');\n }\n let indexPointer;\n for (let i = 0; i < indexSq.length; ++i) {\n // Dimension Organization UID (required)\n const indexOrg = indexSq[i]['00209164'].value[0];\n if (indexOrg !== orgUID) {\n throw new Error(\n 'Dimension Index Sequence contains a unknown Dimension Organization');\n }\n // Dimension Index Pointer (required)\n indexPointer = indexSq[i]['00209165'].value[0];\n\n const index = {\n DimensionOrganizationUID: indexOrg,\n DimensionIndexPointer: indexPointer\n };\n // Dimension Description Label (optional)\n if (typeof indexSq[i]['00209421'] !== 'undefined') {\n index.DimensionDescriptionLabel = indexSq[i]['00209421'].value[0];\n }\n // store\n indices.push(index);\n }\n // expecting Image Position at last position\n if (indexPointer !== '(0020,0032)') {\n throw new Error('Unsupported non image position as last index');\n }\n }\n\n return {\n organizations: {\n value: [\n {\n DimensionOrganizationUID: orgUID\n }\n ]\n },\n indices: {\n value: indices\n }\n };\n}\n\n/**\n * Get a spacing object from a dicom measure element.\n *\n * @param {DataElements} dataElements The dicom element.\n * @returns {Spacing} A spacing object.\n */\nexport function getSpacingFromMeasure(dataElements) {\n // Pixel Spacing\n if (typeof dataElements['00280030'] === 'undefined') {\n return null;\n }\n const pixelSpacing = dataElements['00280030'];\n // spacing order: [row, column]\n const spacingValues = [\n parseFloat(pixelSpacing.value[1]),\n parseFloat(pixelSpacing.value[0]),\n ];\n // Spacing Between Slices\n if (typeof dataElements['00180088'] !== 'undefined') {\n spacingValues.push(parseFloat(dataElements['00180088'].value[0]));\n }\n return new Spacing(spacingValues);\n}\n\n/**\n * Get an orientation matrix from a dicom orientation element.\n *\n * @param {DataElements} dataElements The dicom element.\n * @returns {Matrix33|undefined} The orientation matrix.\n */\nexport function getOrientationMatrix(dataElements) {\n const imageOrientationPatient = dataElements['00200037'];\n let orientationMatrix;\n // slice orientation (cosines are matrices' columns)\n // http://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.7.6.2.html#sect_C.7.6.2.1.1\n if (typeof imageOrientationPatient !== 'undefined') {\n orientationMatrix =\n getOrientationFromCosines(\n imageOrientationPatient.value.map((item) => parseFloat(item))\n );\n }\n return orientationMatrix;\n}\n\n/**\n * Get a dicom item from a measure sequence.\n *\n * @param {Spacing} spacing The spacing object.\n * @returns {object} The dicom item.\n */\nexport function getDicomMeasureItem(spacing) {\n return {\n SpacingBetweenSlices: spacing.get(2),\n PixelSpacing: [spacing.get(1), spacing.get(0)]\n };\n}\n\n/**\n * Get a dicom element from a plane orientation sequence.\n *\n * @param {Matrix33} orientation The image orientation.\n * @returns {object} The dicom element.\n */\nexport function getDicomPlaneOrientationItem(orientation) {\n return {\n ImageOrientationPatient: [\n orientation.get(0, 0),\n orientation.get(1, 0),\n orientation.get(2, 0),\n orientation.get(0, 1),\n orientation.get(1, 1),\n orientation.get(2, 1)\n ]\n };\n}\n\n/**\n * Gets the sop class uid from the data elements.\n *\n * @param {object} dataElements The data elements. *.\n * @returns {string | undefined} The sop class uid value.\n */\nexport function getSopClassUid(dataElements) {\n const SOPClassUID = dataElements['00080016'];\n if (typeof SOPClassUID !== 'undefined') {\n return SOPClassUID.value[0];\n }\n return;\n}\n\n/**\n * Check if the received string represents a secondary capture.\n *\n * @param {string} SOPClassUID The sop class uid.\n * @returns {boolean} True if it is secondary capture.\n */\nexport function isSecondatyCapture(SOPClassUID) {\n const pattern = /^1\\.2\\.840\\.10008\\.5\\.1\\.4\\.1\\.1\\.7/;\n return !SOPClassUID && pattern.test(SOPClassUID);\n}\n\n/**\n * Gets the photometric interpretation from the data elements.\n *\n * @param {object} dataElements The data elements.\n * @returns {string | undefined} The photometric interpretation value.\n */\nexport function getPhotometricInterpretation(dataElements) {\n const photometricInterpretation = dataElements['00280004'];\n const syntaxElement = dataElements['00020010'];\n const spp = dataElements['00280002'];\n // samplesPerPixel\n let samplesPerPixel = 1;\n if (typeof spp !== 'undefined') {\n samplesPerPixel = spp.value[0];\n }\n\n if (typeof photometricInterpretation !== 'undefined' &&\n typeof syntaxElement !== 'undefined') {\n let photo = photometricInterpretation.value[0].toUpperCase();\n // TransferSyntaxUID\n const syntax = syntaxElement.value[0];\n const jpeg2000 = isJpeg2000TransferSyntax(syntax);\n const jpegBase = isJpegBaselineTransferSyntax(syntax);\n const jpegLoss = isJpegLosslessTransferSyntax(syntax);\n // jpeg decoders output RGB data\n if ((jpeg2000 || jpegBase || jpegLoss) &&\n (photo !== 'MONOCHROME1' && photo !== 'MONOCHROME2')) {\n photo = 'RGB';\n }\n // check samples per pixels\n if (photo === 'RGB' && samplesPerPixel === 1) {\n photo = 'PALETTE COLOR';\n }\n return photo;\n }\n}\n\n/**\n * Check if an input photometricInterpretation is monochrome.\n *\n * @param {string} photometricInterpretation The photometric interpretation.\n * @returns {boolean} True if the input string starts with 'MONOCHROME'.\n */\nexport function isMonochrome(photometricInterpretation) {\n return typeof photometricInterpretation !== 'undefined' &&\n photometricInterpretation.match(/MONOCHROME/) !== null;\n}\n\n/**\n * Check an input tag.\n *\n * @param {object} element The element to check.\n * @param {string} name The element name.\n * @param {Array} [values] The expected values.\n * @returns {string} A warning if the element is not as expected.\n */\nfunction checkTag(element, name, values) {\n let warning = '';\n if (typeof element === 'undefined') {\n warning += ' ' + name + ' is undefined,';\n } else if (element.value.length === 0) {\n warning += ' ' + name + ' is empty,';\n } else {\n if (typeof values !== 'undefined') {\n for (let i = 0; i < values.length; ++i) {\n\n if (!element.value.includes(values[i])) {\n warning += ' ' + name + ' does not contain ' + values[i] +\n ' (value: ' + element.value + '),';\n }\n }\n }\n }\n return warning;\n}\n\n/**\n * Get the decayed dose (Bq).\n *\n * @param {object} elements The DICOM elements to check.\n * @returns {object} The value and a warning if\n * the elements are not as expected.\n */\nfunction getDecayedDose(elements) {\n let warning = '';\n let warn;\n\n // SeriesDate (type1)\n const seriesDateEl = elements['00080021'];\n const seriesDateObj = getDate(seriesDateEl);\n\n let totalDose;\n let halfLife;\n let radioStart;\n\n const radioInfoSqStr = 'RadiopharmaceuticalInformationSequence (00540016)';\n const radioInfoSq = elements['00540016'];\n warning += checkTag(radioInfoSq, radioInfoSqStr);\n if (typeof radioInfoSq !== 'undefined') {\n if (radioInfoSq.value.length !== 1) {\n logger.warn(\n 'Found more than 1 istopes in RadiopharmaceuticalInformation Sequence.'\n );\n }\n\n // RadionuclideTotalDose (type3, Bq)\n const totalDoseStr = 'RadionuclideTotalDose (00181074)';\n const totalDoseEl = radioInfoSq.value[0]['00181074'];\n warn = checkTag(totalDoseEl, totalDoseStr);\n if (warn.length === 0) {\n const dose = parseFloat(totalDoseEl.value[0]);\n if (!isNaN(dose)) {\n totalDose = dose;\n } else {\n warning += ' TotalDose is not a number';\n }\n } else {\n warning += warn;\n }\n\n // RadionuclideHalfLife (type3, seconds)\n const halfLifeStr = 'RadionuclideHalfLife (00181075)';\n const halfLifeEl = radioInfoSq.value[0]['00181075'];\n warn = checkTag(halfLifeEl, halfLifeStr);\n if (warn.length === 0) {\n const hl = parseFloat(halfLifeEl.value[0]);\n if (!isNaN(hl)) {\n halfLife = hl;\n } else {\n warning += ' HalfLife is not a number';\n }\n } else {\n warning += warn;\n }\n\n // RadiopharmaceuticalStartDateTime (type3)\n const radioStartDateTimeEl = radioInfoSq.value[0]['00181078'];\n let radioStartDateObj;\n let radioStartTimeObj;\n if (typeof radioStartDateTimeEl === 'undefined') {\n // use seriesDate as radioStartDate\n radioStartDateObj = seriesDateObj;\n // try RadiopharmaceuticalStartTime (type3)\n const radioStartTimeEl = radioInfoSq.value[0]['00181072'];\n radioStartTimeObj = getTime(radioStartTimeEl);\n } else {\n const radioStartDateTime = getDateTime(radioStartDateTimeEl);\n radioStartDateObj = radioStartDateTime.date;\n radioStartTimeObj = radioStartDateTime.time;\n }\n if (typeof radioStartTimeObj === 'undefined') {\n radioStartTimeObj = {\n hours: 0, minutes: 0, seconds: 0, milliseconds: 0\n };\n }\n radioStart = new Date(\n radioStartDateObj.year,\n radioStartDateObj.monthIndex,\n radioStartDateObj.day,\n radioStartTimeObj.hours,\n radioStartTimeObj.minutes,\n radioStartTimeObj.seconds,\n radioStartTimeObj.milliseconds\n );\n }\n\n // SeriesTime (type1)\n const seriesTimeEl = elements['00080031'];\n const seriesTimeObj = getTime(seriesTimeEl);\n // Series date/time\n let scanStart = new Date(\n seriesDateObj.year,\n seriesDateObj.monthIndex,\n seriesDateObj.day,\n seriesTimeObj.hours,\n seriesTimeObj.minutes,\n seriesTimeObj.seconds,\n seriesTimeObj.milliseconds\n );\n\n // scanStart Date check\n // AcquisitionDate (type3)\n const acqDateEl = elements['00080022'];\n // AcquisitionTime (type3)\n const acqTimeEl = elements['00080032'];\n if (typeof acqDateEl !== 'undefined' &&\n typeof acqTimeEl !== 'undefined') {\n const acqDateObj = getDate(acqDateEl);\n const acqTimeObj = getTime(acqTimeEl);\n const acqDate = new Date(\n acqDateObj.year,\n acqDateObj.monthIndex,\n acqDateObj.day,\n acqTimeObj.hours,\n acqTimeObj.minutes,\n acqTimeObj.seconds,\n acqTimeObj.milliseconds\n );\n\n if (scanStart > acqDate) {\n const diff = scanStart.getTime() - acqDate.getTime();\n const warn = 'Series date/time is after Aquisition date/time (diff=' +\n diff.toString() + 'ms) ';\n logger.debug(warn);\n\n // back compute from center (average count rate) of time window\n // for bed position (frame) in series (reliable in all cases)\n\n let frameRefTime = 0;\n const frameRefTimeElStr = 'FrameReferenceTime (00541300)';\n const frameRefTimeEl = elements['00541300'];\n warning += checkTag(frameRefTimeEl, frameRefTimeElStr);\n if (typeof frameRefTimeEl !== 'undefined') {\n frameRefTime = frameRefTimeEl.value[0];\n }\n let actualFrameDuration = 0;\n const actualFrameDurationElStr = 'ActualFrameDuration (0018,1242)';\n const actualFrameDurationEl = elements['00181242'];\n warning += checkTag(actualFrameDurationEl, actualFrameDurationElStr);\n if (typeof actualFrameDurationEl !== 'undefined') {\n actualFrameDuration = actualFrameDurationEl.value[0];\n }\n if (frameRefTime > 0 && actualFrameDuration > 0) {\n // convert to seconds\n actualFrameDuration = actualFrameDuration / 1000;\n frameRefTime = frameRefTime / 1000;\n const decayConstant = Math.log(2) / halfLife;\n const decayDuringFrame = decayConstant * actualFrameDuration;\n const averageCountRateTimeWithinFrame =\n 1 /\n decayConstant *\n Math.log(decayDuringFrame / (1 - Math.exp(-decayDuringFrame)));\n const offsetSeconds = averageCountRateTimeWithinFrame - frameRefTime;\n scanStart = new Date(\n acqDateObj.year,\n acqDateObj.monthIndex,\n acqDateObj.day,\n acqTimeObj.hours,\n acqTimeObj.minutes,\n acqTimeObj.seconds + offsetSeconds,\n acqTimeObj.milliseconds\n );\n }\n }\n }\n\n // decayed dose (Bq)\n let decayedDose;\n if (typeof scanStart !== 'undefined' &&\n typeof radioStart !== 'undefined' &&\n typeof totalDose !== 'undefined' &&\n typeof halfLife !== 'undefined') {\n // decay time (s) (Date diff is in milliseconds)\n const decayTime = (scanStart.getTime() - radioStart.getTime()) / 1000;\n const decay = Math.pow(2, (-decayTime / halfLife));\n decayedDose = totalDose * decay;\n }\n\n return {\n value: decayedDose,\n warning: warning\n };\n}\n\n/**\n * Get the PET SUV factor.\n *\n * Ref:\n * - {@link https://qibawiki.rsna.org/index.php/Standardized_Uptake_Value_(SUV)#SUV_Calculation},\n * - {@link https://qibawiki.rsna.org/images/6/62/SUV_vendorneutral_pseudocode_happypathonly_20180626_DAC.pdf},\n * - {@link https://qibawiki.rsna.org/images/8/86/SUV_vendorneutral_pseudocode_20180626_DAC.pdf}.\n *\n * @param {object} elements The DICOM elements.\n * @returns {object} The value and a warning if\n * the elements are not as expected.\n */\nexport function getSuvFactor(elements) {\n let warning = '';\n const result = {};\n\n\n // CorrectedImage (type2): must contain ATTN and DECY\n const corrImageTagStr = 'Corrected Image (00280051)';\n const corrImageEl = elements['00280051'];\n warning += checkTag(corrImageEl, corrImageTagStr, ['ATTN', 'DECY']);\n // DecayCorrection (type1): must be START\n const decayCorrTagStr = 'Decay Correction (00541102)';\n const decayCorrEl = elements['00541102'];\n warning += checkTag(decayCorrEl, decayCorrTagStr, ['START']);\n // Units (type1): must be BQML\n const unitTagStr = 'Units (00541001)';\n const unitEl = elements['00541001'];\n warning += checkTag(unitEl, unitTagStr, ['BQML']);\n\n // PatientWeight (type3, kg)\n let patWeight;\n const patientWeightStr = ' PatientWeight (00101030)';\n const patWeightEl = elements['00101030'];\n const warn = checkTag(patWeightEl, patientWeightStr);\n if (warn.length === 0) {\n const weight = parseFloat(patWeightEl.value[0]);\n if (!isNaN(weight)) {\n patWeight = weight;\n } else {\n warning += ' PatientWeight is not a number';\n }\n } else {\n warning += warn;\n }\n\n // Decayed dose (Bq)\n const decayedDose = getDecayedDose(elements);\n warning += decayedDose.warning;\n\n\n if (warning.length !== 0) {\n result.warning = 'Cannot calculate PET SUV:' + warning;\n } else {\n // SUV factor (grams/Bq)\n result.value = (patWeight * 1000) / decayedDose.value;\n }\n\n return result;\n}\n\n\n/**\n * Get the file list from a DICOMDIR.\n *\n * @param {object} data The buffer data of the DICOMDIR.\n * @returns {Array|undefined} The file list as an array ordered by\n * STUDY > SERIES > IMAGES.\n */\nexport function getFileListFromDicomDir(data) {\n // parse file\n const parser = new DicomParser();\n parser.parse(data);\n const elements = parser.getDicomElements();\n\n // Directory Record Sequence\n if (typeof elements['00041220'] === 'undefined' ||\n typeof elements['00041220'].value === 'undefined') {\n logger.warn('No Directory Record Sequence found in DICOMDIR.');\n return undefined;\n }\n const dirSeq = elements['00041220'].value;\n\n if (dirSeq.length === 0) {\n logger.warn('The Directory Record Sequence of the DICOMDIR is empty.');\n return undefined;\n }\n\n const records = [];\n let series = null;\n let study = null;\n for (let i = 0; i < dirSeq.length; ++i) {\n // Directory Record Type\n if (typeof dirSeq[i]['00041430'] === 'undefined' ||\n typeof dirSeq[i]['00041430'].value === 'undefined') {\n continue;\n }\n const recType = dirSeq[i]['00041430'].value[0];\n\n // supposed to come in order...\n if (recType === 'STUDY') {\n study = [];\n records.push(study);\n } else if (recType === 'SERIES') {\n series = [];\n study.push(series);\n } else if (recType === 'IMAGE') {\n // Referenced File ID\n if (typeof dirSeq[i]['00041500'] === 'undefined' ||\n typeof dirSeq[i]['00041500'].value === 'undefined') {\n continue;\n }\n const refFileIds = dirSeq[i]['00041500'].value;\n // join ids\n series.push(refFileIds.join('/'));\n }\n }\n return records;\n}\n\n/**\n * Methods used to extract values from DICOM elements.\n *\n * Implemented as class and method to allow for override via its prototype.\n */\nexport class TagValueExtractor {\n /**\n * Get the time.\n *\n * @param {Object} _elements The DICOM elements.\n * @returns {number|undefined} The time value if available.\n */\n getTime(_elements) {\n // default returns undefined\n return undefined;\n }\n}\n","import {Size} from './size';\nimport {Geometry} from './geometry';\nimport {RescaleSlopeAndIntercept} from './rsi';\nimport {WindowLevel} from './windowLevel';\nimport {Image} from './image';\nimport {ColourMap} from './luts';\nimport {\n isJpeg2000TransferSyntax,\n isJpegBaselineTransferSyntax,\n isJpegLosslessTransferSyntax\n} from '../dicom/dicomParser';\nimport {\n getImage2DSize,\n getPixelSpacing,\n getPixelUnit,\n TagValueExtractor,\n getSuvFactor,\n getOrientationMatrix,\n isSecondatyCapture,\n getPhotometricInterpretation,\n getSopClassUid,\n isMonochrome\n} from '../dicom/dicomElementsWrapper';\nimport {Point3D} from '../math/point';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * @typedef {Object} DataElements\n */\n\n/**\n * {@link Image} factory.\n */\nexport class ImageFactory {\n\n /**\n * Possible warning created by checkElements.\n *\n * @type {string|undefined}\n */\n #warning;\n\n /**\n * The PET SUV factor.\n *\n * @type {number|undefined}\n */\n #suvFactor;\n\n /**\n * Get a warning string if elements are not as expected.\n * Created by checkElements.\n *\n * @returns {string|undefined} The warning.\n */\n getWarning() {\n return this.#warning;\n }\n\n /**\n * Check dicom elements. Throws an error if not suitable.\n *\n * @param {DataElements} dataElements The DICOM data elements.\n * @returns {string|undefined} A possible warning.\n */\n checkElements(dataElements) {\n // reset\n this.#warning = undefined;\n // will throw if columns or rows is not defined\n getImage2DSize(dataElements);\n // check PET SUV\n let modality;\n const element = dataElements['00080060'];\n if (typeof element !== 'undefined') {\n modality = element.value[0];\n\n if (modality === 'PT') {\n const photometricInterpretation =\n getPhotometricInterpretation(dataElements);\n const SOPClassUID = getSopClassUid(dataElements);\n if (isSecondatyCapture(SOPClassUID) ||\n !isMonochrome(photometricInterpretation)) {\n return this.#warning;\n }\n const suvFactor = getSuvFactor(dataElements);\n this.#suvFactor = suvFactor.value;\n this.#warning = suvFactor.warning;\n }\n }\n\n return this.#warning;\n }\n\n /**\n * Get an {@link Image} object from the read DICOM file.\n *\n * @param {DataElements} dataElements The DICOM tags.\n * @param {Uint8Array | Int8Array |\n * Uint16Array | Int16Array |\n * Uint32Array | Int32Array} pixelBuffer The pixel buffer.\n * @param {number} numberOfFiles The input number of files.\n * @returns {Image} A new Image.\n */\n create(dataElements, pixelBuffer, numberOfFiles) {\n const size2D = getImage2DSize(dataElements);\n const sizeValues = [size2D[0], size2D[1], 1];\n\n // NumberOfFrames\n const numberOfFramesEl = dataElements['00280008'];\n if (typeof numberOfFramesEl !== 'undefined') {\n const number = parseInt(numberOfFramesEl.value[0], 10);\n if (number > 1) {\n sizeValues.push(number);\n }\n }\n\n // image size\n const size = new Size(sizeValues);\n\n // image spacing\n const spacing = getPixelSpacing(dataElements);\n\n // TransferSyntaxUID\n const syntax = dataElements['00020010'].value[0];\n const jpeg2000 = isJpeg2000TransferSyntax(syntax);\n const jpegBase = isJpegBaselineTransferSyntax(syntax);\n const jpegLoss = isJpegLosslessTransferSyntax(syntax);\n\n // ImagePositionPatient\n const imagePositionPatient = dataElements['00200032'];\n // slice position\n let slicePosition = new Array(0, 0, 0);\n if (typeof imagePositionPatient !== 'undefined') {\n slicePosition = [\n parseFloat(imagePositionPatient.value[0]),\n parseFloat(imagePositionPatient.value[1]),\n parseFloat(imagePositionPatient.value[2])\n ];\n }\n\n // Image orientation patient\n const orientationMatrix = getOrientationMatrix(dataElements);\n\n // geometry\n const origin = new Point3D(\n slicePosition[0], slicePosition[1], slicePosition[2]);\n const extractor = new TagValueExtractor();\n const time = extractor.getTime(dataElements);\n const geometry = new Geometry(\n origin, size, spacing, orientationMatrix, time);\n\n // SOP Instance UID\n let sopInstanceUid;\n const siu = dataElements['00080018'];\n if (typeof siu !== 'undefined') {\n sopInstanceUid = siu.value[0];\n }\n\n // Sample per pixels\n let samplesPerPixel = 1;\n const spp = dataElements['00280002'];\n if (typeof spp !== 'undefined') {\n samplesPerPixel = spp.value[0];\n }\n\n // check buffer size\n const bufferSize = size.getTotalSize() * samplesPerPixel;\n if (bufferSize !== pixelBuffer.length) {\n logger.warn('Badly sized pixel buffer: ' +\n pixelBuffer.length + ' != ' + bufferSize);\n if (bufferSize < pixelBuffer.length) {\n pixelBuffer = pixelBuffer.slice(0, size.getTotalSize());\n } else {\n throw new Error('Underestimated buffer size, can\\'t fix it...');\n }\n }\n\n // image\n const image = new Image(geometry, pixelBuffer, [sopInstanceUid]);\n // PhotometricInterpretation\n const photometricInterpretation = dataElements['00280004'];\n if (typeof photometricInterpretation !== 'undefined') {\n let photo = photometricInterpretation.value[0].toUpperCase();\n // jpeg decoders output RGB data\n if ((jpeg2000 || jpegBase || jpegLoss) &&\n (photo !== 'MONOCHROME1' && photo !== 'MONOCHROME2')) {\n photo = 'RGB';\n }\n // check samples per pixels\n if (photo === 'RGB' && samplesPerPixel === 1) {\n photo = 'PALETTE COLOR';\n }\n image.setPhotometricInterpretation(photo);\n }\n // PlanarConfiguration\n const planarConfiguration = dataElements['00280006'];\n if (typeof planarConfiguration !== 'undefined') {\n image.setPlanarConfiguration(planarConfiguration.value[0]);\n }\n\n // rescale slope and intercept\n let slope = 1;\n // RescaleSlope\n const rescaleSlope = dataElements['00281053'];\n if (typeof rescaleSlope !== 'undefined') {\n const value = parseFloat(rescaleSlope.value[0]);\n if (!isNaN(value)) {\n slope = value;\n }\n }\n let intercept = 0;\n // RescaleIntercept\n const rescaleIntercept = dataElements['00281052'];\n if (typeof rescaleIntercept !== 'undefined') {\n const value = parseFloat(rescaleIntercept.value[0]);\n if (!isNaN(value)) {\n intercept = value;\n }\n }\n\n // meta information\n const meta = {\n numberOfFiles: numberOfFiles\n };\n\n // Modality\n const modality = dataElements['00080060'];\n if (typeof modality !== 'undefined') {\n meta.Modality = modality.value[0];\n }\n\n // PET SUV\n let isPetWithSuv = false;\n let intensityFactor = 1;\n if (typeof this.#suvFactor !== 'undefined') {\n isPetWithSuv = true;\n intensityFactor = this.#suvFactor;\n logger.info('Applying PET SUV calibration: ' + intensityFactor);\n slope *= intensityFactor;\n intercept *= intensityFactor;\n }\n const rsi = new RescaleSlopeAndIntercept(slope, intercept);\n image.setRescaleSlopeAndIntercept(rsi);\n\n const safeGet = function (key) {\n let res;\n const element = dataElements[key];\n if (typeof element !== 'undefined') {\n res = element.value[0];\n }\n return res;\n };\n\n // defaults\n meta.TransferSyntaxUID = safeGet('00020010');\n meta.MediaStorageSOPClassUID = safeGet('00020002');\n meta.SOPClassUID = safeGet('00080016');\n meta.Modality = safeGet('00080060');\n meta.ImageType = safeGet('00080008');\n meta.SamplesPerPixel = safeGet('00280002');\n meta.PhotometricInterpretation = safeGet('00280004');\n meta.PixelRepresentation = safeGet('00280103');\n meta.BitsAllocated = safeGet('00280100');\n meta.BitsStored = safeGet('00280101');\n meta.HighBit = safeGet('00280102');\n\n // Study\n meta.StudyDate = safeGet('00080020');\n meta.StudyTime = safeGet('00080030');\n meta.StudyInstanceUID = safeGet('0020000D');\n meta.StudyID = safeGet('00200010');\n // Series\n meta.SeriesInstanceUID = safeGet('0020000E');\n meta.SeriesNumber = safeGet('00200011');\n // ReferringPhysicianName\n meta.ReferringPhysicianName = safeGet('00080090');\n // patient info\n meta.PatientName = safeGet('00100010');\n meta.PatientID = safeGet('00100020');\n meta.PatientBirthDate = safeGet('00100030');\n meta.PatientSex = safeGet('00100040');\n // General Equipment Module\n meta.Manufacturer = safeGet('00080070');\n meta.ManufacturerModelName = safeGet('00081090');\n meta.DeviceSerialNumber = safeGet('00181000');\n meta.SoftwareVersions = safeGet('00181020');\n\n meta.ImageOrientationPatient = safeGet('00200037');\n meta.FrameOfReferenceUID = safeGet('00200052');\n\n // PixelRepresentation -> is signed\n meta.IsSigned = meta.PixelRepresentation === 1;\n // local pixel unit\n if (isPetWithSuv) {\n meta.pixelUnit = 'SUV';\n } else {\n const pixelUnit = getPixelUnit(dataElements);\n if (typeof pixelUnit !== 'undefined') {\n meta.pixelUnit = pixelUnit;\n }\n }\n // window level presets\n const windowPresets = {};\n const windowCenter = dataElements['00281050'];\n const windowWidth = dataElements['00281051'];\n const windowCWExplanation = dataElements['00281055'];\n if (typeof windowCenter !== 'undefined' &&\n typeof windowWidth !== 'undefined') {\n let name;\n for (let j = 0; j < windowCenter.value.length; ++j) {\n const center = parseFloat(windowCenter.value[j]);\n let width = parseFloat(windowWidth.value[j]);\n if (center && width && width !== 0) {\n name = '';\n if (typeof windowCWExplanation !== 'undefined') {\n name = windowCWExplanation.value[j];\n }\n if (name === '') {\n name = 'Default' + j;\n }\n width *= intensityFactor;\n if (width < 1) {\n width = 1;\n }\n windowPresets[name] = {\n wl: [new WindowLevel(\n center * intensityFactor,\n width\n )],\n name: name\n };\n }\n if (width === 0) {\n logger.warn('Zero window width found in DICOM.');\n }\n }\n }\n meta.windowPresets = windowPresets;\n\n // PALETTE COLOR luts\n if (image.getPhotometricInterpretation() === 'PALETTE COLOR') {\n // Red Palette Color Lookup Table Data\n const redLutElement = dataElements['00281201'];\n // Green Palette Color Lookup Table Data\n const greenLutElement = dataElements['00281202'];\n // Blue Palette Color Lookup Table Data\n const blueLutElement = dataElements['00281203'];\n let redLut;\n let greenLut;\n let blueLut;\n // check red palette descriptor (should all be equal)\n // Red Palette Color Lookup Table Descriptor\n // 0: number of entries in the lookup table\n // 1: first input value mapped\n // 2: number of bits for each entry in the Lookup Table Data (8 or 16)\n const descriptor = dataElements['00281101'];\n if (typeof descriptor !== 'undefined' &&\n descriptor.value.length === 3) {\n if (descriptor.value[2] === 16) {\n let doScale = false;\n // (C.7.6.3.1.5 Palette Color Lookup Table Descriptor)\n // Some implementations have encoded 8 bit entries with 16 bits\n // allocated, padding the high bits;\n let descSize = descriptor.value[0];\n // (C.7.6.3.1.5 Palette Color Lookup Table Descriptor)\n // The first Palette Color Lookup Table Descriptor value is the\n // number of entries in the lookup table. When the number of table\n // entries is equal to 216 then this value shall be 0.\n if (descSize === 0) {\n descSize = 65536;\n }\n // red palette VL\n // TODO vl is undefined, find info elsewhere...\n const vlSize = redLutElement.vl;\n // check double size\n if (vlSize !== 2 * descSize) {\n doScale = true;\n logger.info('16bits lut but size is not double. desc: ' +\n descSize + ' vl: ' + vlSize);\n }\n // (C.7.6.3.1.6 Palette Color Lookup Table Data)\n // Palette color values must always be scaled across the full\n // range of available intensities\n const bitsAllocated = parseInt(\n dataElements['00280100'].value[0], 10);\n if (bitsAllocated === 8) {\n doScale = true;\n logger.info(\n 'Scaling 16bits color lut since bits allocated is 8.');\n }\n\n if (doScale) {\n const scaleTo8 = function (value) {\n return value >> 8;\n };\n\n redLut = redLutElement.value.map(scaleTo8);\n greenLut = greenLutElement.value.map(scaleTo8);\n blueLut = blueLutElement.value.map(scaleTo8);\n }\n } else if (descriptor.value[2] === 8) {\n // lut with vr=OW was read as Uint16, convert it to Uint8\n logger.info(\n 'Scaling 16bits color lut since the lut descriptor is 8.');\n let clone = redLutElement.value.slice(0);\n // @ts-expect-error\n redLut = Array.from(new Uint8Array(clone.buffer));\n clone = greenLutElement.value.slice(0);\n // @ts-expect-error\n greenLut = Array.from(new Uint8Array(clone.buffer));\n clone = blueLutElement.value.slice(0);\n // @ts-expect-error\n blueLut = Array.from(new Uint8Array(clone.buffer));\n }\n }\n // set the palette\n image.setPaletteColourMap(new ColourMap(redLut, greenLut, blueLut));\n }\n\n // RecommendedDisplayFrameRate\n const recommendedDisplayFrameRate = dataElements['00082144'];\n if (typeof recommendedDisplayFrameRate !== 'undefined') {\n meta.RecommendedDisplayFrameRate = parseInt(\n recommendedDisplayFrameRate.value[0], 10);\n }\n\n // store the meta data\n image.setMeta(meta);\n\n return image;\n }\n\n}","/**\n * Data writer.\n */\nexport class DataWriter {\n\n /**\n * Is the endianness Little Endian.\n *\n * @type {boolean}\n */\n #isLittleEndian = true;\n\n /**\n * The main data view.\n *\n * @type {DataView}\n */\n #view;\n\n /**\n * @param {ArrayBuffer} buffer The input array buffer.\n * @param {boolean} [isLittleEndian] Flag to tell if the data is\n * little or big endian.\n */\n constructor(buffer, isLittleEndian) {\n // Set endian flag if not defined.\n if (typeof isLittleEndian !== 'undefined') {\n this.#isLittleEndian = isLittleEndian;\n }\n this.#view = new DataView(buffer);\n }\n\n /**\n * Write Uint8 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeUint8(byteOffset, value) {\n this.#view.setUint8(byteOffset, value);\n return byteOffset + Uint8Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Int8 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeInt8(byteOffset, value) {\n this.#view.setInt8(byteOffset, value);\n return byteOffset + Int8Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Uint16 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeUint16(byteOffset, value) {\n this.#view.setUint16(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Uint16Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Int16 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeInt16(byteOffset, value) {\n this.#view.setInt16(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Int16Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Uint32 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeUint32(byteOffset, value) {\n this.#view.setUint32(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Uint32Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Uint64 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {bigint} value The data to write.\n * @returns {number} The new offset position.\n */\n writeUint64(byteOffset, value) {\n this.#view.setBigUint64(byteOffset, value, this.#isLittleEndian);\n return byteOffset + BigUint64Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Int32 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeInt32(byteOffset, value) {\n this.#view.setInt32(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Int32Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Int64 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {bigint} value The data to write.\n * @returns {number} The new offset position.\n */\n writeInt64(byteOffset, value) {\n this.#view.setBigInt64(byteOffset, value, this.#isLittleEndian);\n return byteOffset + BigInt64Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Float32 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeFloat32(byteOffset, value) {\n this.#view.setFloat32(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Float32Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write Float64 data.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {number} value The data to write.\n * @returns {number} The new offset position.\n */\n writeFloat64(byteOffset, value) {\n this.#view.setFloat64(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Float64Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write string data of length 4 as hexadecimal (no '0x' prefix).\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {string} str The hexadecimal string to write ('####').\n * @returns {number} The new offset position.\n */\n writeHex(byteOffset, str) {\n // remove first two chars and parse\n const value = parseInt(str, 16);\n this.#view.setUint16(byteOffset, value, this.#isLittleEndian);\n return byteOffset + Uint16Array.BYTES_PER_ELEMENT;\n }\n\n /**\n * Write a boolean array as binary.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeBinaryArray(byteOffset, array) {\n if (array.length % 8 !== 0) {\n throw new Error('Cannot write boolean array as binary.');\n }\n let byte = null;\n let val = null;\n for (let i = 0, len = array.length; i < len; i += 8) {\n byte = 0;\n for (let j = 0; j < 8; ++j) {\n val = array[i + j] === 0 ? 0 : 1;\n byte += val << j;\n }\n byteOffset = this.writeUint8(byteOffset, byte);\n }\n return byteOffset;\n }\n\n /**\n * Write Uint8 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array|Uint8Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeUint8Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeUint8(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Int8 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeInt8Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeInt8(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Uint16 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeUint16Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeUint16(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Int16 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeInt16Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeInt16(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Uint32 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeUint32Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeUint32(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Uint64 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeUint64Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeUint64(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Int32 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeInt32Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeInt32(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Int64 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeInt64Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeInt64(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Float32 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeFloat32Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeFloat32(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n /**\n * Write Float64 array.\n *\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} array The array to write.\n * @returns {number} The new offset position.\n */\n writeFloat64Array(byteOffset, array) {\n for (let i = 0, len = array.length; i < len; ++i) {\n byteOffset = this.writeFloat64(byteOffset, array[i]);\n }\n return byteOffset;\n }\n\n} // class DataWriter\n","import {\n is32bitVLVR,\n isCharSetStringVR,\n vrTypes\n} from './dictionary';\nimport {\n Tag,\n getTagFromDictionary,\n getTagFromKey,\n getItemTag,\n getItemDelimitationItemTag,\n getSequenceDelimitationItemTag,\n getFileMetaInformationGroupLengthTag,\n isPixelDataTag,\n isItemTag,\n isItemDelimitationItemTag,\n tagCompareFunction\n} from './dicomTag';\nimport {\n getDwvVersion,\n isImplicitTransferSyntax,\n isBigEndianTransferSyntax,\n getDataElementPrefixByteSize\n} from './dicomParser';\nimport {DataElement} from './dataElement';\nimport {DataWriter} from './dataWriter';\nimport {DataReader} from './dataReader';\nimport {logger} from '../utils/logger';\n\n/**\n * Get the dwv UID prefix.\n * Issued by Medical Connections Ltd (www.medicalconnections.co.uk)\n * on 25/10/2017.\n *\n * @returns {string} The dwv UID prefix.\n */\nfunction getDwvUIDPrefix() {\n return '1.2.826.0.1.3680043.9.7278.1';\n}\n\n// local generated uid counter\nlet _uidCount = 0;\n\n/**\n * Writer rule.\n */\nexport class WriterRule {\n /**\n * Rule action: `copy`, `remove`, `clear` or `replace`.\n *\n * @type {string}\n */\n action;\n /**\n * Optional value to use for replace action.\n *\n * @type {any|undefined}\n */\n value;\n\n /**\n * @param {string} action The rule action.\n */\n constructor(action) {\n this.action = action;\n }\n}\n\n/**\n * Possible writer actions.\n *\n * @type {Object}\n */\nconst writerActions = {\n copy: function (item) {\n return item;\n },\n remove: function () {\n return null;\n },\n clear: function (item) {\n item.value = [];\n return item;\n },\n replace: function (item, value) {\n item.value = [value];\n return item;\n }\n};\n\n/**\n * Get simple (non official) DICOM anonymisation rules.\n *\n * @returns {Object} The rules.\n */\nexport function getDefaultAnonymisationRules() {\n return {\n default: {action: 'copy', value: null},\n PatientName: {action: 'replace', value: 'Anonymized'}, // tag\n 'Meta Element': {action: 'copy', value: null}, // group '0002'\n Acquisition: {action: 'copy', value: null}, // group '0018'\n 'Image Presentation': {action: 'copy', value: null}, // group '0028'\n Procedure: {action: 'copy', value: null}, // group '0040'\n 'Pixel Data': {action: 'copy', value: null} // group '7fe0'\n };\n}\n\n/**\n * Get a UID for a DICOM tag.\n *\n * Note: Use {@link https://github.com/uuidjs/uuid}?\n *\n * Ref:\n * - {@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/chapter_9.html},\n * - {@link http://dicomiseasy.blogspot.com/2011/12/chapter-4-dicom-objects-in-chapter-3.html},\n * - {@link https://stackoverflow.com/questions/46304306/how-to-generate-unique-dicom-uid}.\n *\n * @param {string} tagName The input tag.\n * @returns {string} The corresponding UID.\n */\nexport function getUID(tagName) {\n const prefix = getDwvUIDPrefix() + '.';\n let uid = '';\n if (tagName === 'ImplementationClassUID') {\n uid = prefix + getDwvVersion();\n } else {\n // date (only numbers), do not keep milliseconds\n const date = (new Date()).toISOString().replace(/\\D/g, '');\n const datePart = '.' + date.substring(0, 14);\n // count\n _uidCount += 1;\n const countPart = '.' + _uidCount;\n\n // uid = prefix . tag . date . count\n uid = prefix;\n\n // limit tag part to not exceed 64 length\n const nonTagLength = prefix.length + countPart.length + datePart.length;\n const leni = Math.min(tagName.length, 64 - nonTagLength);\n if (leni > 1) {\n let tagNumber = '';\n for (let i = 0; i < leni; ++i) {\n tagNumber += tagName.charCodeAt(i);\n }\n uid += tagNumber.substring(0, leni);\n }\n\n // finish\n uid += datePart + countPart;\n }\n return uid;\n}\n\n/**\n * Return true if the input number is even.\n *\n * @param {number} number The number to check.\n * @returns {boolean} True is the number is even.\n */\nfunction isEven(number) {\n return number % 2 === 0;\n}\n\n/**\n * Is the input VR a VR that stores data in a typed array.\n * TODO: include ox and xs?\n *\n * @param {string} vr The element VR.\n * @returns {boolean} True if the VR is a typed array one.\n */\nfunction isTypedArrayVr(vr) {\n const vrType = vrTypes[vr];\n return typeof vrType !== 'undefined' &&\n vrType !== 'string';\n}\n\n/**\n * Is the input VR a string VR.\n *\n * @param {string} vr The element VR.\n * @returns {boolean} True if the VR is a string one.\n */\nfunction isStringVr(vr) {\n const vrType = vrTypes[vr];\n return typeof vrType !== 'undefined' &&\n vrType === 'string';\n}\n\n/**\n * Is the input VR a VR that could need padding.\n *\n * See {@link http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_6.2.html}.\n *\n * @param {string} vr The element VR.\n * @returns {boolean} True if the VR needs padding.\n */\nfunction isVrToPad(vr) {\n return isStringVr(vr) || vr === 'OB';\n}\n\n/**\n * Get the VR specific padding value.\n *\n * @param {string} vr The element VR.\n * @returns {string} The value used to pad.\n */\nfunction getVrPad(vr) {\n let pad = '';\n if (isStringVr(vr)) {\n if (vr === 'UI') {\n pad = '\\0';\n } else {\n pad = ' ';\n }\n }\n return pad;\n}\n\n/**\n * Push a value at the end of an input Uint8Array.\n *\n * @param {Array|Uint8Array} arr The input array.\n * @param {Array|Uint8Array} value The value to push.\n * @returns {Uint8Array} The new array.\n */\nfunction uint8ArrayPush(arr, value) {\n const newArr = new Uint8Array(arr.length + 1);\n newArr.set(arr);\n newArr.set(value, arr.length);\n return newArr;\n}\n\n/**\n * Pad an input OB value.\n *\n * @param {Array|Uint8Array} value The input value.\n * @returns {Array|Uint8Array} The padded input.\n */\nfunction padOBValue(value) {\n if (value !== null &&\n typeof value !== 'undefined' &&\n typeof value.length !== 'undefined') {\n // calculate size and pad if needed\n if (value.length !== 0 &&\n typeof value[0].length !== 'undefined') {\n // handle array of array\n let size = 0;\n for (let i = 0; i < value.length; ++i) {\n size += value[i].length;\n }\n if (!isEven(size)) {\n value[value.length - 1] = uint8ArrayPush(\n value[value.length - 1], [0]);\n }\n } else {\n if (!isEven(value.length)) {\n value = uint8ArrayPush(value, [0]);\n }\n }\n } else {\n throw new Error('Cannot pad undefined or null OB value.');\n }\n // uint8ArrayPush may create a new array so we\n // need to return it\n return value;\n}\n\n/**\n * Helper method to flatten an array of typed arrays to 2D typed array.\n *\n * @param {Array} initialArray Array of typed arrays.\n * @returns {object} A typed array containing all values.\n */\nfunction flattenArrayOfTypedArrays(initialArray) {\n const initialArrayLength = initialArray.length;\n const arrayLength = initialArray[0].length;\n // If this is not a array of arrays, just return the initial one:\n if (typeof arrayLength === 'undefined') {\n return initialArray;\n }\n\n const flattenendArrayLength = initialArrayLength * arrayLength;\n\n const flattenedArray = new initialArray[0].constructor(flattenendArrayLength);\n\n for (let i = 0; i < initialArrayLength; i++) {\n const indexFlattenedArray = i * arrayLength;\n flattenedArray.set(initialArray[i], indexFlattenedArray);\n }\n return flattenedArray;\n}\n\n/**\n * Default text encoder.\n */\nclass DefaultTextEncoder {\n /**\n * Encode an input string.\n *\n * @param {string} str The string to encode.\n * @returns {Uint8Array} The encoded string.\n */\n encode(str) {\n const result = new Uint8Array(str.length);\n for (let i = 0, leni = str.length; i < leni; ++i) {\n result[i] = str.charCodeAt(i);\n }\n return result;\n }\n}\n\n/**\n * Small list of used tag keys.\n */\nconst TagKeys = {\n TransferSyntax: '00020010',\n SpecificCharacterSet: '00080005',\n BitsAllocated: '00280100',\n};\n\n/**\n * DICOM writer.\n *\n * @example\n * // add link to html\n * const link = document.createElement(\"a\");\n * link.appendChild(document.createTextNode(\"download\"));\n * const div = document.getElementById(\"dwv\");\n * div.appendChild(link);\n * // XMLHttpRequest onload callback\n * const onload = function (event) {\n * const parser = new dwv.DicomParser();\n * parser.parse(event.target.response);\n * // create writer\n * const writer = new dwv.DicomWriter();\n * // get buffer using default rules\n * const dicomBuffer = writer.getBuffer(parser.getDicomElements());\n * // create blob\n * const blob = new Blob([dicomBuffer], {type: 'application/dicom'});\n * // add blob to download link\n * link.href = URL.createObjectURL(blob);\n * link.download = \"anonym.dcm\";\n * };\n * // DICOM file request\n * const request = new XMLHttpRequest();\n * const url = 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm';\n * request.open('GET', url);\n * request.responseType = 'arraybuffer';\n * request.onload = onload;\n * request.send();\n */\nexport class DicomWriter {\n\n /**\n * Flag to use VR=UN for private sequences, default to false\n * (mainly used in tests).\n *\n * @type {boolean}\n */\n #useUnVrForPrivateSq = false;\n\n /**\n * Flag to activate or not the vr=UN tag check and fix\n * if present in the dictionary. Default to true.\n *\n * @type {boolean}\n */\n #fixUnknownVR = true;\n\n /**\n * Default rules: just copy.\n *\n * @type {Object}\n */\n #defaultRules = {\n default: {action: 'copy', value: null}\n };\n\n /**\n * Writing rules.\n *\n * @type {Object}\n */\n #rules = this.#defaultRules;\n\n /**\n * List of compulsory tags keys.\n *\n * @type {string[]}\n */\n #compulsoryTags = [];\n\n /**\n * Default text encoder.\n *\n * @type {DefaultTextEncoder}\n */\n #defaultTextEncoder = new DefaultTextEncoder();\n\n /**\n * Special text encoder.\n *\n * @type {DefaultTextEncoder|TextEncoder}\n */\n #textEncoder = this.#defaultTextEncoder;\n\n /**\n * Set the use UN VR for private sequence flag.\n *\n * @param {boolean} flag True to use UN VR.\n */\n setUseUnVrForPrivateSq(flag) {\n this.#useUnVrForPrivateSq = flag;\n }\n\n /**\n * Set the vr=UN check and fix flag.\n *\n * @param {boolean} flag True to activate the check and fix.\n */\n setFixUnknownVR(flag) {\n this.#fixUnknownVR = flag;\n }\n\n /**\n * Set the writing rules.\n * List of writer rules indexed by either `default`,\n * tagKey, tagName or groupName.\n * Each DICOM element will be checked to see if a rule is applicable.\n * First checked by tagKey, tagName and then by groupName,\n * if nothing is found the default rule is applied.\n *\n * @param {Object} rules The input rules.\n * @param {boolean} [addMissingTags] If true, explicit tags that\n * have replace rule and a value will be\n * added if missing. Defaults to false.\n */\n setRules(rules, addMissingTags) {\n this.#rules = rules;\n\n // default compulsory list is empty\n this.#compulsoryTags = [];\n\n // use replace rule tags as compulsory tags\n if (addMissingTags) {\n const keys = Object.keys(rules);\n for (const key of keys) {\n const rule = rules[key];\n if (rule.action === 'replace' &&\n typeof rule.value !== 'undefined' &&\n rule.value !== null) {\n // check if key really exists\n let isKey = false;\n if (key.length === 8) {\n const tag = getTagFromKey(key);\n isKey = typeof tag.getNameFromDictionary() !== 'undefined';\n }\n // get tag key, rules can use key or tag name\n let tagKey;\n if (isKey) {\n tagKey = key;\n } else {\n // try tag name\n const tag = getTagFromDictionary(key);\n if (typeof tag !== 'undefined') {\n tagKey = tag.getKey();\n }\n }\n // add to list\n if (typeof tagKey !== 'undefined') {\n this.#compulsoryTags.push(tagKey);\n }\n }\n }\n }\n }\n\n /**\n * Encode string data.\n *\n * @param {string} str The string to encode.\n * @returns {Uint8Array} The encoded string.\n */\n #encodeString(str) {\n return this.#defaultTextEncoder.encode(str);\n }\n\n /**\n * Encode data as a UTF-8.\n *\n * @param {string} str The string to write.\n * @returns {Uint8Array} The encoded string.\n */\n #encodeSpecialString(str) {\n return this.#textEncoder.encode(str);\n }\n\n /**\n * Use a TextEncoder instead of the default text decoder.\n */\n useSpecialTextEncoder() {\n /**\n * The text encoder.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder}.\n *\n * @external TextEncoder\n */\n this.#textEncoder = new TextEncoder();\n }\n\n /**\n * Get the element to write according to the class rules.\n * Priority order: tagName, groupName, default.\n *\n * @param {DataElement} element The element to check.\n * @returns {DataElement|null} The element to write, can be null.\n */\n getElementToWrite(element) {\n // get group and tag string name\n const groupName = element.tag.getGroupName();\n const tagName = element.tag.getNameFromDictionary();\n\n // apply rules:\n let rule;\n if (typeof this.#rules[element.tag.getKey()] !== 'undefined') {\n // 1. tag itself\n rule = this.#rules[element.tag.getKey()];\n } else if (typeof tagName !== 'undefined' &&\n typeof this.#rules[tagName] !== 'undefined') {\n // 2. tag name\n rule = this.#rules[tagName];\n } else if (typeof this.#rules[groupName] !== 'undefined') {\n // 3. group name\n rule = this.#rules[groupName];\n } else {\n // 4. default\n rule = this.#rules['default'];\n }\n // apply action on element and return\n return writerActions[rule.action](element, rule.value);\n }\n\n /**\n * Write a list of items.\n *\n * @param {DataWriter} writer The raw data writer.\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} items The list of items to write.\n * @param {boolean} isImplicit Is the DICOM VR implicit?\n * @returns {number} The new offset position.\n */\n #writeDataElementItems(\n writer, byteOffset, items, isImplicit) {\n let item;\n for (let i = 0; i < items.length; ++i) {\n item = items[i];\n if (item.length === 0) {\n continue;\n }\n // item element (create new to not modify original)\n let undefinedLength = false;\n const itemTag = item.find((subItem) => isItemTag(subItem.tag));\n if (typeof itemTag !== 'undefined' &&\n typeof itemTag.undefinedLength !== 'undefined') {\n undefinedLength = itemTag.undefinedLength;\n }\n const itemElement = new DataElement('NONE');\n itemElement.vl = undefinedLength ? 0xffffffff : itemTag.vl,\n itemElement.tag = getItemTag();\n itemElement.value = [];\n byteOffset = this.#writeDataElement(\n writer, itemElement, byteOffset, isImplicit);\n // write rest\n for (const subItem of item) {\n if (!isItemTag(subItem.tag) &&\n !isItemDelimitationItemTag(subItem.tag)) {\n byteOffset = this.#writeDataElement(\n writer, subItem, byteOffset, isImplicit);\n }\n }\n // item delimitation\n if (undefinedLength) {\n const itemDelimElement = new DataElement('NONE');\n itemDelimElement.vl = 0;\n itemDelimElement.tag = getItemDelimitationItemTag();\n itemDelimElement.value = [];\n byteOffset = this.#writeDataElement(\n writer, itemDelimElement, byteOffset, isImplicit);\n }\n }\n\n // return new offset\n return byteOffset;\n }\n\n /**\n * Write data with a specific Value Representation (VR).\n *\n * @param {DataWriter} writer The raw data writer.\n * @param {DataElement} element The element to write.\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} value The array to write.\n * @param {boolean} isImplicit Is the DICOM VR implicit?\n * @returns {number} The new offset position.\n */\n #writeDataElementValue(\n writer, element, byteOffset, value, isImplicit) {\n\n const startOffset = byteOffset;\n\n if (element.vr === 'NONE') {\n // nothing to do!\n } else if (value instanceof Uint8Array) {\n // binary data has been expanded 8 times at read\n if (value.length === 8 * element.vl) {\n byteOffset = writer.writeBinaryArray(byteOffset, value);\n } else {\n byteOffset = writer.writeUint8Array(byteOffset, value);\n }\n } else if (value instanceof Int8Array) {\n byteOffset = writer.writeInt8Array(byteOffset, value);\n } else if (value instanceof Uint16Array) {\n byteOffset = writer.writeUint16Array(byteOffset, value);\n } else if (value instanceof Int16Array) {\n byteOffset = writer.writeInt16Array(byteOffset, value);\n } else if (value instanceof Uint32Array) {\n byteOffset = writer.writeUint32Array(byteOffset, value);\n } else if (value instanceof Int32Array) {\n byteOffset = writer.writeInt32Array(byteOffset, value);\n } else if (value instanceof BigUint64Array) {\n byteOffset = writer.writeUint64Array(byteOffset, value);\n } else if (value instanceof BigInt64Array) {\n byteOffset = writer.writeInt64Array(byteOffset, value);\n } else {\n // switch according to VR if input type is undefined\n const vrType = vrTypes[element.vr];\n if (typeof vrType !== 'undefined') {\n if (vrType === 'Uint8') {\n byteOffset = writer.writeUint8Array(byteOffset, value);\n } else if (vrType === 'Uint16') {\n byteOffset = writer.writeUint16Array(byteOffset, value);\n } else if (vrType === 'Int16') {\n byteOffset = writer.writeInt16Array(byteOffset, value);\n } else if (vrType === 'Uint32') {\n byteOffset = writer.writeUint32Array(byteOffset, value);\n } else if (vrType === 'Int32') {\n byteOffset = writer.writeInt32Array(byteOffset, value);\n } else if (vrType === 'Uint64') {\n byteOffset = writer.writeUint64Array(byteOffset, value);\n } else if (vrType === 'Int64') {\n byteOffset = writer.writeInt64Array(byteOffset, value);\n } else if (vrType === 'Float32') {\n byteOffset = writer.writeFloat32Array(byteOffset, value);\n } else if (vrType === 'Float64') {\n byteOffset = writer.writeFloat64Array(byteOffset, value);\n } else if (vrType === 'string') {\n byteOffset = writer.writeUint8Array(byteOffset, value);\n } else {\n throw new Error('Unknown VR type: ' + vrType);\n }\n } else if (element.vr === 'SQ') {\n byteOffset = this.#writeDataElementItems(\n writer, byteOffset, value, isImplicit);\n } else if (element.vr === 'AT') {\n for (let i = 0; i < value.length; ++i) {\n const hexString = value[i] + '';\n const hexString1 = hexString.substring(1, 5);\n const hexString2 = hexString.substring(6, 10);\n const dec1 = parseInt(hexString1, 16);\n const dec2 = parseInt(hexString2, 16);\n const atValue = [dec1, dec2];\n byteOffset = writer.writeUint16Array(byteOffset, atValue);\n }\n } else if (element.vr === 'xs') {\n // TODO would be better to use pixelRepresentation in if\n if (value instanceof Int16Array) {\n byteOffset = writer.writeInt16Array(byteOffset, value);\n } else {\n byteOffset = writer.writeUint16Array(byteOffset, value);\n }\n } else {\n logger.warn('Unknown VR: ' + element.vr);\n }\n }\n\n if (element.vr !== 'SQ' && element.vr !== 'NONE') {\n const diff = byteOffset - startOffset;\n if (diff !== element.vl) {\n let message = 'Offset difference and VL are not equal: ' +\n diff + ' != ' + element.vl;\n message += ' (';\n if (typeof element.tag !== 'undefined') {\n message += element.tag + ', ';\n }\n message += 'vr:' + element.vr + ')';\n logger.warn(message);\n }\n }\n\n // return new offset\n return byteOffset;\n }\n\n /**\n * Write a pixel data element.\n *\n * @param {DataWriter} writer The raw data writer.\n * @param {DataElement} element The element to write.\n * @param {number} byteOffset The offset to start writing from.\n * @param {Array} value The array to write.\n * @param {boolean} isImplicit Is the DICOM VR implicit?\n * @returns {number} The new offset position.\n */\n #writePixelDataElementValue(\n writer, element, byteOffset, value, isImplicit) {\n // undefined length flag\n let undefinedLength = false;\n if (typeof element.undefinedLength !== 'undefined') {\n undefinedLength = element.undefinedLength;\n }\n // explicit length\n if (!undefinedLength) {\n let finalValue = value[0];\n // flatten multi frame\n if (value.length > 1) {\n finalValue = flattenArrayOfTypedArrays(value);\n }\n // write\n byteOffset = this.#writeDataElementValue(\n writer, element, byteOffset, finalValue, isImplicit);\n } else {\n // pixel data as sequence\n const item = {};\n // first item: basic offset table\n item['FFFEE000'] = {\n tag: getItemTag(),\n vr: 'NONE',\n vl: 0,\n value: []\n };\n // data\n for (let i = 0; i < value.length; ++i) {\n item[i] = {\n tag: getItemTag(),\n vr: element.vr,\n vl: value[i].length,\n value: value[i]\n };\n }\n // write\n byteOffset = this.#writeDataElementItems(\n writer, byteOffset, [item], isImplicit);\n }\n\n // return new offset\n return byteOffset;\n }\n\n /**\n * Write a data element.\n *\n * @param {DataWriter} writer The raw data writer.\n * @param {DataElement} element The DICOM data element to write.\n * @param {number} byteOffset The offset to start writing from.\n * @param {boolean} isImplicit Is the DICOM VR implicit?\n * @returns {number} The new offset position.\n */\n #writeDataElement(\n writer, element, byteOffset, isImplicit) {\n const isTagWithVR = element.tag.isWithVR();\n const is32bitVL = (isImplicit || !isTagWithVR)\n ? true : is32bitVLVR(element.vr);\n // group\n byteOffset = writer.writeHex(byteOffset, element.tag.getGroup());\n // element\n byteOffset = writer.writeHex(byteOffset, element.tag.getElement());\n // VR\n let vr = element.vr;\n // use VR=UN for private sequence\n if (this.#useUnVrForPrivateSq &&\n element.tag.isPrivate() &&\n vr === 'SQ') {\n logger.warn('Write element using VR=UN for private sequence.');\n vr = 'UN';\n }\n if (isTagWithVR && !isImplicit) {\n byteOffset = writer.writeUint8Array(byteOffset, this.#encodeString(vr));\n // reserved 2 bytes for 32bit VL\n if (is32bitVL) {\n byteOffset += 2;\n }\n }\n\n let undefinedLengthSequence = false;\n if (element.vr === 'SQ' ||\n isPixelDataTag(element.tag)) {\n if (typeof element.undefinedLength !== 'undefined') {\n undefinedLengthSequence = element.undefinedLength;\n }\n }\n let undefinedLengthItem = false;\n if (isItemTag(element.tag)) {\n if (typeof element.undefinedLength !== 'undefined') {\n undefinedLengthItem = element.undefinedLength;\n }\n }\n\n // update vl for sequence or item with undefined length\n let vl = element.vl;\n if (undefinedLengthSequence || undefinedLengthItem) {\n vl = 0xffffffff;\n }\n // VL\n if (is32bitVL) {\n byteOffset = writer.writeUint32(byteOffset, vl);\n } else {\n byteOffset = writer.writeUint16(byteOffset, vl);\n }\n\n // value\n let value = element.value;\n // check value\n if (typeof value === 'undefined') {\n value = [];\n }\n // write\n if (isPixelDataTag(element.tag)) {\n byteOffset = this.#writePixelDataElementValue(\n writer, element, byteOffset, value, isImplicit);\n } else {\n byteOffset = this.#writeDataElementValue(\n writer, element, byteOffset, value, isImplicit);\n }\n\n // sequence delimitation item for sequence with undefined length\n if (undefinedLengthSequence) {\n const seqDelimElement = new DataElement('NONE');\n seqDelimElement.vl = 0;\n seqDelimElement.tag = getSequenceDelimitationItemTag();\n seqDelimElement.value = [];\n byteOffset = this.#writeDataElement(\n writer, seqDelimElement, byteOffset, isImplicit);\n }\n\n // return new offset\n return byteOffset;\n }\n\n /**\n * Get the ArrayBuffer corresponding to input DICOM elements.\n *\n * @param {Object} dataElements The elements to write.\n * @returns {ArrayBuffer} The elements as a buffer.\n */\n getBuffer(dataElements) {\n // Transfer Syntax\n const syntax = dataElements[TagKeys.TransferSyntax].value[0];\n const isImplicit = isImplicitTransferSyntax(syntax);\n const isBigEndian = isBigEndianTransferSyntax(syntax);\n // Specific CharacterSet\n if (typeof dataElements[TagKeys.SpecificCharacterSet] !== 'undefined') {\n const oldscs = dataElements[TagKeys.SpecificCharacterSet].value[0];\n // force UTF-8 if not default character set\n if (typeof oldscs !== 'undefined' && oldscs !== 'ISO-IR 6') {\n logger.debug('Change charset to UTF, was: ' + oldscs);\n this.useSpecialTextEncoder();\n dataElements[TagKeys.SpecificCharacterSet].value = ['ISO_IR 192'];\n }\n }\n // Bits Allocated (for image data)\n let bitsAllocated;\n if (typeof dataElements[TagKeys.BitsAllocated] !== 'undefined') {\n bitsAllocated = dataElements[TagKeys.BitsAllocated].value[0];\n }\n\n // calculate buffer size and split elements (meta and non meta)\n let totalSize = 128 + 4; // DICM\n let localSize = 0;\n const metaElements = [];\n const rawElements = [];\n let element;\n let groupName;\n let metaLength = 0;\n // FileMetaInformationGroupLength\n const fmiglTag = getFileMetaInformationGroupLengthTag();\n // FileMetaInformationVersion\n const fmivTag = new Tag('0002', '0001');\n // ImplementationClassUID\n const icUIDTag = new Tag('0002', '0012');\n // ImplementationVersionName\n const ivnTag = new Tag('0002', '0013');\n\n // missing tag list: start as a copy of compulsory\n const missingTags = this.#compulsoryTags.slice();\n\n // loop through elements to get the buffer size\n const keys = Object.keys(dataElements);\n for (let i = 0, leni = keys.length; i < leni; ++i) {\n const originalElement = dataElements[keys[i]];\n originalElement.tag = getTagFromKey(keys[i]);\n element = this.getElementToWrite(originalElement);\n if (element !== null &&\n !fmiglTag.equals(element.tag) &&\n !fmivTag.equals(element.tag) &&\n !icUIDTag.equals(element.tag) &&\n !ivnTag.equals(element.tag)) {\n localSize = 0;\n\n // check if compulsory tag, if present remove from missing list\n const index = missingTags.indexOf(element.tag.getKey());\n if (index !== -1) {\n missingTags.splice(index, 1);\n }\n\n // XB7 2020-04-17\n // Check if UN can be converted to correct VR.\n // This check must be done BEFORE calculating totalSize,\n // otherwise there may be extra null bytes at the end of the file\n // (dcmdump may crash because of these bytes)\n if (this.#fixUnknownVR) {\n checkAndFixUnknownVR(element, !isBigEndian);\n }\n\n // update value and vl\n this.#setElementValue(\n element, element.value, isImplicit, bitsAllocated);\n\n // tag group name\n groupName = element.tag.getGroupName();\n\n // prefix\n if (groupName === 'Meta Element') {\n localSize += getDataElementPrefixByteSize(element.vr, false);\n } else {\n localSize += getDataElementPrefixByteSize(\n element.vr, isImplicit);\n }\n\n // value\n localSize += element.vl;\n\n // sort elements\n if (groupName === 'Meta Element') {\n metaElements.push(element);\n metaLength += localSize;\n } else {\n rawElements.push(element);\n }\n\n // add to total size\n totalSize += localSize;\n }\n }\n\n // add compulsory tags to output data if not present\n for (const key of missingTags) {\n const tag = getTagFromKey(key);\n const dataElement = new DataElement(tag.getVrFromDictionary());\n dataElement.tag = tag;\n // rules are indexed by key or tag name\n let value;\n if (typeof this.#rules[key] !== 'undefined') {\n value = this.#rules[key].value;\n } else {\n const name = tag.getNameFromDictionary();\n value = this.#rules[name].value;\n }\n // add element\n let size = getDataElementPrefixByteSize(dataElement.vr, isImplicit);\n size += this.#setElementValue(dataElement, [value], isImplicit);\n rawElements.push(dataElement);\n totalSize += size;\n }\n\n // FileMetaInformationVersion\n const fmiv = getDataElement('FileMetaInformationVersion');\n let fmivSize = getDataElementPrefixByteSize(fmiv.vr, false);\n fmivSize += this.#setElementValue(fmiv, [0, 1], false);\n metaElements.push(fmiv);\n metaLength += fmivSize;\n totalSize += fmivSize;\n // ImplementationClassUID\n const icUID = getDataElement('ImplementationClassUID');\n let icUIDSize = getDataElementPrefixByteSize(icUID.vr, false);\n const icUIDValue =\n getUID('ImplementationClassUID').replace('-beta', '.99');\n icUIDSize += this.#setElementValue(icUID, [icUIDValue], false);\n metaElements.push(icUID);\n metaLength += icUIDSize;\n totalSize += icUIDSize;\n // ImplementationVersionName\n const ivn = getDataElement('ImplementationVersionName');\n let ivnSize = getDataElementPrefixByteSize(ivn.vr, false);\n const dwvVersion = getDwvVersion().replace('-beta', '.99');\n const ivnValue = 'DWV_' + dwvVersion;\n ivnSize += this.#setElementValue(ivn, [ivnValue], false);\n metaElements.push(ivn);\n metaLength += ivnSize;\n totalSize += ivnSize;\n\n // sort elements\n const elemSortFunc = function (a, b) {\n return tagCompareFunction(a.tag, b.tag);\n };\n metaElements.sort(elemSortFunc);\n rawElements.sort(elemSortFunc);\n\n // create the FileMetaInformationGroupLength element\n const fmigl = getDataElement('FileMetaInformationGroupLength');\n let fmiglSize = getDataElementPrefixByteSize(fmigl.vr, false);\n fmiglSize += this.#setElementValue(\n fmigl, new Uint32Array([metaLength]), false);\n totalSize += fmiglSize;\n\n // create buffer\n const buffer = new ArrayBuffer(totalSize);\n const metaWriter = new DataWriter(buffer);\n const dataWriter = new DataWriter(buffer, !isBigEndian);\n\n let offset = 128;\n // DICM\n offset = metaWriter.writeUint8Array(offset, this.#encodeString('DICM'));\n // FileMetaInformationGroupLength\n offset = this.#writeDataElement(metaWriter, fmigl, offset, false);\n // write meta\n for (let j = 0, lenj = metaElements.length; j < lenj; ++j) {\n offset = this.#writeDataElement(\n metaWriter, metaElements[j], offset, false);\n }\n\n // check meta position\n const preambleSize = 128 + 4;\n const metaOffset = preambleSize + fmiglSize + metaLength;\n if (offset !== metaOffset) {\n logger.warn('Bad size calculation... meta offset: ' + offset +\n ', calculated size:' + metaOffset +\n ' (diff:' + (offset - metaOffset) + ')');\n }\n\n // write non meta\n for (let k = 0, lenk = rawElements.length; k < lenk; ++k) {\n offset = this.#writeDataElement(\n dataWriter, rawElements[k], offset, isImplicit);\n }\n\n // check final position\n if (offset !== totalSize) {\n logger.warn('Bad size calculation... final offset: ' + offset +\n ', calculated size:' + totalSize +\n ' (diff:' + (offset - totalSize) + ')');\n }\n // return\n return buffer;\n }\n\n /**\n * Set a DICOM element value according to its VR (Value Representation).\n *\n * @param {DataElement} element The DICOM element to set the value.\n * @param {object} value The value to set.\n * @param {boolean} isImplicit Does the data use implicit VR?\n * @param {number} [bitsAllocated] Bits allocated used for pixel data.\n * @returns {number} The total element size.\n */\n #setElementValue(\n element, value, isImplicit, bitsAllocated) {\n // byte size of the element\n let size = 0;\n // special sequence case\n if (element.vr === 'SQ') {\n\n if (value !== null && value !== 0) {\n const newItems = [];\n\n // explicit or undefined length sequence\n let undefinedLength = false;\n if (typeof element.undefinedLength !== 'undefined') {\n undefinedLength = element.undefinedLength;\n delete element.undefinedLength;\n }\n\n // items\n for (let i = 0; i < value.length; ++i) {\n const oldItemElements = value[i];\n const newItemElements = [];\n let subSize = 0;\n\n // check data\n if (oldItemElements === null || oldItemElements === 0) {\n continue;\n }\n\n // possible local bitsAllocated\n let sqBitsAllocated = bitsAllocated;\n const dataElement = oldItemElements[TagKeys.BitsAllocated];\n if (typeof dataElement !== 'undefined' &&\n typeof dataElement.value !== 'undefined') {\n sqBitsAllocated = dataElement.value[0];\n }\n\n // elements\n const itemKeys = Object.keys(oldItemElements);\n for (let j = 0, lenj = itemKeys.length; j < lenj; ++j) {\n const itemKey = itemKeys[j];\n const subElement = oldItemElements[itemKey];\n subElement.tag = getTagFromKey(itemKey);\n\n if (isItemTag(subElement.tag)) {\n continue;\n }\n // set item value\n subSize += this.#setElementValue(\n subElement, subElement.value, isImplicit, sqBitsAllocated);\n newItemElements.push(subElement);\n // add prefix size\n subSize += getDataElementPrefixByteSize(\n subElement.vr, isImplicit);\n }\n\n // add item element (used to store its size)\n const itemElement = {\n tag: getItemTag(),\n vr: 'NONE',\n vl: subSize,\n value: []\n };\n if (undefinedLength) {\n itemElement.undefinedLength = undefinedLength;\n }\n newItemElements.push(itemElement);\n subSize += getDataElementPrefixByteSize(\n itemElement.vr, isImplicit);\n\n // add item delimitation size\n if (undefinedLength) {\n subSize += getDataElementPrefixByteSize(\n 'NONE', isImplicit);\n }\n\n // sort\n const elemSortFunc = function (a, b) {\n return tagCompareFunction(a.tag, b.tag);\n };\n newItemElements.sort(elemSortFunc);\n\n size += subSize;\n newItems.push(newItemElements);\n }\n\n // add sequence delimitation size\n if (undefinedLength) {\n size += getDataElementPrefixByteSize('NONE', isImplicit);\n }\n\n // update sequence element\n element.value = newItems;\n element.vl = size;\n if (undefinedLength) {\n element.undefinedLength = undefinedLength;\n }\n }\n } else {\n // pad if necessary\n if (isVrToPad(element.vr)) {\n const padStr = getVrPad(element.vr);\n // encode string\n // TODO: not sure for UN...\n if (isStringVr(element.vr)) {\n let pad;\n if (isCharSetStringVR(element.vr)) {\n value = this.#encodeSpecialString(value.join('\\\\'));\n pad = this.#encodeSpecialString(padStr);\n } else {\n value = this.#encodeString(value.join('\\\\'));\n pad = this.#encodeString(padStr);\n }\n if (!isEven(value.length)) {\n value = uint8ArrayPush(value, pad);\n }\n } else if (element.vr === 'OB') {\n value = padOBValue(value);\n }\n }\n\n // calculate byte size\n size = 0;\n if (element.vr === 'AT') {\n size = 4 * value.length;\n } else if (element.vr === 'xs') {\n size = value.length * Uint16Array.BYTES_PER_ELEMENT;\n } else if (isTypedArrayVr(element.vr) || element.vr === 'ox') {\n if (isPixelDataTag(element.tag) &&\n Array.isArray(value)) {\n size = 0;\n for (let b = 0; b < value.length; ++b) {\n size += value[b].length;\n }\n } else {\n size = value.length;\n }\n\n // convert size to bytes\n const vrType = vrTypes[element.vr];\n if (isPixelDataTag(element.tag) || element.vr === 'ox') {\n if (element.undefinedLength) {\n const itemPrefixSize =\n getDataElementPrefixByteSize('NONE', isImplicit);\n // offset table\n size += itemPrefixSize;\n // pixel items\n size += itemPrefixSize * value.length;\n // add sequence delimitation size\n size += itemPrefixSize;\n } else {\n // use bitsAllocated for pixel data\n // no need to multiply for 8 bits\n if (typeof bitsAllocated !== 'undefined') {\n if (bitsAllocated === 1) {\n // binary data\n size /= 8;\n } else if (bitsAllocated === 16) {\n size *= Uint16Array.BYTES_PER_ELEMENT;\n }\n }\n }\n } else if (typeof vrType !== 'undefined') {\n const bpe = getBpeForVrType(vrType);\n if (typeof bpe !== 'undefined') {\n size *= bpe;\n } else {\n throw new Error('Unknown bytes per element for VR type: ' + vrType);\n }\n } else {\n throw new Error('Unsupported element: ' + element.vr);\n }\n } else {\n size = value.length;\n }\n\n element.value = value;\n element.vl = size;\n }\n\n // return the size of that data\n return size;\n }\n\n} // class DicomWriter\n\n/**\n * Fix for broken DICOM elements: replace \"UN\" with correct VR if the\n * element exists in dictionary.\n *\n * @param {DataElement} element The DICOM element.\n * @param {boolean} [isLittleEndian] Flag to tell if the data is little\n * or big endian (default: true).\n */\nfunction checkAndFixUnknownVR(element, isLittleEndian) {\n if (element.vr === 'UN') {\n const dictVr = element.tag.getVrFromDictionary();\n if (typeof dictVr !== 'undefined' && element.vr !== dictVr) {\n element.vr = dictVr;\n // cast typed array value from Uint8 to vr type\n const vrType = vrTypes[element.vr];\n if (typeof vrType !== 'undefined' &&\n vrType !== 'Uint8' &&\n vrType !== 'string') {\n const data = getUint8ToVrValue(\n element.value, element.vr, isLittleEndian);\n if (typeof data !== 'undefined') {\n element.value = data;\n }\n }\n logger.info('Element ' + element.tag.getGroup() +\n ' ' + element.tag.getElement() +\n ' VR changed from UN to ' + element.vr);\n }\n }\n}\n\n/**\n * Get the casted typed array value from Uint8 to vr type.\n *\n * @param {object} value The value to cast.\n * @param {string} vr The DICOM element VR.\n * @param {boolean} [isLittleEndian] Flag to tell if the data is little\n * or big endian (default: true).\n * @returns {object} The element value casted to the vr type.\n */\nfunction getUint8ToVrValue(value, vr, isLittleEndian) {\n let data;\n if (typeof value.buffer === 'undefined') {\n return data;\n }\n const reader = new DataReader(value.buffer, isLittleEndian);\n const offset = value.byteOffset;\n const vl = value.length; // size before cast\n const vrType = vrTypes[vr];\n if (vrType === 'Uint16') {\n data = reader.readUint16Array(offset, vl);\n } else if (vrType === 'Uint32') {\n data = reader.readUint32Array(offset, vl);\n } else if (vrType === 'Uint64') {\n data = reader.readUint64Array(offset, vl);\n } else if (vrType === 'Int16') {\n data = Array.from(reader.readInt16Array(offset, vl));\n } else if (vrType === 'Int32') {\n data = Array.from(reader.readInt32Array(offset, vl));\n } else if (vrType === 'Int64') {\n data = reader.readInt64Array(offset, vl);\n } else if (vrType === 'Float32') {\n data = Array.from(reader.readFloat32Array(offset, vl));\n } else if (vrType === 'Float64') {\n data = Array.from(reader.readFloat64Array(offset, vl));\n }\n return data;\n}\n\n/**\n * Get a DICOM element from its tag name (value set separatly).\n *\n * @param {string} tagName The string tag name.\n * @returns {DataElement} The DICOM element.\n */\nfunction getDataElement(tagName) {\n const tag = getTagFromDictionary(tagName);\n const element = new DataElement(tag.getVrFromDictionary());\n element.tag = tag;\n return element;\n}\n\n/**\n * Get the number of bytes per element for a given VR type.\n *\n * @param {string} vrType The VR type as defined in the dictionary.\n * @returns {number} The bytes per element.\n */\nfunction getBpeForVrType(vrType) {\n let bpe;\n if (vrType === 'Uint8') {\n bpe = Uint8Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Uint16') {\n bpe = Uint16Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Int16') {\n bpe = Int16Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Uint32') {\n bpe = Uint32Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Int32') {\n bpe = Int32Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Float32') {\n bpe = Float32Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Float64') {\n bpe = Float64Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Uint64') {\n bpe = BigUint64Array.BYTES_PER_ELEMENT;\n } else if (vrType === 'Int64') {\n bpe = BigInt64Array.BYTES_PER_ELEMENT;\n }\n return bpe;\n}\n\n/**\n * Get the DICOM elements from a 'simple' DICOM tags object.\n * The input object is a simplified version of the oficial DICOM json with\n * tag names instead of keys and direct values (no value property) for\n * simple tags. See synthetic test data (in tests/dicom) for examples.\n *\n * @param {Object} simpleTags The 'simple' DICOM\n * tags object.\n * @returns {Object} The DICOM elements.\n */\nexport function getElementsFromJSONTags(simpleTags) {\n const keys = Object.keys(simpleTags);\n const dataElements = {};\n for (let k = 0, len = keys.length; k < len; ++k) {\n // get the DICOM element definition from its name\n const tag = getTagFromDictionary(keys[k]);\n if (typeof tag === 'undefined') {\n continue;\n }\n const vr = tag.getVrFromDictionary();\n // tag value\n let value;\n let undefinedLength = false;\n const simpleTag = simpleTags[keys[k]];\n if (vr === 'SQ') {\n const items = [];\n if (typeof simpleTag.undefinedLength !== 'undefined') {\n undefinedLength = simpleTag.undefinedLength;\n }\n if (typeof simpleTag.value !== 'undefined' &&\n simpleTag.value !== null) {\n for (let i = 0; i < simpleTag.value.length; ++i) {\n items.push(getElementsFromJSONTags(simpleTag.value[i]));\n }\n } else {\n logger.trace('Undefined or null simpleTag SQ value.');\n }\n value = items;\n } else {\n if (Array.isArray(simpleTag)) {\n value = simpleTag;\n } else {\n value = [simpleTag];\n }\n }\n // create element\n const dataElement = new DataElement(vr);\n dataElement.tag = tag;\n dataElement.value = value;\n if (undefinedLength) {\n dataElement.undefinedLength = undefinedLength;\n }\n // store\n dataElements[tag.getKey()] = dataElement;\n }\n // return\n // @ts-expect-error\n return dataElements;\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * DICOM code tag keys.\n */\nconst TagKeys = {\n CodeValue: '00080100',\n CodingSchemeDesignator: '00080102',\n CodeMeaning: '00080104',\n LongCodeValue: '00080119',\n URNCodeValue: '00080120'\n};\n\n/**\n * DICOM code: item of a basic code sequence.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_8.8.html}.\n */\nexport class DicomCode {\n /**\n * Code meaning.\n *\n * @type {string}\n */\n meaning;\n /**\n * Code value.\n *\n * @type {string|undefined}\n */\n value;\n /**\n * Long code value.\n *\n * @type {string|undefined}\n */\n longValue;\n /**\n * URN code value.\n *\n * @type {string|undefined}\n */\n urnValue;\n /**\n * Coding scheme designator.\n *\n * @type {string|undefined}\n */\n schemeDesignator;\n\n /**\n * @param {string} meaning The code meaning.\n */\n constructor(meaning) {\n this.meaning = meaning;\n }\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The code as string.\n */\n toString() {\n return '(' + this.value + ', ' +\n this.schemeDesignator + ', \\'' +\n this.meaning + '\\')';\n }\n}\n\n/**\n * Check if two code objects are equal.\n *\n * @param {DicomCode} code1 The first code.\n * @param {DicomCode} code2 The second code.\n * @returns {boolean} True if both codes are equal.\n */\nexport function isEqualCode(code1, code2) {\n return Object.keys(code1).length === Object.keys(code2).length &&\n Object.keys(code1).every(key =>\n Object.prototype.hasOwnProperty.call(code2, key) &&\n code1[key] === code2[key]\n );\n}\n\n/**\n * Get a code object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {DicomCode} A code object.\n */\nexport function getCode(dataElements) {\n // meaning -> CodeMeaning (type1)\n const code = new DicomCode(dataElements[TagKeys.CodeMeaning].value[0]);\n // value -> CodeValue (type1C)\n // longValue -> LongCodeValue (type1C)\n // urnValue -> URNCodeValue (type1C)\n if (typeof dataElements[TagKeys.CodeValue] !== 'undefined') {\n code.value = dataElements[TagKeys.CodeValue].value[0];\n } else if (typeof dataElements[TagKeys.LongCodeValue] !== 'undefined') {\n code.longValue = dataElements[TagKeys.LongCodeValue].value[0];\n } else if (typeof dataElements[TagKeys.URNCodeValue] !== 'undefined') {\n code.urnValue = dataElements[TagKeys.URNCodeValue].value[0];\n } else {\n throw new Error(\n 'Invalid code with no value, no long value and no urn value.');\n }\n // schemeDesignator -> CodingSchemeDesignator (type1C)\n if (typeof code.value !== 'undefined' ||\n typeof code.longValue !== 'undefined') {\n if (typeof dataElements[TagKeys.CodingSchemeDesignator] !== 'undefined') {\n code.schemeDesignator =\n dataElements[TagKeys.CodingSchemeDesignator].value[0];\n } else {\n throw new Error(\n 'No coding sheme designator when code value or long value is present');\n }\n }\n return code;\n}\n\n/**\n * Get a simple dicom element item from a code object.\n *\n * @param {DicomCode} code The code object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomCodeItem(code) {\n // dicom item (tags are in group/element order)\n const item = {};\n // value\n if (typeof code.value !== 'undefined') {\n item.CodeValue = code.value;\n } else if (typeof code.longValue !== 'undefined') {\n item.LongCodeValue = code.longValue;\n } else if (typeof code.urnValue !== 'undefined') {\n item.URNCodeValue = code.urnValue;\n }\n // CodingSchemeDesignator\n if (typeof code.schemeDesignator !== 'undefined') {\n item.CodingSchemeDesignator = code.schemeDesignator;\n }\n // CodeMeaning\n item.CodeMeaning = code.meaning;\n // return\n return item;\n}\n\n/**\n * DICOM codes.\n * List: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part16/chapter_d.html}.\n */\nconst DcmCodes = {\n 111030: 'Image Region',\n 112039: 'Tracking Identifier',\n 112040: 'Tracking Unique Identifier',\n 113048: 'Pixel by pixel Maximum',\n 113049: 'Pixel by pixel mean',\n 113051: 'Pixel by pixel Minimum',\n 113061: 'Standard Deviation',\n 113076: 'Segmentation',\n 121055: 'Path',\n 121207: 'Height',\n 121322: 'Source image for image processing operation',\n 121324: 'Source Image',\n 122438: 'Reference Points',\n 125007: 'Measurement Group',\n 125309: 'Short label',\n 128773: 'Reference Geometry'\n};\n\n/**\n * SNOMED-CT codes.\n * List: {@link https://browser.ihtsdotools.org}.\n */\nconst SctCodes = {\n 1483009: 'Angle',\n 42798000: 'Area',\n 103355008: 'Width',\n 103339001: 'Long axis',\n 103340004: 'Short axis',\n 131190003: 'Radius',\n 261665006: 'Unknown',\n 410668003: 'Length',\n 718499004: 'Color'\n};\n\n/**\n * UCUM codes.\n * Definition: {@link https://unitsofmeasure.org/ucum}.\n * List: {@link https://ucum.nlm.nih.gov/ucum-lhc/demo.html}.\n */\nconst UcumCodes = {\n 1: 'No units',\n mm: 'Millimeter',\n deg: 'Degree - plane angle',\n cm2: 'Square centimeter',\n 'cm2/ml': 'Square centimeter per milliliter',\n '/cm': 'Per centimeter',\n 'g/ml': 'Gram per milliliter',\n 'g/ml{SUVbw}': 'Standardized Uptake Value body weight',\n 'mg/ml': 'Milligram per milliliter',\n 'umol/ml': 'Micromole per milliliter',\n 'Bq/ml': 'Becquerels per milliliter',\n 'mg/min/ml': 'Milligrams per minute per milliliter',\n 'umol/min/ml': 'Micromole per minute per milliliter',\n 'ml/min/g': 'Milliliter per minute per gram',\n 'ml/g': 'Milliliter per gram',\n 'ml/min/ml': 'Milliliter per minute per milliliter',\n 'ml/ml': 'Milliliter per milliliter',\n '%': 'Percentage',\n '[hnsf\\'U]': 'Hounsfield unit',\n '10*23/ml': 'Electron density',\n '{counts}': 'Counts',\n '{counts}/s': 'Counts per second',\n '{propcounts}': 'Proportional to counts',\n '{propcounts}/s': 'Proportional to counts per second',\n};\n\n/**\n * Get a DICOM code from a value (~id).\n *\n * @param {string} value The code value.\n * @param {string} scheme The scheme designator.\n * @returns {DicomCode|undefined} The DICOM code.\n */\nfunction getDicomCode(value, scheme) {\n let meaning;\n if (scheme === 'DCM') {\n meaning = DcmCodes[value];\n } else if (scheme === 'SCT') {\n meaning = SctCodes[value];\n } else if (scheme === 'UCUM') {\n meaning = UcumCodes[value];\n }\n let code;\n if (typeof meaning !== 'undefined') {\n code = new DicomCode(meaning);\n code.schemeDesignator = scheme;\n code.value = value;\n }\n return code;\n}\n\n/**\n * Get a measurement group DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getMeasurementGroupCode() {\n return getDicomCode('125007', 'DCM');\n}\n\n/**\n * Get an image region DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getImageRegionCode() {\n return getDicomCode('111030', 'DCM');\n}\n\n/**\n * Get a reference geometry DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getReferenceGeometryCode() {\n return getDicomCode('128773', 'DCM');\n}\n\n/**\n * Get a path DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getPathCode() {\n return getDicomCode('121055', 'DCM');\n}\n\n/**\n * Get a source image DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getSourceImageCode() {\n return getDicomCode('121324', 'DCM');\n}\n\n/**\n * Get a tracking identifier DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getTrackingIdentifierCode() {\n return getDicomCode('112039', 'DCM');\n}\n\n/**\n * Get a segmentation DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getSegmentationCode() {\n return getDicomCode('113076', 'DCM');\n}\n\n/**\n * Get a source image for processing DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getSourceImageForProcessingCode() {\n return getDicomCode('121322', 'DCM');\n}\n\n/**\n * Get a short label DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getShortLabelCode() {\n return getDicomCode('125309', 'DCM');\n}\n\n/**\n * Get a reference points DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getReferencePointsCode() {\n return getDicomCode('122438', 'DCM');\n}\n\n/**\n * Get a colour DICOM code.\n *\n * @returns {DicomCode} The code.\n */\nexport function getColourCode() {\n return getDicomCode('718499004', 'SCT');\n}\n\n/**\n * Quantification name to dictionary item.\n */\nconst QuantificationName2DictItem = {\n angle: {key: '1483009', scheme: 'SCT'},\n length: {key: '410668003', scheme: 'SCT'},\n surface: {key: '42798000', scheme: 'SCT'},\n height: {key: '121207', scheme: 'DCM'},\n width: {key: '103355008', scheme: 'SCT'},\n radius: {key: '131190003', scheme: 'SCT'},\n a: {key: '103339001', scheme: 'SCT'},\n b: {key: '103340004', scheme: 'SCT'},\n min: {key: '113051', scheme: 'DCM'},\n max: {key: '113048', scheme: 'DCM'},\n mean: {key: '113049', scheme: 'DCM'},\n stddev: {key: '113061', scheme: 'DCM'},\n // median\n // 25th percentile\n // 75th percentile\n};\n\n/**\n * Get a concept name DICOM code.\n *\n * @param {string} name The measurment name as defined\n * in a quantification object.\n * @returns {DicomCode|undefined} The code.\n */\nexport function getConceptNameCode(name) {\n const item = QuantificationName2DictItem[name];\n let code;\n if (typeof item !== 'undefined') {\n code = getDicomCode(item.key, item.scheme);\n }\n return code;\n}\n\n/**\n * Get the DICOM code for a quantification name.\n *\n * @param {DicomCode} code The Dicom code.\n * @returns {string|undefined} The quantification name.\n */\nexport function getQuantificationName(code) {\n let name;\n for (const propKey in QuantificationName2DictItem) {\n const item = QuantificationName2DictItem[propKey];\n if (item.scheme === code.schemeDesignator &&\n item.key === code.value) {\n name = propKey;\n break;\n }\n }\n return name;\n}\n\n/**\n * Quantification unit to UCUM key. Associated tags:\n * - Rescale type {@link https://dicom.innolitics.com/ciods/computed-radiography-image/modality-lut/00281054},\n * - Units {@link https://dicom.innolitics.com/ciods/positron-emission-tomography-image/pet-series/00541001}.\n * - SUV {@link https://dicom.nema.org/medical/dicom/current/output/chtml/part16/sect_CID_85.html}.\n */\nconst QuantificationUnit2UcumKey = {\n 'unit.mm': 'mm',\n 'unit.cm2': 'cm2',\n 'unit.degree': 'deg',\n // OD optical density\n HU: '[hnsf\\'U]',\n // US: '1', // duplicates 'NONE'\n MGML: 'mg/ml',\n // Z_EFF Effective Atomic Number (i.e., Effective-Z)\n ED: '10*23/ml',\n // EDW Electron density normalized\n // HU_MOD Modified Hounsfield Unit\n PCT: '%',\n CNTS: '{counts}',\n NONE: '1',\n CM2: 'cm2',\n CM2ML: 'cm2/ml',\n PCNT: '%',\n CPS: '{counts}/s',\n BQML: 'Bq/ml',\n MGMINML: 'mg/min/ml',\n UMOLMINML: 'umol/min/ml',\n MLMING: 'ml/min/g',\n MLG: 'ml/g',\n '1CM': '/cm',\n UMOLML: 'umol/ml',\n PROPCNTS: '{propcounts}',\n PROPCPS: '{propcounts}/s',\n MLMINML: 'ml/min/ml',\n MLML: 'ml/ml',\n GML: 'g/ml',\n //STDDEV\n SUV: 'g/ml{SUVbw}',\n};\n\n/**\n * Get a measurement units DICOM code.\n *\n * @param {string} name The unit name as defined in a quantification object.\n * @returns {DicomCode|undefined} The code.\n */\nexport function getMeasurementUnitsCode(name) {\n const key = QuantificationUnit2UcumKey[name];\n let code;\n if (typeof key !== 'undefined') {\n code = getDicomCode(key, 'UCUM');\n } else if (typeof key === 'undefined') {\n // no unit\n code = getDicomCode('1', 'UCUM');\n }\n return code;\n}\n\n/**\n * Get a quantification unit name.\n *\n * @param {DicomCode} code The code to get the unit from.\n * @returns {string} The quantification unit.\n */\nexport function getQuantificationUnit(code) {\n let unit;\n for (const propKey in QuantificationUnit2UcumKey) {\n const ucumKey = QuantificationUnit2UcumKey[propKey];\n if (code.schemeDesignator === 'UCUM' &&\n ucumKey === code.value) {\n unit = propKey;\n break;\n }\n }\n return unit;\n}\n","import {\n isEqualRgb,\n cielabToSrgb,\n uintLabToLab,\n labToUintLab,\n srgbToCielab\n} from '../utils/colour';\nimport {\n getCode,\n getDicomCodeItem\n} from './dicomCode';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {RGB} from '../utils/colour';\nimport {DataElement} from './dataElement';\nimport {DicomCode} from './dicomCode';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n SegmentNumber: '00620004',\n SegmentLabel: '00620005',\n SegmentAlgorithmType: '00620008',\n SegmentAlgorithmName: '00620009',\n RecommendedDisplayGrayscaleValue: '0062000C',\n RecommendedDisplayCIELabValue: '0062000D',\n SegmentedPropertyCategoryCodeSequence: '00620003',\n SegmentedPropertyTypeCodeSequence: '0062000F',\n TrackingID: '00620020',\n TrackingUID: '00620021'\n};\n\n/**\n * DICOM (mask) segment: item of a SegmentSequence (0062,0002).\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.8.20.4.html}.\n */\nexport class MaskSegment {\n /**\n * Segment number (0062,0004).\n *\n * @type {number}\n */\n number;\n /**\n * Segment label (0062,0005).\n *\n * @type {string}\n */\n label;\n /**\n * Segment algorithm type (0062,0008).\n *\n * @type {string}\n */\n algorithmType;\n /**\n * Segment algorithm name (0062,0009).\n *\n * @type {string|undefined}\n */\n algorithmName;\n /**\n * Segment display value as simple value.\n *\n * @type {number|undefined}\n */\n displayValue;\n /**\n * Segment display value as RGB colour ({r,g,b}).\n *\n * @type {RGB|undefined}\n */\n displayRGBValue;\n /**\n * Segment property code: specific property\n * the segment represents (0062,000F).\n *\n * @type {DicomCode|undefined}\n */\n propertyTypeCode;\n /**\n * Segment property category code: general category\n * of the property the segment represents (0062,0003).\n *\n * @type {DicomCode|undefined}\n */\n propertyCategoryCode;\n /**\n * Segment tracking UID (0062,0021).\n *\n * @type {string|undefined}\n */\n trackingUid;\n /**\n * Segment tracking id: text label for the UID (0062,0020).\n *\n * @type {string|undefined}\n */\n trackingId;\n\n /**\n * @param {number} number The segment number.\n * @param {string} label The segment label.\n * @param {string} algorithmType The segment number.\n */\n constructor(number, label, algorithmType) {\n this.number = number;\n this.label = label;\n this.algorithmType = algorithmType;\n }\n}\n\n/**\n * Get a segment object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {MaskSegment} A segment object.\n */\nexport function getSegment(dataElements) {\n // number -> SegmentNumber (type1)\n // label -> SegmentLabel (type1)\n // algorithmType -> SegmentAlgorithmType (type1)\n const segment = new MaskSegment(\n dataElements[TagKeys.SegmentNumber].value[0],\n dataElements[TagKeys.SegmentLabel]\n ? dataElements[TagKeys.SegmentLabel].value[0] : 'n/a',\n dataElements[TagKeys.SegmentAlgorithmType].value[0]\n );\n // algorithmName -> SegmentAlgorithmName (type1C)\n if (typeof dataElements[TagKeys.SegmentAlgorithmName] !== 'undefined') {\n segment.algorithmName = dataElements[TagKeys.SegmentAlgorithmName].value[0];\n }\n // // required if type is not MANUAL\n // if (segment.algorithmType !== 'MANUAL' &&\n // (typeof segment.algorithmName === 'undefined' ||\n // segment.algorithmName.length === 0)) {\n // throw new Error('Empty algorithm name for non MANUAL algorithm type.');\n // }\n // displayValue ->\n // - RecommendedDisplayGrayscaleValue\n // - RecommendedDisplayCIELabValue converted to RGB\n if (typeof dataElements[TagKeys.RecommendedDisplayGrayscaleValue] !==\n 'undefined') {\n segment.displayValue =\n dataElements[TagKeys.RecommendedDisplayGrayscaleValue].value[0];\n } else if (typeof dataElements[TagKeys.RecommendedDisplayCIELabValue] !==\n 'undefined') {\n const cielabElement =\n dataElements[TagKeys.RecommendedDisplayCIELabValue].value;\n const rgb = cielabToSrgb(uintLabToLab({\n l: cielabElement[0],\n a: cielabElement[1],\n b: cielabElement[2]\n }));\n segment.displayRGBValue = rgb;\n }\n // Segmented Property Category Code Sequence (type1, only one)\n if (typeof dataElements[TagKeys.SegmentedPropertyCategoryCodeSequence] !==\n 'undefined') {\n segment.propertyCategoryCode =\n getCode(\n dataElements[TagKeys.SegmentedPropertyCategoryCodeSequence].value[0]\n );\n } else {\n throw new Error('Missing Segmented Property Category Code Sequence.');\n }\n // Segmented Property Type Code Sequence (type1)\n if (typeof dataElements[TagKeys.SegmentedPropertyTypeCodeSequence] !==\n 'undefined') {\n segment.propertyTypeCode =\n getCode(dataElements[TagKeys.SegmentedPropertyTypeCodeSequence].value[0]);\n } else {\n throw new Error('Missing Segmented Property Type Code Sequence.');\n }\n // tracking Id and UID (type1C)\n if (typeof dataElements[TagKeys.TrackingID] !== 'undefined') {\n segment.trackingId = dataElements[TagKeys.TrackingID].value[0];\n segment.trackingUid = dataElements[TagKeys.TrackingUID].value[0];\n }\n\n return segment;\n}\n\n/**\n * Check if two segment objects are equal.\n *\n * @param {MaskSegment} seg1 The first segment.\n * @param {MaskSegment} seg2 The second segment.\n * @returns {boolean} True if both segment are equal.\n */\nexport function isEqualSegment(seg1, seg2) {\n // basics\n if (typeof seg1 === 'undefined' ||\n typeof seg2 === 'undefined' ||\n seg1 === null ||\n seg2 === null) {\n return false;\n }\n let isEqual = seg1.number === seg2.number &&\n seg1.label === seg2.label &&\n seg1.algorithmType === seg2.algorithmType;\n // display value\n if (typeof seg1.displayRGBValue !== 'undefined' &&\n typeof seg2.displayRGBValue !== 'undefined') {\n isEqual = isEqual &&\n isEqualRgb(seg1.displayRGBValue, seg2.displayRGBValue);\n } else if (typeof seg1.displayValue !== 'undefined' &&\n typeof seg2.displayValue !== 'undefined') {\n isEqual = isEqual &&\n seg1.displayValue === seg2.displayValue;\n } else {\n isEqual = false;\n }\n // algorithmName\n if (typeof seg1.algorithmName !== 'undefined') {\n if (typeof seg2.algorithmName === 'undefined') {\n isEqual = false;\n } else {\n isEqual = isEqual &&\n seg1.algorithmName === seg2.algorithmName;\n }\n }\n\n return isEqual;\n}\n\n/**\n * Check if two segment objects are similar: either the\n * number or the displayValue are equal.\n *\n * @param {MaskSegment} seg1 The first segment.\n * @param {MaskSegment} seg2 The second segment.\n * @returns {boolean} True if both segment are similar.\n */\nexport function isSimilarSegment(seg1, seg2) {\n // basics\n if (typeof seg1 === 'undefined' ||\n typeof seg2 === 'undefined' ||\n seg1 === null ||\n seg2 === null) {\n return false;\n }\n let isSimilar = seg1.number === seg2.number;\n // display value\n if (typeof seg1.displayRGBValue !== 'undefined' &&\n typeof seg2.displayRGBValue !== 'undefined') {\n isSimilar = isSimilar ||\n isEqualRgb(seg1.displayRGBValue, seg2.displayRGBValue);\n } else if (typeof seg1.displayValue !== 'undefined' &&\n typeof seg2.displayValue !== 'undefined') {\n isSimilar = isSimilar ||\n seg1.displayValue === seg2.displayValue;\n } else {\n isSimilar = false;\n }\n\n return isSimilar;\n}\n\n/**\n * Get a dicom simple tag from a segment object.\n *\n * @param {MaskSegment} segment The segment object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomSegmentItem(segment) {\n let algoType = segment.algorithmType;\n if (algoType === undefined) {\n algoType = 'MANUAL';\n }\n // dicom item (tags are in group/element order)\n const segmentItem = {\n SegmentNumber: segment.number,\n SegmentLabel: segment.label,\n SegmentAlgorithmType: algoType\n };\n // SegmentAlgorithmName\n if (algoType !== 'MANUAL' && segment.algorithmName !== undefined) {\n segmentItem.SegmentAlgorithmName = segment.algorithmName;\n }\n // RecommendedDisplay value\n if (segment.displayRGBValue) {\n const cieLab = labToUintLab(srgbToCielab(segment.displayRGBValue));\n segmentItem.RecommendedDisplayCIELabValue = [\n Math.round(cieLab.l),\n Math.round(cieLab.a),\n Math.round(cieLab.b)\n ];\n } else {\n segmentItem.RecommendedDisplayGrayscaleValue = segment.displayValue;\n }\n // SegmentedPropertyCategoryCodeSequence\n if (segment.propertyCategoryCode) {\n segmentItem.SegmentedPropertyCategoryCodeSequence = {\n value: [getDicomCodeItem(segment.propertyCategoryCode)]\n };\n }\n // SegmentedPropertyTypeCodeSequence\n if (segment.propertyTypeCode) {\n segmentItem.SegmentedPropertyTypeCodeSequence = {\n value: [getDicomCodeItem(segment.propertyTypeCode)]\n };\n }\n // tracking\n if (segment.trackingId) {\n segmentItem.TrackingID = segment.trackingId;\n segmentItem.TrackingUID = segment.trackingUid;\n }\n // return\n return segmentItem;\n}\n","import {getSpacingFromMeasure} from './dicomElementsWrapper';\nimport {logger} from '../utils/logger';\nimport {arrayEquals} from '../utils/array';\nimport {\n getDicomCodeItem,\n getSegmentationCode,\n getSourceImageForProcessingCode\n} from './dicomCode';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\nimport {Spacing} from '../image/spacing';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n DerivationImageSequence: '00089124',\n SourceImageSequence: '00082112',\n ReferencedSOPClassUID: '00081150',\n ReferencedSOPInstanceUID: '00081155',\n FrameContentSequence: '00209111',\n DimensionIndexValue: '00209157',\n SegmentIdentificationSequence: '0062000A',\n ReferencedSegmentNumber: '0062000B',\n PlanePositionSequence: '00209113',\n ImagePosition: '00200032',\n PlaneOrientationSequence: '00209116',\n ImageOrientation: '00200037',\n PixelMeasuresSequence: '00289110'\n};\n\n/**\n * DICOM segment frame info: item of a\n * PerframeFunctionalGroupsSequence (5200,9230).\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.7.6.16.html}.\n */\nexport class DicomSegmentFrameInfo {\n /**\n * The dimension index.\n *\n * @type {number[]}\n */\n dimIndex;\n /**\n * The frame image position patient.\n *\n * @type {number[]}\n */\n imagePosPat;\n /**\n * List of derivation images.\n *\n * @type {Array}\n */\n derivationImages;\n /**\n * The reference segment number.\n *\n * @type {number}\n */\n refSegmentNumber;\n\n /**\n * The frame image orientation.\n *\n * @type {number[]|undefined}\n */\n imageOrientationPatient;\n /**\n * The frame spacing.\n *\n * @type {Spacing|undefined}\n */\n spacing;\n\n /**\n * @param {number[]} dimIndex The dimension index.\n * @param {number[]} imagePosPat The frame image position patient.\n * @param {Array} derivationImages List of derivation images.\n * @param {number} refSegmentNumber The reference segment number.\n */\n constructor(dimIndex, imagePosPat, derivationImages, refSegmentNumber) {\n this.dimIndex = dimIndex;\n this.imagePosPat = imagePosPat;\n this.derivationImages = derivationImages;\n this.refSegmentNumber = refSegmentNumber;\n }\n}\n\n/**\n * Get a frame information object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {DicomSegmentFrameInfo} A frame information object.\n */\nexport function getSegmentFrameInfo(dataElements) {\n // Derivation Image Sequence\n const derivationImages = [];\n if (typeof dataElements[TagKeys.DerivationImageSequence] !== 'undefined') {\n const derivationImageSq =\n dataElements[TagKeys.DerivationImageSequence].value;\n // Source Image Sequence\n for (let i = 0; i < derivationImageSq.length; ++i) {\n const sourceImages = [];\n if (typeof derivationImageSq[i][TagKeys.SourceImageSequence] !==\n 'undefined') {\n const sourceImageSq =\n derivationImageSq[i][TagKeys.SourceImageSequence].value;\n for (let j = 0; j < sourceImageSq.length; ++j) {\n const sourceImage = {};\n // Referenced SOP Class UID\n if (typeof sourceImageSq[j][TagKeys.ReferencedSOPClassUID] !==\n 'undefined') {\n sourceImage.referencedSOPClassUID =\n sourceImageSq[j][TagKeys.ReferencedSOPClassUID].value[0];\n }\n // Referenced SOP Instance UID\n if (typeof sourceImageSq[j][TagKeys.ReferencedSOPInstanceUID] !==\n 'undefined') {\n sourceImage.referencedSOPInstanceUID =\n sourceImageSq[j][TagKeys.ReferencedSOPInstanceUID].value[0];\n }\n sourceImages.push(sourceImage);\n }\n }\n derivationImages.push({\n sourceImages: sourceImages\n });\n }\n }\n // Frame Content Sequence (required, only one)\n const frameContentSq = dataElements[TagKeys.FrameContentSequence].value;\n // Dimension Index Value\n const dimIndex = frameContentSq[0][TagKeys.DimensionIndexValue].value;\n // Segment Identification Sequence (required, only one)\n const segmentIdSq = dataElements[TagKeys.SegmentIdentificationSequence].value;\n // Referenced Segment Number\n const refSegmentNumber =\n parseInt(segmentIdSq[0][TagKeys.ReferencedSegmentNumber].value[0], 0);\n // Plane Position Sequence (required, only one)\n const planePosSq = dataElements[TagKeys.PlanePositionSequence].value;\n // Image Position (Patient) (conditionally required)\n const imagePosPat = planePosSq[0][TagKeys.ImagePosition].value;\n for (let p = 0; p < imagePosPat.length; ++p) {\n imagePosPat[p] = parseFloat(imagePosPat[p]);\n }\n const frameInfo = new DicomSegmentFrameInfo(\n dimIndex,\n imagePosPat,\n derivationImages,\n refSegmentNumber\n );\n // Plane Orientation Sequence\n if (typeof dataElements[TagKeys.PlaneOrientationSequence] !== 'undefined') {\n const framePlaneOrientationSeq =\n dataElements[TagKeys.PlaneOrientationSequence];\n if (framePlaneOrientationSeq.value.length !== 0) {\n // should only be one Image Orientation (Patient)\n const frameImageOrientation =\n framePlaneOrientationSeq.value[0][TagKeys.ImageOrientation].value;\n if (typeof frameImageOrientation !== 'undefined') {\n frameInfo.imageOrientationPatient = frameImageOrientation;\n }\n }\n }\n // Pixel Measures Sequence\n if (typeof dataElements[TagKeys.PixelMeasuresSequence] !== 'undefined') {\n const framePixelMeasuresSeq = dataElements[TagKeys.PixelMeasuresSequence];\n if (framePixelMeasuresSeq.value.length !== 0) {\n // should only be one\n const frameSpacing =\n getSpacingFromMeasure(framePixelMeasuresSeq.value[0]);\n if (typeof frameSpacing !== 'undefined') {\n frameInfo.spacing = frameSpacing;\n }\n } else {\n logger.warn(\n 'No shared functional group pixel measure sequence items.');\n }\n }\n\n return frameInfo;\n}\n\n/**\n * Check if two frame info objects are equal.\n *\n * @param {DicomSegmentFrameInfo} dsfi1 The first frame info.\n * @param {DicomSegmentFrameInfo} dsfi2 The second frame info.\n * @returns {boolean} True if both frame info are equal.\n */\nexport function isEqualSegmentFrameInfo(dsfi1, dsfi2) {\n // basics\n if (typeof dsfi1 === 'undefined' ||\n typeof dsfi2 === 'undefined' ||\n dsfi1 === null ||\n dsfi2 === null) {\n return false;\n }\n let isEqual =\n arrayEquals(dsfi1.dimIndex, dsfi2.dimIndex) &&\n arrayEquals(dsfi1.imagePosPat, dsfi2.imagePosPat) &&\n dsfi1.refSegmentNumber === dsfi2.refSegmentNumber;\n\n isEqual = isEqual &&\n dsfi1.derivationImages.length === dsfi2.derivationImages.length;\n for (let i = 0; i < dsfi1.derivationImages.length; ++i) {\n const derivationImage1 = dsfi1.derivationImages[i];\n const derivationImage2 = dsfi2.derivationImages[i];\n isEqual = isEqual &&\n derivationImage1.sourceImages.length ===\n derivationImage2.sourceImages.length;\n for (let j = 0; j < derivationImage1.length; ++j) {\n const sourceImage1 = derivationImage1.sourceImages[j];\n const sourceImage2 = derivationImage2.sourceImages[j];\n isEqual = isEqual &&\n sourceImage1.referencedSOPClassUID ===\n sourceImage2.referencedSOPClassUID &&\n sourceImage1.referencedSOPInstanceUID ===\n sourceImage2.referencedSOPInstanceUID;\n }\n }\n\n return isEqual;\n}\n\n/**\n * Get a dicom item from a frame information object.\n *\n * @param {object} frameInfo The frame information object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomSegmentFrameInfoItem(frameInfo) {\n const item = {\n FrameContentSequence: {\n value: [\n {\n DimensionIndexValues: frameInfo.dimIndex\n }\n ]\n },\n PlanePositionSequence: {\n value: [\n {\n ImagePositionPatient: frameInfo.imagePosPat\n }\n ]\n },\n SegmentIdentificationSequence: {\n value: [\n {\n ReferencedSegmentNumber: frameInfo.refSegmentNumber\n }\n ]\n }\n };\n // optional DerivationImageSequence\n if (frameInfo.derivationImages !== undefined) {\n const sourceImgPurposeOfReferenceCode =\n getDicomCodeItem(getSourceImageForProcessingCode());\n const segDerivationCode =\n getDicomCodeItem(getSegmentationCode());\n\n const derivationImageItems = [];\n for (const derivationImage of frameInfo.derivationImages) {\n const sourceImages = [];\n for (const sourceImage of derivationImage.sourceImages) {\n sourceImages.push({\n PurposeOfReferenceCodeSequence: {\n value: [sourceImgPurposeOfReferenceCode]\n },\n ReferencedSOPClassUID: sourceImage.referencedSOPClassUID,\n ReferencedSOPInstanceUID: sourceImage.referencedSOPInstanceUID\n });\n }\n\n derivationImageItems.push({\n DerivationCodeSequence: {\n value: [segDerivationCode]\n },\n SourceImageSequence: {\n value: sourceImages\n }\n });\n }\n\n item.DerivationImageSequence = {\n value: derivationImageItems\n };\n }\n\n return item;\n}\n","import {\n dateToDateObj,\n getDicomDate,\n dateToTimeObj,\n getDicomTime,\n} from '../dicom/dicomDate';\nimport {\n getImage2DSize,\n getSpacingFromMeasure,\n getDimensionOrganization,\n getDicomMeasureItem,\n getDicomPlaneOrientationItem\n} from '../dicom/dicomElementsWrapper';\nimport {Tag} from '../dicom/dicomTag';\nimport {getElementsFromJSONTags} from '../dicom/dicomWriter';\nimport {\n getSegment,\n getDicomSegmentItem,\n} from '../dicom/dicomSegment';\nimport {\n getSegmentFrameInfo,\n getDicomSegmentFrameInfoItem\n} from '../dicom/dicomSegmentFrameInfo';\nimport {transferSyntaxKeywords} from '../dicom/dictionary';\nimport {Image} from '../image/image';\nimport {Geometry} from '../image/geometry';\nimport {Point, Point3D} from '../math/point';\nimport {Vector3D} from '../math/vector';\nimport {Index} from '../math/index';\nimport {Matrix33, REAL_WORLD_EPSILON} from '../math/matrix';\nimport {logger} from '../utils/logger';\nimport {arraySortEquals} from '../utils/array';\nimport {Size} from './size';\nimport {ColourMap} from './luts';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from '../dicom/dataElement';\nimport {MaskSegment} from '../dicom/dicomSegment';\n/* eslint-enable no-unused-vars */\n\n/**\n * @typedef {Object} DataElements\n */\n\n/**\n * Check two position patients for equality.\n *\n * @param {*} pos1 The first position patient.\n * @param {*} pos2 The second position patient.\n * @returns {boolean} True is equal.\n */\nfunction equalPosPat(pos1, pos2) {\n return JSON.stringify(pos1) === JSON.stringify(pos2);\n}\n\n/**\n * @callback compareFn\n * @param {object} a The first object.\n * @param {object} b The first object.\n * @returns {number} >0 to sort a after b, <0 to sort a before b,\n * 0 to not change order.\n */\n\n/**\n * Get a position patient compare function accroding to an\n * input orientation.\n *\n * @param {Matrix33} orientation The orientation matrix.\n * @returns {compareFn} The position compare function.\n */\nfunction getComparePosPat(orientation) {\n const invOrientation = orientation.getInverse();\n return function (pos1, pos2) {\n const p1 = invOrientation.multiplyArray3D(pos1);\n const p2 = invOrientation.multiplyArray3D(pos2);\n return p1[2] - p2[2];\n };\n}\n\n/**\n * Merge two tag lists.\n *\n * @param {object} tags1 Base list, will be modified.\n * @param {object} tags2 List to merge.\n */\nfunction mergeTags(tags1, tags2) {\n const keys2 = Object.keys(tags2);\n for (const tagName2 of keys2) {\n if (tags1[tagName2] !== undefined) {\n logger.trace('Overwritting tag: ' + tagName2);\n }\n tags1[tagName2] = tags2[tagName2];\n }\n}\n\n/**\n * Check that a DICOM tag definition is present in a parsed element.\n *\n * @param {DataElements} dataElements The root dicom element.\n * @param {object} tagDefinition The tag definition as {name, tag, type, enum}.\n */\nfunction checkTag(dataElements, tagDefinition) {\n const element = dataElements[tagDefinition.tag];\n // check null and undefined\n if (tagDefinition.type === 1 || tagDefinition.type === 2) {\n if (typeof element === 'undefined') {\n throw new Error('Missing or empty ' + tagDefinition.name);\n }\n } else {\n if (typeof element === 'undefined') {\n // non mandatory value, exit\n return;\n }\n }\n let includes = false;\n let tagValue;\n if (element.value.length === 1) {\n tagValue = element.value[0];\n } else {\n tagValue = element.value;\n }\n if (Array.isArray(tagValue)) {\n for (let i = 0; i < tagDefinition.enum.length; ++i) {\n if (!Array.isArray(tagDefinition.enum[i])) {\n throw new Error('Cannot compare array and non array tag value.');\n }\n if (arraySortEquals(tagDefinition.enum[i], tagValue)) {\n includes = true;\n break;\n }\n }\n } else {\n includes = tagDefinition.enum.includes(tagValue);\n }\n if (!includes) {\n throw new Error(\n 'Unsupported ' + tagDefinition.name + ' value: ' + tagValue);\n }\n}\n\n/**\n * Create ROI slice buffers.\n *\n * @param {Image} image The mask image.\n * @param {MaskSegment[]} segments The mask segments.\n * @param {number} sliceOffset The slice offset.\n * @returns {object} The ROI slice image buffers.\n */\nfunction createRoiSliceBuffers(\n image,\n segments,\n sliceOffset\n) {\n // create binary mask buffers\n const geometry = image.getGeometry();\n const size = geometry.getSize();\n const sliceSize = size.getDimSize(2);\n const buffers = {};\n for (let o = 0; o < sliceSize; ++o) {\n const inputOffset = sliceOffset + o;\n const pixelValue = image.getValueAtOffset(inputOffset);\n for (const segment of segments) {\n const segmentIndex = segment.number - 1;\n if (pixelValue === segment.number) {\n if (buffers[segmentIndex] === undefined) {\n buffers[segmentIndex] = new Uint8Array(sliceSize);\n }\n buffers[segmentIndex][o] = 1;\n }\n }\n }\n return buffers;\n}\n\n/**\n * Create ROI buffers.\n *\n * @param {Image} image The mask image.\n * @param {MaskSegment[]} segments The mask segments.\n * @returns {object} The ROI buffers.\n */\nfunction createRoiBuffers(image, segments) {\n const geometry = image.getGeometry();\n const size = geometry.getSize();\n\n // image buffer to multi frame\n const sliceSize = size.getDimSize(2);\n const roiBuffers = {};\n for (let k = 0; k < size.get(2); ++k) {\n const sliceOffset = k * sliceSize;\n // create slice buffers\n const buffers = createRoiSliceBuffers(image, segments, sliceOffset);\n // store slice buffers\n const keys0 = Object.keys(buffers);\n for (const key0 of keys0) {\n if (roiBuffers[key0] === undefined) {\n roiBuffers[key0] = {};\n }\n // ordering by slice index (follows posPat)\n roiBuffers[key0][k] = buffers[key0];\n }\n }\n return roiBuffers;\n}\n\n/**\n * List of DICOM Seg required tags.\n */\nconst RequiredDicomSegTags = [\n {\n name: 'TransferSyntaxUID',\n tag: '00020010',\n type: '1',\n enum: [\n transferSyntaxKeywords.ImplicitVRLittleEndian,\n transferSyntaxKeywords.ExplicitVRLittleEndian,\n transferSyntaxKeywords.ExplicitVRBigEndian\n ]\n },\n {\n name: 'MediaStorageSOPClassUID',\n tag: '00020002',\n type: '1',\n enum: ['1.2.840.10008.5.1.4.1.1.66.4']\n },\n {\n name: 'SOPClassUID',\n tag: '00020002',\n type: '1',\n enum: ['1.2.840.10008.5.1.4.1.1.66.4']\n },\n {\n name: 'Modality',\n tag: '00080060',\n type: '1',\n enum: ['SEG']\n },\n {\n name: 'SegmentationType',\n tag: '00620001',\n type: '1',\n enum: ['BINARY']\n },\n {\n name: 'DimensionOrganizationType',\n tag: '00209311',\n type: '3',\n enum: ['3D']\n },\n {\n name: 'ImageType',\n tag: '00080008',\n type: '1',\n enum: [['DERIVED', 'PRIMARY']]\n },\n {\n name: 'SamplesPerPixel',\n tag: '00280002',\n type: '1',\n enum: [1]\n },\n {\n name: 'PhotometricInterpretation',\n tag: '00280004',\n type: '1',\n enum: ['MONOCHROME2']\n },\n {\n name: 'PixelRepresentation',\n tag: '00280103',\n type: '1',\n enum: [0]\n },\n {\n name: 'BitsAllocated',\n tag: '00280100',\n type: '1',\n enum: [1]\n },\n {\n name: 'BitsStored',\n tag: '00280101',\n type: '1',\n enum: [1]\n },\n {\n name: 'HighBit',\n tag: '00280102',\n type: '1',\n enum: [0]\n },\n];\n\n/**\n * Get the default DICOM seg tags as an object.\n *\n * @returns {object} The default tags.\n */\nexport function getDefaultDicomSegJson() {\n const tags = {};\n for (let i = 0; i < RequiredDicomSegTags.length; ++i) {\n const reqTag = RequiredDicomSegTags[i];\n tags[reqTag.name] = reqTag.enum[0];\n }\n return tags;\n}\n\n/**\n * Mask {@link Image} factory.\n */\nexport class MaskFactory {\n\n /**\n * Possible warning created by checkElements.\n *\n * @type {string|undefined}\n */\n #warning;\n\n /**\n * Get a warning string if elements are not as expected.\n * Created by checkElements.\n *\n * @returns {string|undefined} The warning.\n */\n getWarning() {\n return this.#warning;\n }\n\n /**\n * Check dicom elements. Throws an error if not suitable.\n *\n * @param {Object} _dicomElements The DICOM tags.\n * @returns {string|undefined} A possible warning.\n */\n checkElements(_dicomElements) {\n // does nothing\n return;\n }\n\n /**\n * Get an {@link Image} object from the read DICOM file.\n *\n * @param {Object} dataElements The DICOM tags.\n * @param {Uint8Array | Int8Array |\n * Uint16Array | Int16Array |\n * Uint32Array | Int32Array} pixelBuffer The pixel buffer.\n * @returns {Image} A new Image.\n */\n create(dataElements, pixelBuffer) {\n // check required and supported tags\n for (let d = 0; d < RequiredDicomSegTags.length; ++d) {\n checkTag(dataElements, RequiredDicomSegTags[d]);\n }\n\n // image size\n const size2D = getImage2DSize(dataElements);\n const size = new Size([size2D[0], size2D[1], 1]);\n\n const sliceSize = size.getTotalSize();\n\n // frames\n let frames = 1;\n const framesElem = dataElements['00280008'];\n if (typeof framesElem !== 'undefined') {\n frames = parseInt(framesElem.value[0], 10);\n }\n\n if (frames !== pixelBuffer.length / sliceSize) {\n throw new Error(\n 'Buffer and numberOfFrames meta are not equal.' +\n frames + ' ' + pixelBuffer.length / sliceSize);\n }\n\n // Dimension Organization and Index\n const dimension = getDimensionOrganization(dataElements);\n\n // Segment Sequence\n const segSequence = dataElements['00620002'];\n if (typeof segSequence === 'undefined') {\n throw new Error('Missing or empty segmentation sequence');\n }\n const segments = [];\n // segment number is unique and starts at 1, use 0 as background\n const redLut = [0];\n const greenLut = [0];\n const blueLut = [0];\n for (let i = 0; i < segSequence.value.length; ++i) {\n const segment = getSegment(segSequence.value[i]);\n if (typeof segment.displayRGBValue !== 'undefined') {\n // add palette colour\n redLut[segment.number] = segment.displayRGBValue.r;\n greenLut[segment.number] = segment.displayRGBValue.g;\n blueLut[segment.number] = segment.displayRGBValue.b;\n }\n // store\n segments.push(segment);\n }\n\n let hasDisplayRGBValue = false;\n let paletteColourMap;\n if (redLut.length > 1) {\n hasDisplayRGBValue = true;\n paletteColourMap = new ColourMap(redLut, greenLut, blueLut);\n }\n\n // Shared Functional Groups Sequence\n let spacing;\n let imageOrientationPatient;\n const sharedFunctionalGroupsSeq = dataElements['52009229'];\n if (typeof sharedFunctionalGroupsSeq !== 'undefined') {\n // should be only one\n const funcGroup0 = sharedFunctionalGroupsSeq.value[0];\n // Plane Orientation Sequence\n if (typeof funcGroup0['00209116'] !== 'undefined') {\n const planeOrientationSeq = funcGroup0['00209116'];\n if (planeOrientationSeq.value.length !== 0) {\n // should be only one\n imageOrientationPatient =\n planeOrientationSeq.value[0]['00200037'].value;\n } else {\n logger.warn(\n 'No shared functional group plane orientation sequence items.');\n }\n }\n // Pixel Measures Sequence\n if (typeof funcGroup0['00289110'] !== 'undefined') {\n const pixelMeasuresSeq = funcGroup0['00289110'];\n if (pixelMeasuresSeq.value.length !== 0) {\n // should be only one\n spacing = getSpacingFromMeasure(pixelMeasuresSeq.value[0]);\n } else {\n logger.warn(\n 'No shared functional group pixel measure sequence items.');\n }\n }\n }\n\n const includesPosPat = function (arr, val) {\n return arr.some(function (arrVal) {\n return equalPosPat(val, arrVal);\n });\n };\n\n const findIndexPosPat = function (arr, val) {\n return arr.findIndex(function (arrVal) {\n return equalPosPat(val, arrVal);\n });\n };\n\n // Per-frame Functional Groups Sequence\n const perFrameFuncGroupSequence = dataElements['52009230'];\n if (typeof perFrameFuncGroupSequence === 'undefined') {\n throw new Error('Missing or empty per frame functional sequence');\n }\n if (frames !== perFrameFuncGroupSequence.value.length) {\n throw new Error(\n 'perFrameFuncGroupSequence meta and numberOfFrames are not equal.');\n }\n // create frame info object from per frame func\n const frameInfos = [];\n for (let j = 0; j < perFrameFuncGroupSequence.value.length; ++j) {\n frameInfos.push(\n getSegmentFrameInfo(perFrameFuncGroupSequence.value[j]));\n }\n\n // check frame infos\n const framePosPats = [];\n for (let ii = 0; ii < frameInfos.length; ++ii) {\n if (!includesPosPat(framePosPats, frameInfos[ii].imagePosPat)) {\n framePosPats.push(frameInfos[ii].imagePosPat);\n }\n // store orientation if needed, avoid multi\n if (typeof frameInfos[ii].imageOrientationPatient !== 'undefined') {\n if (typeof imageOrientationPatient === 'undefined') {\n imageOrientationPatient = frameInfos[ii].imageOrientationPatient;\n } else {\n if (!arraySortEquals(\n imageOrientationPatient, frameInfos[ii].imageOrientationPatient)) {\n throw new Error('Unsupported multi orientation dicom seg.');\n }\n }\n }\n // store spacing if needed, avoid multi\n if (typeof frameInfos[ii].spacing !== 'undefined') {\n if (typeof spacing === 'undefined') {\n spacing = frameInfos[ii].spacing;\n } else {\n if (!spacing.equals(frameInfos[ii].spacing)) {\n throw new Error('Unsupported multi resolution dicom seg.');\n }\n }\n }\n }\n\n // check spacing and orientation\n if (typeof spacing === 'undefined') {\n throw new Error('No spacing found for DICOM SEG');\n }\n if (spacing.length() !== 3) {\n throw new Error('Incomplete spacing found for DICOM SEG');\n }\n if (typeof imageOrientationPatient === 'undefined') {\n throw new Error('No imageOrientationPatient found for DICOM SEG');\n }\n if (imageOrientationPatient.length !== 6) {\n throw new Error('Incomplete imageOrientationPatient found for DICOM SEG');\n }\n\n // orientation\n const rowCosines = new Vector3D(\n parseFloat(imageOrientationPatient[0]),\n parseFloat(imageOrientationPatient[1]),\n parseFloat(imageOrientationPatient[2]));\n const colCosines = new Vector3D(\n parseFloat(imageOrientationPatient[3]),\n parseFloat(imageOrientationPatient[4]),\n parseFloat(imageOrientationPatient[5]));\n const normal = rowCosines.crossProduct(colCosines);\n /* eslint-disable @stylistic/js/array-element-newline */\n const orientationMatrix = new Matrix33([\n rowCosines.getX(), colCosines.getX(), normal.getX(),\n rowCosines.getY(), colCosines.getY(), normal.getY(),\n rowCosines.getZ(), colCosines.getZ(), normal.getZ()\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n\n // sort positions patient\n framePosPats.sort(getComparePosPat(orientationMatrix));\n\n const point3DFromArray = function (arr) {\n return new Point3D(arr[0], arr[1], arr[2]);\n };\n\n // frame origins\n const frameOrigins = [];\n for (let n = 0; n < framePosPats.length; ++n) {\n frameOrigins.push(point3DFromArray(framePosPats[n]));\n }\n\n // tmp geometry with correct spacing but only one slice\n const tmpGeometry = new Geometry(\n frameOrigins[0], size, spacing, orientationMatrix);\n\n // origin distance test\n // TODO: maybe use sliceSpacing / 10\n const isAboveEpsilon = function (value) {\n let res = value > REAL_WORLD_EPSILON;\n if (res) {\n // try larger epsilon\n res = value > REAL_WORLD_EPSILON * 10;\n if (!res) {\n // warn if epsilon < value < epsilon * 10\n logger.warn(\n 'Using larger real world epsilon in SEG pos pat adding'\n );\n } else {\n res = value > REAL_WORLD_EPSILON * 100;\n if (!res) {\n // warn if epsilon < value < epsilon * 100\n logger.warn(\n 'Using larger+ real world epsilon in SEG pos pat adding'\n );\n }\n }\n }\n return res;\n };\n\n // add possibly missing posPats\n const posPats = [];\n posPats.push(framePosPats[0]);\n let sliceIndex = 0;\n for (let g = 1; g < framePosPats.length; ++g) {\n ++sliceIndex;\n let index = new Index([0, 0, sliceIndex]);\n let point = tmpGeometry.indexToWorld(index).get3D();\n const frameOrigin = frameOrigins[g];\n // check if more pos pats are needed\n let dist = frameOrigin.getDistance(point);\n const distPrevious = dist;\n // TODO: good threshold?\n while (isAboveEpsilon(dist)) {\n logger.debug('Adding intermediate pos pats for DICOM seg at ' +\n point.toString());\n posPats.push([point.getX(), point.getY(), point.getZ()]);\n ++sliceIndex;\n index = new Index([0, 0, sliceIndex]);\n point = tmpGeometry.indexToWorld(index).get3D();\n dist = frameOrigin.getDistance(point);\n if (dist > distPrevious) {\n throw new Error(\n 'Test distance is increasing when adding intermediate pos pats');\n }\n }\n // add frame pos pat\n posPats.push(framePosPats[g]);\n }\n\n // as many slices as posPats\n const numberOfSlices = posPats.length;\n\n // final geometry\n const geometry = new Geometry(\n frameOrigins[0], size, spacing, orientationMatrix);\n const uids = ['0'];\n for (let m = 1; m < numberOfSlices; ++m) {\n geometry.appendOrigin(point3DFromArray(posPats[m]), m);\n uids.push(m.toString());\n }\n\n const getFindSegmentFunc = function (number) {\n return function (item) {\n return item.number === number;\n };\n };\n\n // create output buffer\n const buffer =\n // @ts-ignore\n new pixelBuffer.constructor(sliceSize * numberOfSlices);\n buffer.fill(0);\n // merge frame buffers\n let sliceOffset = null;\n let frameOffset = null;\n for (let f = 0; f < frameInfos.length; ++f) {\n // get the slice index from the position in the posPat array\n sliceIndex = findIndexPosPat(posPats, frameInfos[f].imagePosPat);\n frameOffset = sliceSize * f;\n sliceOffset = sliceSize * sliceIndex;\n // get the frame display value\n const frameSegment = segments.find(\n getFindSegmentFunc(frameInfos[f].refSegmentNumber)\n );\n for (let l = 0; l < sliceSize; ++l) {\n if (pixelBuffer[frameOffset + l] !== 0) {\n const offset = sliceOffset + l;\n if (hasDisplayRGBValue) {\n buffer[offset] = frameSegment.number;\n } else {\n buffer[offset] = frameSegment.displayValue;\n }\n }\n }\n }\n\n // create image\n const image = new Image(geometry, buffer, uids);\n if (hasDisplayRGBValue) {\n image.setPhotometricInterpretation('PALETTE COLOR');\n image.setPaletteColourMap(paletteColourMap);\n }\n // meta information\n const meta = getDefaultDicomSegJson();\n const safeGet = function (key) {\n let res;\n const element = dataElements[key];\n if (typeof element !== 'undefined') {\n res = element.value[0];\n }\n return res;\n };\n // Study\n meta.StudyDate = safeGet('00080020');\n meta.StudyTime = safeGet('00080030');\n meta.StudyInstanceUID = safeGet('0020000D');\n meta.StudyID = safeGet('00200010');\n // Series\n meta.SeriesDate = safeGet('00080021');\n meta.SeriesTime = safeGet('00080031');\n meta.SeriesInstanceUID = safeGet('0020000E');\n meta.SeriesNumber = safeGet('00200011');\n // ReferringPhysicianName\n meta.ReferringPhysicianName = safeGet('00080090');\n // patient info\n meta.PatientName = safeGet('00100010');\n meta.PatientID = safeGet('00100020');\n meta.PatientBirthDate = safeGet('00100030');\n meta.PatientSex = safeGet('00100040');\n // Enhanced General Equipment Module\n meta.Manufacturer = safeGet('00080070');\n meta.ManufacturerModelName = safeGet('00081090');\n meta.DeviceSerialNumber = safeGet('00181000');\n meta.SoftwareVersions = safeGet('00181020');\n // dicom seg dimension\n meta.DimensionOrganizationSequence = dimension.organizations;\n meta.DimensionIndexSequence = dimension.indices;\n // custom\n meta.custom = {\n segments: segments,\n frameInfos: frameInfos,\n SOPInstanceUID: dataElements['00080018'].value[0]\n };\n\n // number of files: in this case equal to number slices,\n // used to calculate buffer size\n meta.numberOfFiles = numberOfSlices;\n // FrameOfReferenceUID (optional)\n const frameOfReferenceUID = dataElements['00200052'];\n if (frameOfReferenceUID) {\n meta.FrameOfReferenceUID = frameOfReferenceUID.value[0];\n }\n // LossyImageCompression (optional)\n const lossyImageCompression = dataElements['00282110'];\n if (lossyImageCompression) {\n meta.LossyImageCompression = lossyImageCompression.value[0];\n }\n\n image.setMeta(meta);\n\n return image;\n }\n\n /**\n * Convert a mask image into a DICOM segmentation object.\n *\n * @param {Image} image The mask image.\n * @param {MaskSegment[]} segments The mask segments.\n * @param {Image} sourceImage The source image.\n * @param {Object} [extraTags] Optional list of extra tags.\n * @returns {Object} A list of dicom elements.\n */\n toDicom(\n image,\n segments,\n sourceImage,\n extraTags\n ) {\n // original image tags\n const tags = image.getMeta();\n\n // use image segments if not provided as input\n if (segments === undefined) {\n segments = tags.segments;\n }\n\n const geometry = image.getGeometry();\n const size = geometry.getSize();\n\n // (not in meta)\n tags.Rows = size.get(1);\n tags.Columns = size.get(0);\n // update content tags\n const now = new Date();\n tags.ContentDate = getDicomDate(dateToDateObj(now));\n tags.ContentTime = getDicomTime(dateToTimeObj(now));\n\n // keep source image StudyInstanceUID\n if (sourceImage !== undefined) {\n tags.StudyInstanceUID = (sourceImage.getMeta()).StudyInstanceUID;\n }\n\n // segments\n const segmentItems = [];\n for (const segment of segments) {\n segmentItems.push(getDicomSegmentItem(segment));\n }\n tags.SegmentSequence = {\n value: segmentItems\n };\n\n // Shared Functional Groups Sequence\n tags.SharedFunctionalGroupsSequence = {\n value: [\n {\n PlaneOrientationSequence: {\n value: [getDicomPlaneOrientationItem(geometry.getOrientation())]\n },\n PixelMeasuresSequence: {\n value: [getDicomMeasureItem(geometry.getSpacing())]\n }\n }\n ]\n };\n\n // image buffer to multi frame\n const roiBuffers = createRoiBuffers(image, segments);\n\n const frameInfos = [];\n\n // flatten buffer array\n const finalBuffers = [];\n const referencedSOPs = [];\n for (const segment of segments) {\n const number40 = segment.number;\n const number4 = number40 - 1;\n // check if buffer has values\n if (roiBuffers[number4] === undefined) {\n continue;\n }\n const keys1 = Object.keys(roiBuffers[number4]);\n // revert slice order\n for (let k1 = keys1.length - 1; k1 >= 0; --k1) {\n const key1 = Number.parseInt(keys1[k1], 10);\n finalBuffers.push(roiBuffers[number4][key1]);\n // frame info\n const posPat = image.getGeometry().getOrigins()[key1];\n const posPatArray = [posPat.getX(), posPat.getY(), posPat.getZ()];\n const frameInfo = {\n dimIndex: [number40, keys1.length - k1],\n imagePosPat: posPatArray,\n refSegmentNumber: number40\n };\n // derivation image info\n if (sourceImage !== undefined) {\n const sourceGeometry = sourceImage.getGeometry();\n const sourceIndex = sourceGeometry.worldToIndex(\n new Point([posPat.getX(), posPat.getY(), posPat.getZ()])\n );\n frameInfo.derivationImages = [\n {\n sourceImages: [\n {\n referencedSOPInstanceUID:\n sourceImage.getImageUid(sourceIndex),\n referencedSOPClassUID:\n (sourceImage.getMeta()).SOPClassUID\n }\n ]\n }\n ];\n // store as tag\n referencedSOPs.push({\n ReferencedSOPInstanceUID:\n sourceImage.getImageUid(sourceIndex),\n ReferencedSOPClassUID:\n (sourceImage.getMeta()).SOPClassUID\n });\n }\n frameInfos.push(frameInfo);\n }\n }\n\n tags.NumberOfFrames = finalBuffers.length.toString();\n\n // frame infos\n const frameInfosTag = [];\n for (const frameInfo of frameInfos) {\n frameInfosTag.push(getDicomSegmentFrameInfoItem(frameInfo));\n }\n tags.PerFrameFunctionalGroupsSequence = {\n value: frameInfosTag\n };\n\n // also store referenced SOPs in ReferencedSeriesSequence\n if (sourceImage !== undefined) {\n const refSeriesTag = [];\n refSeriesTag.push({\n ReferencedInstanceSequence: {\n value: referencedSOPs\n },\n SeriesInstanceUID: (sourceImage.getMeta()).SeriesInstanceUID\n });\n tags.ReferencedSeriesSequence = {\n value: refSeriesTag\n };\n }\n\n // merge extra tags if provided\n if (extraTags !== undefined) {\n mergeTags(tags, extraTags);\n }\n\n // convert JSON to DICOM element object\n const dicomElements = getElementsFromJSONTags(tags);\n\n // pixel value length: divide by 8 to trigger binary write\n const sliceSize = size.getDimSize(2);\n const pixVl = (finalBuffers.length * sliceSize) / 8;\n const de = new DataElement('OB');\n de.tag = new Tag('7FE0', '0010');\n de.vl = pixVl;\n de.value = finalBuffers;\n dicomElements['7FE00010'] = de;\n\n return dicomElements;\n }\n\n} // class MaskFactory\n","import {Index} from '../math/index';\nimport {Point3D} from '../math/point';\nimport {logger} from '../utils/logger';\nimport {arrayContains} from '../utils/array';\nimport {getTypedArray} from '../dicom/dicomParser';\nimport {ListenerHandler} from '../utils/listen';\nimport {valueRange} from './iterator';\nimport {RescaleSlopeAndIntercept} from './rsi';\nimport {ImageFactory} from './imageFactory';\nimport {MaskFactory} from './maskFactory';\nimport {isMonochrome} from '../dicom/dicomElementsWrapper';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Geometry} from './geometry';\nimport {Matrix33} from '../math/matrix';\nimport {NumberRange} from '../math/stats';\nimport {DataElement} from '../dicom/dataElement';\nimport {RGB} from '../utils/colour';\nimport {ColourMap} from './luts';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get the slice index of an input slice into a volume geometry.\n *\n * @param {Geometry} volumeGeometry The volume geometry.\n * @param {Geometry} sliceGeometry The slice geometry.\n * @returns {Index} The index of the slice in the volume geomtry.\n */\nfunction getSliceIndex(volumeGeometry, sliceGeometry) {\n // possible time\n const timeId = sliceGeometry.getInitialTime();\n // index values\n const values = [];\n // x, y\n values.push(0);\n values.push(0);\n // z\n values.push(volumeGeometry.getSliceIndex(sliceGeometry.getOrigin(), timeId));\n // time\n if (typeof timeId !== 'undefined') {\n values.push(timeId);\n }\n // return index\n return new Index(values);\n}\n\n/**\n * Create an Image from DICOM elements.\n *\n * @param {Object} elements The DICOM elements.\n * @returns {Image} The Image object.\n */\nexport function createImage(elements) {\n const factory = new ImageFactory();\n return factory.create(\n elements,\n elements['7FE00010'].value[0],\n 1\n );\n}\n\n/**\n * Create a mask Image from DICOM elements.\n *\n * @param {Object} elements The DICOM elements.\n * @returns {Image} The mask Image object.\n */\nexport function createMaskImage(elements) {\n const factory = new MaskFactory();\n return factory.create(\n elements,\n elements['7FE00010'].value[0]\n );\n}\n\n/**\n * Image class.\n * Usable once created, optional are:\n * - rescale slope and intercept (default 1:0),\n * - photometric interpretation (default MONOCHROME2),\n * - planar configuration (default RGBRGB...).\n *\n * @example\n * // XMLHttpRequest onload callback\n * const onload = function (event) {\n * // parse the dicom buffer\n * const dicomParser = new dwv.DicomParser();\n * dicomParser.parse(event.target.response);\n * // create the image object\n * const image = dwv.createImage(dicomParser.getDicomElements());\n * // result div\n * const div = document.getElementById('dwv');\n * // display the image size\n * const size = image.getGeometry().getSize();\n * div.appendChild(document.createTextNode(\n * 'Size: ' + size.toString() +\n * ' (should be 256,256,1)'));\n * // break line\n * div.appendChild(document.createElement('br'));\n * // display a pixel value\n * div.appendChild(document.createTextNode(\n * 'Pixel @ [128,40,0]: ' +\n * image.getRescaledValue(128,40,0) +\n * ' (should be 101)'));\n * };\n * // DICOM file request\n * const request = new XMLHttpRequest();\n * const url = 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm';\n * request.open('GET', url);\n * request.responseType = 'arraybuffer';\n * request.onload = onload;\n * request.send();\n */\nexport class Image {\n\n /**\n * Data geometry.\n *\n * @type {Geometry}\n */\n #geometry;\n\n /**\n * List of compatible typed arrays.\n *\n * @typedef {(\n * Uint8Array | Int8Array |\n * Uint16Array | Int16Array |\n * Uint32Array | Int32Array\n * )} TypedArray\n */\n\n /**\n * Data buffer.\n *\n * @type {TypedArray}\n */\n #buffer;\n\n /**\n * Image UIDs.\n *\n * @type {string[]}\n */\n #imageUids;\n\n /**\n * Constant rescale slope and intercept (default).\n *\n * @type {RescaleSlopeAndIntercept}\n */\n #rsi = new RescaleSlopeAndIntercept(1, 0);\n\n /**\n * Varying rescale slope and intercept.\n *\n * @type {RescaleSlopeAndIntercept[]}\n */\n #rsis = null;\n\n /**\n * Flag to know if the RSIs are all identity (1,0).\n *\n * @type {boolean}\n */\n #isIdentityRSI = true;\n\n /**\n * Flag to know if the RSIs are all equals.\n *\n * @type {boolean}\n */\n #isConstantRSI = true;\n\n /**\n * Photometric interpretation (MONOCHROME, RGB...).\n *\n * @type {string}\n */\n #photometricInterpretation = 'MONOCHROME2';\n\n /**\n * Palette colour map.\n *\n * @type {ColourMap}\n */\n #paletteColourMap;\n\n /**\n * Planar configuration for RGB data (`0:RGBRGBRGBRGB...` or\n * `1:RRR...GGG...BBB...`).\n *\n * @type {number}\n */\n #planarConfiguration = 0;\n\n /**\n * Number of components.\n *\n * @type {number}\n */\n #numberOfComponents;\n\n /**\n * Meta information.\n *\n * @type {Object}\n */\n #meta = {};\n\n /**\n * Data range.\n *\n * @type {NumberRange}\n */\n #dataRange = null;\n\n /**\n * Rescaled data range.\n *\n * @type {NumberRange}\n */\n #rescaledDataRange = null;\n\n /**\n * Histogram.\n *\n * @type {Array}\n */\n #histogram = null;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * @param {Geometry} geometry The geometry of the image.\n * @param {TypedArray} buffer The image data as a one dimensional buffer.\n * @param {string[]} [imageUids] An array of Uids indexed to slice number.\n */\n constructor(geometry, buffer, imageUids) {\n this.#geometry = geometry;\n this.#buffer = buffer;\n this.#imageUids = imageUids;\n\n this.#numberOfComponents = this.#buffer.length / (\n this.#geometry.getSize().getTotalSize());\n }\n\n /**\n * Get the image UID at a given index.\n *\n * @param {Index} [index] The index at which to get the id.\n * @returns {string} The UID.\n */\n getImageUid(index) {\n let uid = this.#imageUids[0];\n if (this.#imageUids.length !== 1 && typeof index !== 'undefined') {\n uid = this.#imageUids[this.getSecondaryOffset(index)];\n }\n return uid;\n }\n\n /**\n * Get the image origin for a image UID.\n *\n * @param {string} uid The UID.\n * @returns {Point3D|undefined} The origin.\n */\n getOriginForImageUid(uid) {\n let origin;\n const uidIndex = this.#imageUids.indexOf(uid);\n if (uidIndex !== -1) {\n const origins = this.getGeometry().getOrigins();\n origin = origins[uidIndex];\n }\n return origin;\n }\n\n /**\n * Check if the image includes an UID.\n *\n * @param {string} uid The UID.\n * @returns {boolean} True if present.\n */\n includesImageUid(uid) {\n return this.#imageUids.includes(uid);\n }\n\n /**\n * Check if this image includes the input uids.\n *\n * @param {string[]} uids UIDs to test for presence.\n * @returns {boolean} True if all uids are in this image uids.\n */\n containsImageUids(uids) {\n return arrayContains(this.#imageUids, uids);\n }\n\n /**\n * Get the geometry of the image.\n *\n * @returns {Geometry} The geometry.\n */\n getGeometry() {\n return this.#geometry;\n }\n\n /**\n * Get the data buffer of the image.\n *\n * @todo Dangerous...\n * @returns {TypedArray} The data buffer of the image.\n */\n getBuffer() {\n return this.#buffer;\n }\n\n /**\n * Can the image values be quantified?\n *\n * @returns {boolean} True if only one component.\n */\n canQuantify() {\n return this.getNumberOfComponents() === 1;\n }\n\n /**\n * Can window and level be applied to the data?\n *\n * @returns {boolean} True if the data is monochrome.\n * @deprecated Since v0.33, please use isMonochrome instead.\n */\n canWindowLevel() {\n return this.isMonochrome();\n }\n\n /**\n * Is the data monochrome.\n *\n * @returns {boolean} True if the data is monochrome.\n */\n isMonochrome() {\n return isMonochrome(this.getPhotometricInterpretation());\n }\n\n /**\n * Can the data be scrolled?\n *\n * @param {Matrix33} viewOrientation The view orientation.\n * @returns {boolean} True if the data has a third dimension greater than one\n * after applying the view orientation.\n */\n canScroll(viewOrientation) {\n const size = this.getGeometry().getSize();\n // also check the numberOfFiles in case we are in the middle of a load\n let nFiles = 1;\n if (typeof this.#meta.numberOfFiles !== 'undefined') {\n nFiles = this.#meta.numberOfFiles;\n }\n return size.canScroll(viewOrientation) || nFiles !== 1;\n }\n\n /**\n * Get the secondary offset max.\n *\n * @returns {number} The maximum offset.\n */\n #getSecondaryOffsetMax() {\n return this.#geometry.getSize().getTotalSize(2);\n }\n\n /**\n * Get the secondary offset: an offset that takes into account\n * the slice and above dimension numbers.\n *\n * @param {Index} index The index.\n * @returns {number} The offset.\n */\n getSecondaryOffset(index) {\n return this.#geometry.getSize().indexToOffset(index, 2);\n }\n\n /**\n * Get the rescale slope and intercept.\n *\n * @param {Index} [index] The index (only needed for non constant rsi).\n * @returns {RescaleSlopeAndIntercept} The rescale slope and intercept.\n */\n getRescaleSlopeAndIntercept(index) {\n let res = this.#rsi;\n if (!this.isConstantRSI()) {\n if (typeof index === 'undefined') {\n throw new Error('Cannot get non constant RSI with empty slice index.');\n }\n const offset = this.getSecondaryOffset(index);\n if (typeof this.#rsis[offset] !== 'undefined') {\n res = this.#rsis[offset];\n } else {\n logger.warn('undefined non constant rsi at ' + offset);\n }\n }\n return res;\n }\n\n /**\n * Get the rsi at a specified (secondary) offset.\n *\n * @param {number} offset The desired (secondary) offset.\n * @returns {RescaleSlopeAndIntercept} The coresponding rsi.\n */\n #getRescaleSlopeAndInterceptAtOffset(offset) {\n return this.#rsis[offset];\n }\n\n /**\n * Set the rescale slope and intercept.\n *\n * @param {RescaleSlopeAndIntercept} inRsi The input rescale\n * slope and intercept.\n * @param {number} [offset] The rsi offset (only needed for non constant rsi).\n */\n setRescaleSlopeAndIntercept(inRsi, offset) {\n // update identity flag\n this.#isIdentityRSI = this.#isIdentityRSI && inRsi.isID();\n // update constant flag\n if (!this.#isConstantRSI) {\n if (typeof offset === 'undefined') {\n throw new Error(\n 'Cannot store non constant RSI with empty slice index.');\n }\n this.#rsis.splice(offset, 0, inRsi);\n } else {\n if (!this.#rsi.equals(inRsi)) {\n if (typeof offset === 'undefined') {\n // no slice index, replace existing\n this.#rsi = inRsi;\n } else {\n // first non constant rsi\n this.#isConstantRSI = false;\n // switch to non constant mode\n this.#rsis = [];\n // initialise RSIs\n for (let i = 0, leni = this.#getSecondaryOffsetMax(); i < leni; ++i) {\n this.#rsis.push(this.#rsi);\n }\n // store\n this.#rsi = null;\n this.#rsis.splice(offset, 0, inRsi);\n }\n }\n }\n }\n\n /**\n * Are all the RSIs identity (1,0).\n *\n * @returns {boolean} True if they are.\n */\n isIdentityRSI() {\n return this.#isIdentityRSI;\n }\n\n /**\n * Are all the RSIs equal.\n *\n * @returns {boolean} True if they are.\n */\n isConstantRSI() {\n return this.#isConstantRSI;\n }\n\n /**\n * Get the photometricInterpretation of the image.\n *\n * @returns {string} The photometricInterpretation of the image.\n */\n getPhotometricInterpretation() {\n return this.#photometricInterpretation;\n }\n\n /**\n * Set the photometricInterpretation of the image.\n *\n * @param {string} interp The photometricInterpretation of the image.\n */\n setPhotometricInterpretation(interp) {\n this.#photometricInterpretation = interp;\n }\n\n /**\n * Set the palette colour map.\n *\n * @param {ColourMap} map The colour map.\n */\n setPaletteColourMap(map) {\n this.#paletteColourMap = map;\n // fire imagecontentchange\n this.#fireEvent({type: 'imagecontentchange'});\n }\n\n /**\n * Get the palette colour map.\n *\n * @returns {ColourMap} The colour map.\n */\n getPaletteColourMap() {\n return this.#paletteColourMap;\n }\n\n /**\n * Update the palette colour map.\n *\n * @param {number} index The index to change the colour of.\n * @param {RGB} colour The colour to use at index.\n */\n updatePaletteColourMap(index, colour) {\n this.#paletteColourMap.red[index] = colour.r;\n this.#paletteColourMap.green[index] = colour.g;\n this.#paletteColourMap.blue[index] = colour.b;\n // fire imagecontentchange\n this.#fireEvent({type: 'imagecontentchange'});\n }\n\n /**\n * Get the planarConfiguration of the image.\n *\n * @returns {number} The planarConfiguration of the image.\n */\n getPlanarConfiguration() {\n return this.#planarConfiguration;\n }\n\n /**\n * Set the planarConfiguration of the image.\n *\n * @param {number} config The planarConfiguration of the image.\n */\n setPlanarConfiguration(config) {\n this.#planarConfiguration = config;\n }\n\n /**\n * Get the numberOfComponents of the image.\n *\n * @returns {number} The numberOfComponents of the image.\n */\n getNumberOfComponents() {\n return this.#numberOfComponents;\n }\n\n /**\n * Get the meta information of the image.\n *\n * @returns {Object} The meta information of the image.\n */\n getMeta() {\n return this.#meta;\n }\n\n /**\n * Set the meta information of the image.\n *\n * @param {Object} rhs The meta information of the image.\n */\n setMeta(rhs) {\n this.#meta = rhs;\n }\n\n /**\n * Get value at offset. Warning: No size check...\n *\n * @param {number} offset The desired offset.\n * @returns {number} The value at offset.\n */\n getValueAtOffset(offset) {\n return this.#buffer[offset];\n }\n\n /**\n * Get the offsets where the buffer equals the input value.\n * Loops through the whole volume, can get long for big data...\n *\n * @param {number|RGB} value The value to check.\n * @returns {number[]} The list of offsets.\n */\n getOffsets(value) {\n // value to array\n let bufferValue;\n if (typeof value === 'number') {\n if (this.#numberOfComponents !== 1) {\n throw new Error(\n 'Number of components is not 1 for getting single value.');\n }\n bufferValue = [value];\n } else if (typeof value.r !== 'undefined' &&\n typeof value.g !== 'undefined' &&\n typeof value.b !== 'undefined') {\n if (this.#numberOfComponents !== 3) {\n throw new Error(\n 'Number of components is not 3 for getting RGB value.');\n }\n bufferValue = [value.r, value.g, value.b];\n }\n\n // main loop\n const offsets = [];\n let equal;\n for (let i = 0; i < this.#buffer.length; i = i + this.#numberOfComponents) {\n equal = true;\n for (let j = 0; j < this.#numberOfComponents; ++j) {\n if (this.#buffer[i + j] !== bufferValue[j]) {\n equal = false;\n break;\n }\n }\n if (equal) {\n offsets.push(i);\n }\n }\n return offsets;\n }\n\n /**\n * Check if the input values are in the buffer.\n * Could loop through the whole volume, can get long for big data...\n *\n * @param {Array} values The values to check.\n * @returns {boolean[]} A list of booleans for each input value,\n * set to true if the value is present in the buffer.\n */\n hasValues(values) {\n // check input\n if (typeof values === 'undefined' ||\n values.length === 0) {\n return [];\n }\n // final array value\n const finalValues = [];\n for (let v1 = 0; v1 < values.length; ++v1) {\n if (this.#numberOfComponents === 1) {\n finalValues.push([values[v1]]);\n } else if (this.#numberOfComponents === 3) {\n finalValues.push([\n values[v1].r,\n values[v1].g,\n values[v1].b\n ]);\n }\n }\n // find callback\n let equalFunc;\n if (this.#numberOfComponents === 1) {\n equalFunc = function (a, b) {\n return a[0] === b[0];\n };\n } else if (this.#numberOfComponents === 3) {\n equalFunc = function (a, b) {\n return a[0] === b[0] &&\n a[1] === b[1] &&\n a[2] === b[2];\n };\n }\n const getEqualCallback = function (value) {\n return function (item) {\n return equalFunc(item, value);\n };\n };\n // main loop\n const res = new Array(values.length);\n res.fill(false);\n const valuesToFind = finalValues.slice();\n let equal;\n let indicesToRemove;\n for (let i = 0, leni = this.#buffer.length;\n i < leni; i = i + this.#numberOfComponents) {\n indicesToRemove = [];\n for (let v = 0; v < valuesToFind.length; ++v) {\n equal = true;\n // check value(s)\n for (let j = 0; j < this.#numberOfComponents; ++j) {\n if (this.#buffer[i + j] !== valuesToFind[v][j]) {\n equal = false;\n break;\n }\n }\n // if found, store answer and add to indices to remove\n if (equal) {\n const valIndex = finalValues.findIndex(\n getEqualCallback(valuesToFind[v]));\n res[valIndex] = true;\n indicesToRemove.push(v);\n }\n }\n // remove found values\n for (let r = 0; r < indicesToRemove.length; ++r) {\n valuesToFind.splice(indicesToRemove[r], 1);\n }\n // exit if no values to find\n if (valuesToFind.length === 0) {\n break;\n }\n }\n // return\n return res;\n }\n\n /**\n * Clone the image.\n *\n * @returns {Image} A clone of this image.\n */\n clone() {\n // clone the image buffer\n const clonedBuffer = this.#buffer.slice(0);\n // create the image copy\n const copy = new Image(this.getGeometry(), clonedBuffer, this.#imageUids);\n // copy the RSI(s)\n if (this.isConstantRSI()) {\n copy.setRescaleSlopeAndIntercept(this.getRescaleSlopeAndIntercept());\n } else {\n for (let i = 0; i < this.#getSecondaryOffsetMax(); ++i) {\n copy.setRescaleSlopeAndIntercept(\n this.#getRescaleSlopeAndInterceptAtOffset(i), i);\n }\n }\n // copy extras\n copy.setPhotometricInterpretation(this.getPhotometricInterpretation());\n copy.setPlanarConfiguration(this.getPlanarConfiguration());\n copy.setMeta(this.getMeta());\n // return\n return copy;\n }\n\n /**\n * Re-allocate buffer memory to an input size.\n *\n * @param {number} size The new size.\n */\n #realloc(size) {\n // save buffer\n let tmpBuffer = this.#buffer;\n // create new\n this.#buffer = getTypedArray(\n this.#buffer.BYTES_PER_ELEMENT * 8,\n this.#meta.IsSigned ? 1 : 0,\n size);\n if (this.#buffer === null) {\n throw new Error('Cannot reallocate data for image.');\n }\n // put old in new\n this.#buffer.set(tmpBuffer);\n // clean\n tmpBuffer = null;\n }\n\n /**\n * Append a slice to the image.\n *\n * @param {Image} rhs The slice to append.\n * @fires Image#imagegeometrychange\n */\n appendSlice(rhs) {\n // check input\n if (rhs === null) {\n throw new Error('Cannot append null slice');\n }\n const rhsSize = rhs.getGeometry().getSize();\n let size = this.#geometry.getSize();\n if (rhsSize.get(2) !== 1) {\n throw new Error('Cannot append more than one slice');\n }\n if (size.get(0) !== rhsSize.get(0)) {\n throw new Error('Cannot append a slice with different number of columns');\n }\n if (size.get(1) !== rhsSize.get(1)) {\n throw new Error('Cannot append a slice with different number of rows');\n }\n if (!this.#geometry.getOrientation().equals(\n rhs.getGeometry().getOrientation(), 0.0001)) {\n throw new Error('Cannot append a slice with different orientation');\n }\n if (this.#photometricInterpretation !==\n rhs.getPhotometricInterpretation()) {\n throw new Error(\n 'Cannot append a slice with different photometric interpretation');\n }\n // all meta should be equal\n for (const key in this.#meta) {\n if (key === 'windowPresets' || key === 'numberOfFiles' ||\n key === 'custom') {\n continue;\n }\n if (this.#meta[key] !== rhs.getMeta()[key]) {\n throw new Error('Cannot append a slice with different ' + key +\n ': ' + this.#meta[key] + ' != ' + rhs.getMeta()[key]);\n }\n }\n\n // update ranges\n const rhsRange = rhs.getDataRange();\n const range = this.getDataRange();\n this.#dataRange = {\n min: Math.min(rhsRange.min, range.min),\n max: Math.max(rhsRange.max, range.max),\n };\n const rhsResRange = rhs.getRescaledDataRange();\n const resRange = this.getRescaledDataRange();\n this.#rescaledDataRange = {\n min: Math.min(rhsResRange.min, resRange.min),\n max: Math.max(rhsResRange.max, resRange.max),\n };\n\n // possible time\n const timeId = rhs.getGeometry().getInitialTime();\n\n // append frame if needed\n let isNewFrame = false;\n if (typeof timeId !== 'undefined' &&\n !this.#geometry.hasSlicesAtTime(timeId)) {\n // update grometry\n this.appendFrame(timeId, rhs.getGeometry().getOrigin());\n // update size\n size = this.#geometry.getSize();\n // update flag\n isNewFrame = true;\n }\n\n // get slice index\n const index = getSliceIndex(this.#geometry, rhs.getGeometry());\n\n // calculate slice size\n const sliceSize = this.#numberOfComponents * size.getDimSize(2);\n\n // create full buffer if not done yet\n if (typeof this.#meta.numberOfFiles === 'undefined') {\n throw new Error('Missing number of files for buffer manipulation.');\n }\n const fullBufferSize = sliceSize * this.#meta.numberOfFiles;\n if (this.#buffer.length !== fullBufferSize) {\n this.#realloc(fullBufferSize);\n }\n\n // slice index\n const sliceIndex = index.get(2);\n\n // slice index including possible 4D\n let fullSliceIndex = sliceIndex;\n if (typeof timeId !== 'undefined') {\n fullSliceIndex +=\n this.#geometry.getCurrentNumberOfSlicesBeforeTime(timeId);\n }\n // offset of the input slice\n const indexOffset = fullSliceIndex * sliceSize;\n const maxOffset =\n this.#geometry.getCurrentTotalNumberOfSlices() * sliceSize;\n // move content if needed\n if (indexOffset < maxOffset) {\n this.#buffer.set(\n this.#buffer.subarray(indexOffset, maxOffset),\n indexOffset + sliceSize\n );\n }\n // add new slice content\n this.#buffer.set(rhs.getBuffer(), indexOffset);\n\n // update geometry\n if (!isNewFrame) {\n this.#geometry.appendOrigin(\n rhs.getGeometry().getOrigin(), sliceIndex, timeId);\n }\n // update rsi\n // (rhs should just have one rsi)\n this.setRescaleSlopeAndIntercept(\n rhs.getRescaleSlopeAndIntercept(), fullSliceIndex);\n\n // current number of images\n const numberOfImages = this.#imageUids.length;\n\n // insert sop instance UIDs\n this.#imageUids.splice(fullSliceIndex, 0, rhs.getImageUid());\n\n // update window presets\n if (typeof this.#meta.windowPresets !== 'undefined') {\n const windowPresets = this.#meta.windowPresets;\n const rhsPresets = rhs.getMeta().windowPresets;\n const keys = Object.keys(rhsPresets);\n let pkey = null;\n for (let i = 0; i < keys.length; ++i) {\n pkey = keys[i];\n const rhsPreset = rhsPresets[pkey];\n const windowPreset = windowPresets[pkey];\n if (typeof windowPreset !== 'undefined') {\n // if not set or false, check perslice\n if (typeof windowPreset.perslice === 'undefined' ||\n windowPreset.perslice === false) {\n // if different preset.wl, mark it as perslice\n if (!windowPreset.wl[0].equals(rhsPreset.wl[0])) {\n windowPreset.perslice = true;\n // fill wl array with copy of wl[0]\n // (loop on number of images minus the existing one)\n for (let j = 0; j < numberOfImages - 1; ++j) {\n windowPreset.wl.push(windowPreset.wl[0]);\n }\n }\n }\n // store (first) rhs preset.wl if needed\n if (typeof windowPreset.perslice !== 'undefined' &&\n windowPreset.perslice === true) {\n windowPresets[pkey].wl.splice(\n fullSliceIndex, 0, rhsPreset.wl[0]);\n }\n } else {\n // if not defined (it should be), store all\n windowPresets[pkey] = rhsPresets[pkey];\n }\n }\n }\n /**\n * Image geometry change event.\n *\n * @event Image#imagegeometrychange\n * @type {object}\n * @property {string} type The event type.\n */\n this.#fireEvent({\n type: 'imagegeometrychange'\n });\n }\n\n /**\n * Append a frame buffer to the image.\n *\n * @param {object} frameBuffer The frame buffer to append.\n * @param {number} frameIndex The frame index.\n */\n appendFrameBuffer(frameBuffer, frameIndex) {\n // create full buffer if not done yet\n const size = this.#geometry.getSize();\n const frameSize = this.#numberOfComponents * size.getDimSize(2);\n if (typeof this.#meta.numberOfFiles === 'undefined') {\n throw new Error('Missing number of files for frame buffer manipulation.');\n }\n const fullBufferSize = frameSize * this.#meta.numberOfFiles;\n if (this.#buffer.length !== fullBufferSize) {\n this.#realloc(fullBufferSize);\n }\n // check index\n if (frameIndex >= this.#meta.numberOfFiles) {\n logger.warn('Ignoring frame at index ' + frameIndex +\n ' (size: ' + this.#meta.numberOfFiles + ')');\n return;\n }\n // append\n this.#buffer.set(frameBuffer, frameSize * frameIndex);\n // update geometry\n this.appendFrame(frameIndex, new Point3D(0, 0, 0));\n }\n\n /**\n * Append a frame to the image.\n *\n * @param {number} time The frame time value.\n * @param {Point3D} origin The origin of the frame.\n */\n appendFrame(time, origin) {\n this.#geometry.appendFrame(origin, time);\n /**\n * Append frame event.\n *\n * @event Image#appendframe\n * @type {object}\n * @property {string} type The event type.\n */\n this.#fireEvent({\n type: 'appendframe'\n });\n // memory will be updated at the first appendSlice or appendFrameBuffer\n }\n\n /**\n * Get the data range.\n *\n * @returns {NumberRange} The data range.\n */\n getDataRange() {\n if (!this.#dataRange) {\n this.#dataRange = this.calculateDataRange();\n }\n return this.#dataRange;\n }\n\n /**\n * Get the rescaled data range.\n *\n * @returns {NumberRange} The rescaled data range.\n */\n getRescaledDataRange() {\n if (!this.#rescaledDataRange) {\n this.#rescaledDataRange = this.calculateRescaledDataRange();\n }\n return this.#rescaledDataRange;\n }\n\n /**\n * Get the histogram.\n *\n * @returns {Array} The histogram.\n */\n getHistogram() {\n if (!this.#histogram) {\n const res = this.calculateHistogram();\n this.#dataRange = res.dataRange;\n this.#rescaledDataRange = res.rescaledDataRange;\n this.#histogram = res.histogram;\n }\n return this.#histogram;\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n // ****************************************\n // image data modifiers... carefull...\n // ****************************************\n\n /**\n * Set the inner buffer values at given offsets.\n *\n * @param {number[]} offsets List of offsets where to set the data.\n * @param {number|RGB} value The value to set at the given offsets.\n * @fires Image#imagecontentchange\n */\n setAtOffsets(offsets, value) {\n // value to array\n let bufferValue;\n if (typeof value === 'number') {\n if (this.#numberOfComponents !== 1) {\n throw new Error(\n 'Number of components is not 1 for setting single value.');\n }\n bufferValue = [value];\n } else if (typeof value.r !== 'undefined' &&\n typeof value.g !== 'undefined' &&\n typeof value.b !== 'undefined') {\n if (this.#numberOfComponents !== 3) {\n throw new Error(\n 'Number of components is not 3 for setting RGB value.');\n }\n bufferValue = [value.r, value.g, value.b];\n }\n\n let offset;\n for (let i = 0, leni = offsets.length; i < leni; ++i) {\n offset = offsets[i];\n for (let j = 0; j < this.#numberOfComponents; ++j) {\n this.#buffer[offset + j] = bufferValue[j];\n }\n }\n // fire imagecontentchange\n this.#fireEvent({type: 'imagecontentchange'});\n }\n\n /**\n * Set the inner buffer values at given offsets.\n *\n * @param {number[][]} offsetsLists List of offset lists where\n * to set the data.\n * @param {number} value The value to set at the given offsets.\n * @returns {Array} A list of objects representing the original values before\n * replacing them.\n * @fires Image#imagecontentchange\n */\n setAtOffsetsAndGetOriginals(offsetsLists, value) {\n const originalValuesLists = [];\n\n // update and store\n for (let j = 0; j < offsetsLists.length; ++j) {\n const offsets = offsetsLists[j];\n // first value\n let offset = offsets[0];\n let previousValue = this.#buffer[offset];\n // original value storage\n const originalValues = [];\n originalValues.push({\n index: 0,\n value: previousValue\n });\n for (let i = 0; i < offsets.length; ++i) {\n offset = offsets[i];\n const currentValue = this.#buffer[offset];\n // check if new value\n if (previousValue !== currentValue) {\n // store new value\n originalValues.push({\n index: i,\n value: currentValue\n });\n previousValue = currentValue;\n }\n // write update value\n this.#buffer[offset] = value;\n }\n originalValuesLists.push(originalValues);\n }\n // fire imagecontentchange\n this.#fireEvent({type: 'imagecontentchange'});\n return originalValuesLists;\n }\n\n /**\n * Set the inner buffer values at given offsets.\n *\n * @param {number[][]} offsetsLists List of offset lists\n * where to set the data.\n * @param {number|Array} value The value to set at the given offsets.\n * @fires Image#imagecontentchange\n */\n setAtOffsetsWithIterator(offsetsLists, value) {\n const isValueArray = Array.isArray(value);\n\n for (let j = 0; j < offsetsLists.length; ++j) {\n const offsets = offsetsLists[j];\n let iterator;\n if (isValueArray) {\n // input value is a list of iterators\n // created by setAtOffsetsAndGetOriginals\n iterator = valueRange(\n value[j], offsets.length);\n } else {\n // input value is a simple color\n iterator = valueRange(\n [{index: 0, value: value}], offsets.length);\n }\n\n // set values\n let ival = iterator.next();\n while (!ival.done) {\n const offset = offsets[ival.index];\n this.#buffer[offset] = ival.value;\n ival = iterator.next();\n }\n }\n /**\n * Image content change event.\n *\n * @event Image#imagecontentchange\n * @type {object}\n * @property {string} type The event type.\n */\n this.#fireEvent({type: 'imagecontentchange'});\n }\n\n /**\n * Get the value of the image at a specific coordinate.\n *\n * @param {number} i The X index.\n * @param {number} j The Y index.\n * @param {number} k The Z index.\n * @param {number} f The frame number.\n * @returns {number} The value at the desired position.\n * Warning: No size check...\n */\n getValue(i, j, k, f) {\n const frame = (f || 0);\n const index = new Index([i, j, k, frame]);\n return this.getValueAtOffset(\n this.getGeometry().getSize().indexToOffset(index));\n }\n\n /**\n * Get the value of the image at a specific index.\n *\n * @param {Index} index The index.\n * @returns {number} The value at the desired position.\n * Warning: No size check...\n */\n getValueAtIndex(index) {\n return this.getValueAtOffset(\n this.getGeometry().getSize().indexToOffset(index));\n }\n\n /**\n * Get the rescaled value of the image at a specific position.\n *\n * @param {number} i The X index.\n * @param {number} j The Y index.\n * @param {number} k The Z index.\n * @param {number} f The frame number.\n * @returns {number} The rescaled value at the desired position.\n * Warning: No size check...\n */\n getRescaledValue(i, j, k, f) {\n if (typeof f === 'undefined') {\n f = 0;\n }\n let val = this.getValue(i, j, k, f);\n if (!this.isIdentityRSI()) {\n if (this.isConstantRSI()) {\n val = this.getRescaleSlopeAndIntercept().apply(val);\n } else {\n const values = [i, j, k, f];\n const index = new Index(values);\n val = this.getRescaleSlopeAndIntercept(index).apply(val);\n }\n }\n return val;\n }\n\n /**\n * Get the rescaled value of the image at a specific index.\n *\n * @param {Index} index The index.\n * @returns {number} The rescaled value at the desired position.\n * Warning: No size check...\n */\n getRescaledValueAtIndex(index) {\n return this.getRescaledValueAtOffset(\n this.getGeometry().getSize().indexToOffset(index)\n );\n }\n\n /**\n * Get the rescaled value of the image at a specific offset.\n *\n * @param {number} offset The desired offset.\n * @returns {number} The rescaled value at the desired offset.\n * Warning: No size check...\n */\n getRescaledValueAtOffset(offset) {\n let val = this.getValueAtOffset(offset);\n if (!this.isIdentityRSI()) {\n if (this.isConstantRSI()) {\n val = this.getRescaleSlopeAndIntercept().apply(val);\n } else {\n const index = this.getGeometry().getSize().offsetToIndex(offset);\n val = this.getRescaleSlopeAndIntercept(index).apply(val);\n }\n }\n return val;\n }\n\n /**\n * Calculate the data range of the image.\n * WARNING: for speed reasons, only calculated on the first frame...\n *\n * @returns {object} The range {min, max}.\n */\n calculateDataRange() {\n let min = this.getValueAtOffset(0);\n let max = min;\n let value = 0;\n const size = this.getGeometry().getSize();\n let leni = size.getTotalSize();\n // max to 3D\n if (size.length() >= 3) {\n leni = size.getDimSize(3);\n }\n for (let i = 0; i < leni; ++i) {\n value = this.getValueAtOffset(i);\n if (value > max) {\n max = value;\n }\n if (value < min) {\n min = value;\n }\n }\n // return\n return {min: min, max: max};\n }\n\n /**\n * Calculate the rescaled data range of the image.\n * WARNING: for speed reasons, only calculated on the first frame...\n *\n * @returns {object} The range {min, max}.\n */\n calculateRescaledDataRange() {\n if (this.isIdentityRSI()) {\n return this.getDataRange();\n } else if (this.isConstantRSI()) {\n const range = this.getDataRange();\n const resmin = this.getRescaleSlopeAndIntercept().apply(range.min);\n const resmax = this.getRescaleSlopeAndIntercept().apply(range.max);\n return {\n min: ((resmin < resmax) ? resmin : resmax),\n max: ((resmin > resmax) ? resmin : resmax)\n };\n } else {\n let rmin = this.getRescaledValueAtOffset(0);\n let rmax = rmin;\n let rvalue = 0;\n const size = this.getGeometry().getSize();\n let leni = size.getTotalSize();\n // max to 3D\n if (size.length() === 3) {\n leni = size.getDimSize(3);\n }\n for (let i = 0; i < leni; ++i) {\n rvalue = this.getRescaledValueAtOffset(i);\n if (rvalue > rmax) {\n rmax = rvalue;\n }\n if (rvalue < rmin) {\n rmin = rvalue;\n }\n }\n // return\n return {min: rmin, max: rmax};\n }\n }\n\n /**\n * Calculate the histogram of the image.\n *\n * @returns {object} The histogram, data range and rescaled data range.\n */\n calculateHistogram() {\n const size = this.getGeometry().getSize();\n const histo = [];\n let min = this.getValueAtOffset(0);\n let max = min;\n let value = 0;\n let rmin = this.getRescaledValueAtOffset(0);\n let rmax = rmin;\n let rvalue = 0;\n for (let i = 0, leni = size.getTotalSize(); i < leni; ++i) {\n value = this.getValueAtOffset(i);\n if (value > max) {\n max = value;\n }\n if (value < min) {\n min = value;\n }\n rvalue = this.getRescaledValueAtOffset(i);\n if (rvalue > rmax) {\n rmax = rvalue;\n }\n if (rvalue < rmin) {\n rmin = rvalue;\n }\n histo[rvalue] = (histo[rvalue] || 0) + 1;\n }\n // set data range\n const dataRange = {min: min, max: max};\n const rescaledDataRange = {min: rmin, max: rmax};\n // generate data for plotting\n const histogram = [];\n for (let b = rmin; b <= rmax; ++b) {\n histogram.push([b, (histo[b] || 0)]);\n }\n // return\n return {\n dataRange: dataRange,\n rescaledDataRange: rescaledDataRange,\n histogram: histogram\n };\n }\n\n /**\n * Convolute the image with a given 2D kernel.\n *\n * Note: Uses raw buffer values.\n *\n * @param {number[]} weights The weights of the 2D kernel as a 3x3 matrix.\n * @returns {Image} The convoluted image.\n */\n convolute2D(weights) {\n if (weights.length !== 9) {\n throw new Error(\n 'The convolution matrix does not have a length of 9; it has ' +\n weights.length);\n }\n\n const newImage = this.clone();\n const newBuffer = newImage.getBuffer();\n\n const imgSize = this.getGeometry().getSize();\n const dimOffset = imgSize.getDimSize(2) * this.getNumberOfComponents();\n for (let k = 0; k < imgSize.get(2); ++k) {\n this.convoluteBuffer(weights, newBuffer, k * dimOffset);\n }\n\n return newImage;\n }\n\n /**\n * Convolute an image buffer with a given 2D kernel.\n *\n * Note: Uses raw buffer values.\n *\n * @param {number[]} weights The weights of the 2D kernel as a 3x3 matrix.\n * @param {TypedArray} buffer The buffer to convolute.\n * @param {number} startOffset The index to start at.\n */\n convoluteBuffer(\n weights, buffer, startOffset) {\n const imgSize = this.getGeometry().getSize();\n const ncols = imgSize.get(0);\n const nrows = imgSize.get(1);\n const ncomp = this.getNumberOfComponents();\n\n // number of component and planar configuration vars\n let factor = 1;\n let componentOffset = 1;\n if (ncomp === 3) {\n if (this.getPlanarConfiguration() === 0) {\n factor = 3;\n } else {\n componentOffset = imgSize.getDimSize(2);\n }\n }\n\n // allow special indent for matrices\n /*jshint indent:false */\n\n // default weight offset matrix\n const wOff = [];\n wOff[0] = (-ncols - 1) * factor;\n wOff[1] = (-ncols) * factor;\n wOff[2] = (-ncols + 1) * factor;\n wOff[3] = -factor;\n wOff[4] = 0;\n wOff[5] = 1 * factor;\n wOff[6] = (ncols - 1) * factor;\n wOff[7] = (ncols) * factor;\n wOff[8] = (ncols + 1) * factor;\n\n // border weight offset matrices\n // borders are extended (see http://en.wikipedia.org/wiki/Kernel_%28image_processing%29)\n\n // i=0, j=0\n const wOff00 = [];\n wOff00[0] = wOff[4]; wOff00[1] = wOff[4]; wOff00[2] = wOff[5];\n wOff00[3] = wOff[4]; wOff00[4] = wOff[4]; wOff00[5] = wOff[5];\n wOff00[6] = wOff[7]; wOff00[7] = wOff[7]; wOff00[8] = wOff[8];\n // i=0, j=*\n const wOff0x = [];\n wOff0x[0] = wOff[1]; wOff0x[1] = wOff[1]; wOff0x[2] = wOff[2];\n wOff0x[3] = wOff[4]; wOff0x[4] = wOff[4]; wOff0x[5] = wOff[5];\n wOff0x[6] = wOff[7]; wOff0x[7] = wOff[7]; wOff0x[8] = wOff[8];\n // i=0, j=nrows\n const wOff0n = [];\n wOff0n[0] = wOff[1]; wOff0n[1] = wOff[1]; wOff0n[2] = wOff[2];\n wOff0n[3] = wOff[4]; wOff0n[4] = wOff[4]; wOff0n[5] = wOff[5];\n wOff0n[6] = wOff[4]; wOff0n[7] = wOff[4]; wOff0n[8] = wOff[5];\n\n // i=*, j=0\n const wOffx0 = [];\n wOffx0[0] = wOff[3]; wOffx0[1] = wOff[4]; wOffx0[2] = wOff[5];\n wOffx0[3] = wOff[3]; wOffx0[4] = wOff[4]; wOffx0[5] = wOff[5];\n wOffx0[6] = wOff[6]; wOffx0[7] = wOff[7]; wOffx0[8] = wOff[8];\n // i=*, j=* -> wOff\n // i=*, j=nrows\n const wOffxn = [];\n wOffxn[0] = wOff[0]; wOffxn[1] = wOff[1]; wOffxn[2] = wOff[2];\n wOffxn[3] = wOff[3]; wOffxn[4] = wOff[4]; wOffxn[5] = wOff[5];\n wOffxn[6] = wOff[3]; wOffxn[7] = wOff[4]; wOffxn[8] = wOff[5];\n\n // i=ncols, j=0\n const wOffn0 = [];\n wOffn0[0] = wOff[3]; wOffn0[1] = wOff[4]; wOffn0[2] = wOff[4];\n wOffn0[3] = wOff[3]; wOffn0[4] = wOff[4]; wOffn0[5] = wOff[4];\n wOffn0[6] = wOff[6]; wOffn0[7] = wOff[7]; wOffn0[8] = wOff[7];\n // i=ncols, j=*\n const wOffnx = [];\n wOffnx[0] = wOff[0]; wOffnx[1] = wOff[1]; wOffnx[2] = wOff[1];\n wOffnx[3] = wOff[3]; wOffnx[4] = wOff[4]; wOffnx[5] = wOff[4];\n wOffnx[6] = wOff[6]; wOffnx[7] = wOff[7]; wOffnx[8] = wOff[7];\n // i=ncols, j=nrows\n const wOffnn = [];\n wOffnn[0] = wOff[0]; wOffnn[1] = wOff[1]; wOffnn[2] = wOff[1];\n wOffnn[3] = wOff[3]; wOffnn[4] = wOff[4]; wOffnn[5] = wOff[4];\n wOffnn[6] = wOff[3]; wOffnn[7] = wOff[4]; wOffnn[8] = wOff[4];\n\n // restore indent for rest of method\n /*jshint indent:4 */\n\n // loop vars\n let pixelOffset = startOffset;\n let newValue = 0;\n let wOffFinal = [];\n for (let c = 0; c < ncomp; ++c) {\n // component offset\n pixelOffset += c * componentOffset;\n for (let j = 0; j < nrows; ++j) {\n for (let i = 0; i < ncols; ++i) {\n wOffFinal = wOff;\n // special border cases\n if (i === 0 && j === 0) {\n wOffFinal = wOff00;\n } else if (i === 0 && j === (nrows - 1)) {\n wOffFinal = wOff0n;\n } else if (i === (ncols - 1) && j === 0) {\n wOffFinal = wOffn0;\n } else if (i === (ncols - 1) && j === (nrows - 1)) {\n wOffFinal = wOffnn;\n } else if (i === 0 && j !== (nrows - 1) && j !== 0) {\n wOffFinal = wOff0x;\n } else if (i === (ncols - 1) && j !== (nrows - 1) && j !== 0) {\n wOffFinal = wOffnx;\n } else if (i !== 0 && i !== (ncols - 1) && j === 0) {\n wOffFinal = wOffx0;\n } else if (i !== 0 && i !== (ncols - 1) && j === (nrows - 1)) {\n wOffFinal = wOffxn;\n }\n // calculate the weighed sum of the source image pixels that\n // fall under the convolution matrix\n newValue = 0;\n for (let wi = 0; wi < 9; ++wi) {\n newValue += this.getValueAtOffset(\n pixelOffset + wOffFinal[wi]) * weights[wi];\n }\n buffer[pixelOffset] = newValue;\n // increment pixel offset\n pixelOffset += factor;\n }\n }\n }\n }\n\n /**\n * Transform an image using a specific operator.\n * WARNING: no size check!\n *\n * @param {Function} operator The operator to use when transforming.\n * @returns {Image} The transformed image.\n * Note: Uses the raw buffer values.\n */\n transform(operator) {\n const newImage = this.clone();\n const newBuffer = newImage.getBuffer();\n for (let i = 0, leni = newBuffer.length; i < leni; ++i) {\n newBuffer[i] = operator(newImage.getValueAtOffset(i));\n }\n return newImage;\n }\n\n /**\n * Compose this image with another one and using a specific operator.\n * WARNING: no size check!\n *\n * @param {Image} rhs The image to compose with.\n * @param {Function} operator The operator to use when composing.\n * @returns {Image} The composed image.\n * Note: Uses the raw buffer values.\n */\n compose(rhs, operator) {\n const newImage = this.clone();\n const newBuffer = newImage.getBuffer();\n for (let i = 0, leni = newBuffer.length; i < leni; ++i) {\n // using the operator on the local buffer, i.e. the\n // latest (not original) data\n newBuffer[i] = Math.floor(\n operator(this.getValueAtOffset(i), rhs.getValueAtOffset(i))\n );\n }\n return newImage;\n }\n\n} // class Image\n","import {View} from './view';\nimport {\n WindowLevel,\n defaultPresets\n} from './windowLevel';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * {@link View} factory.\n */\nexport class ViewFactory {\n\n /**\n * Get an View object from the read DICOM file.\n *\n * @param {Object} dataElements The DICOM tags.\n * @param {Image} image The associated image.\n * @returns {View} The new View.\n */\n create(dataElements, image) {\n // view\n const view = new View(image);\n\n // default color map\n if (image.getPhotometricInterpretation() === 'MONOCHROME1') {\n view.setColourMap('invPlain');\n }\n\n // window level presets\n let windowPresets = {};\n // image presets\n if (typeof image.getMeta().windowPresets !== 'undefined') {\n windowPresets = image.getMeta().windowPresets;\n }\n // min/max\n // Not filled yet since it is stil too costly to calculate min/max\n // for each slice... It will be filled at first use\n // (see view.setWindowLevelPreset).\n // Order is important, if no wl from DICOM, this will be the default.\n windowPresets.minmax = {name: 'minmax'};\n // optional modality presets\n if (typeof defaultPresets !== 'undefined') {\n const modality = image.getMeta().Modality;\n for (const key in defaultPresets[modality]) {\n const preset = defaultPresets[modality][key];\n windowPresets[key] = {\n wl: [new WindowLevel(preset.center, preset.width)],\n name: key\n };\n }\n }\n\n // store\n view.setWindowPresets(windowPresets);\n\n // initialise the view\n view.init();\n\n return view;\n }\n\n} // class ViewFactory\n","import {Index} from '../math/index';\nimport {ModalityLut} from './modalityLut';\nimport {WindowLut} from './windowLut';\nimport {luts} from './luts';\nimport {VoiLut} from './voiLut';\nimport {WindowLevel} from './windowLevel';\nimport {generateImageDataMonochrome} from './viewMonochrome';\nimport {generateImageDataPaletteColor} from './viewPaletteColor';\nimport {generateImageDataRgb} from './viewRgb';\nimport {generateImageDataYbrFull} from './viewYbrFull';\nimport {ViewFactory} from './viewFactory';\nimport {isIdentityMat33} from '../math/matrix';\nimport {getSliceIterator} from '../image/iterator';\nimport {ListenerHandler} from '../utils/listen';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {RescaleSlopeAndIntercept} from './rsi';\nimport {ColourMap} from './luts';\nimport {Matrix33} from '../math/matrix';\nimport {\n Point,\n Point3D\n} from '../math/point';\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * List of view event names.\n *\n * @type {string[]}\n */\nexport const viewEventNames = [\n 'wlchange',\n 'wlpresetadd',\n 'colourmapchange',\n 'positionchange',\n 'opacitychange',\n 'alphafuncchange'\n];\n\n/**\n * Create a View from DICOM elements and image.\n *\n * @param {Object} elements The DICOM elements.\n * @param {Image} image The associated image.\n * @returns {View} The View object.\n */\nexport function createView(elements, image) {\n const factory = new ViewFactory();\n return factory.create(elements, image);\n}\n\n/**\n * View class.\n *\n * Need to set the window lookup table once created\n * (either directly or with helper methods).\n *\n * @example\n * // XMLHttpRequest onload callback\n * const onload = function (event) {\n * // parse the dicom buffer\n * const dicomParser = new dwv.DicomParser();\n * dicomParser.parse(event.target.response);\n * // create the image object\n * const image = dwv.createImage(dicomParser.getDicomElements());\n * // create the view\n * const view = dwv.createView(dicomParser.getDicomElements(), image);\n * // setup canvas\n * const canvas = document.createElement('canvas');\n * canvas.width = 256;\n * canvas.height = 256;\n * const ctx = canvas.getContext(\"2d\");\n * // update the image data\n * const imageData = ctx.createImageData(256, 256);\n * view.generateImageData(imageData);\n * ctx.putImageData(imageData, 0, 0);\n * // update html\n * const div = document.getElementById('dwv');\n * div.appendChild(canvas);;\n * };\n * // DICOM file request\n * const request = new XMLHttpRequest();\n * const url = 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm';\n * request.open('GET', url);\n * request.responseType = 'arraybuffer';\n * request.onload = onload;\n * request.send();\n */\nexport class View {\n\n /**\n * The associated image.\n *\n * @type {Image}\n */\n #image;\n\n /**\n * Window lookup tables, indexed per Rescale Slope and Intercept (RSI).\n *\n * @type {WindowLut}\n */\n #windowLut;\n\n /**\n * Flag for image constant RSI.\n *\n * @type {boolean}\n */\n #isConstantRSI;\n\n /**\n * Window presets.\n * Minmax will be filled at first use (see view.setWindowLevelPreset).\n *\n * @type {object}\n */\n #windowPresets = {minmax: {name: 'minmax'}};\n\n /**\n * Current window preset name.\n *\n * @type {string}\n */\n #currentPresetName = null;\n\n /**\n * Current window level.\n *\n * @type {WindowLevel}\n */\n #currentWl;\n\n /**\n * Colour map name.\n *\n * @type {string}\n */\n #colourMapName = 'plain';\n\n /**\n * Current position as a Point.\n * Store position and not index to stay geometry independent.\n *\n * @type {Point}\n */\n #currentPosition = null;\n\n /**\n * View orientation. Undefined will use the original slice ordering.\n *\n * @type {Matrix33}\n */\n #orientation;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * @param {Image} image The associated image.\n */\n constructor(image) {\n this.#image = image;\n\n // listen to appendframe event to update the current position\n // to add the extra dimension\n this.#image.addEventListener('appendframe', () => {\n // update current position if first appendFrame\n const index = this.getCurrentIndex();\n if (index.length() === 3) {\n // add dimension\n const values = index.getValues();\n values.push(0);\n this.setCurrentIndex(new Index(values));\n }\n });\n }\n\n /**\n * Get the associated image.\n *\n * @returns {Image} The associated image.\n */\n getImage() {\n return this.#image;\n }\n\n /**\n * Set the associated image.\n *\n * @param {Image} inImage The associated image.\n */\n setImage(inImage) {\n this.#image = inImage;\n }\n\n /**\n * Get the view orientation.\n *\n * @returns {Matrix33} The orientation matrix.\n */\n getOrientation() {\n return this.#orientation;\n }\n\n /**\n * Set the view orientation.\n *\n * @param {Matrix33} mat33 The orientation matrix.\n */\n setOrientation(mat33) {\n this.#orientation = mat33;\n }\n\n /**\n * Initialise the view: set initial index.\n */\n init() {\n this.setInitialIndex();\n }\n\n /**\n * Set the initial index to the middle position.\n */\n setInitialIndex() {\n const geometry = this.#image.getGeometry();\n const size = geometry.getSize();\n const values = new Array(size.length());\n values.fill(0);\n // middle\n values[0] = Math.floor(size.get(0) / 2);\n values[1] = Math.floor(size.get(1) / 2);\n values[2] = Math.floor(size.get(2) / 2);\n this.setCurrentIndex(new Index(values), true);\n }\n\n /**\n * Get the milliseconds per frame from frame rate.\n *\n * @param {number} recommendedDisplayFrameRate Recommended Display Frame Rate.\n * @returns {number} The milliseconds per frame.\n */\n getPlaybackMilliseconds(recommendedDisplayFrameRate) {\n if (!recommendedDisplayFrameRate) {\n // Default to 10 FPS if none is found in the meta\n recommendedDisplayFrameRate = 10;\n }\n // round milliseconds per frame to nearest whole number\n return Math.round(1000 / recommendedDisplayFrameRate);\n }\n\n /**\n * Per value alpha function.\n *\n * @param {number[]|number} _value The pixel value.\n * Can be a number for monochrome data or an array for RGB data.\n * @param {number} _index The index of the value.\n * @returns {number} The coresponding alpha [0,255].\n */\n #alphaFunction = function (_value, _index) {\n // default always returns fully visible\n return 0xff;\n };\n\n /**\n * @callback alphaFn\n * @param {number[]|number} value The pixel value.\n * @param {number} index The values' index.\n * @returns {number} The opacity of the input value.\n */\n\n /**\n * Get the alpha function.\n *\n * @returns {alphaFn} The function.\n */\n getAlphaFunction() {\n return this.#alphaFunction;\n }\n\n /**\n * Set alpha function.\n *\n * @param {alphaFn} func The function.\n * @fires View#alphafuncchange\n */\n setAlphaFunction(func) {\n this.#alphaFunction = func;\n /**\n * Alpha func change event.\n *\n * @event View#alphafuncchange\n * @type {object}\n * @property {string} type The event type.\n */\n this.#fireEvent({\n type: 'alphafuncchange'\n });\n }\n\n /**\n * Get the window LUT of the image.\n * Warning: can be undefined in no window/level was set.\n *\n * @returns {WindowLut} The window LUT of the image.\n * @fires View#wlchange\n */\n #getCurrentWindowLut() {\n // special case for 'perslice' presets\n if (this.#currentPresetName &&\n typeof this.#windowPresets[this.#currentPresetName] !== 'undefined' &&\n typeof this.#windowPresets[this.#currentPresetName].perslice !==\n 'undefined' &&\n this.#windowPresets[this.#currentPresetName].perslice === true) {\n // check position\n if (!this.getCurrentIndex()) {\n this.setInitialIndex();\n }\n // get the slice window level\n const currentIndex = this.getCurrentIndex();\n const offset = this.#image.getSecondaryOffset(currentIndex);\n const currentPreset = this.#windowPresets[this.#currentPresetName];\n const sliceWl = currentPreset.wl[offset];\n // set window level: will send a change event, mark it as silent as\n // this change is always triggered by a position change\n this.setWindowLevel(sliceWl, this.#currentPresetName, true);\n }\n\n // if no current, use first id\n if (typeof this.#currentWl === 'undefined') {\n this.setWindowLevelPresetById(0, true);\n }\n\n // get the window lut\n if (typeof this.#isConstantRSI === 'undefined' ||\n this.#image.isConstantRSI() !== this.#isConstantRSI) {\n this.#isConstantRSI = this.#image.isConstantRSI();\n // set or update windowLut if isConstantRSI has changed\n // (can be different at first slice and after having loaded\n // the full volume...)\n let rsi;\n let isDiscrete;\n if (this.#isConstantRSI) {\n rsi = this.#image.getRescaleSlopeAndIntercept();\n isDiscrete = true;\n } else {\n rsi = new RescaleSlopeAndIntercept(1, 0);\n isDiscrete = false;\n }\n // create the rescale lookup table\n const modalityLut = new ModalityLut(\n rsi,\n this.#image.getMeta().BitsStored);\n // create the window lookup table\n this.#windowLut = new WindowLut(\n modalityLut,\n this.#image.getMeta().IsSigned,\n isDiscrete);\n }\n\n // update VOI lut if not present or its window level\n // is different from the current one\n const voiLut = this.#windowLut.getVoiLut();\n let voiLutWl;\n if (typeof voiLut !== 'undefined') {\n voiLutWl = voiLut.getWindowLevel();\n }\n if (typeof voiLut === 'undefined' ||\n !this.#currentWl.equals(voiLutWl)) {\n // set lut window level\n const voiLut = new VoiLut(this.#currentWl);\n this.#windowLut.setVoiLut(voiLut);\n }\n\n // return\n return this.#windowLut;\n }\n\n /**\n * Get the window presets.\n *\n * @returns {object} The window presets.\n */\n getWindowPresets() {\n return this.#windowPresets;\n }\n\n /**\n * Get the window presets names.\n *\n * @returns {string[]} The list of window presets names.\n */\n getWindowPresetsNames() {\n return Object.keys(this.#windowPresets);\n }\n\n /**\n * Set the window presets.\n *\n * @param {object} presets The window presets.\n */\n setWindowPresets(presets) {\n this.#windowPresets = presets;\n }\n\n /**\n * Add window presets to the existing ones.\n *\n * @param {object} presets The window presets.\n */\n addWindowPresets(presets) {\n const keys = Object.keys(presets);\n let key = null;\n for (let i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (typeof this.#windowPresets[key] !== 'undefined') {\n if (typeof this.#windowPresets[key].perslice !== 'undefined' &&\n this.#windowPresets[key].perslice === true) {\n throw new Error('Cannot add perslice preset');\n } else {\n // update existing\n this.#windowPresets[key] = presets[key];\n }\n } else {\n // add new\n this.#windowPresets[key] = presets[key];\n // fire event\n /**\n * Window/level add preset event.\n *\n * @event View#wlpresetadd\n * @type {object}\n * @property {string} type The event type.\n * @property {string} name The name of the preset.\n */\n this.#fireEvent({\n type: 'wlpresetadd',\n name: key\n });\n }\n }\n }\n\n /**\n * Get the current window level preset name.\n *\n * @returns {string} The preset name.\n */\n getCurrentWindowPresetName() {\n return this.#currentPresetName;\n }\n\n /**\n * Get the colour map of the image.\n *\n * @returns {string} The colour map name.\n */\n getColourMap() {\n return this.#colourMapName;\n }\n\n /**\n * Get the colour map object.\n *\n * @returns {ColourMap} The colour map.\n */\n #getColourMapLut() {\n return luts[this.#colourMapName];\n }\n\n /**\n * Set the colour map of the image.\n *\n * @param {string} name The colour map name.\n * @fires View#colourmapchange\n */\n setColourMap(name) {\n // check if we have it\n if (!luts[name]) {\n throw new Error('Unknown colour map: \\'' + name + '\\'');\n }\n\n this.#colourMapName = name;\n\n /**\n * Color change event.\n *\n * @event View#colourmapchange\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} value The changed value.\n */\n this.#fireEvent({\n type: 'colourmapchange',\n value: [name]\n });\n }\n\n /**\n * Get the current position.\n *\n * @returns {Point} The current position.\n */\n getCurrentPosition() {\n return this.#currentPosition;\n }\n\n /**\n * Get the current index.\n *\n * @returns {Index} The current index.\n */\n getCurrentIndex() {\n const position = this.getCurrentPosition();\n if (!position) {\n return null;\n }\n const geometry = this.getImage().getGeometry();\n return geometry.worldToIndex(position);\n }\n\n /**\n * Get the SOP image UID of the current image.\n *\n * @returns {string} The UID.\n */\n getCurrentImageUid() {\n return this.#image.getImageUid(this.getCurrentIndex());\n }\n\n /**\n * Get the image origin for a image UID.\n *\n * @param {string} uid The UID.\n * @returns {Point3D|undefined} The origin.\n */\n getOriginForImageUid(uid) {\n return this.#image.getOriginForImageUid(uid);\n }\n\n /**\n * Check if the image includes an UID.\n *\n * @param {string} uid The UID.\n * @returns {boolean} True if present.\n */\n includesImageUid(uid) {\n return this.#image.includesImageUid(uid);\n }\n\n /**\n * Check if the current position (default) or\n * the provided position is in bounds.\n *\n * @param {Point} [position] Optional position.\n * @returns {boolean} True is the position is in bounds.\n */\n isPositionInBounds(position) {\n if (typeof position === 'undefined') {\n position = this.#currentPosition;\n }\n const geometry = this.#image.getGeometry();\n const index = geometry.worldToIndex(position);\n const dirs = [this.getScrollIndex()];\n if (index.length() === 4) {\n dirs.push(3);\n }\n return geometry.isIndexInBounds(index, dirs);\n }\n\n /**\n * Get the first origin or at a given position.\n *\n * @param {Point} [position] Optional position.\n * @returns {Point3D} The origin.\n */\n getOrigin(position) {\n const geometry = this.#image.getGeometry();\n let originIndex = 0;\n if (typeof position !== 'undefined') {\n const index = geometry.worldToIndex(position);\n // index is reoriented, 2 is scroll index\n originIndex = index.get(2);\n }\n return geometry.getOrigins()[originIndex];\n }\n\n /**\n * Set the current position.\n *\n * @param {Point} position The new position.\n * @param {boolean} [silent] Flag to fire event or not.\n * @returns {boolean} False if not in bounds.\n * @fires View#positionchange\n */\n setCurrentPosition(position, silent) {\n // send invalid event if not in bounds\n const geometry = this.#image.getGeometry();\n const index = geometry.worldToIndex(position);\n const dirs = [this.getScrollIndex()];\n if (index.length() === 4) {\n dirs.push(3);\n }\n if (!geometry.isIndexInBounds(index, dirs)) {\n if (!silent) {\n this.#currentPosition = position;\n // fire event with valid: false\n this.#fireEvent({\n type: 'positionchange',\n value: [\n index.getValues(),\n position.getValues(),\n ],\n valid: false\n });\n }\n return false;\n }\n return this.setCurrentIndex(index, silent);\n }\n\n /**\n * Set the current index.\n *\n * @param {Index} index The new index.\n * @param {boolean} [silent] Flag to fire event or not.\n * @returns {boolean} False if not in bounds.\n * @fires View#positionchange\n */\n setCurrentIndex(index, silent) {\n // check input\n if (typeof silent === 'undefined') {\n silent = false;\n }\n\n const geometry = this.#image.getGeometry();\n const position = geometry.indexToWorld(index);\n\n // check if possible\n const dirs = [this.getScrollIndex()];\n if (index.length() === 4) {\n dirs.push(3);\n }\n if (!geometry.isIndexInBounds(index, dirs)) {\n if (!silent) {\n this.#currentPosition = position;\n // fire event with valid: false\n this.#fireEvent({\n type: 'positionchange',\n value: [\n index.getValues(),\n position.getValues(),\n ],\n valid: false\n });\n }\n\n // do no send invalid positionchange event: avoid empty repaint\n return false;\n }\n\n // calculate diff dims before updating internal\n let diffDims = null;\n let currentIndex = null;\n if (this.getCurrentPosition()) {\n currentIndex = this.getCurrentIndex();\n }\n if (currentIndex) {\n if (currentIndex.canCompare(index)) {\n diffDims = currentIndex.compare(index);\n } else {\n diffDims = [];\n const minLen = Math.min(currentIndex.length(), index.length());\n for (let i = 0; i < minLen; ++i) {\n if (currentIndex.get(i) !== index.get(i)) {\n diffDims.push(i);\n }\n }\n const maxLen = Math.max(currentIndex.length(), index.length());\n for (let j = minLen; j < maxLen; ++j) {\n diffDims.push(j);\n }\n }\n } else {\n diffDims = [];\n for (let k = 0; k < index.length(); ++k) {\n diffDims.push(k);\n }\n }\n\n // assign\n this.#currentPosition = position;\n\n if (!silent) {\n /**\n * Position change event.\n *\n * @event View#positionchange\n * @type {object}\n * @property {Array} value The changed value as [index, pixelValue].\n * @property {number[]} diffDims An array of modified indices.\n */\n const posEvent = {\n type: 'positionchange',\n value: [\n index.getValues(),\n position.getValues(),\n ],\n diffDims: diffDims,\n data: {\n imageUid: this.#image.getImageUid(index)\n }\n };\n\n // add value if possible\n if (this.#image.canQuantify()) {\n const pixValue = this.#image.getRescaledValueAtIndex(index);\n posEvent.value.push(pixValue);\n }\n\n // fire\n this.#fireEvent(posEvent);\n }\n\n // all good\n return true;\n }\n\n /**\n * Set the view window/level.\n *\n * @param {WindowLevel} wl The window and level.\n * @param {string} [name] Associated preset name, defaults to 'manual'.\n * Warning: uses the latest set rescale LUT or the default linear one.\n * @param {boolean} [silent] Flag to launch events with skipGenerate.\n * @fires View#wlchange\n */\n setWindowLevel(wl, name, silent) {\n // check input\n if (typeof name === 'undefined') {\n name = 'manual';\n }\n if (name !== 'manual' &&\n typeof this.#windowPresets[name] === 'undefined') {\n throw new Error('Unknown window level preset: \\'' + name + '\\'');\n }\n if (typeof silent === 'undefined') {\n silent = false;\n }\n\n // check if new wl\n const isNewWl = !wl.equals(this.#currentWl);\n // check if new name\n const isNewName = this.#currentPresetName !== name;\n\n // compare to previous if present\n if (isNewWl || isNewName) {\n // assign\n this.#currentWl = wl;\n this.#currentPresetName = name;\n\n // update manual\n if (name === 'manual') {\n if (typeof this.#windowPresets[name] !== 'undefined') {\n this.#windowPresets[name].wl[0] = wl;\n } else {\n // add if not present\n this.addWindowPresets({\n manual: {\n wl: [wl],\n name: 'manual'\n }\n });\n }\n }\n\n /**\n * Window/level change event.\n *\n * @event View#wlchange\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} value The changed value.\n * @property {number} wc The new window center value.\n * @property {number} ww The new window wdth value.\n * @property {boolean} skipGenerate Flag to skip view generation.\n */\n this.#fireEvent({\n type: 'wlchange',\n value: [wl.center, wl.width, name],\n wc: wl.center,\n ww: wl.width,\n skipGenerate: silent\n });\n }\n }\n\n /**\n * Get the window/level.\n *\n * @returns {WindowLevel} The window and level.\n */\n getWindowLevel() {\n // same as #currentWl...\n const windowLut = this.#getCurrentWindowLut();\n return windowLut.getVoiLut().getWindowLevel();\n }\n\n /**\n * Set the window level to the preset with the input name.\n *\n * @param {string} name The name of the preset to activate.\n * @param {boolean} [silent] Flag to launch events with skipGenerate.\n */\n setWindowLevelPreset(name, silent) {\n const preset = this.getWindowPresets()[name];\n if (typeof preset === 'undefined') {\n throw new Error('Unknown window level preset: \\'' + name + '\\'');\n }\n // special min/max\n if (name === 'minmax' && typeof preset.wl === 'undefined') {\n preset.wl = [this.getWindowLevelMinMax()];\n }\n // default to first\n let wl = preset.wl[0];\n // check if 'perslice' case\n if (typeof preset.perslice !== 'undefined' &&\n preset.perslice === true) {\n const offset = this.#image.getSecondaryOffset(this.getCurrentIndex());\n wl = preset.wl[offset];\n }\n // set w/l\n this.setWindowLevel(wl, name, silent);\n }\n\n /**\n * Set the window level to the preset with the input id.\n *\n * @param {number} id The id of the preset to activate.\n * @param {boolean} [silent] Flag to launch events with skipGenerate.\n */\n setWindowLevelPresetById(id, silent) {\n const keys = Object.keys(this.getWindowPresets());\n this.setWindowLevelPreset(keys[id], silent);\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n /**\n * Get the image window/level that covers the full data range.\n * Warning: uses the latest set rescale LUT or the default linear one.\n *\n * @returns {WindowLevel} A min/max window level.\n */\n getWindowLevelMinMax() {\n const range = this.getImage().getRescaledDataRange();\n const min = range.min;\n const max = range.max;\n let width = max - min;\n // full black / white images, defaults to 1.\n if (width < 1) {\n logger.warn('Zero or negative window width, defaulting to one.');\n width = 1;\n }\n const center = min + width / 2;\n return new WindowLevel(center, width);\n }\n\n /**\n * Set the image window/level to cover the full data range.\n * Warning: uses the latest set rescale LUT or the default linear one.\n */\n setWindowLevelMinMax() {\n // calculate center and width\n const wl = this.getWindowLevelMinMax();\n // set window level\n this.setWindowLevel(wl, 'minmax');\n }\n\n /**\n * Generate display image data to be given to a canvas.\n *\n * @param {ImageData} data The iamge data to fill in.\n * @param {Index} index Optional index at which to generate,\n * otherwise generates at current index.\n */\n generateImageData(data, index) {\n // check index\n if (typeof index === 'undefined') {\n if (!this.getCurrentIndex()) {\n this.setInitialIndex();\n }\n index = this.getCurrentIndex();\n }\n\n const image = this.getImage();\n const isRescaled = !image.isConstantRSI();\n const iterator = getSliceIterator(\n image, index, isRescaled, this.getOrientation());\n\n const photoInterpretation = image.getPhotometricInterpretation();\n switch (photoInterpretation) {\n case 'MONOCHROME1':\n case 'MONOCHROME2':\n generateImageDataMonochrome(\n data,\n iterator,\n this.getAlphaFunction(),\n this.#getCurrentWindowLut(),\n this.#getColourMapLut()\n );\n break;\n\n case 'PALETTE COLOR':\n generateImageDataPaletteColor(\n data,\n iterator,\n this.getAlphaFunction(),\n image.getPaletteColourMap(),\n image.getMeta().BitsStored === 16\n );\n break;\n\n case 'RGB':\n generateImageDataRgb(\n data,\n iterator,\n this.getAlphaFunction()\n );\n break;\n\n case 'YBR_FULL':\n generateImageDataYbrFull(\n data,\n iterator,\n this.getAlphaFunction()\n );\n break;\n\n default:\n throw new Error(\n 'Unsupported photometric interpretation: ' + photoInterpretation);\n }\n }\n\n /**\n * Get the scroll dimension index.\n *\n * @returns {number} The index.\n */\n getScrollIndex() {\n let index = null;\n const orientation = this.getOrientation();\n if (typeof orientation !== 'undefined') {\n index = orientation.getThirdColMajorDirection();\n } else {\n index = 2;\n }\n return index;\n }\n\n /**\n * Is this view in the same orientation as the image aquisition.\n *\n * @returns {boolean} True if in aquisition plane.\n */\n isAquisitionOrientation() {\n return isIdentityMat33(this.#orientation);\n }\n\n} // class View\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {WindowLut} from './windowLut';\nimport {ColourMap} from './luts';\n/* eslint-enable no-unused-vars */\n\n/**\n * Generate image data for 'MONOCHROME*' photometric interpretation.\n *\n * @param {ImageData} array The array to store the outut data.\n * @param {object} iterator Position iterator.\n * @param {Function} alphaFunc The alpha function.\n * @param {WindowLut} windowLut The window/level LUT.\n * @param {ColourMap} colourMap The colour map.\n */\nexport function generateImageDataMonochrome(\n array,\n iterator,\n alphaFunc,\n windowLut,\n colourMap) {\n let index = 0;\n let pxValue = 0;\n let ival = iterator.next();\n while (!ival.done) {\n // pixel value\n pxValue = windowLut.getValue(ival.value);\n // store data\n array.data[index] = colourMap.red[pxValue];\n array.data[index + 1] = colourMap.green[pxValue];\n array.data[index + 2] = colourMap.blue[pxValue];\n array.data[index + 3] = alphaFunc(ival.value, ival.index);\n // increment\n index += 4;\n ival = iterator.next();\n }\n}\n","import {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {ColourMap} from './luts';\n/* eslint-enable no-unused-vars */\n\n/**\n * Generate image data for 'PALETTE COLOR' photometric interpretation.\n *\n * @param {ImageData} array The array to store the outut data.\n * @param {object} iterator Position iterator.\n * @param {Function} alphaFunc The alpha function.\n * @param {ColourMap} colourMap The colour map.\n * @param {boolean} is16BitsStored Flag to know if the data is 16bits.\n */\nexport function generateImageDataPaletteColor(\n array,\n iterator,\n alphaFunc,\n colourMap,\n is16BitsStored) {\n // right shift 8\n const to8 = function (value) {\n return value >> 8;\n };\n\n if (is16BitsStored) {\n logger.info('Scaling 16bits data to 8bits.');\n }\n\n let index = 0;\n let pxValue = 0;\n let ival = iterator.next();\n while (!ival.done) {\n // pixel value\n pxValue = ival.value;\n // store data\n // TODO check pxValue fits in lut\n if (is16BitsStored) {\n array.data[index] = to8(colourMap.red[pxValue]);\n array.data[index + 1] = to8(colourMap.green[pxValue]);\n array.data[index + 2] = to8(colourMap.blue[pxValue]);\n } else {\n array.data[index] = colourMap.red[pxValue];\n array.data[index + 1] = colourMap.green[pxValue];\n array.data[index + 2] = colourMap.blue[pxValue];\n }\n array.data[index + 3] = alphaFunc(pxValue, ival.index);\n // increment\n index += 4;\n ival = iterator.next();\n }\n}\n","/**\n * Generate image data for 'RGB' photometric interpretation.\n *\n * @param {ImageData} array The array to store the outut data.\n * @param {object} iterator Position iterator.\n * @param {Function} alphaFunc The alpha function.\n */\nexport function generateImageDataRgb(\n array,\n iterator,\n alphaFunc) {\n let index = 0;\n let ival = iterator.next();\n while (!ival.done) {\n // store data\n array.data[index] = ival.value[0];\n array.data[index + 1] = ival.value[1];\n array.data[index + 2] = ival.value[2];\n array.data[index + 3] = alphaFunc(ival.value, ival.index);\n // increment\n index += 4;\n ival = iterator.next();\n }\n}\n","import {ybrToRgb} from '../utils/colour';\n\n/**\n * Generate image data for 'YBR_FULL' photometric interpretation.\n *\n * @param {ImageData} array The array to store the outut data.\n * @param {object} iterator Position iterator.\n * @param {Function} alphaFunc The alpha function.\n */\nexport function generateImageDataYbrFull(\n array,\n iterator,\n alphaFunc) {\n let index = 0;\n let rgb = null;\n let ival = iterator.next();\n while (!ival.done) {\n // convert ybr to rgb\n rgb = ybrToRgb(ival.value[0], ival.value[1], ival.value[2]);\n // store data\n array.data[index] = rgb.r;\n array.data[index + 1] = rgb.g;\n array.data[index + 2] = rgb.b;\n array.data[index + 3] = alphaFunc(ival.value, ival.index);\n // increment\n index += 4;\n ival = iterator.next();\n }\n}\n","import {Vector3D} from '../math/vector';\nimport {Point3D, Point2D} from '../math/point';\nimport {isIdentityMat33} from '../math/matrix';\nimport {\n getCosinesFromOrientation,\n getTargetOrientation\n} from '../math/orientation';\nimport {getOrientedArray3D, getDeOrientedArray3D} from './geometry';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point} from '../math/point';\nimport {Index} from '../math/index';\nimport {Geometry} from '../image/geometry';\nimport {Matrix33} from '../math/matrix';\nimport {Spacing} from './spacing';\nimport {Scalar2D, Scalar3D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Plane geometry helper.\n */\nexport class PlaneHelper {\n\n /**\n * The image geometry.\n *\n * @type {Geometry}\n */\n #imageGeometry;\n\n /**\n * The associated spacing.\n *\n * @type {Spacing}\n */\n #spacing;\n\n /**\n * The image orientation.\n *\n * @type {Matrix33}\n */\n #imageOrientation;\n\n /**\n * The viewe orientation.\n *\n * @type {Matrix33}\n */\n #viewOrientation;\n\n /**\n * The target orientation.\n *\n * @type {Matrix33}\n */\n #targetOrientation;\n\n /**\n * @param {Geometry} imageGeometry The image geometry.\n * @param {Matrix33} viewOrientation The view orientation.\n */\n constructor(imageGeometry, viewOrientation) {\n this.#imageGeometry = imageGeometry;\n this.#spacing = imageGeometry.getRealSpacing();\n this.#imageOrientation = imageGeometry.getOrientation();\n this.#viewOrientation = viewOrientation;\n\n this.#targetOrientation = getTargetOrientation(\n this.#imageOrientation, viewOrientation);\n }\n\n /**\n * Get the view orientation.\n *\n * @returns {Matrix33} The orientation matrix.\n */\n getViewOrientation() {\n return this.#viewOrientation;\n }\n\n /**\n * Get the target orientation.\n *\n * @returns {Matrix33} The orientation matrix.\n */\n getTargetOrientation() {\n return this.#targetOrientation;\n }\n\n /**\n * Get a 3D offset from a plane one.\n *\n * @param {Scalar2D} offset2D The plane offset as {x,y}.\n * @returns {Vector3D} The 3D world offset.\n */\n getOffset3DFromPlaneOffset(offset2D) {\n // make 3D\n const planeOffset = new Vector3D(\n offset2D.x, offset2D.y, 0);\n // de-orient\n const pixelOffset = this.getTargetDeOrientedVector3D(planeOffset);\n // ~indexToWorld\n return new Vector3D(\n pixelOffset.getX() * this.#spacing.get(0),\n pixelOffset.getY() * this.#spacing.get(1),\n pixelOffset.getZ() * this.#spacing.get(2));\n }\n\n /**\n * Get a plane offset from a 3D one.\n *\n * @param {Scalar3D} offset3D The 3D offset as {x,y,z}.\n * @returns {Scalar2D} The plane offset as {x,y}.\n */\n getPlaneOffsetFromOffset3D(offset3D) {\n // ~worldToIndex\n const pixelOffset = new Vector3D(\n offset3D.x / this.#spacing.get(0),\n offset3D.y / this.#spacing.get(1),\n offset3D.z / this.#spacing.get(2));\n // orient\n const planeOffset = this.getTargetOrientedVector3D(pixelOffset);\n // make 2D\n return {\n x: planeOffset.getX(),\n y: planeOffset.getY()\n };\n }\n\n /**\n * Orient an input vector from real to target space.\n *\n * @param {Vector3D} vector The input vector.\n * @returns {Vector3D} The oriented vector.\n */\n getTargetOrientedVector3D(vector) {\n let planeVector = vector;\n if (typeof this.#targetOrientation !== 'undefined') {\n planeVector =\n this.#targetOrientation.getInverse().multiplyVector3D(vector);\n }\n return planeVector;\n }\n\n /**\n * De-orient an input vector from target to real space.\n *\n * @param {Vector3D} planeVector The input vector.\n * @returns {Vector3D} The de-orienteded vector.\n */\n getTargetDeOrientedVector3D(planeVector) {\n let vector = planeVector;\n if (typeof this.#targetOrientation !== 'undefined') {\n vector = this.#targetOrientation.multiplyVector3D(planeVector);\n }\n return vector;\n }\n\n /**\n * De-orient an input point from target to real space.\n *\n * @param {Point3D} planePoint The input point.\n * @returns {Point3D} The de-orienteded point.\n */\n getTargetDeOrientedPoint3D(planePoint) {\n let point = planePoint;\n if (typeof this.#targetOrientation !== 'undefined') {\n point = this.#targetOrientation.multiplyPoint3D(planePoint);\n }\n return point;\n }\n\n /**\n * Orient an input vector from target to image space.\n *\n * @param {Vector3D} planeVector The input vector.\n * @returns {Vector3D} The orienteded vector.\n */\n getImageOrientedVector3D(planeVector) {\n let vector = planeVector;\n if (typeof this.#viewOrientation !== 'undefined') {\n // image oriented => view de-oriented\n const values = getDeOrientedArray3D(\n [\n planeVector.getX(),\n planeVector.getY(),\n planeVector.getZ()\n ],\n this.#viewOrientation);\n vector = new Vector3D(\n values[0],\n values[1],\n values[2]\n );\n }\n return vector;\n }\n\n /**\n * Orient an input point from target to image space.\n *\n * @param {Point3D} planePoint The input vector.\n * @returns {Point3D} The orienteded vector.\n */\n getImageOrientedPoint3D(planePoint) {\n let point = planePoint;\n if (typeof this.#viewOrientation !== 'undefined') {\n // image oriented => view de-oriented\n const values = getDeOrientedArray3D(\n [\n planePoint.getX(),\n planePoint.getY(),\n planePoint.getZ()\n ],\n this.#viewOrientation);\n point = new Point3D(\n values[0],\n values[1],\n values[2]\n );\n }\n return point;\n }\n\n /**\n * De-orient an input vector from image to target space.\n *\n * @param {Vector3D} vector The input vector.\n * @returns {Vector3D} The de-orienteded vector.\n */\n getImageDeOrientedVector3D(vector) {\n let planeVector = vector;\n if (typeof this.#viewOrientation !== 'undefined') {\n // image de-oriented => view oriented\n const orientedValues = getOrientedArray3D(\n [\n vector.getX(),\n vector.getY(),\n vector.getZ()\n ],\n this.#viewOrientation);\n planeVector = new Vector3D(\n orientedValues[0],\n orientedValues[1],\n orientedValues[2]\n );\n }\n return planeVector;\n }\n\n /**\n * De-orient an input point from image to target space.\n *\n * @param {Point3D} point The input point.\n * @returns {Point3D} The de-orienteded point.\n */\n getImageDeOrientedPoint3D(point) {\n let planePoint = point;\n if (typeof this.#viewOrientation !== 'undefined') {\n // image de-oriented => view oriented\n const orientedValues = getOrientedArray3D(\n [\n point.getX(),\n point.getY(),\n point.getZ()\n ],\n this.#viewOrientation);\n planePoint = new Point3D(\n orientedValues[0],\n orientedValues[1],\n orientedValues[2]\n );\n }\n return planePoint;\n }\n\n /**\n * Get a world position from a 2D plane position.\n *\n * @param {Point2D} point2D The plane point.\n * @param {number} k The slice index.\n * @returns {Point3D} The world position.\n */\n getPositionFromPlanePoint(point2D, k) {\n const planePoint = new Point3D(point2D.getX(), point2D.getY(), k);\n // de-orient\n const point = this.getImageOrientedPoint3D(planePoint);\n // ~indexToWorld to not loose precision\n return this.#imageGeometry.pointToWorld(point);\n }\n\n /**\n * Get a 2D plane position from a world position.\n *\n * @param {Point} point The world position.\n * @returns {Point3D} The plane point.\n */\n getPlanePointFromPosition(point) {\n const point3D = this.#imageGeometry.worldToPoint(point);\n return this.getImageDeOrientedPoint3D(point3D);\n }\n\n /**\n * Get the cosines of this plane.\n *\n * @returns {number[]} The 2 cosines vectors (3D).\n */\n getCosines() {\n return getCosinesFromOrientation(this.#targetOrientation);\n }\n\n /**\n * Get a list of points that define the plane at input position,\n * given this classes orientation.\n *\n * @param {Point} position The position.\n * @returns {Point3D[]} An origin and 2 cosines vectors.\n */\n getPlanePoints(position) {\n // get plane point\n const planePoint = this.getPlanePointFromPosition(position);\n // get origin\n const planeOrigin = this.getPositionFromPlanePoint(\n new Point2D(0, 0), planePoint.getZ());\n\n // plane cosines\n const cosines = this.getCosines();\n\n return [\n planeOrigin,\n new Point3D(cosines[0], cosines[1], cosines[2]),\n new Point3D(cosines[3], cosines[4], cosines[5])\n ];\n }\n\n /**\n * Image world to index.\n *\n * @param {Point} point The input point.\n * @returns {Index} The corresponding index.\n */\n worldToIndex(point) {\n return this.#imageGeometry.worldToIndex(point);\n }\n\n /**\n * Is this view in the same orientation as the image aquisition.\n *\n * @returns {boolean} True if in aquisition plane.\n */\n isAquisitionOrientation() {\n return isIdentityMat33(this.#viewOrientation);\n }\n\n /**\n * Reorder values to follow target orientation.\n *\n * @param {Scalar3D} values Values as {x,y,z}.\n * @returns {Scalar3D} Reoriented values as {x,y,z}.\n */\n getTargetOrientedPositiveXYZ(values) {\n const orientedValues = getOrientedArray3D(\n [\n values.x,\n values.y,\n values.z\n ],\n this.#targetOrientation);\n return {\n x: orientedValues[0],\n y: orientedValues[1],\n z: orientedValues[2]\n };\n }\n\n /**\n * Get the (view) scroll dimension index.\n *\n * @returns {number} The index.\n */\n getScrollIndex() {\n let index = null;\n if (typeof this.#viewOrientation !== 'undefined') {\n index = this.#viewOrientation.getThirdColMajorDirection();\n } else {\n index = 2;\n }\n return index;\n }\n\n /**\n * Get the native (image) scroll dimension index.\n *\n * @returns {number} The index.\n */\n getNativeScrollIndex() {\n let index = null;\n if (typeof this.#imageOrientation !== 'undefined') {\n index = this.#imageOrientation.getThirdColMajorDirection();\n } else {\n index = 2;\n }\n return index;\n }\n\n} // class PlaneHelper\n","import {Index} from '../math/index';\nimport {Vector3D} from '../math/vector';\nimport {Point3D} from '../math/point';\nimport {isIdentityMat33} from '../math/matrix';\nimport {Size} from '../image/size';\nimport {Spacing} from '../image/spacing';\nimport {Image} from '../image/image';\nimport {Geometry} from '../image/geometry';\nimport {PlaneHelper} from '../image/planeHelper';\nimport {\n getSliceIterator,\n getIteratorValues,\n getRegionSliceIterator,\n getVariableRegionSliceIterator\n} from '../image/iterator';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {View} from '../image/view';\nimport {WindowLevel} from '../image/windowLevel';\nimport {Point, Point2D} from '../math/point';\nimport {Scalar2D} from '../math/scalar';\nimport {Matrix33} from '../math/matrix';\nimport {ViewLayer} from '../gui/viewLayer';\n/* eslint-enable no-unused-vars */\n\n/**\n * View controller.\n */\nexport class ViewController {\n\n /**\n * Associated View.\n *\n * @type {View}\n */\n #view;\n\n /**\n * Plane helper.\n *\n * @type {PlaneHelper}\n */\n #planeHelper;\n\n /**\n * Third dimension player ID (created by setInterval).\n *\n * @type {number|undefined}\n */\n #playerID;\n\n /**\n * Is DICOM seg mask flag.\n *\n * @type {boolean}\n */\n #isMask = false;\n\n /**\n * @param {View} view The associated view.\n */\n constructor(view) {\n // check view\n if (typeof view.getImage() === 'undefined') {\n throw new Error('View does not have an image, cannot setup controller');\n }\n\n this.#view = view;\n\n // setup the plane helper\n this.#planeHelper = new PlaneHelper(\n view.getImage().getGeometry(),\n view.getOrientation()\n );\n\n // mask segment helper\n if (view.getImage().getMeta().Modality === 'SEG') {\n this.#isMask = true;\n }\n }\n\n /**\n * Get the plane helper.\n *\n * @returns {PlaneHelper} The helper.\n */\n getPlaneHelper() {\n return this.#planeHelper;\n }\n\n /**\n * Check is the associated image is a mask.\n *\n * @returns {boolean} True if the associated image is a mask.\n */\n isMask() {\n return this.#isMask;\n }\n\n /**\n * Initialise the controller.\n */\n initialise() {\n // set window/level to first preset\n this.setWindowLevelPresetById(0);\n // default position\n this.setCurrentPosition(this.getPositionFromPlanePoint(\n new Point2D(0, 0)\n ));\n }\n\n /**\n * Get the image modality.\n *\n * @returns {string} The modality.\n */\n getModality() {\n return this.#view.getImage().getMeta().Modality;\n }\n\n /**\n * Get the window/level presets names.\n *\n * @returns {string[]} The presets names.\n */\n getWindowLevelPresetsNames() {\n return this.#view.getWindowPresetsNames();\n }\n\n /**\n * Add window/level presets to the view.\n *\n * @param {object} presets A preset object.\n * @returns {object} The list of presets.\n */\n addWindowLevelPresets(presets) {\n return this.#view.addWindowPresets(presets);\n }\n\n /**\n * Set the window level to the preset with the input name.\n *\n * @param {string} name The name of the preset to activate.\n */\n setWindowLevelPreset(name) {\n this.#view.setWindowLevelPreset(name);\n }\n\n /**\n * Set the window level to the preset with the input id.\n *\n * @param {number} id The id of the preset to activate.\n */\n setWindowLevelPresetById(id) {\n this.#view.setWindowLevelPresetById(id);\n }\n\n /**\n * Check if the controller is playing.\n *\n * @returns {boolean} True if the controler is playing.\n */\n isPlaying() {\n return (typeof this.#playerID !== 'undefined');\n }\n\n /**\n * Get the current position.\n *\n * @returns {Point} The position.\n */\n getCurrentPosition() {\n return this.#view.getCurrentPosition();\n }\n\n /**\n * Get the current index.\n *\n * @returns {Index} The current index.\n */\n getCurrentIndex() {\n return this.#view.getCurrentIndex();\n }\n\n /**\n * Get the SOP image UID of the current image.\n *\n * @returns {string} The UID.\n */\n getCurrentImageUid() {\n return this.#view.getCurrentImageUid();\n }\n\n /**\n * Get the image origin for a image UID.\n *\n * @param {string} uid The UID.\n * @returns {Point3D|undefined} The origin.\n */\n getOriginForImageUid(uid) {\n return this.#view.getOriginForImageUid(uid);\n }\n\n /**\n * Check if the image includes an UID.\n *\n * @param {string} uid The UID.\n * @returns {boolean} True if present.\n */\n includesImageUid(uid) {\n return this.#view.includesImageUid(uid);\n }\n\n /**\n * Get the current oriented index.\n *\n * @returns {Index} The index.\n */\n getCurrentOrientedIndex() {\n let res = this.#view.getCurrentIndex();\n if (typeof this.#view.getOrientation() !== 'undefined') {\n // view oriented => image de-oriented\n const vector = this.#planeHelper.getImageDeOrientedVector3D(\n new Vector3D(res.get(0), res.get(1), res.get(2))\n );\n res = new Index([\n vector.getX(), vector.getY(), vector.getZ()\n ]);\n }\n return res;\n }\n\n /**\n * Get the scroll index.\n *\n * @returns {number} The index.\n */\n getScrollIndex() {\n return this.#view.getScrollIndex();\n }\n\n /**\n * Get the current scroll index value.\n *\n * @returns {object} The value.\n */\n getCurrentScrollIndexValue() {\n return this.#view.getCurrentIndex().get(this.#view.getScrollIndex());\n }\n\n /**\n * Get the first origin or at a given position.\n *\n * @param {Point} [position] Optional position.\n * @returns {Point3D} The origin.\n */\n getOrigin(position) {\n return this.#view.getOrigin(position);\n }\n\n /**\n * Is this view in the same orientation as the image aquisition.\n *\n * @returns {boolean} True if in aquisition plane.\n */\n isAquisitionOrientation() {\n return this.#view.isAquisitionOrientation();\n }\n\n /**\n * Get a list of points that define the plane at input position,\n * given this classes orientation.\n *\n * @param {Point} position The position.\n * @returns {Point3D[]} An origin and 2 cosines vectors.\n */\n getPlanePoints(position) {\n return this.#planeHelper.getPlanePoints(position);\n }\n\n /**\n * Get the current scroll position value.\n *\n * @returns {number} The value.\n */\n getCurrentScrollPosition() {\n const scrollIndex = this.#view.getScrollIndex();\n return this.#view.getCurrentPosition().get(scrollIndex);\n }\n\n /**\n * Generate display image data to be given to a canvas.\n *\n * @param {ImageData} array The array to fill in.\n * @param {Index} [index] Optional index at which to generate,\n * otherwise generates at current index.\n */\n generateImageData(array, index) {\n this.#view.generateImageData(array, index);\n }\n\n /**\n * Set the associated image.\n *\n * @param {Image} img The associated image.\n */\n setImage(img) {\n this.#view.setImage(img);\n }\n\n /**\n * Get the current view (2D) spacing.\n *\n * @returns {Scalar2D} The spacing as a 2D array.\n */\n get2DSpacing() {\n const spacing = this.#view.getImage().getGeometry().getSpacing(\n this.#view.getOrientation());\n return spacing.get2D();\n }\n\n /**\n * Get the image rescaled value at the input position.\n *\n * @param {Point} position The input position.\n * @returns {number|undefined} The image value or undefined if out of bounds\n * or no quantifiable (for ex RGB).\n */\n getRescaledImageValue(position) {\n const image = this.#view.getImage();\n if (!image.canQuantify()) {\n return;\n }\n const geometry = image.getGeometry();\n const index = geometry.worldToIndex(position);\n let value;\n if (geometry.isIndexInBounds(index)) {\n value = image.getRescaledValueAtIndex(index);\n }\n return value;\n }\n\n /**\n * Get the image pixel unit.\n *\n * @returns {string} The unit.\n */\n getPixelUnit() {\n return this.#view.getImage().getMeta().pixelUnit;\n }\n\n /**\n * Extract a slice from an image at the given index and orientation.\n *\n * @param {Image} image The image to parse.\n * @param {Index} index The current index.\n * @param {boolean} isRescaled Flag for rescaled values (default false).\n * @param {Matrix33} orientation The desired orientation.\n * @returns {Image} The extracted slice.\n */\n #getSlice(image, index, isRescaled, orientation) {\n // generate slice values\n const sliceIter = getSliceIterator(\n image,\n index,\n isRescaled,\n orientation\n );\n const sliceValues = getIteratorValues(sliceIter);\n // oriented geometry\n const orientedSize = image.getGeometry().getSize(orientation);\n const sizeValues = orientedSize.getValues();\n sizeValues[2] = 1;\n const sliceSize = new Size(sizeValues);\n const orientedSpacing = image.getGeometry().getSpacing(orientation);\n const spacingValues = orientedSpacing.getValues();\n spacingValues[2] = 1;\n const sliceSpacing = new Spacing(spacingValues);\n const sliceOrigin = new Point3D(0, 0, 0);\n const sliceGeometry =\n new Geometry(sliceOrigin, sliceSize, sliceSpacing);\n // slice image\n // @ts-ignore\n return new Image(sliceGeometry, sliceValues);\n }\n\n /**\n * Get some values from the associated image in a region.\n *\n * @param {Point2D} min Minimum point.\n * @param {Point2D} max Maximum point.\n * @returns {Array} A list of values.\n */\n getImageRegionValues(min, max) {\n let image = this.#view.getImage();\n const orientation = this.#view.getOrientation();\n let currentIndex = this.getCurrentIndex();\n let rescaled = true;\n\n // create oriented slice if needed\n if (!isIdentityMat33(orientation)) {\n image = this.#getSlice(image, currentIndex, rescaled, orientation);\n // update position\n currentIndex = new Index([0, 0, 0]);\n rescaled = false;\n }\n\n // get region values\n const iter = getRegionSliceIterator(\n image, currentIndex, rescaled, min, max);\n let values = [];\n if (iter) {\n values = getIteratorValues(iter);\n }\n return values;\n }\n\n /**\n * Get some values from the associated image in variable regions.\n *\n * @param {number[][][]} regions A list of [x, y] pairs (min, max).\n * @returns {Array} A list of values.\n */\n getImageVariableRegionValues(regions) {\n let image = this.#view.getImage();\n const orientation = this.#view.getOrientation();\n let currentIndex = this.getCurrentIndex();\n let rescaled = true;\n\n // create oriented slice if needed\n if (!isIdentityMat33(orientation)) {\n image = this.#getSlice(image, currentIndex, rescaled, orientation);\n // update position\n currentIndex = new Index([0, 0, 0]);\n rescaled = false;\n }\n\n // get region values\n const iter = getVariableRegionSliceIterator(\n image, currentIndex, rescaled, regions);\n let values = [];\n if (iter) {\n values = getIteratorValues(iter);\n }\n return values;\n }\n\n /**\n * Can the image values be quantified?\n *\n * @returns {boolean} True if possible.\n */\n canQuantifyImage() {\n return this.#view.getImage().canQuantify();\n }\n\n /**\n * Can window and level be applied to the data?\n *\n * @returns {boolean} True if possible.\n * @deprecated Since v0.33, please use isMonochrome instead.\n */\n canWindowLevel() {\n return this.isMonochrome();\n }\n\n /**\n * Is the data monochrome.\n *\n * @returns {boolean} True if the data is monochrome.\n */\n isMonochrome() {\n return this.#view.getImage().isMonochrome();\n }\n\n /**\n * Can the data be scrolled?\n *\n * @returns {boolean} True if the data has either the third dimension\n * or above greater than one.\n */\n canScroll() {\n return this.#view.getImage().canScroll(this.#view.getOrientation());\n }\n\n /**\n * Get the oriented image size.\n *\n * @returns {Size} The size.\n */\n getImageSize() {\n return this.#view.getImage().getGeometry().getSize(\n this.#view.getOrientation());\n }\n\n\n /**\n * Is the data size larger than one in the given dimension?\n *\n * @param {number} dim The dimension.\n * @returns {boolean} True if the image size is larger than one\n * in the given dimension.\n */\n moreThanOne(dim) {\n return this.getImageSize().moreThanOne(dim);\n }\n\n /**\n * Get the image world (mm) 2D size.\n *\n * @returns {Scalar2D} The 2D size as {x,y}.\n */\n getImageWorldSize() {\n const geometry = this.#view.getImage().getGeometry();\n const size = geometry.getSize(this.#view.getOrientation()).get2D();\n const spacing = geometry.getSpacing(this.#view.getOrientation()).get2D();\n return {\n x: size.x * spacing.x,\n y: size.y * spacing.y\n };\n }\n\n /**\n * Get the image rescaled data range.\n *\n * @returns {object} The range as {min, max}.\n */\n getImageRescaledDataRange() {\n return this.#view.getImage().getRescaledDataRange();\n }\n\n /**\n * Compare the input meta data to the associated image one.\n *\n * @param {object} meta The meta data.\n * @returns {boolean} True if the associated image has equal meta data.\n */\n equalImageMeta(meta) {\n const imageMeta = this.#view.getImage().getMeta();\n // loop through input meta keys\n const metaKeys = Object.keys(meta);\n for (let i = 0; i < metaKeys.length; ++i) {\n const metaKey = metaKeys[i];\n if (typeof imageMeta[metaKey] === 'undefined') {\n return false;\n }\n if (imageMeta[metaKey] !== meta[metaKey]) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Check if the current position (default) or\n * the provided position is in bounds.\n *\n * @param {Point} [position] Optional position.\n * @returns {boolean} True is the position is in bounds.\n */\n isPositionInBounds(position) {\n return this.#view.isPositionInBounds(position);\n }\n\n /**\n * Set the current position.\n *\n * @param {Point} pos The position.\n * @param {boolean} [silent] If true, does not fire a\n * positionchange event.\n * @returns {boolean} False if not in bounds.\n */\n setCurrentPosition(pos, silent) {\n return this.#view.setCurrentPosition(pos, silent);\n }\n\n /**\n * Get a world position from a 2D plane position.\n *\n * @param {Point2D} point2D The input point.\n * @param {number} [k] Optional slice index,\n * if undefined, uses the current one.\n * @returns {Point} The associated position.\n */\n getPositionFromPlanePoint(point2D, k) {\n // keep third direction\n if (typeof k === 'undefined') {\n k = this.getCurrentScrollIndexValue();\n }\n const planePoint = new Point3D(point2D.getX(), point2D.getY(), k);\n // de-orient\n const point = this.#planeHelper.getImageOrientedPoint3D(planePoint);\n // ~indexToWorld to not loose precision\n const geometry = this.#view.getImage().getGeometry();\n const point3D = geometry.pointToWorld(point);\n // merge with current position to keep extra dimensions\n return this.getCurrentPosition().mergeWith3D(point3D);\n }\n\n /**\n * Get a 2D plane position from a world position.\n *\n * @param {Point} point The 3D position.\n * @returns {Point2D} The 2D position.\n */\n getPlanePositionFromPosition(point) {\n // orient\n const geometry = this.#view.getImage().getGeometry();\n // ~worldToIndex to not loose precision\n const point3D = geometry.worldToPoint(point);\n const planePoint = this.#planeHelper.getImageDeOrientedPoint3D(point3D);\n // return\n return new Point2D(\n planePoint.getX(),\n planePoint.getY(),\n );\n }\n\n /**\n * Get the index of a world position.\n *\n * @param {Point} point The 3D position.\n * @returns {Index} The index.\n */\n getIndexFromPosition(point) {\n // orient\n const geometry = this.#view.getImage().getGeometry();\n // ~worldToIndex to not loose precision\n return geometry.worldToIndex(point);\n }\n\n /**\n * Set the current index.\n *\n * @param {Index} index The index.\n * @param {boolean} [silent] If true, does not fire a positionchange event.\n * @returns {boolean} False if not in bounds.\n */\n setCurrentIndex(index, silent) {\n return this.#view.setCurrentIndex(index, silent);\n }\n\n /**\n * Get a plane 3D position from a plane 2D position: does not compensate\n * for the image origin. Needed for setting the scale center...\n *\n * @param {Point2D} point2D The 2D position.\n * @returns {Point3D} The 3D point.\n */\n getPlanePositionFromPlanePoint(point2D) {\n // keep third direction\n const k = this.getCurrentScrollIndexValue();\n const planePoint = new Point3D(point2D.getX(), point2D.getY(), k);\n // de-orient\n const point = this.#planeHelper.getTargetDeOrientedPoint3D(planePoint);\n // ~indexToWorld to not loose precision\n const geometry = this.#view.getImage().getGeometry();\n const spacing = geometry.getRealSpacing();\n return new Point3D(\n point.getX() * spacing.get(0),\n point.getY() * spacing.get(1),\n point.getZ() * spacing.get(2));\n }\n\n /**\n * Get a 3D offset from a plane one.\n *\n * @param {Scalar2D} offset2D The plane offset as {x,y}.\n * @returns {Vector3D} The 3D world offset.\n */\n getOffset3DFromPlaneOffset(offset2D) {\n return this.#planeHelper.getOffset3DFromPlaneOffset(offset2D);\n }\n\n /**\n * Get the current index incremented in the input direction.\n *\n * @param {number} dim The direction in which to increment.\n * @returns {Index} The resulting index.\n */\n #getIncrementIndex(dim) {\n const index = this.getCurrentIndex();\n const values = new Array(index.length());\n values.fill(0);\n if (dim < values.length) {\n values[dim] = 1;\n } else {\n console.warn('Cannot increment given index: ', dim, values.length);\n }\n const incr = new Index(values);\n return index.add(incr);\n }\n\n /**\n * Get the current index decremented in the input direction.\n *\n * @param {number} dim The direction in which to decrement.\n * @returns {Index} The resulting index.\n */\n #getDecrementIndex(dim) {\n const index = this.getCurrentIndex();\n const values = new Array(index.length());\n values.fill(0);\n if (dim < values.length) {\n values[dim] = -1;\n } else {\n console.warn('Cannot decrement given index: ', dim, values.length);\n }\n const incr = new Index(values);\n return index.add(incr);\n }\n\n /**\n * Get the current index incremented in the scroll direction.\n *\n * @returns {Index} The resulting index.\n */\n #getIncrementScrollIndex() {\n return this.#getIncrementIndex(this.getScrollIndex());\n }\n\n /**\n * Get the current index decremented in the scroll direction.\n *\n * @returns {Index} The resulting index.\n */\n #getDecrementScrollIndex() {\n return this.#getDecrementIndex(this.getScrollIndex());\n }\n\n /**\n * Get the current position incremented in the input direction.\n *\n * @param {number} dim The direction in which to increment.\n * @returns {Point} The resulting point.\n */\n getIncrementPosition(dim) {\n const geometry = this.#view.getImage().getGeometry();\n return geometry.indexToWorld(this.#getIncrementIndex(dim));\n }\n\n /**\n * Get the current position decremented in the input direction.\n *\n * @param {number} dim The direction in which to decrement.\n * @returns {Point} The resulting point.\n */\n getDecrementPosition(dim) {\n const geometry = this.#view.getImage().getGeometry();\n return geometry.indexToWorld(this.#getDecrementIndex(dim));\n }\n\n /**\n * Get the current position decremented in the scroll direction.\n *\n * @returns {Point} The resulting point.\n */\n getIncrementScrollPosition() {\n const geometry = this.#view.getImage().getGeometry();\n return geometry.indexToWorld(this.#getIncrementScrollIndex());\n }\n\n /**\n * Get the current position decremented in the scroll direction.\n *\n * @returns {Point} The resulting point.\n */\n getDecrementScrollPosition() {\n const geometry = this.#view.getImage().getGeometry();\n return geometry.indexToWorld(this.#getDecrementScrollIndex());\n }\n\n /**\n * Increment the provided dimension.\n *\n * @param {number} dim The dimension to increment.\n * @param {boolean} [silent] Do not send event.\n * @returns {boolean} False if not in bounds.\n */\n incrementIndex(dim, silent) {\n return this.setCurrentIndex(this.#getIncrementIndex(dim), silent);\n }\n\n /**\n * Decrement the provided dimension.\n *\n * @param {number} dim The dimension to increment.\n * @param {boolean} [silent] Do not send event.\n * @returns {boolean} False if not in bounds.\n */\n decrementIndex(dim, silent) {\n return this.setCurrentIndex(this.#getDecrementIndex(dim), silent);\n }\n\n /**\n * Decrement the scroll dimension index.\n *\n * @param {boolean} [silent] Do not send event.\n * @returns {boolean} False if not in bounds.\n */\n decrementScrollIndex(silent) {\n return this.setCurrentIndex(this.#getDecrementScrollIndex(), silent);\n }\n\n /**\n * Increment the scroll dimension index.\n *\n * @param {boolean} [silent] Do not send event.\n * @returns {boolean} False if not in bounds.\n */\n incrementScrollIndex(silent) {\n return this.setCurrentIndex(this.#getIncrementScrollIndex(), silent);\n }\n\n /**\n * Scroll play: loop through all slices.\n */\n play() {\n // ensure data is scrollable: dim >= 3\n if (!this.canScroll()) {\n return;\n }\n if (typeof this.#playerID === 'undefined') {\n const image = this.#view.getImage();\n const recommendedDisplayFrameRate =\n image.getMeta().RecommendedDisplayFrameRate;\n const milliseconds = this.#view.getPlaybackMilliseconds(\n recommendedDisplayFrameRate);\n const size = image.getGeometry().getSize();\n const canScroll3D = size.canScroll3D();\n\n this.#playerID = window.setInterval(() => {\n let canDoMore = false;\n if (canScroll3D) {\n canDoMore = this.incrementScrollIndex();\n } else {\n canDoMore = this.incrementIndex(3);\n }\n // end of scroll, loop back\n if (!canDoMore) {\n const pos1 = this.getCurrentIndex();\n const values = pos1.getValues();\n const orientation = this.#view.getOrientation();\n if (canScroll3D) {\n values[orientation.getThirdColMajorDirection()] = 0;\n } else {\n values[3] = 0;\n }\n const index = new Index(values);\n const geometry = this.#view.getImage().getGeometry();\n this.setCurrentPosition(geometry.indexToWorld(index));\n }\n }, milliseconds);\n } else {\n this.stop();\n }\n }\n\n /**\n * Stop scroll playing.\n */\n stop() {\n if (typeof this.#playerID !== 'undefined') {\n clearInterval(this.#playerID);\n this.#playerID = undefined;\n }\n }\n\n /**\n * Get the window/level.\n *\n * @returns {WindowLevel} The window and level.\n */\n getWindowLevel() {\n return this.#view.getWindowLevel();\n }\n\n /**\n * Get the current window level preset name.\n *\n * @returns {string} The preset name.\n */\n getCurrentWindowPresetName() {\n return this.#view.getCurrentWindowPresetName();\n }\n\n /**\n * Set the window and level.\n *\n * @param {WindowLevel} wl The window and level.\n */\n setWindowLevel(wl) {\n this.#view.setWindowLevel(wl);\n }\n\n /**\n * Get the colour map.\n *\n * @returns {string} The colour map name.\n */\n getColourMap() {\n return this.#view.getColourMap();\n }\n\n /**\n * Set the colour map.\n *\n * @param {string} name The colour map name.\n */\n setColourMap(name) {\n this.#view.setColourMap(name);\n }\n\n /**\n * @callback alphaFn\n * @param {number[]|number} value The pixel value.\n * @param {number} index The values' index.\n * @returns {number} The opacity of the input value.\n */\n\n /**\n * Set the view per value alpha function.\n *\n * @param {alphaFn} func The function.\n */\n setViewAlphaFunction(func) {\n this.#view.setAlphaFunction(func);\n }\n\n /**\n * Bind the view image to the provided layer.\n *\n * @param {ViewLayer} viewLayer The layer to bind.\n */\n bindImageAndLayer(viewLayer) {\n const image = this.#view.getImage();\n image.addEventListener('imagecontentchange',\n viewLayer.onimagecontentchange\n );\n image.addEventListener('imagegeometrychange',\n viewLayer.onimagegeometrychange\n );\n }\n\n /**\n * Unbind the view image to the provided layer.\n *\n * @param {ViewLayer} viewLayer The layer to bind.\n */\n unbindImageAndLayer(viewLayer) {\n const image = this.#view.getImage();\n image.removeEventListener('imagecontentchange',\n viewLayer.onimagecontentchange\n );\n image.removeEventListener('imagegeometrychange',\n viewLayer.onimagegeometrychange\n );\n }\n\n} // class ViewController\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get a normalised spin speed in the Y direction to try to support\n * trackpads (small and large deltaY) and mouse wheel (large deltaY).\n * Should return 1 or -1 for a single mouse wheel tick.\n *\n * @param {object} event The wheel event.\n * @returns {number} The normalised spin Y.\n */\nfunction getSpinY(event) {\n // (notes of 03/2024)\n\n // firefox seems to change the value of deltaY\n // if you ask for deltaMode before (?????)\n\n // deltaY (for a single mouse wheel tick):\n // - chrome: [linux] 120, [mac]: 4\n // - firefox: [linux] 132, [mac]: 16\n\n // wheelDelta (for a single mouse wheel tick):\n // - chrome: [linux] 120, [mac]: 240\n // - firefox: [linux] 120, [mac]: 48\n\n // -> using wheelDelta for mouse wheel detection as\n // it is consistently larger than trackpad scroll\n\n // wheelDeltaY and deltaY do not go in the same direction,\n // using -deltaY so that they do...\n\n if (typeof event.wheelDeltaY === 'undefined') {\n //logger.warn('No wheel delta, scroll could be tricky...);\n return -event.deltaY;\n } else {\n const threshold = 45;\n if (event.wheelDeltaY > threshold) {\n return 1;\n } else if (event.wheelDeltaY < -threshold) {\n return -1;\n } else {\n return -event.deltaY / 60;\n }\n }\n}\n\n/**\n * Class to sum wheel events and know if that sum\n * corresponds to a 'tick'.\n */\nclass ScrollSum {\n /**\n * The scroll sum.\n *\n * @type {number}\n */\n #sum = 0;\n\n /**\n * Get the scroll sum.\n *\n * @returns {number} The scroll sum.\n */\n getSum() {\n return this.#sum;\n }\n\n /**\n * Add scroll.\n *\n * @param {object} event The wheel event.\n */\n add(event) {\n this.#sum += getSpinY(event);\n }\n\n /**\n * Clear the scroll sum.\n */\n clear() {\n this.#sum = 0;\n }\n\n /**\n * Does the accumulated scroll correspond to a 'tick'.\n *\n * @returns {boolean} True if the sum corresponds to a 'tick'.\n */\n isTick() {\n return Math.abs(this.#sum) >= 1;\n }\n}\n\n/**\n * Scroll wheel class: provides a wheel event handler\n * that scroll the corresponding data.\n */\nexport class ScrollWheel {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Accumulated scroll.\n *\n * @type {ScrollSum}\n */\n #scrollSum = new ScrollSum();\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Handle mouse wheel event.\n *\n * @param {WheelEvent} event The mouse wheel event.\n */\n wheel(event) {\n this.#scrollSum.add(event);\n const up = this.#scrollSum.getSum() >= 0;\n\n // exit if no tick\n if (!this.#scrollSum.isTick()) {\n return;\n } else {\n this.#scrollSum.clear();\n }\n\n // prevent default page scroll\n event.preventDefault();\n\n const layerDetails = getLayerDetailsFromEvent(event);\n const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n let newPosition;\n if (layerGroup.canScroll()) {\n if (up) {\n newPosition = viewController.getIncrementScrollPosition();\n } else {\n newPosition = viewController.getDecrementScrollPosition();\n }\n } else if (layerGroup.moreThanOne(3)) {\n if (up) {\n newPosition = viewController.getIncrementPosition(3);\n } else {\n newPosition = viewController.getDecrementPosition(3);\n }\n }\n\n // set all layers if at least one can be set\n if (typeof newPosition !== 'undefined' &&\n layerGroup.isPositionInBounds(newPosition)) {\n viewController.setCurrentPosition(newPosition);\n }\n }\n\n} // ScrollWheel class\n","import {Point2D} from './point';\nimport {\n isSimilar,\n REAL_WORLD_EPSILON,\n} from './matrix';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {ViewController} from '../app/viewController';\nimport {Scalar2D} from './scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Line shape.\n */\nexport class Line {\n\n /**\n * Line begin point.\n *\n * @type {Point2D}\n */\n #begin;\n\n /**\n * Line end point.\n *\n * @type {Point2D}\n */\n #end;\n\n /**\n * @param {Point2D} begin A Point2D representing the beginning\n * of the line.\n * @param {Point2D} end A Point2D representing the end of the line.\n */\n constructor(begin, end) {\n this.#begin = begin;\n this.#end = end;\n }\n\n /**\n * Get the begin point of the line.\n *\n * @returns {Point2D} The beginning point of the line.\n */\n getBegin() {\n return this.#begin;\n }\n\n /**\n * Get the end point of the line.\n *\n * @returns {Point2D} The ending point of the line.\n */\n getEnd() {\n return this.#end;\n }\n\n /**\n * Check for equality.\n *\n * @param {Line} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.getBegin().equals(rhs.getBegin()) &&\n this.getEnd().equals(rhs.getEnd());\n }\n\n /**\n * Get the line delta in the X direction.\n *\n * @returns {number} The delta in the X direction.\n */\n getDeltaX() {\n return this.getEnd().getX() - this.getBegin().getX();\n }\n\n /**\n * Get the line delta in the Y direction.\n *\n * @returns {number} The delta in the Y direction.\n */\n getDeltaY() {\n return this.getEnd().getY() - this.getBegin().getY();\n }\n\n /**\n * Get the length of the line.\n *\n * @returns {number} The length of the line.\n */\n getLength() {\n return Math.sqrt(\n this.getDeltaX() * this.getDeltaX() +\n this.getDeltaY() * this.getDeltaY()\n );\n }\n\n /**\n * Get the length of the line according to a spacing.\n *\n * @param {Scalar2D} spacing2D The 2D spacing.\n * @returns {number} The length of the line with spacing\n * or null for null spacings.\n */\n getWorldLength(spacing2D) {\n let wlen = null;\n if (spacing2D !== null) {\n const dxs = this.getDeltaX() * spacing2D.x;\n const dys = this.getDeltaY() * spacing2D.y;\n wlen = Math.sqrt(dxs * dxs + dys * dys);\n }\n return wlen;\n }\n\n /**\n * Get the mid point of the line.\n *\n * @returns {Point2D} The mid point of the line.\n */\n getMidpoint() {\n return new Point2D(\n (this.getBegin().getX() + this.getEnd().getX()) / 2,\n (this.getBegin().getY() + this.getEnd().getY()) / 2\n );\n }\n\n /**\n * Get the centroid of the line.\n *\n * @returns {Point2D} THe centroid point.\n */\n getCentroid() {\n return this.getMidpoint();\n }\n\n /**\n * Get the slope of the line.\n *\n * @returns {number} The slope of the line.\n */\n getSlope() {\n return this.getDeltaY() / this.getDeltaX();\n }\n\n /**\n * Get the intercept of the line.\n *\n * @returns {number} The slope of the line.\n */\n getIntercept() {\n return (\n this.getEnd().getX() * this.getBegin().getY() -\n this.getBegin().getX() * this.getEnd().getY()\n ) / this.getDeltaX();\n }\n\n /**\n * Get the inclination of the line.\n *\n * @returns {number} The inclination of the line.\n */\n getInclination() {\n // tan(theta) = slope\n const angle =\n Math.atan2(this.getDeltaY(), this.getDeltaX()) * 180 / Math.PI;\n // shift?\n return 180 - angle;\n }\n\n /**\n * Quantify a line according to view information.\n *\n * @param {ViewController} viewController The associated view controller.\n * @returns {object} A quantification object.\n */\n quantify(viewController) {\n const quant = {};\n // length\n const spacing2D = viewController.get2DSpacing();\n const length = this.getWorldLength(spacing2D);\n if (length !== null) {\n quant.length = {value: length, unit: 'unit.mm'};\n }\n // return\n return quant;\n }\n\n} // Line class\n\n/**\n * Get the angle between two lines in degree.\n *\n * @param {Line} line0 The first line.\n * @param {Line} line1 The second line.\n * @returns {number} The angle.\n */\nexport function getAngle(line0, line1) {\n const dx0 = line0.getDeltaX();\n const dy0 = line0.getDeltaY();\n const dx1 = line1.getDeltaX();\n const dy1 = line1.getDeltaY();\n // dot = ||a||*||b||*cos(theta)\n const dot = dx0 * dx1 + dy0 * dy1;\n // cross = ||a||*||b||*sin(theta)\n const det = dx0 * dy1 - dy0 * dx1;\n // tan = sin / cos\n const angle = Math.atan2(det, dot) * 180 / Math.PI;\n // complementary angle\n // shift?\n return 360 - (180 - angle);\n}\n\n/**\n * Check if two lines are orthogonal.\n *\n * @param {Line} line0 The first line.\n * @param {Line} line1 The second line.\n * @returns {boolean} True if both lines are orthogonal.\n */\nexport function areOrthogonal(line0, line1) {\n const dx0 = line0.getDeltaX();\n const dy0 = line0.getDeltaY();\n const dx1 = line1.getDeltaX();\n const dy1 = line1.getDeltaY();\n // dot = ||a||*||b||*cos(theta)\n return (dx0 * dx1 + dy0 * dy1) === 0;\n}\n\n/**\n * Check if a point is in a line coordinate range.\n *\n * @param {Point2D} point The input point.\n * @param {Line} line The input line.\n * @returns {boolean} True if the input point is in the line coordinate range.\n */\nexport function isPointInLineRange(point, line) {\n const minX = Math.min(line.getBegin().getX(), line.getEnd().getX());\n const maxX = Math.max(line.getBegin().getX(), line.getEnd().getX());\n const minY = Math.min(line.getBegin().getY(), line.getEnd().getY());\n const maxY = Math.max(line.getBegin().getY(), line.getEnd().getY());\n return point.getX() >= minX &&\n point.getX() <= maxX &&\n point.getY() >= minY &&\n point.getY() <= maxY;\n}\n\n/**\n * Get a perpendicular line to an input one at a given point.\n *\n * @param {Line} line The line to be perpendicular to.\n * @param {Point2D} point The middle point of the perpendicular line.\n * @param {number} length The length of the perpendicular line.\n * @param {Scalar2D} [spacing] Optional image spacing, default to [1,1].\n * @returns {Line} The perpendicular line.\n */\nexport function getPerpendicularLine(line, point, length, spacing) {\n if (typeof spacing === 'undefined') {\n spacing = {x: 1, y: 1};\n }\n const sx2 = spacing.x * spacing.x;\n const sy2 = spacing.y * spacing.y;\n // a0 * a1 = -1 (in square space)\n const perpSlope = -sx2 / (sy2 * line.getSlope());\n // y0 = a1*x0 + b1 -> b1 = y0 - a1*x0\n const prepIntercept = point.getY() - perpSlope * point.getX();\n // return\n return getLineFromEquation(perpSlope, prepIntercept, point, length, spacing);\n}\n\n/**\n * Get a perpendicular line to an input one at a given distance\n * of its begin point.\n *\n * @param {Line} line The line to be perpendicular to.\n * @param {number} distance The distance to the input line begin point.\n * @param {number} length The length of the perpendicular line.\n * @param {Scalar2D} [spacing] Optional image spacing, default to [1,1].\n * @returns {Line} The perpendicular line.\n */\nexport function getPerpendicularLineAtDistance(\n line, distance, length, spacing) {\n // get a line along the input one and centered on begin point\n const lineFromEq = getLineFromEquation(\n line.getSlope(),\n line.getIntercept(),\n line.getBegin(),\n distance,\n spacing\n );\n // select the point on the input line\n let startPoint;\n if (isPointInLineRange(lineFromEq.getBegin(), line)) {\n startPoint = lineFromEq.getBegin();\n } else {\n startPoint = lineFromEq.getEnd();\n }\n // use it as base for a perpendicular line\n return getPerpendicularLine(line, startPoint, length, spacing);\n}\n\n/**\n * Get a line from an equation, a middle point and a length.\n *\n * @param {number} slope The line slope.\n * @param {number} intercept The line intercept.\n * @param {Point2D} point The middle point of the line.\n * @param {number} length The line length.\n * @param {Scalar2D} [spacing] Optional image spacing, default to [1,1].\n * @returns {Line} The resulting line.\n */\nexport function getLineFromEquation(slope, intercept, point, length, spacing) {\n if (typeof spacing === 'undefined') {\n spacing = {x: 1, y: 1};\n }\n // begin point\n let beginX = 0;\n let beginY = 0;\n // end point\n let endX = 0;\n let endY = 0;\n\n if (isSimilar(slope, 0, REAL_WORLD_EPSILON)) {\n // slope = ~0 -> horizontal input line\n beginX = point.getX() - length / (2 * spacing.x);\n beginY = point.getY();\n endX = point.getX() + length / (2 * spacing.x);\n endY = point.getY();\n } else if (Math.abs(slope) > 1e6) {\n // slope = ~(+/-)Infinity -> vertical input line\n beginX = point.getX();\n beginY = point.getY() - length / (2 * spacing.y);\n endX = point.getX();\n endY = point.getY() + length / (2 * spacing.y);\n } else {\n const sx2 = spacing.x * spacing.x;\n const sy2 = spacing.y * spacing.y;\n\n // 1. [length] sx^2 * (x - x0)^2 + sy^2 * (y - y0)^2 = d^2\n // 2. [slope] a = (y - y0) / (x - x0) -> y - y0 = a*(x - x0)\n // -> sx^2 * (x - x0)^2 + sy^2 * a^2 * (x - x0)^2 = d^2\n // -> (x - x0)^2 = d^2 / (sx^2 + sy^2 * a^2)\n // -> x = x0 +- d / sqrt(sx^2 + sy^2 * a^2)\n\n // length is the distance between begin and end,\n // point is half way between both -> d = length / 2\n const dx = length / (2 * Math.sqrt(sx2 + sy2 * slope * slope));\n\n // begin point\n beginX = point.getX() - dx;\n beginY = slope * beginX + intercept;\n // end point\n endX = point.getX() + dx;\n endY = slope * endX + intercept;\n }\n return new Line(\n new Point2D(beginX, beginY),\n new Point2D(endX, endY));\n}\n","import {logger} from '../utils/logger';\nimport {ListenerHandler} from '../utils/listen';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Annotation} from './annotation';\nimport {ViewController} from '../app/viewController';\n/* eslint-enable no-unused-vars */\n\n/**\n * Annotation group.\n */\nexport class AnnotationGroup {\n /**\n * @type {Annotation[]}\n */\n #list;\n\n /**\n * Annotation meta data.\n *\n * @type {Object}\n */\n #meta = {};\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Editable flag.\n *\n * @type {boolean}\n */\n #editable;\n\n /**\n * Group colour as hex string. If defined, it will be used as\n * default colour for new annotations in draw tool.\n *\n * @type {string|undefined}\n */\n #colour;\n\n /**\n * @param {Annotation[]} [list] Optional list, will\n * create new if not provided.\n */\n constructor(list) {\n if (typeof list !== 'undefined') {\n this.#list = list;\n } else {\n this.#list = [];\n }\n this.#editable = true;\n }\n\n /**\n * Get the annotation group as an array.\n *\n * @returns {Annotation[]} The array.\n */\n getList() {\n return this.#list;\n }\n\n /**\n * Get the number of annotations of this list.\n *\n * @returns {number} The number of annotations.\n */\n getLength() {\n return this.#list.length;\n }\n\n /**\n * Check if the annotation group is editable.\n *\n * @returns {boolean} True if editable.\n */\n isEditable() {\n return this.#editable;\n }\n\n /**\n * Set the annotation group editability.\n *\n * @param {boolean} flag True to make the annotation group editable.\n */\n setEditable(flag) {\n this.#editable = flag;\n /**\n * Annotation group editable flag change event.\n *\n * @event AnnotationGroup#annotationgroupeditablechange\n * @type {object}\n * @property {string} type The event type.\n * @property {boolean} data The value of the editable flag.\n */\n this.#fireEvent({\n type: 'annotationgroupeditablechange',\n data: flag\n });\n }\n\n /**\n * Get the group colour.\n *\n * @returns {string} The colour as hex string.\n */\n getColour() {\n return this.#colour;\n }\n\n /**\n * Set the group colour.\n *\n * @param {string} colour The colour as hex string.\n */\n setColour(colour) {\n this.#colour = colour;\n }\n\n /**\n * Add a new annotation.\n *\n * @param {Annotation} annotation The annotation to add.\n */\n add(annotation) {\n this.#list.push(annotation);\n /**\n * Annotation add event.\n *\n * @event AnnotationGroup#annotationadd\n * @type {object}\n * @property {string} type The event type.\n * @property {Annotation} data The added annnotation.\n */\n this.#fireEvent({\n type: 'annotationadd',\n data: annotation\n });\n }\n\n /**\n * Update an existing annotation.\n *\n * @param {Annotation} annotation The annotation to update.\n * @param {string[]} [propKeys] Optional properties that got updated.\n */\n update(annotation, propKeys) {\n const index = this.#list.findIndex((item) => item.id === annotation.id);\n if (index !== -1) {\n this.#list[index] = annotation;\n /**\n * Annotation update event.\n *\n * @event AnnotationGroup#annotationupdate\n * @type {object}\n * @property {string} type The event type.\n * @property {Annotation} data The added annnotation.\n * @property {string[]} keys The properties that were updated.\n */\n this.#fireEvent({\n type: 'annotationupdate',\n data: annotation,\n keys: propKeys\n });\n } else {\n logger.warn('Cannot find annotation to update');\n }\n }\n\n /**\n * Remove an annotation.\n *\n * @param {string} id The id of the annotation to remove.\n */\n remove(id) {\n const index = this.#list.findIndex((item) => item.id === id);\n if (index !== -1) {\n const annotation = this.#list.splice(index, 1)[0];\n /**\n * Annotation update event.\n *\n * @event AnnotationGroup#annotationremove\n * @type {object}\n * @property {string} type The event type.\n * @property {Annotation} data The added annnotation.\n * @property {string[]} keys The properties that were updated.\n */\n this.#fireEvent({\n type: 'annotationremove',\n data: annotation\n });\n } else {\n logger.warn('Cannot find annotation to remove');\n }\n }\n\n /**\n * Set the associated view controller.\n *\n * @param {ViewController} viewController The associated view controller.\n */\n setViewController(viewController) {\n for (const item of this.#list) {\n item.setViewController(viewController);\n item.updateQuantification();\n }\n }\n\n /**\n * Find an annotation.\n *\n * @param {string} id The id of the annotation to find.\n * @returns {Annotation|undefined} The found annotation.\n */\n find(id) {\n return this.#list.find((item) => item.id === id);\n }\n\n /**\n * Get the meta data.\n *\n * @returns {Object} The meta data.\n */\n getMeta() {\n return this.#meta;\n }\n\n /**\n * Check if this list contains a meta data value.\n *\n * @param {string} key The key to check.\n * @returns {boolean} True if the meta data is present.\n */\n hasMeta(key) {\n return typeof this.#meta[key] !== 'undefined';\n }\n\n /**\n * Get a meta data value.\n *\n * @param {string} key The meta data key.\n * @returns {string|object} The meta data value.\n */\n getMetaValue(key) {\n return this.#meta[key];\n }\n\n /**\n * Set a meta data.\n *\n * @param {string} key The meta data key.\n * @param {string|object} value The value of the meta data.\n */\n setMetaValue(key, value) {\n this.#meta[key] = value;\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n}\n","import {AnnotationGroup} from '../image/annotationGroup';\nimport {\n RemoveAnnotationCommand,\n UpdateAnnotationCommand\n} from '../tools/drawCommands';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Draw controller.\n */\nexport class DrawController {\n\n /**\n * The annotation group.\n *\n * @type {AnnotationGroup}\n */\n #annotationGroup;\n\n /**\n * Get an annotation.\n *\n * @param {string} id The annotation id.\n * @returns {Annotation|undefined} The annotation.\n */\n getAnnotation(id) {\n return this.#annotationGroup.find(id);\n }\n\n /**\n * Get the annotation group.\n *\n * @returns {AnnotationGroup} The list.\n */\n getAnnotationGroup() {\n return this.#annotationGroup;\n }\n\n /**\n * Check if the annotation group is editable.\n *\n * @returns {boolean} True if editable.\n */\n isAnnotationGroupEditable() {\n return this.#annotationGroup.isEditable();\n }\n\n /**\n * Set the annotation group editability.\n *\n * @param {boolean} flag True to make the annotation group editable.\n */\n setAnnotationGroupEditable(flag) {\n this.#annotationGroup.setEditable(flag);\n }\n\n /**\n * Add an annotation.\n *\n * @param {Annotation} annotation The annotation to add.\n */\n addAnnotation(annotation) {\n this.#annotationGroup.add(annotation);\n }\n\n /**\n * Update an anotation from the list.\n *\n * @param {Annotation} annotation The annotation to update.\n * @param {string[]} [propKeys] Optional properties that got updated.\n */\n updateAnnotation(annotation, propKeys) {\n this.#annotationGroup.update(annotation, propKeys);\n }\n\n /**\n * Remove an anotation for the list.\n *\n * @param {string} id The id of the annotation to remove.\n */\n removeAnnotation(id) {\n this.#annotationGroup.remove(id);\n }\n\n /**\n * Remove an annotation via a remove command (triggers draw actions).\n *\n * @param {string} id The annotation id.\n * @param {Function} exeCallback The undo stack callback.\n */\n removeAnnotationWithCommand(id, exeCallback) {\n const annotation = this.getAnnotation(id);\n if (typeof annotation === 'undefined') {\n logger.warn(\n 'Cannot create remove command for undefined annotation: ' + id);\n return;\n }\n // create remove annotation command\n const command = new RemoveAnnotationCommand(annotation, this);\n // add command to undo stack\n exeCallback(command);\n // execute command: triggers draw remove\n command.execute();\n }\n\n /**\n * Update an annotation via an update command (triggers draw actions).\n *\n * @param {string} id The annotation id.\n * @param {object} originalProps The original annotation properties\n * that will be updated.\n * @param {object} newProps The new annotation properties\n * that will replace the original ones.\n * @param {Function} exeCallback The undo stack callback.\n */\n updateAnnotationWithCommand(id, originalProps, newProps, exeCallback) {\n const annotation = this.getAnnotation(id);\n if (typeof annotation === 'undefined') {\n logger.warn(\n 'Cannot create update command for undefined annotation: ' + id);\n return;\n }\n // create remove annotation command\n const command = new UpdateAnnotationCommand(\n annotation, originalProps, newProps, this);\n // add command to undo stack\n exeCallback(command);\n // execute command: triggers draw remove\n command.execute();\n }\n\n /**\n * Remove all annotations via remove commands (triggers draw actions).\n *\n * @param {Function} exeCallback The undo stack callback.\n */\n removeAllAnnotationsWithCommand(exeCallback) {\n for (const annotation of this.#annotationGroup.getList()) {\n this.removeAnnotationWithCommand(annotation.id, exeCallback);\n }\n }\n\n /**\n * @param {AnnotationGroup} [group] Optional annotation group.\n */\n constructor(group) {\n if (typeof group !== 'undefined') {\n this.#annotationGroup = group;\n } else {\n this.#annotationGroup = new AnnotationGroup();\n }\n }\n\n /**\n * Check if the annotation group contains a meta data value.\n *\n * @param {string} key The key to check.\n * @returns {boolean} True if the meta data is present.\n */\n hasAnnotationMeta(key) {\n return this.#annotationGroup.hasMeta(key);\n }\n\n /**\n * Set an annotation meta data.\n *\n * @param {string} key The meta data to set.\n * @param {string} value The value of the meta data.\n */\n setAnnotationMeta(key, value) {\n this.#annotationGroup.setMetaValue(key, value);\n }\n\n} // class DrawController\n","import {getShadowColour} from '../utils/colour';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Scalar2D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Style class.\n */\nexport class Style {\n /**\n * Font size.\n *\n * @type {number}\n */\n #fontSize = 10;\n\n /**\n * Font family.\n *\n * @type {string}\n */\n #fontFamily = 'Verdana';\n\n /**\n * Text colour.\n *\n * @type {string}\n */\n #textColour = '#fff';\n\n /**\n * Line colour.\n *\n * @type {string}\n */\n #lineColour = '#ffff80';\n\n /**\n * Base scale.\n *\n * @type {Scalar2D}\n */\n #baseScale = {x: 1, y: 1};\n\n /**\n * Zoom scale.\n *\n * @type {Scalar2D}\n */\n #zoomScale = {x: 1, y: 1};\n\n /**\n * Stroke width.\n *\n * @type {number}\n */\n #strokeWidth = 2;\n\n /**\n * Shadow offset.\n *\n * @type {Scalar2D}\n */\n #shadowOffset = {x: 0.25, y: 0.25};\n\n /**\n * Tag opacity.\n *\n * @type {number}\n */\n #tagOpacity = 0.2;\n\n /**\n * Text padding.\n *\n * @type {number}\n */\n #textPadding = 3;\n\n /**\n * Get the font family.\n *\n * @returns {string} The font family.\n */\n getFontFamily() {\n return this.#fontFamily;\n }\n\n /**\n * Get the font size.\n *\n * @returns {number} The font size.\n */\n getFontSize() {\n return this.#fontSize;\n }\n\n /**\n * Get the stroke width.\n *\n * @returns {number} The stroke width.\n */\n getStrokeWidth() {\n return this.#strokeWidth;\n }\n\n /**\n * Get the text colour.\n *\n * @returns {string} The text colour.\n */\n getTextColour() {\n return this.#textColour;\n }\n\n /**\n * Get the line colour.\n *\n * @returns {string} The line colour.\n */\n getLineColour() {\n return this.#lineColour;\n }\n\n /**\n * Set the line colour.\n *\n * @param {string} colour The line colour.\n */\n setLineColour(colour) {\n this.#lineColour = colour;\n }\n\n /**\n * Set the base scale.\n *\n * @param {Scalar2D} scale The scale as {x,y}.\n */\n setBaseScale(scale) {\n this.#baseScale = scale;\n }\n\n /**\n * Set the zoom scale.\n *\n * @param {Scalar2D} scale The scale as {x,y}.\n */\n setZoomScale(scale) {\n this.#zoomScale = scale;\n }\n\n /**\n * Get the base scale.\n *\n * @returns {Scalar2D} The scale as {x,y}.\n */\n getBaseScale() {\n return this.#baseScale;\n }\n\n /**\n * Get the zoom scale.\n *\n * @returns {Scalar2D} The scale as {x,y}.\n */\n getZoomScale() {\n return this.#zoomScale;\n }\n\n /**\n * Scale an input value using the base scale.\n *\n * @param {number} value The value to scale.\n * @returns {number} The scaled value.\n */\n scale(value) {\n // TODO: 2D?\n return value / this.#baseScale.x;\n }\n\n /**\n * Apply zoom scale on an input value.\n *\n * @param {number} value The value to scale.\n * @returns {Scalar2D} The scaled value as {x,y}.\n */\n applyZoomScale(value) {\n return {\n x: value / this.#zoomScale.x,\n y: value / this.#zoomScale.y\n };\n }\n\n /**\n * Multiply an input value by the zoom ratio (zx/zy).\n *\n * @param {number} value The value to scale.\n * @returns {number} The scaled value.\n */\n applyZoomRatio(value) {\n return value * this.#zoomScale.x / this.#zoomScale.y;\n }\n\n /**\n * Get the shadow offset.\n *\n * @returns {Scalar2D} The offset as {x,y}.\n */\n getShadowOffset() {\n return this.#shadowOffset;\n }\n\n /**\n * Get the tag opacity.\n *\n * @returns {number} The opacity.\n */\n getTagOpacity() {\n return this.#tagOpacity;\n }\n\n /**\n * Get the text padding.\n *\n * @returns {number} The padding.\n */\n getTextPadding() {\n return this.#textPadding;\n }\n\n /**\n * Get the font definition string.\n *\n * @returns {string} The font definition string.\n */\n getFontStr() {\n return ('normal ' + this.getFontSize() + 'px sans-serif');\n }\n\n /**\n * Get the line height.\n *\n * @returns {number} The line height.\n */\n getLineHeight() {\n return (this.getFontSize() + this.getFontSize() / 5);\n }\n\n /**\n * Get the font size scaled to the display.\n *\n * @returns {number} The scaled font size.\n */\n getScaledFontSize() {\n return this.scale(this.getFontSize());\n }\n\n /**\n * Get the stroke width scaled to the display.\n *\n * @returns {number} The scaled stroke width.\n */\n getScaledStrokeWidth() {\n return this.scale(this.getStrokeWidth());\n }\n\n /**\n * Get the shadow line colour.\n *\n * @returns {string} The shadow line colour.\n */\n getShadowLineColour() {\n return getShadowColour(this.getLineColour());\n }\n\n} // class Style\n","import {Point2D} from '../math/point';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Scalar2D} from '../math/scalar';\nimport {Style} from '../gui/style';\n// external\nimport Konva from 'konva';\n/* eslint-enable no-unused-vars */\n\n/**\n * Is an input node's name 'label'.\n *\n * @param {Konva.Node} node A Konva node.\n * @returns {boolean} True if the node's name is 'label'.\n */\nexport function isNodeNameLabel(node) {\n return node.name() === 'label';\n}\n\n/**\n * Is an input node's name 'shape'.\n *\n * @param {Konva.Node} node A Konva node.\n * @returns {boolean} True if the node's name is 'shape'.\n */\nexport function isNodeNameShape(node) {\n return node.name() === 'shape';\n}\n\n/**\n * Is an input node a position node.\n *\n * @param {Konva.Node} node A Konva node.\n * @returns {boolean} True if the node's name is 'position-group'.\n */\nexport function isPositionNode(node) {\n return node.name() === 'position-group';\n}\n\n/**\n * Get a Konva.Line shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Line|undefined} The shape.\n */\nexport function getLineShape(group) {\n const kshape = group.getChildren(isNodeNameShape)[0];\n if (!(kshape instanceof Konva.Line)) {\n return;\n }\n return kshape;\n}\n\n/**\n * Get a Konva.Ellipse anchor shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @param {number} index The anchor index.\n * @returns {Konva.Ellipse|undefined} The anchor shape.\n */\nexport function getAnchorShape(group, index) {\n const kshape = group.getChildren(function (node) {\n return node.id() === 'anchor' + index;\n })[0];\n if (!(kshape instanceof Konva.Ellipse)) {\n return;\n }\n return kshape;\n}\n\n/**\n * @callback testFn\n * @param {Konva.Node} node The node.\n * @returns {boolean} True if the node passes the test.\n */\n\n/**\n * Get a lambda to check a node's id.\n *\n * @param {string} id The id to check.\n * @returns {testFn} A function to check a node's id.\n */\nexport function isNodeWithId(id) {\n return function (node) {\n return node.id() === id;\n };\n}\n\n/**\n * Draw Debug flag.\n */\nexport const DRAW_DEBUG = false;\n\n/**\n * Get the default anchor shape.\n *\n * @param {number} x The X position.\n * @param {number} y The Y position.\n * @param {string} id The shape id.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse} The default anchor shape.\n */\nexport function getDefaultAnchor(x, y, id, style) {\n const radius = style.applyZoomScale(6);\n const absRadius = {\n x: Math.abs(radius.x),\n y: Math.abs(radius.y)\n };\n return new Konva.Ellipse({\n x: x,\n y: y,\n stroke: '#999',\n fill: 'rgba(100,100,100,0.7',\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n radius: absRadius,\n radiusX: absRadius.x,\n radiusY: absRadius.y,\n name: 'anchor',\n id: id.toString(),\n dragOnTop: false,\n draggable: true,\n visible: false\n });\n}\n\n/**\n * Get an anchor index from its id.\n *\n * @param {string} id The anchor id as 'anchor#'.\n * @returns {number} The anchor index.\n */\nexport function getAnchorIndex(id) {\n // 'anchor'.length = 6\n return parseInt(id.substring(6), 10);\n}\n\n/**\n * Bound a node position.\n *\n * @param {Konva.Node} node The node to bound the position.\n * @param {Point2D} min The minimum position.\n * @param {Point2D} max The maximum position.\n * @returns {boolean} True if the position was corrected.\n */\nfunction boundNodePosition(node, min, max) {\n let changed = false;\n if (node.x() < min.getX()) {\n node.x(min.getX());\n changed = true;\n } else if (node.x() > max.getX()) {\n node.x(max.getX());\n changed = true;\n }\n if (node.y() < min.getY()) {\n node.y(min.getY());\n changed = true;\n } else if (node.y() > max.getY()) {\n node.y(max.getY());\n changed = true;\n }\n return changed;\n}\n\n/**\n * Get a shape top left position range.\n *\n * @param {Scalar2D} stageSize The stage size as {x,y}.\n * @param {Konva.Shape} shape The shape to evaluate.\n * @returns {object} The range as {min, max}.\n */\nexport function getShapePositionRange(stageSize, shape) {\n const min = new Point2D(0, 0);\n const max = new Point2D(\n stageSize.x - Math.abs(shape.width()),\n stageSize.y - Math.abs(shape.height())\n );\n\n return {min: min, max: max};\n}\n\n/**\n * Is an input shape top left position in the input range.\n *\n * @param {Konva.Shape} shape The shape to evaluate.\n * @param {Point2D} min The minimum top left position.\n * @param {Point2D} max The maximum top left position.\n * @returns {boolean} True if in range.\n */\nexport function isShapeInRange(shape, min, max) {\n // use client rect to get the shape's top left position\n const boundRect = shape.getClientRect({relativeTo: shape.getParent()});\n return boundRect.x > min.getX() &&\n boundRect.x < max.getX() &&\n boundRect.y > min.getY() &&\n boundRect.y < max.getY();\n}\n\n/**\n * Validate an anchor position.\n *\n * @param {Scalar2D} stageSize The stage size {x,y}.\n * @param {Konva.Shape} anchor The anchor to evaluate.\n * @returns {boolean} True if the position was corrected.\n */\nexport function validateAnchorPosition(stageSize, anchor) {\n const group = anchor.getParent();\n\n const min = new Point2D(\n -group.x(),\n -group.y()\n );\n const max = new Point2D(\n stageSize.x - group.x(),\n stageSize.y - group.y()\n );\n\n return boundNodePosition(anchor, min, max);\n}\n","import {Point2D} from './point';\nimport {getStats} from './stats';\nimport {Index} from './index';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {ViewController} from '../app/viewController';\nimport {Scalar2D} from './scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Mulitply the three inputs if the last two are not null.\n *\n * @param {number} a The first input.\n * @param {number} b The second input.\n * @param {number} c The third input.\n * @returns {number} The multiplication of the three inputs or\n * null if one of the last two is null.\n */\nfunction mulABC(a, b, c) {\n let res = null;\n if (b !== null && c !== null) {\n res = a * b * c;\n }\n return res;\n}\n\n/**\n * Rectangle shape.\n */\nexport class Rectangle {\n\n /**\n * Rectangle begin point.\n *\n * @type {Point2D}\n */\n #begin;\n\n /**\n * Rectangle end point.\n *\n * @type {Point2D}\n */\n #end;\n\n /**\n * @param {Point2D} begin A Point2D representing the beginning\n * of the rectangle.\n * @param {Point2D} end A Point2D representing the end\n * of the rectangle.\n */\n constructor(begin, end) {\n this.#begin = new Point2D(\n Math.min(begin.getX(), end.getX()),\n Math.min(begin.getY(), end.getY())\n );\n this.#end = new Point2D(\n Math.max(begin.getX(), end.getX()),\n Math.max(begin.getY(), end.getY())\n );\n }\n\n /**\n * Get the begin point of the rectangle.\n *\n * @returns {Point2D} The begin point of the rectangle.\n */\n getBegin() {\n return this.#begin;\n }\n\n /**\n * Get the end point of the rectangle.\n *\n * @returns {Point2D} The end point of the rectangle.\n */\n getEnd() {\n return this.#end;\n }\n\n /**\n * Check for equality.\n *\n * @param {Rectangle} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.getBegin().equals(rhs.getBegin()) &&\n this.getEnd().equals(rhs.getEnd());\n }\n\n /**\n * Get the surface of the rectangle.\n *\n * @returns {number} The surface of the rectangle.\n */\n getSurface() {\n const begin = this.getBegin();\n const end = this.getEnd();\n return Math.abs(end.getX() - begin.getX()) *\n Math.abs(end.getY() - begin.getY());\n }\n\n /**\n * Get the surface of the rectangle according to a spacing.\n *\n * @param {Scalar2D} spacing2D The 2D spacing.\n * @returns {number} The surface of the rectangle multiplied by the given\n * spacing or null for null spacings.\n */\n getWorldSurface(spacing2D) {\n return mulABC(this.getSurface(), spacing2D.x, spacing2D.y);\n }\n\n /**\n * Get the real width of the rectangle.\n *\n * @returns {number} The real width of the rectangle.\n */\n getRealWidth() {\n return this.getEnd().getX() - this.getBegin().getX();\n }\n\n /**\n * Get the real height of the rectangle.\n *\n * @returns {number} The real height of the rectangle.\n */\n getRealHeight() {\n return this.getEnd().getY() - this.getBegin().getY();\n }\n\n /**\n * Get the width of the rectangle.\n *\n * @returns {number} The width of the rectangle.\n */\n getWidth() {\n return Math.abs(this.getRealWidth());\n }\n\n /**\n * Get the height of the rectangle.\n *\n * @returns {number} The height of the rectangle.\n */\n getHeight() {\n return Math.abs(this.getRealHeight());\n }\n\n /**\n * Get the rounded limits of the rectangle.\n *\n * @returns {object} The rounded limits as {min, max} (Point2D).\n */\n getRound() {\n const roundBegin = new Point2D(\n Math.round(this.getBegin().getX()),\n Math.round(this.getBegin().getY())\n );\n const roundEnd = new Point2D(\n Math.round(this.getEnd().getX()),\n Math.round(this.getEnd().getY())\n );\n return {\n min: roundBegin,\n max: roundEnd\n };\n }\n\n /**\n * Get the centroid of the rectangle.\n *\n * @returns {Point2D} The centroid point.\n */\n getCentroid() {\n return new Point2D(\n this.getBegin().getX() + this.getWidth() / 2,\n this.getBegin().getY() + this.getHeight() / 2\n );\n }\n\n /**\n * Quantify a rectangle according to view information.\n *\n * @param {ViewController} viewController The associated view controller.\n * @param {string[]} flags A list of stat values to calculate.\n * @returns {object} A quantification object.\n */\n quantify(viewController, flags) {\n const quant = {};\n // shape quantification\n const spacing2D = viewController.get2DSpacing();\n quant.width = {\n value: this.getWidth() * spacing2D.x,\n unit: 'unit.mm'\n };\n quant.height = {\n value: this.getHeight() * spacing2D.y,\n unit: 'unit.mm'\n };\n const surface = this.getWorldSurface(spacing2D);\n if (surface !== null) {\n quant.surface = {\n value: surface / 100,\n unit: 'unit.cm2'\n };\n }\n\n // pixel values quantification\n if (viewController.canQuantifyImage()) {\n const round = this.getRound();\n const values = viewController.getImageRegionValues(round.min, round.max);\n const unit = viewController.getPixelUnit();\n const quantif = getStats(values, flags);\n quant.min = {value: quantif.min, unit: unit};\n quant.max = {value: quantif.max, unit: unit};\n quant.mean = {value: quantif.mean, unit: unit};\n quant.stdDev = {value: quantif.stdDev, unit: unit};\n if (typeof quantif.median !== 'undefined') {\n quant.median = {value: quantif.median, unit: unit};\n }\n if (typeof quantif.p25 !== 'undefined') {\n quant.p25 = {value: quantif.p25, unit: unit};\n }\n if (typeof quantif.p75 !== 'undefined') {\n quant.p75 = {value: quantif.p75, unit: unit};\n }\n }\n\n // return\n return quant;\n }\n\n} // Rectangle class\n\n/**\n * Get the indices that form a rectangle.\n *\n * @param {Index} center The rectangle center.\n * @param {number[]} size The 2 rectangle sizes.\n * @param {number[]} dir The 2 rectangle directions.\n * @returns {Index[]} The indices of the rectangle.\n */\nexport function getRectangleIndices(center, size, dir) {\n const centerValues = center.getValues();\n // keep all values for possible extra dimensions\n const values = centerValues.slice();\n const indices = [];\n const sizeI = size[0];\n const halfSizeI = Math.floor(sizeI / 2);\n const sizeJ = size[1];\n const halfSizeJ = Math.floor(sizeJ / 2);\n const di = dir[0];\n const dj = dir[1];\n for (let j = 0; j < sizeJ; ++j) {\n values[dj] = centerValues[dj] - halfSizeJ + j;\n for (let i = 0; i < sizeI; ++i) {\n values[di] = centerValues[di] - halfSizeI + i;\n indices.push(new Index(values.slice()));\n }\n }\n return indices;\n}\n","import {Point2D} from '../math/point';\n\n/**\n * Region Of Interest shape.\n * Note: should be a closed path.\n */\nexport class ROI {\n\n /**\n * List of points.\n *\n * @type {Point2D[]}\n */\n #points = [];\n\n /**\n * @param {Point2D[]} [points] Optional initial point list.\n */\n constructor(points) {\n if (typeof points !== 'undefined') {\n this.#points = points;\n }\n }\n\n /**\n * Get a point of the list at a given index.\n *\n * @param {number} index The index of the point to get\n * (beware, no size check).\n * @returns {Point2D|undefined} The Point2D at the given index.\n */\n getPoint(index) {\n return this.#points[index];\n }\n\n /**\n * Get the point list.\n *\n * @returns {Point2D[]} The list.\n */\n getPoints() {\n return this.#points;\n }\n\n /**\n * Get the length of the point list.\n *\n * @returns {number} The length of the point list.\n */\n getLength() {\n return this.#points.length;\n }\n\n /**\n * Add a point to the ROI.\n *\n * @param {Point2D} point The Point2D to add.\n */\n addPoint(point) {\n this.#points.push(point);\n }\n\n /**\n * Add points to the ROI.\n *\n * @param {Point2D[]} rhs The array of POints2D to add.\n */\n addPoints(rhs) {\n this.#points = this.#points.concat(rhs);\n }\n\n /**\n * Get the centroid of the roi. Only valid for\n * a non-self-intersecting closed polygon.\n * Ref: {@link https://en.wikipedia.org/wiki/Centroid#Of_a_polygon}.\n *\n * @returns {Point2D} The centroid point.\n */\n getCentroid() {\n let a = 0;\n let cx = 0;\n let cy = 0;\n for (let i = 0; i < this.#points.length; ++i) {\n const pi = this.#points[i];\n let pi1;\n if (i === this.#points.length - 1) {\n pi1 = this.#points[0];\n } else {\n pi1 = this.#points[i + 1];\n }\n const ai = pi.getX() * pi1.getY() - pi1.getX() * pi.getY();\n a += ai;\n cx += (pi.getX() + pi1.getX()) * ai;\n cy += (pi.getY() + pi1.getY()) * ai;\n }\n a *= 0.5;\n const a1 = 1 / (6 * a);\n cx *= a1;\n cy *= a1;\n\n return new Point2D(cx, cy);\n }\n\n} // ROI class\n","import {Line, getAngle} from './line';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\nimport {ViewController} from '../app/viewController';\n/* eslint-enable no-unused-vars */\n\n/**\n * Protractor shape: 3 points from which to calculate an angle.\n */\nexport class Protractor {\n\n /**\n * List of points.\n *\n * @type {Point2D[]}\n */\n #points;\n\n /**\n * @param {Point2D[]} points The list of Point2D that make\n * the protractor.\n */\n constructor(points) {\n if (points.length > 3) {\n throw new Error('Too many points for a protractor');\n }\n this.#points = points.slice(0, 3);\n }\n\n /**\n * Get a point of the list.\n *\n * @param {number} index The index of the point\n * to get (beware, no size check).\n * @returns {Point2D|undefined} The Point2D at the given index.\n */\n getPoint(index) {\n return this.#points[index];\n }\n\n /**\n * Get the length of the path (should be 3).\n *\n * @returns {number} The length of the path.\n */\n getLength() {\n return this.#points.length;\n }\n\n /**\n * Get the centroid of the protractor.\n *\n * @returns {Point2D} THe centroid point.\n */\n getCentroid() {\n return this.#points[1];\n }\n\n /**\n * Quantify a path according to view information.\n *\n * @param {ViewController} _viewController The associated view controller.\n * @param {string[]} _flags A list of stat values to calculate.\n * @returns {object} A quantification object.\n */\n quantify(_viewController, _flags) {\n const quant = {};\n if (this.#points.length === 3) {\n const line0 = new Line(this.#points[0], this.#points[1]);\n const line1 = new Line(this.#points[1], this.#points[2]);\n let angle = getAngle(line0, line1);\n if (angle > 180) {\n angle = 360 - angle;\n }\n quant.angle = {\n value: angle,\n unit: 'unit.degree'\n };\n }\n return quant;\n }\n\n} // Protractor class\n","import {getStats} from './stats';\nimport {Index} from './index';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\nimport {ViewController} from '../app/viewController';\nimport {Scalar2D} from './scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Mulitply the three inputs if the last two are not null.\n *\n * @param {number} a The first input.\n * @param {number} b The second input.\n * @param {number} c The third input.\n * @returns {number} The multiplication of the three inputs or\n * null if one of the last two is null.\n */\nfunction mulABC(a, b, c) {\n let res = null;\n if (b !== null && c !== null) {\n res = a * b * c;\n }\n return res;\n}\n\n/**\n * Ellipse shape.\n */\nexport class Ellipse {\n\n /**\n * Ellipse centre.\n *\n * @type {Point2D}\n */\n #centre;\n\n /**\n * Ellipse horizontal radius.\n *\n * @type {number}\n */\n #a;\n\n /**\n * Ellipse vertical radius.\n *\n * @type {number}\n */\n #b;\n\n /**\n * @param {Point2D} centre A Point2D representing the centre\n * of the ellipse.\n * @param {number} a The radius of the ellipse on the horizontal axe.\n * @param {number} b The radius of the ellipse on the vertical axe.\n */\n constructor(centre, a, b) {\n this.#centre = centre;\n this.#a = a;\n this.#b = b;\n }\n\n /**\n * Get the centre (point) of the ellipse.\n *\n * @returns {Point2D} The center (point) of the ellipse.\n */\n getCenter() {\n return this.#centre;\n }\n\n /**\n * Get the centroid of the ellipse.\n *\n * @returns {Point2D} The centroid point.\n */\n getCentroid() {\n return this.#centre;\n }\n\n /**\n * Get the radius of the ellipse on the horizontal axe.\n *\n * @returns {number} The radius of the ellipse on the horizontal axe.\n */\n getA() {\n return this.#a;\n }\n\n /**\n * Get the radius of the ellipse on the vertical axe.\n *\n * @returns {number} The radius of the ellipse on the vertical axe.\n */\n getB() {\n return this.#b;\n }\n\n /**\n * Check for equality.\n *\n * @param {Ellipse} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.getCenter().equals(rhs.getCenter()) &&\n this.getA() === rhs.getA() &&\n this.getB() === rhs.getB();\n }\n\n /**\n * Get the surface of the ellipse.\n *\n * @returns {number} The surface of the ellipse.\n */\n getSurface() {\n return Math.PI * this.getA() * this.getB();\n }\n\n /**\n * Get the surface of the ellipse according to a spacing.\n *\n * @param {Scalar2D} spacing2D The 2D spacing.\n * @returns {number} The surface of the ellipse multiplied by the given\n * spacing or null for null spacings.\n */\n getWorldSurface(spacing2D) {\n return mulABC(this.getSurface(), spacing2D.x, spacing2D.y);\n }\n\n /**\n * Get the rounded limits of the ellipse.\n *\n * See: {@link https://en.wikipedia.org/wiki/Ellipse#Standard_equation}.\n *\n * Ellipse formula: `x*x / a*a + y*y / b*b = 1`.\n *\n * Implies: `y = (+-)(b/a) * sqrt(a*a - x*x)`.\n *\n * @returns {number[][][]} The rounded limits:\n * list of [x, y] pairs (min, max).\n */\n getRound() {\n const centerX = this.getCenter().getX();\n const centerY = this.getCenter().getY();\n const radiusX = this.getA();\n const radiusY = this.getB();\n const radiusRatio = radiusX / radiusY;\n const rySquare = Math.pow(radiusY, 2);\n // Y bounds\n const minY = centerY - radiusY;\n const maxY = centerY + radiusY;\n const regions = [];\n // loop through lines and store limits\n for (let y = minY; y < maxY; ++y) {\n const diff = rySquare - Math.pow(y - centerY, 2);\n // remove small values (possibly negative)\n if (Math.abs(diff) < 1e-7) {\n continue;\n }\n const transX = radiusRatio * Math.sqrt(diff);\n // remove small values\n if (transX < 0.5) {\n continue;\n }\n regions.push([\n [Math.round(centerX - transX), Math.round(y)],\n [Math.round(centerX + transX), Math.round(y)]\n ]);\n }\n return regions;\n }\n\n /**\n * Quantify an ellipse according to view information.\n *\n * @param {ViewController} viewController The associated view controller.\n * @param {string[]} flags A list of stat values to calculate.\n * @returns {object} A quantification object.\n */\n quantify(viewController, flags) {\n const quant = {};\n // shape quantification\n const spacing2D = viewController.get2DSpacing();\n quant.a = {\n value: this.getA() * spacing2D.x,\n unit: 'unit.mm'\n };\n quant.b = {\n value: this.getB() * spacing2D.y,\n unit: 'unit.mm'\n };\n const surface = this.getWorldSurface(spacing2D);\n if (surface !== null) {\n quant.surface = {\n value: surface / 100,\n unit: 'unit.cm2'\n };\n }\n\n // pixel values quantification\n if (viewController.canQuantifyImage()) {\n const regions = this.getRound();\n if (regions.length !== 0) {\n const values = viewController.getImageVariableRegionValues(regions);\n const unit = viewController.getPixelUnit();\n const quantif = getStats(values, flags);\n quant.min = {value: quantif.min, unit: unit};\n quant.max = {value: quantif.max, unit: unit};\n quant.mean = {value: quantif.mean, unit: unit};\n quant.stdDev = {value: quantif.stdDev, unit: unit};\n if (typeof quantif.median !== 'undefined') {\n quant.median = {value: quantif.median, unit: unit};\n }\n if (typeof quantif.p25 !== 'undefined') {\n quant.p25 = {value: quantif.p25, unit: unit};\n }\n if (typeof quantif.p75 !== 'undefined') {\n quant.p75 = {value: quantif.p75, unit: unit};\n }\n }\n }\n\n // return\n return quant;\n }\n\n} // Ellipse class\n\n/**\n * Get the indices that form a ellpise.\n *\n * @param {Index} center The ellipse center.\n * @param {number[]} radius The 2 ellipse radiuses.\n * @param {number[]} dir The 2 ellipse directions.\n * @returns {Index[]} The indices of the ellipse.\n */\nexport function getEllipseIndices(center, radius, dir) {\n const centerValues = center.getValues();\n // keep all values for possible extra dimensions\n const values = centerValues.slice();\n const indices = [];\n const radiusI = radius[0];\n const radiusJ = radius[1];\n const radiusRatio = radiusI / radiusJ;\n const radiusJ2 = Math.pow(radiusJ, 2);\n const di = dir[0];\n const dj = dir[1];\n // deduce 4 positions from top right\n for (let j = 0; j < radiusJ; ++j) {\n // right triangle formed by radiuses, j and len\n // ellipse: i*i / a*a + j*j / b*b = 1\n // -> i = a/b * sqrt(b*b - j*j)\n const len = Math.round(\n radiusRatio * Math.sqrt(radiusJ2 - Math.pow(j, 2)));\n const jmax = centerValues[dj] + j;\n const jmin = centerValues[dj] - j;\n for (let i = 0; i < len; ++i) {\n const imax = centerValues[di] + i;\n const imin = centerValues[di] - i;\n\n // right\n values[di] = imax;\n // right - top\n values[dj] = jmax;\n indices.push(new Index(values.slice()));\n // right - bottom\n if (jmin !== jmax) {\n values[dj] = jmin;\n indices.push(new Index(values.slice()));\n }\n\n // left\n if (imin !== imax) {\n values[di] = imin;\n // left - top\n values[dj] = jmax;\n indices.push(new Index(values.slice()));\n // left - bottom\n if (jmin !== jmax) {\n values[dj] = jmin;\n indices.push(new Index(values.slice()));\n }\n }\n }\n }\n return indices;\n}\n","import {getStats} from './stats';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\nimport {ViewController} from '../app/viewController';\nimport {Scalar2D} from './scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Mulitply the three inputs if the last two are not null.\n *\n * @param {number} a The first input.\n * @param {number} b The second input.\n * @param {number} c The third input.\n * @returns {number} The multiplication of the three inputs or\n * null if one of the last two is null.\n */\nfunction mulABC(a, b, c) {\n let res = null;\n if (b !== null && c !== null) {\n res = a * b * c;\n }\n return res;\n}\n\n/**\n * Circle shape.\n */\nexport class Circle {\n\n /**\n * Circle centre.\n *\n * @type {Point2D}\n */\n #centre;\n\n /**\n * Circle radius.\n *\n * @type {number}\n */\n #radius;\n\n /**\n * @param {Point2D} centre A Point2D representing the centre\n * of the circle.\n * @param {number} radius The radius of the circle.\n */\n constructor(centre, radius) {\n this.#centre = centre;\n this.#radius = radius;\n }\n\n /**\n * Get the centre (point) of the circle.\n *\n * @returns {Point2D} The center (point) of the circle.\n */\n getCenter() {\n return this.#centre;\n }\n\n /**\n * Get the centroid of the circle.\n *\n * @returns {Point2D} The centroid point.\n */\n getCentroid() {\n return this.#centre;\n }\n\n /**\n * Get the radius of the circle.\n *\n * @returns {number} The radius of the circle.\n */\n getRadius() {\n return this.#radius;\n }\n\n\n /**\n * Check for equality.\n *\n * @param {Circle} rhs The object to compare to.\n * @returns {boolean} True if both objects are equal.\n */\n equals(rhs) {\n return rhs !== null &&\n this.getCenter().equals(rhs.getCenter()) &&\n this.getRadius() === rhs.getRadius();\n }\n\n /**\n * Get the surface of the circle.\n *\n * @returns {number} The surface of the circle.\n */\n getSurface() {\n return Math.PI * this.getRadius() * this.getRadius();\n }\n\n /**\n * Get the surface of the circle according to a spacing.\n *\n * @param {Scalar2D} spacing2D The 2D spacing.\n * @returns {number} The surface of the circle multiplied by the given\n * spacing or null for null spacings.\n */\n getWorldSurface(spacing2D) {\n return mulABC(this.getSurface(), spacing2D.x, spacing2D.y);\n }\n\n /**\n * Get the rounded limits of the circle.\n *\n * See: {@link https://en.wikipedia.org/wiki/Circle#Equations}.\n *\n * Circle formula: `x*x + y*y = r*r`.\n *\n * Implies: `y = (+-) sqrt(r*r - x*x)`.\n *\n * @returns {number[][][]} The rounded limits:\n * list of [x, y] pairs (min, max).\n */\n getRound() {\n const centerX = this.getCenter().getX();\n const centerY = this.getCenter().getY();\n const radius = this.getRadius();\n const rSquare = Math.pow(radius, 2);\n // Y bounds\n const minY = centerY - radius;\n const maxY = centerY + radius;\n const regions = [];\n // loop through lines and store limits\n for (let y = minY; y < maxY; ++y) {\n const diff = rSquare - Math.pow(y - centerY, 2);\n // remove small values (possibly negative)\n if (Math.abs(diff) < 1e-7) {\n continue;\n }\n const transX = Math.sqrt(diff);\n // remove small values\n if (transX < 0.5) {\n continue;\n }\n regions.push([\n [Math.round(centerX - transX), Math.round(y)],\n [Math.round(centerX + transX), Math.round(y)]\n ]);\n }\n return regions;\n }\n\n /**\n * Quantify an circle according to view information.\n *\n * @param {ViewController} viewController The associated view controller.\n * @param {string[]} flags A list of stat values to calculate.\n * @returns {object} A quantification object.\n */\n quantify(viewController, flags) {\n const quant = {};\n // shape quantification\n const spacing2D = viewController.get2DSpacing();\n quant.radius = {\n value: this.getRadius() * spacing2D.x,\n unit: 'unit.mm'\n };\n const surface = this.getWorldSurface(spacing2D);\n if (surface !== null) {\n quant.surface = {\n value: surface / 100,\n unit: 'unit.cm2'\n };\n }\n\n // pixel values quantification\n if (viewController.canQuantifyImage()) {\n const regions = this.getRound();\n if (regions.length !== 0) {\n const values = viewController.getImageVariableRegionValues(regions);\n const unit = viewController.getPixelUnit();\n const quantif = getStats(values, flags);\n quant.min = {value: quantif.min, unit: unit};\n quant.max = {value: quantif.max, unit: unit};\n quant.mean = {value: quantif.mean, unit: unit};\n quant.stdDev = {value: quantif.stdDev, unit: unit};\n if (typeof quantif.median !== 'undefined') {\n quant.median = {value: quantif.median, unit: unit};\n }\n if (typeof quantif.p25 !== 'undefined') {\n quant.p25 = {value: quantif.p25, unit: unit};\n }\n if (typeof quantif.p75 !== 'undefined') {\n quant.p75 = {value: quantif.p75, unit: unit};\n }\n }\n }\n\n // return\n return quant;\n }\n\n} // Circle class\n","import {logger} from '../utils/logger';\nimport {UpdateAnnotationCommand} from './drawCommands';\nimport {validateAnchorPosition} from './drawBounds';\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {DrawLayer} from '../gui/drawLayer';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Draw shape editor.\n */\nexport class DrawShapeEditor {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Event callback.\n *\n * @type {Function}\n */\n #eventCallback;\n\n /**\n * @param {App} app The associated application.\n * @param {Function} eventCallback Event callback.\n */\n constructor(app, eventCallback) {\n this.#app = app;\n this.#eventCallback = eventCallback;\n }\n\n /**\n * Current shape factory.\n *\n * @type {object}\n */\n #currentFactory = null;\n\n /**\n * Edited shape.\n *\n * @type {Konva.Shape}\n */\n #shape = null;\n\n /**\n * Associated draw layer. Used to bound anchor move.\n *\n * @type {DrawLayer}\n */\n #drawLayer;\n\n /**\n * The associated annotation.\n *\n * @type {Annotation}\n */\n #annotation;\n\n /**\n * Active flag.\n *\n * @type {boolean}\n */\n #isActive = false;\n\n /**\n * @callback eventFn\n * @param {object} event The event.\n */\n\n /**\n * Set the shape to edit.\n *\n * @param {Konva.Shape} inshape The shape to edit.\n * @param {DrawLayer} drawLayer The associated draw layer.\n * @param {Annotation} annotation The associated annotation.\n */\n setShape(inshape, drawLayer, annotation) {\n this.#shape = inshape;\n this.#drawLayer = drawLayer;\n this.#annotation = annotation;\n\n if (this.#shape) {\n // remove old anchors\n this.#removeAnchors();\n\n this.#currentFactory = annotation.getFactory();\n if (this.#currentFactory === null) {\n throw new Error('Could not find a factory to update shape.');\n }\n\n // add new anchors\n this.#addAnchors();\n }\n }\n\n /**\n * Get the edited shape.\n *\n * @returns {Konva.Shape} The edited shape.\n */\n getShape() {\n return this.#shape;\n }\n\n /**\n * Get the edited annotation.\n *\n * @returns {Annotation} The annotation.\n */\n getAnnotation() {\n return this.#annotation;\n }\n\n /**\n * Get the active flag.\n *\n * @returns {boolean} The active flag.\n */\n isActive() {\n return this.#isActive;\n }\n\n /**\n * Enable the editor. Redraws the layer.\n */\n enable() {\n this.#isActive = true;\n if (this.#shape) {\n this.#setAnchorsVisible(true);\n if (this.#shape.getLayer()) {\n this.#shape.getLayer().draw();\n }\n }\n }\n\n /**\n * Disable the editor. Redraws the layer.\n */\n disable() {\n this.#isActive = false;\n if (this.#shape) {\n this.#setAnchorsVisible(false);\n if (this.#shape.getLayer()) {\n this.#shape.getLayer().draw();\n }\n }\n }\n\n /**\n * Reset the editor.\n */\n reset() {\n this.#shape = undefined;\n this.#drawLayer = undefined;\n this.#annotation = undefined;\n }\n\n /**\n * Reset the anchors.\n */\n resetAnchors() {\n // remove previous controls\n this.#removeAnchors();\n // add anchors\n this.#addAnchors();\n // set them visible\n this.#setAnchorsVisible(true);\n }\n\n /**\n * Apply a function on all anchors.\n *\n * @param {object} func A f(shape) function.\n */\n #applyFuncToAnchors(func) {\n if (this.#shape && this.#shape.getParent()) {\n const anchors = this.#shape.getParent().find('.anchor');\n anchors.forEach(func);\n }\n }\n\n /**\n * Set anchors visibility.\n *\n * @param {boolean} flag The visible flag.\n */\n #setAnchorsVisible(flag) {\n this.#applyFuncToAnchors(function (anchor) {\n anchor.visible(flag);\n });\n }\n\n /**\n * Set anchors active.\n *\n * @param {boolean} flag The active (on/off) flag.\n */\n setAnchorsActive(flag) {\n let func = null;\n if (flag) {\n func = (anchor) => {\n this.#setAnchorOn(anchor);\n };\n } else {\n func = (anchor) => {\n this.#setAnchorOff(anchor);\n };\n }\n this.#applyFuncToAnchors(func);\n }\n\n /**\n * Remove anchors.\n */\n #removeAnchors() {\n this.#applyFuncToAnchors(function (anchor) {\n anchor.remove();\n });\n }\n\n /**\n * Add the shape anchors.\n */\n #addAnchors() {\n // exit if no shape or no layer\n if (!this.#shape || !this.#shape.getLayer()) {\n return;\n }\n // get shape group\n const group = this.#shape.getParent();\n\n // activate and add anchors to group\n const anchors =\n this.#currentFactory.getAnchors(this.#shape, this.#app.getStyle());\n for (let i = 0; i < anchors.length; ++i) {\n // set anchor on\n this.#setAnchorOn(anchors[i]);\n // add the anchor to the group\n group.add(anchors[i]);\n }\n }\n\n /**\n * Set the anchor on listeners.\n *\n * @param {Konva.Ellipse} anchor The anchor to set on.\n */\n #setAnchorOn(anchor) {\n let originalProps;\n\n // drag start listener\n anchor.on('dragstart.edit', (event) => {\n // prevent bubbling upwards\n event.cancelBubble = true;\n // store original properties\n originalProps = {\n mathShape: this.#annotation.mathShape,\n referencePoints: this.#annotation.referencePoints\n };\n });\n // drag move listener\n anchor.on('dragmove.edit', (event) => {\n const anchor = event.target;\n if (!(anchor instanceof Konva.Shape)) {\n return;\n }\n // validate the anchor position\n validateAnchorPosition(this.#drawLayer.getBaseSize(), anchor);\n if (typeof this.#currentFactory.constrainAnchorMove !== 'undefined') {\n this.#currentFactory.constrainAnchorMove(anchor);\n }\n\n // udpate annotation\n this.#currentFactory.updateAnnotationOnAnchorMove(\n this.#annotation, anchor);\n // udpate shape\n this.#currentFactory.updateShapeGroupOnAnchorMove(\n this.#annotation, anchor, this.#app.getStyle());\n\n // redraw\n if (anchor.getLayer()) {\n anchor.getLayer().draw();\n } else {\n logger.warn('No layer to draw the anchor!');\n }\n // prevent bubbling upwards\n event.cancelBubble = true;\n });\n // drag end listener\n anchor.on('dragend.edit', (event) => {\n // update annotation command\n const newProps = {\n mathShape: this.#annotation.mathShape,\n referencePoints: this.#annotation.referencePoints\n };\n const command = new UpdateAnnotationCommand(\n this.#annotation,\n originalProps,\n newProps,\n this.#drawLayer.getDrawController()\n );\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // fire event manually since command is not executed\n this.#eventCallback({\n type: 'annotationupdate',\n data: this.#annotation,\n dataid: this.#drawLayer.getDataId(),\n keys: Object.keys(newProps)\n });\n // update original properties\n originalProps = {\n mathShape: newProps.mathShape,\n referencePoints: newProps.referencePoints\n };\n\n // prevent bubbling upwards\n event.cancelBubble = true;\n });\n // mouse down listener\n anchor.on('mousedown touchstart', (event) => {\n const anchor = event.target;\n anchor.moveToTop();\n });\n // mouse over styling\n anchor.on('mouseover.edit', (event) => {\n const anchor = event.target;\n if (!(anchor instanceof Konva.Shape)) {\n return;\n }\n // style is handled by the group\n anchor.stroke('#ddd');\n if (anchor.getLayer()) {\n anchor.getLayer().draw();\n } else {\n logger.warn('No layer to draw the anchor!');\n }\n });\n // mouse out styling\n anchor.on('mouseout.edit', (event) => {\n const anchor = event.target;\n if (!(anchor instanceof Konva.Shape)) {\n return;\n }\n // style is handled by the group\n anchor.stroke('#999');\n if (anchor.getLayer()) {\n anchor.getLayer().draw();\n } else {\n logger.warn('No layer to draw the anchor!');\n }\n });\n }\n\n /**\n * Set the anchor off listeners.\n *\n * @param {Konva.Ellipse} anchor The anchor to set off.\n */\n #setAnchorOff(anchor) {\n anchor.off('dragstart.edit');\n anchor.off('dragmove.edit');\n anchor.off('dragend.edit');\n anchor.off('mousedown touchstart');\n anchor.off('mouseover.edit');\n anchor.off('mouseout.edit');\n }\n\n} // class Editor\n","import Konva from 'konva';\n\n/* eslint-disable no-unused-vars */\nimport {Scalar2D} from '../math/scalar';\nimport {DrawLayer} from '../gui/drawLayer';\n/* eslint-enable no-unused-vars */\n\nexport class DrawTrash {\n /**\n * Trash draw: a cross.\n *\n * @type {Konva.Group}\n */\n #trash;\n\n constructor() {\n this.createTrashIcon();\n\n }\n\n /**\n * Creates the trash icon o positionates it.\n */\n createTrashIcon() {\n this.#trash = new Konva.Group();\n // first line of the cross\n const trashLine1 = new Konva.Line({\n points: [-10, -10, 10, 10],\n stroke: 'red'\n });\n // second line of the cross\n const trashLine2 = new Konva.Line({\n points: [10, -10, -10, 10],\n stroke: 'red'\n });\n this.#trash.width(20);\n this.#trash.height(20);\n this.#trash.add(trashLine1);\n this.#trash.add(trashLine2);\n }\n\n /**\n *\n * Activates the trash, by showing the icon into the layer draw layer.\n *\n * @param {DrawLayer} drawLayer The draw layer where to draw.\n */\n activate(drawLayer) {\n const stage = drawLayer.getKonvaStage();\n const scale = stage.scale();\n const konvaLayer = drawLayer.getKonvaLayer();\n const invscale = {x: 1 / scale.x, y: 1 / scale.y};\n this.#trash.x(stage.offset().x + (stage.width() / (2 * scale.x)));\n this.#trash.y(stage.offset().y + (stage.height() / (15 * scale.y)));\n this.#trash.scale(invscale);\n konvaLayer.add(this.#trash);\n // draw\n konvaLayer.draw();\n }\n\n /**\n *\n * Change colour on trash over.\n *\n * @param {Scalar2D} eventPosition The event drag move position.\n * @param {Konva.Group} shapeGroup The shape group whose colour\n * must be change.\n * @param {string} originalShapeColour The original shape colour.\n */\n changeChildrenColourOnTrashHover(eventPosition,\n shapeGroup, originalShapeColour) {\n if (this.isOverTrash(eventPosition)) {\n this.changeGroupChildrenColour(this.#trash, 'orange');\n this.changeGroupChildrenColour(shapeGroup, 'red');\n return;\n\n }\n this.changeGroupChildrenColour(this.#trash, 'red');\n this.changeGroupChildrenColour(shapeGroup, originalShapeColour);\n }\n\n /**\n * Change colour on trash out.\n *\n * @param {Konva.Group} group The group whose colour must be change.\n * @param {string} colour The new colour to be set.\n */\n changeGroupChildrenColour(group, colour) {\n group.getChildren().forEach(function (tshape) {\n if (tshape instanceof Konva.Shape &&\n typeof tshape.stroke !== 'undefined') {\n tshape.stroke(colour);\n }\n });\n }\n\n /**\n * Removes the trash from the draw layer.\n */\n remove() {\n this.#trash.remove();\n }\n\n /**\n * Determines if the event is over trash.\n *\n * @param {Scalar2D} eventPosition The event position.\n * @returns {boolean} True if the event is over trash.\n */\n isOverTrash(eventPosition) {\n const trashHalfWidth =\n this.#trash.width() * Math.abs(this.#trash.scaleX()) / 2;\n const trashHalfHeight =\n this.#trash.height() * Math.abs(this.#trash.scaleY()) / 2;\n return Math.abs(eventPosition.x - this.#trash.x()) < trashHalfWidth &&\n Math.abs(eventPosition.y - this.#trash.y()) < trashHalfHeight;\n }\n\n}","import {\n getMousePoint,\n customUI\n} from '../gui/generic';\nimport {\n RemoveAnnotationCommand,\n UpdateAnnotationCommand\n} from './drawCommands';\nimport {\n isNodeNameShape,\n isNodeNameLabel,\n getShapePositionRange,\n isShapeInRange\n} from './drawBounds';\nimport {DrawShapeEditor} from './drawShapeEditor';\nimport {DrawTrash} from './drawTrash';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {Scalar2D} from '../math/scalar';\nimport {DrawLayer} from '../gui/drawLayer';\nimport {Annotation} from '../image/annotation';\nimport {Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * Draw shape handler: handle action on existing shapes.\n */\nexport class DrawShapeHandler {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Shape editor.\n *\n * @type {DrawShapeEditor}\n */\n #shapeEditor;\n\n /**\n * Trash draw: a cross.\n *\n * @type {DrawTrash}\n */\n #trash;\n\n /**\n * Mouse cursor.\n *\n * @type {string}\n */\n #mouseOverCursor = 'pointer';\n\n /**\n * Original mouse cursor.\n *\n * @type {string}\n */\n #originalCursor;\n\n /**\n * Shape with mouse over.\n *\n * @type {Konva.Group}\n */\n #mouseOverShapeGroup;\n\n /**\n * Event callback.\n *\n * @type {Function}\n */\n #eventCallback;\n\n /**\n * @callback eventFn\n * @param {object} event The event.\n */\n\n /**\n * @param {App} app The associated application.\n * @param {Function} eventCallback Event callback.\n */\n constructor(app, eventCallback) {\n this.#app = app;\n this.#eventCallback = eventCallback;\n this.#shapeEditor = new DrawShapeEditor(app, eventCallback);\n this.#trash = new DrawTrash();\n }\n\n /**\n * Set the draw editor shape.\n *\n * @param {Konva.Shape} shape The shape to edit.\n * @param {DrawLayer} drawLayer The layer the shape belongs to.\n */\n setEditorShape(shape, drawLayer) {\n const drawController = drawLayer.getDrawController();\n if (shape &&\n shape instanceof Konva.Shape &&\n shape !== this.#shapeEditor.getShape() &&\n drawController.isAnnotationGroupEditable()) {\n // disable\n this.#shapeEditor.disable();\n // set shape\n this.#shapeEditor.setShape(\n shape,\n drawLayer,\n drawLayer.getDrawController().getAnnotation(shape.getParent().id()));\n // enable\n this.#shapeEditor.enable();\n }\n }\n\n /**\n * Get the currently edited shape group.\n *\n * @returns {Konva.Group|undefined} The edited group.\n */\n getEditorShapeGroup() {\n let res;\n if (this.#shapeEditor.isActive()) {\n res = this.#shapeEditor.getShape().getParent();\n if (!(res instanceof Konva.Group)) {\n return;\n }\n }\n return res;\n }\n\n /**\n * Get the currently edited annotation.\n *\n * @returns {Annotation|undefined} The edited annotation.\n */\n getEditorAnnotation() {\n let res;\n if (this.#shapeEditor.isActive()) {\n res = this.#shapeEditor.getAnnotation();\n }\n return res;\n }\n\n /**\n * Disable and reset the shape editor.\n */\n disableAndResetEditor() {\n this.#shapeEditor.disable();\n this.#shapeEditor.reset();\n }\n\n /**\n * Get the real position from an event.\n * TODO: use layer method?\n *\n * @param {Scalar2D} index The input index as {x,y}.\n * @param {DrawLayer} drawLayer The origin draw layer.\n * @returns {Scalar2D} The real position in the image as {x,y}.\n */\n #getRealPosition(index, drawLayer) {\n const stage = drawLayer.getKonvaStage();\n return {\n x: stage.offset().x + index.x / stage.scale().x,\n y: stage.offset().y + index.y / stage.scale().y\n };\n }\n\n /**\n * Store specific mouse over cursor.\n *\n * @param {string} cursor The cursor name.\n */\n storeMouseOverCursor(cursor) {\n this.#mouseOverCursor = cursor;\n }\n\n /**\n * Handle shape group mouseover.\n */\n #onMouseOverShapeGroup() {\n // mouse cursor\n this.#originalCursor = document.body.style.cursor;\n document.body.style.cursor = this.#mouseOverCursor;\n // shape opacity\n this.#mouseOverShapeGroup.opacity(0.75);\n }\n\n /**\n * Handle shape group mouseout.\n */\n onMouseOutShapeGroup() {\n // mouse cursor\n if (typeof this.#originalCursor !== 'undefined') {\n document.body.style.cursor = this.#originalCursor;\n this.#originalCursor = undefined;\n }\n // shape opacity\n if (typeof this.#mouseOverShapeGroup !== 'undefined') {\n this.#mouseOverShapeGroup.opacity(1);\n }\n }\n\n /**\n * Add shape group mouse over and out listeners: updates\n * shape group opacity and cursor.\n *\n * @param {Konva.Group} shapeGroup The shape group.\n */\n #addShapeOverListeners(shapeGroup) {\n // handle mouse over\n shapeGroup.on('mouseover', () => {\n this.#mouseOverShapeGroup = shapeGroup;\n this.#onMouseOverShapeGroup();\n });\n\n // handle mouse out\n shapeGroup.on('mouseout', () => {\n this.onMouseOutShapeGroup();\n this.#mouseOverShapeGroup = undefined;\n });\n }\n\n /**\n * Remove shape group mouse over and out listeners.\n *\n * @param {Konva.Group} shapeGroup The shape group.\n */\n #removeShapeOverListeners(shapeGroup) {\n shapeGroup.off('mouseover');\n shapeGroup.off('mouseout');\n }\n\n /**\n * Add shape group listeners.\n *\n * @param {Konva.Group} shapeGroup The shape group to set on.\n * @param {Annotation} annotation The associated annotation.\n * @param {DrawLayer} drawLayer The origin draw layer.\n */\n addShapeGroupListeners(shapeGroup, annotation, drawLayer) {\n // shape mouse over\n this.#addShapeOverListeners(shapeGroup);\n\n // make shape draggable\n this.#addShapeListeners(shapeGroup, annotation, drawLayer);\n\n // make label draggable\n this.#addLabelListeners(shapeGroup, annotation, drawLayer);\n\n // double click handling: update annotation text\n shapeGroup.on('dblclick', () => {\n // original text expr\n const originalTextExpr = annotation.textExpr;\n\n const onSaveCallback = (annotation) => {\n // new text expr\n const newTextExpr = annotation.textExpr;\n // create annotation update command\n const command = new UpdateAnnotationCommand(\n annotation,\n {textExpr: originalTextExpr},\n {textExpr: newTextExpr},\n drawLayer.getDrawController()\n );\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // execute command\n command.execute();\n };\n\n // call roi dialog\n customUI.openRoiDialog(annotation, onSaveCallback);\n });\n }\n\n /**\n * Add shape listeners.\n *\n * @param {Konva.Group} shapeGroup The shape group to get the shape from.\n * @param {Annotation} annotation The associated annotation.\n * @param {DrawLayer} drawLayer The origin draw layer.\n */\n #addShapeListeners(shapeGroup, annotation, drawLayer) {\n const konvaLayer = drawLayer.getKonvaLayer();\n\n const shape = shapeGroup.getChildren(isNodeNameShape)[0];\n if (!(shape instanceof Konva.Shape)) {\n return;\n }\n shape.draggable(true);\n\n // cache vars\n let dragStartPos;\n let previousPos;\n let originalProps;\n let colour;\n\n // drag start event handling\n shape.on('dragstart.draw', (event) => {\n // store colour\n colour = shape.stroke();\n // store pos\n dragStartPos = {\n x: shape.x(),\n y: shape.y()\n };\n previousPos = {\n x: event.target.x(),\n y: event.target.y()\n };\n // store original properties\n originalProps = {\n mathShape: annotation.mathShape,\n referencePoints: annotation.referencePoints\n };\n\n // display trash\n this.#trash.activate(drawLayer);\n // deactivate anchors to avoid events on null shape\n this.#shapeEditor.setAnchorsActive(false);\n // draw\n konvaLayer.draw();\n });\n\n // drag move event handling\n shape.on('dragmove.draw', (event) => {\n // if out of range, reset shape position and exit\n const range = getShapePositionRange(drawLayer.getBaseSize(), shape);\n if (range && !isShapeInRange(shape, range.min, range.max)) {\n shape.x(previousPos.x);\n shape.y(previousPos.y);\n return;\n }\n\n // move associated shapes (but not label)\n const diff = {\n x: event.target.x() - previousPos.x,\n y: event.target.y() - previousPos.y\n };\n const children = shapeGroup.getChildren();\n const labelWithDefaultPosition =\n typeof annotation.labelPosition === 'undefined';\n for (const child of children) {\n // skip shape and label with defined position\n if (child === event.target ||\n (child.name() === 'label' && !labelWithDefaultPosition) ||\n child.name() === 'connector'\n ) {\n continue;\n }\n // move other nodes\n child.move(diff);\n }\n\n // store pos\n previousPos = {\n x: event.target.x(),\n y: event.target.y()\n };\n\n // get appropriate factory\n const factory = annotation.getFactory();\n // update annotation\n factory.updateAnnotationOnTranslation(annotation, diff);\n // update label\n factory.updateLabelContent(annotation, shapeGroup, this.#app.getStyle());\n // update connector\n factory.updateConnector(shapeGroup);\n // highlight trash when on it\n const mousePoint = getMousePoint(event.evt);\n const offset = {\n x: mousePoint.getX(),\n y: mousePoint.getY()\n };\n const eventPos = this.#getRealPosition(offset, drawLayer);\n this.#trash.changeChildrenColourOnTrashHover(eventPos,\n shapeGroup, colour);\n // draw\n konvaLayer.draw();\n });\n\n // drag end event handling\n shape.on('dragend.draw', (event) => {\n // remove trash\n this.#trash.remove();\n // activate(false) will also trigger a dragend.draw\n if (typeof event === 'undefined' ||\n typeof event.evt === 'undefined') {\n return;\n }\n const pos = {x: shape.x(), y: shape.y()};\n // delete case\n const mousePoint = getMousePoint(event.evt);\n const offset = {\n x: mousePoint.getX(),\n y: mousePoint.getY()\n };\n const eventPos = this.#getRealPosition(offset, drawLayer);\n if (this.#trash.isOverTrash(eventPos)) {\n // compensate for the drag translation\n shapeGroup.x(dragStartPos.x);\n shapeGroup.y(dragStartPos.y);\n // disable editor\n this.#shapeEditor.disable();\n this.#shapeEditor.reset();\n this.#trash.changeGroupChildrenColour(shapeGroup, colour);\n // reset math shape (for undo)\n annotation.mathShape = originalProps.mathShape;\n annotation.referencePoints = originalProps.referencePoints;\n\n // create remove annotation command\n const command = new RemoveAnnotationCommand(\n annotation,\n drawLayer.getDrawController()\n );\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // execute command: triggers draw remove\n command.execute();\n\n // reset cursor\n this.onMouseOutShapeGroup();\n } else {\n const translation = {\n x: pos.x - dragStartPos.x,\n y: pos.y - dragStartPos.y\n };\n if (translation.x !== 0 || translation.y !== 0) {\n // update annotation command\n const newProps = {\n mathShape: annotation.mathShape,\n referencePoints: annotation.referencePoints\n };\n const command = new UpdateAnnotationCommand(\n annotation,\n originalProps,\n newProps,\n drawLayer.getDrawController()\n );\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // fire event manually since command is not executed\n this.#eventCallback({\n type: 'annotationupdate',\n data: annotation,\n dataid: drawLayer.getDataId(),\n keys: Object.keys(newProps)\n });\n // update original shape\n originalProps = {\n mathShape: newProps.mathShape,\n referencePoints: newProps.referencePoints\n };\n }\n // reset anchors\n this.#shapeEditor.setAnchorsActive(true);\n this.#shapeEditor.resetAnchors();\n }\n // draw\n konvaLayer.draw();\n // reset start position\n dragStartPos = {\n x: shape.x(),\n y: shape.y()\n };\n });\n }\n\n /**\n * Add label listeners.\n *\n * @param {Konva.Group} shapeGroup The shape group to get the label from.\n * @param {Annotation} annotation The associated annotation.\n * @param {DrawLayer} drawLayer The origin draw layer.\n */\n #addLabelListeners(shapeGroup, annotation, drawLayer) {\n const label = shapeGroup.getChildren(isNodeNameLabel)[0];\n if (!(label instanceof Konva.Label)) {\n return;\n }\n label.draggable(true);\n\n // cache vars\n let dragStartPos;\n let originalLabelPosition;\n\n // drag start event handling\n label.on('dragstart.draw', (/*event*/) => {\n // store pos\n dragStartPos = {\n x: label.x(),\n y: label.y()\n };\n // store original position\n originalLabelPosition = annotation.labelPosition;\n });\n\n // drag move event handling\n label.on('dragmove.draw', (/*event*/) => {\n // get factory\n const factory = annotation.getFactory();\n // update label\n factory.updateConnector(shapeGroup);\n });\n\n // drag end event handling\n label.on('dragend.draw', (/*event*/) => {\n const translation = {\n x: label.x() - dragStartPos.x,\n y: label.y() - dragStartPos.y\n };\n if (translation.x !== 0 || translation.y !== 0) {\n const newLabelPosition = new Point2D(label.x(), label.y());\n // set label position\n annotation.labelPosition = newLabelPosition;\n // update annotation command\n const command = new UpdateAnnotationCommand(\n annotation,\n {labelPosition: originalLabelPosition},\n {labelPosition: newLabelPosition},\n drawLayer.getDrawController()\n );\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // fire event manually since command is not executed\n this.#eventCallback({\n type: 'annotationupdate',\n data: annotation,\n dataid: drawLayer.getDataId(),\n keys: ['labelPosition']\n });\n // update original position\n originalLabelPosition = newLabelPosition;\n }\n dragStartPos = {x: label.x(), y: label.y()};\n });\n }\n\n /**\n * Remove shape group listeners.\n *\n * @param {Konva.Group} shapeGroup The shape group to set off.\n */\n removeShapeListeners(shapeGroup) {\n // mouse over\n this.#removeShapeOverListeners(shapeGroup);\n // double click\n shapeGroup.off('dblclick');\n // remove listeners from shape\n const shape = shapeGroup.getChildren(isNodeNameShape)[0];\n if (shape instanceof Konva.Shape) {\n shape.draggable(false);\n shape.off('dragstart.draw');\n shape.off('dragmove.draw');\n shape.off('dragend.draw');\n }\n // remove listeners from label\n const label = shapeGroup.getChildren(isNodeNameLabel)[0];\n if (label instanceof Konva.Label) {\n label.draggable(false);\n label.off('dragstart.draw');\n label.off('dragend.draw');\n }\n }\n} // DrawShapeHandler class","import {ListenerHandler} from '../utils/listen';\nimport {DrawController} from '../app/drawController';\nimport {getScaledOffset} from './layerGroup';\nimport {InteractionEventNames} from './generic';\nimport {logger} from '../utils/logger';\nimport {toStringId} from '../utils/array';\nimport {precisionRound} from '../utils/string';\nimport {AddAnnotationCommand} from '../tools/drawCommands';\nimport {\n isNodeWithId,\n isPositionNode,\n isNodeNameShape,\n isNodeNameLabel\n} from '../tools/drawBounds';\nimport {Style} from '../gui/style';\nimport {Line} from '../math/line';\nimport {Rectangle} from '../math/rectangle';\nimport {ROI} from '../math/roi';\nimport {Protractor} from '../math/protractor';\nimport {Ellipse} from '../math/ellipse';\nimport {Circle} from '../math/circle';\nimport {Point2D} from '../math/point';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point, Point3D} from '../math/point';\nimport {Index} from '../math/index';\nimport {Vector3D} from '../math/vector';\nimport {Scalar2D, Scalar3D} from '../math/scalar';\nimport {PlaneHelper} from '../image/planeHelper';\nimport {Annotation} from '../image/annotation';\nimport {AnnotationGroup} from '../image/annotationGroup';\nimport {DrawShapeHandler} from '../tools/drawShapeHandler';\n/* eslint-enable no-unused-vars */\n\n/**\n * Debug function to output the layer hierarchy as text.\n *\n * @param {object} layer The Konva layer.\n * @param {string} prefix A display prefix (used in recursion).\n * @returns {string} A text representation of the hierarchy.\n */\n// function getHierarchyLog(layer, prefix) {\n// if (typeof prefix === 'undefined') {\n// prefix = '';\n// }\n// const kids = layer.getChildren();\n// let log = prefix + '|__ ' + layer.name() + ': ' + layer.id() + '\\n';\n// for (let i = 0; i < kids.length; ++i) {\n// log += getHierarchyLog(kids[i], prefix + ' ');\n// }\n// return log;\n// }\n\n/**\n * Draw layer.\n */\nexport class DrawLayer {\n\n /**\n * The container div.\n *\n * @type {HTMLDivElement}\n */\n #containerDiv;\n\n /**\n * Konva stage.\n *\n * @type {Konva.Stage}\n */\n #konvaStage = null;\n\n /**\n * The layer base size as {x,y}.\n *\n * @type {Scalar2D}\n */\n #baseSize;\n\n /**\n * The layer base spacing as {x,y}.\n *\n * @type {Scalar2D}\n */\n #baseSpacing;\n\n /**\n * The layer fit scale.\n *\n * @type {Scalar2D}\n */\n #fitScale = {x: 1, y: 1};\n\n /**\n * The layer flip scale.\n *\n * @type {Scalar3D}\n */\n #flipScale = {x: 1, y: 1, z: 1};\n\n /**\n * The base layer offset.\n *\n * @type {Scalar2D}\n */\n #baseOffset = {x: 0, y: 0};\n\n /**\n * The view offset.\n *\n * @type {Scalar2D}\n */\n #viewOffset = {x: 0, y: 0};\n\n /**\n * The zoom offset.\n *\n * @type {Scalar2D}\n */\n #zoomOffset = {x: 0, y: 0};\n\n /**\n * The flip offset.\n *\n * @type {Scalar2D}\n */\n #flipOffset = {x: 0, y: 0};\n\n /**\n * The draw controller.\n *\n * @type {DrawController}\n */\n #drawController;\n\n /**\n * The plane helper.\n *\n * @type {PlaneHelper}\n */\n #planeHelper;\n\n /**\n * The associated data id.\n *\n * @type {string}\n */\n #dataId;\n\n /**\n * The reference layer id.\n *\n * @type {string}\n */\n #referenceLayerId;\n\n /**\n * Current position group id.\n *\n * @type {string|undefined}\n */\n #currentPosGroupId;\n\n /**\n * Draw shape handler.\n *\n * @type {DrawShapeHandler|undefined}\n */\n #shapeHandler;\n\n /**\n * Visible labels flag.\n *\n * @type {boolean}\n */\n #visibleLabels = true;\n\n /**\n * @param {HTMLDivElement} containerDiv The layer div, its id will be used\n * as this layer id.\n */\n constructor(containerDiv) {\n this.#containerDiv = containerDiv;\n // specific css class name\n this.#containerDiv.className += ' drawLayer';\n }\n\n /**\n * Set the draw shape handler.\n *\n * @param {DrawShapeHandler|undefined} handler The shape handler.\n */\n setShapeHandler(handler) {\n this.#shapeHandler = handler;\n }\n\n /**\n * Get the associated data id.\n *\n * @returns {string} The id.\n */\n getDataId() {\n return this.#dataId;\n }\n\n /**\n * Get the reference data id.\n *\n * @returns {string} The id.\n */\n getReferenceLayerId() {\n return this.#referenceLayerId;\n }\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Get the Konva stage.\n *\n * @returns {Konva.Stage} The stage.\n */\n getKonvaStage() {\n return this.#konvaStage;\n }\n\n /**\n * Get the Konva layer.\n *\n * @returns {Konva.Layer} The layer.\n */\n getKonvaLayer() {\n // there should only be one layer\n return this.#konvaStage.getLayers()[0];\n }\n\n /**\n * Get the draw controller.\n *\n * @returns {DrawController} The controller.\n */\n getDrawController() {\n return this.#drawController;\n }\n\n /**\n * Set the plane helper.\n *\n * @param {PlaneHelper} helper The helper.\n */\n setPlaneHelper(helper) {\n this.#planeHelper = helper;\n }\n\n // common layer methods [start] ---------------\n\n /**\n * Get the id of the layer.\n *\n * @returns {string} The string id.\n */\n getId() {\n return this.#containerDiv.id;\n }\n\n /**\n * Remove the HTML element from the DOM.\n */\n removeFromDOM() {\n this.#containerDiv.remove();\n }\n\n /**\n * Get the layer base size (without scale).\n *\n * @returns {Scalar2D} The size as {x,y}.\n */\n getBaseSize() {\n return this.#baseSize;\n }\n\n /**\n * Get the layer opacity.\n *\n * @returns {number} The opacity ([0:1] range).\n */\n getOpacity() {\n return this.#konvaStage.opacity();\n }\n\n /**\n * Set the layer opacity.\n *\n * @param {number} alpha The opacity ([0:1] range).\n */\n setOpacity(alpha) {\n this.#konvaStage.opacity(Math.min(Math.max(alpha, 0), 1));\n }\n\n /**\n * Add a flip offset along the layer X axis.\n */\n addFlipOffsetX() {\n // flip offset\n const scale = this.#konvaStage.scale();\n const size = this.#konvaStage.size();\n this.#flipOffset.x += size.width / scale.x;\n // apply\n const offset = this.#konvaStage.offset();\n offset.x += this.#flipOffset.x;\n this.#konvaStage.offset(offset);\n }\n\n /**\n * Add a flip offset along the layer Y axis.\n */\n addFlipOffsetY() {\n // flip offset\n const scale = this.#konvaStage.scale();\n const size = this.#konvaStage.size();\n this.#flipOffset.y += size.height / scale.y;\n // apply\n const offset = this.#konvaStage.offset();\n offset.y += this.#flipOffset.y;\n this.#konvaStage.offset(offset);\n }\n\n /**\n * Flip the scale along the layer X axis.\n */\n flipScaleX() {\n this.#flipScale.x *= -1;\n }\n\n /**\n * Flip the scale along the layer Y axis.\n */\n flipScaleY() {\n this.#flipScale.y *= -1;\n }\n\n /**\n * Flip the scale along the layer Z axis.\n */\n flipScaleZ() {\n this.#flipScale.z *= -1;\n }\n\n /**\n * Set the layer scale.\n *\n * @param {Scalar3D} newScale The scale as {x,y,z}.\n * @param {Point3D} [center] The scale center.\n */\n setScale(newScale, center) {\n const orientedNewScale =\n this.#planeHelper.getTargetOrientedPositiveXYZ({\n x: newScale.x * this.#flipScale.x,\n y: newScale.y * this.#flipScale.y,\n z: newScale.z * this.#flipScale.z,\n });\n const finalNewScale = {\n x: this.#fitScale.x * orientedNewScale.x,\n y: this.#fitScale.y * orientedNewScale.y\n };\n\n const offset = this.#konvaStage.offset();\n\n if (Math.abs(newScale.x) === 1 &&\n Math.abs(newScale.y) === 1 &&\n Math.abs(newScale.z) === 1) {\n // reset zoom offset for scale=1\n const resetOffset = {\n x: offset.x - this.#zoomOffset.x,\n y: offset.y - this.#zoomOffset.y\n };\n // store new offset\n this.#zoomOffset = {x: 0, y: 0};\n this.#konvaStage.offset(resetOffset);\n } else {\n if (typeof center !== 'undefined') {\n let worldCenter = this.#planeHelper.getPlaneOffsetFromOffset3D({\n x: center.getX(),\n y: center.getY(),\n z: center.getZ()\n });\n // center was obtained with viewLayer.displayToMainPlanePos\n // compensated for baseOffset\n // TODO: justify...\n worldCenter = {\n x: worldCenter.x + this.#baseOffset.x,\n y: worldCenter.y + this.#baseOffset.y\n };\n\n const newOffset = getScaledOffset(\n offset, this.#konvaStage.scale(), finalNewScale, worldCenter);\n\n const newZoomOffset = {\n x: this.#zoomOffset.x + newOffset.x - offset.x,\n y: this.#zoomOffset.y + newOffset.y - offset.y\n };\n // store new offset\n this.#zoomOffset = newZoomOffset;\n this.#konvaStage.offset(newOffset);\n }\n }\n\n this.#konvaStage.scale(finalNewScale);\n // update labels\n this.#updateLabelScale(finalNewScale);\n }\n\n /**\n * Initialise the layer scale.\n *\n * @param {Scalar3D} newScale The scale as {x,y,z}.\n * @param {Scalar2D} absoluteZoomOffset The zoom offset as {x,y}\n * without the fit scale (as provided by getAbsoluteZoomOffset).\n */\n initScale(newScale, absoluteZoomOffset) {\n const orientedNewScale = this.#planeHelper.getTargetOrientedPositiveXYZ({\n x: newScale.x * this.#flipScale.x,\n y: newScale.y * this.#flipScale.y,\n z: newScale.z * this.#flipScale.z,\n });\n const finalNewScale = {\n x: this.#fitScale.x * orientedNewScale.x,\n y: this.#fitScale.y * orientedNewScale.y\n };\n this.#konvaStage.scale(finalNewScale);\n\n this.#zoomOffset = {\n x: absoluteZoomOffset.x / this.#fitScale.x,\n y: absoluteZoomOffset.y / this.#fitScale.y\n };\n const offset = this.#konvaStage.offset();\n this.#konvaStage.offset({\n x: offset.x + this.#zoomOffset.x,\n y: offset.y + this.#zoomOffset.y\n });\n }\n\n /**\n * Set the layer offset.\n *\n * @param {Scalar3D} newOffset The offset as {x,y,z}.\n */\n setOffset(newOffset) {\n const planeNewOffset =\n this.#planeHelper.getPlaneOffsetFromOffset3D(newOffset);\n this.#konvaStage.offset({\n x: planeNewOffset.x +\n this.#viewOffset.x +\n this.#baseOffset.x +\n this.#zoomOffset.x +\n this.#flipOffset.x,\n y: planeNewOffset.y +\n this.#viewOffset.y +\n this.#baseOffset.y +\n this.#zoomOffset.y +\n this.#flipOffset.y\n });\n }\n\n /**\n * Set the base layer offset. Updates the layer offset.\n *\n * @param {Vector3D} scrollOffset The scroll offset vector.\n * @param {Vector3D} planeOffset The plane offset vector.\n * @returns {boolean} True if the offset was updated.\n */\n setBaseOffset(scrollOffset, planeOffset) {\n const scrollIndex = this.#planeHelper.getNativeScrollIndex();\n const newOffset = this.#planeHelper.getPlaneOffsetFromOffset3D({\n x: scrollIndex === 0 ? scrollOffset.getX() : planeOffset.getX(),\n y: scrollIndex === 1 ? scrollOffset.getY() : planeOffset.getY(),\n z: scrollIndex === 2 ? scrollOffset.getZ() : planeOffset.getZ(),\n });\n const needsUpdate = this.#baseOffset.x !== newOffset.x ||\n this.#baseOffset.y !== newOffset.y;\n // reset offset if needed\n if (needsUpdate) {\n const offset = this.#konvaStage.offset();\n this.#konvaStage.offset({\n x: offset.x - this.#baseOffset.x + newOffset.x,\n y: offset.y - this.#baseOffset.y + newOffset.y\n });\n this.#baseOffset = newOffset;\n }\n return needsUpdate;\n }\n\n /**\n * Display the layer.\n *\n * @param {boolean} flag Whether to display the layer or not.\n */\n display(flag) {\n this.#containerDiv.style.display = flag ? '' : 'none';\n }\n\n /**\n * Check if the layer is visible.\n *\n * @returns {boolean} True if the layer is visible.\n */\n isVisible() {\n return this.#containerDiv.style.display === '';\n }\n\n /**\n * Draw the content (imageData) of the layer.\n * The imageData variable needs to be set.\n */\n draw() {\n this.#konvaStage.draw();\n }\n\n /**\n * Initialise the layer: set the canvas and context.\n *\n * @param {Scalar2D} size The image size as {x,y}.\n * @param {Scalar2D} spacing The image spacing as {x,y}.\n * @param {string} refLayerId The reference image dataId.\n */\n initialise(size, spacing, refLayerId) {\n // set locals\n this.#baseSize = size;\n this.#baseSpacing = spacing;\n this.#referenceLayerId = refLayerId;\n\n // create stage\n this.#konvaStage = new Konva.Stage({\n container: this.#containerDiv,\n width: this.#baseSize.x,\n height: this.#baseSize.y,\n listening: false\n });\n // reset style\n // (avoids a not needed vertical scrollbar)\n this.#konvaStage.getContent().setAttribute('style', '');\n\n // create layer\n const konvaLayer = new Konva.Layer({\n listening: false,\n visible: true\n });\n this.#konvaStage.add(konvaLayer);\n }\n\n /**\n * Set the annotation group.\n *\n * @param {AnnotationGroup} annotationGroup The annotation group.\n * @param {string} dataId The associated data id.\n * @param {object} exeCallback The undo stack callback.\n */\n setAnnotationGroup(annotationGroup, dataId, exeCallback) {\n this.#dataId = dataId;\n // local listeners\n annotationGroup.addEventListener('annotationadd', (event) => {\n // draw annotation\n this.#addAnnotationDraw(event.data, true);\n this.getKonvaLayer().draw();\n });\n annotationGroup.addEventListener('annotationupdate', (event) => {\n // update annotation draw\n this.#updateAnnotationDraw(event.data);\n this.getKonvaLayer().draw();\n });\n annotationGroup.addEventListener('annotationremove', (event) => {\n // remove annotation draw\n this.#removeAnnotationDraw(event.data);\n this.getKonvaLayer().draw();\n });\n annotationGroup.addEventListener(\n 'annotationgroupeditablechange',\n (event) => {\n this.activateCurrentPositionShapes(event.data);\n }\n );\n\n // create draw controller\n this.#drawController = new DrawController(annotationGroup);\n\n // annotations are allready in the annotation list,\n // -> no need to add them, just draw and save command\n if (annotationGroup.getLength() !== 0) {\n for (const annotation of annotationGroup.getList()) {\n // draw annotation\n this.#addAnnotationDraw(annotation, false);\n // create the draw command\n const command = new AddAnnotationCommand(\n annotation, this.getDrawController());\n // add command to undo stack\n exeCallback(command);\n }\n }\n }\n\n /**\n * Activate shapes at current position.\n *\n * @param {boolean} flag The flag to activate or not.\n */\n activateCurrentPositionShapes(flag) {\n const konvaLayer = this.getKonvaLayer();\n\n // stop listening\n this.#konvaStage.listening(false);\n\n if (typeof this.#shapeHandler !== 'undefined') {\n // reset shape editor (remove anchors)\n this.#shapeHandler.disableAndResetEditor();\n // remove listeners for all position groups\n const allPosGroups = konvaLayer.getChildren();\n for (const posGroup of allPosGroups) {\n if (posGroup instanceof Konva.Group) {\n posGroup.getChildren().forEach((group) => {\n if (group instanceof Konva.Group) {\n this.#shapeHandler.removeShapeListeners(group);\n }\n });\n }\n }\n }\n\n // activate shape listeners if possible\n const drawController = this.getDrawController();\n if (flag &&\n drawController.getAnnotationGroup().isEditable()) {\n // shape groups at the current position\n const shapeGroups =\n this.#getCurrentPosGroup().getChildren();\n // listen if we have shapes\n if (shapeGroups.length !== 0) {\n this.#konvaStage.listening(true);\n konvaLayer.listening(true);\n }\n // add listeners for position group\n if (typeof this.#shapeHandler !== 'undefined') {\n shapeGroups.forEach((group) => {\n if (group instanceof Konva.Group) {\n const annotation = drawController.getAnnotation(group.id());\n this.#shapeHandler.addShapeGroupListeners(group, annotation, this);\n }\n });\n }\n }\n\n konvaLayer.draw();\n }\n\n /**\n * Get the position group id for an annotation.\n *\n * @param {Annotation} annotation The target annotation.\n * @returns {string|undefined} The group id.\n */\n #getAnnotationPosGroupId(annotation) {\n let points;\n // annotation planePoints are only present\n // for non aquisition plane\n if (typeof annotation.planePoints !== 'undefined') {\n // use plane points\n points = annotation.planePoints;\n } else {\n // just use plane origin\n points = [annotation.planeOrigin];\n }\n return this.#getPositionId(points);\n }\n\n /**\n * Get a string id from input plane points.\n *\n * @param {Point3D[]} points A list of points that defined a plane.\n * @returns {string} The string id.\n */\n #getPositionId(points) {\n let res = '';\n for (const point of points) {\n if (res.length !== 0) {\n res += '-';\n }\n const posValues = [\n precisionRound(point.getX(), 2),\n precisionRound(point.getY(), 2),\n precisionRound(point.getZ(), 2),\n ];\n res += toStringId(posValues);\n }\n return res;\n }\n\n /**\n * Find the shape group associated to an annotation.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Konva.Group|undefined} The shape group.\n */\n #findShapeGroup(annotation) {\n let res;\n\n const posGroupId = this.#getAnnotationPosGroupId(annotation);\n const layerChildren = this.getKonvaLayer().getChildren(\n isNodeWithId(posGroupId));\n if (layerChildren.length !== 0) {\n const posGroup = layerChildren[0];\n if (!(posGroup instanceof Konva.Group)) {\n return;\n }\n const posChildren = posGroup.getChildren(\n isNodeWithId(annotation.id));\n if (posChildren.length !== 0 &&\n posChildren[0] instanceof Konva.Group) {\n res = posChildren[0];\n }\n }\n return res;\n }\n\n /**\n * Draw an annotation: create the shape group and add it to\n * the Konva layer.\n *\n * @param {Annotation} annotation The annotation to draw.\n * @param {boolean} visible The position group visibility.\n */\n #addAnnotationDraw(annotation, visible) {\n // check for compatible view\n if (!annotation.isCompatibleView(this.#planeHelper)) {\n return;\n }\n const posGroupId = this.#getAnnotationPosGroupId(annotation);\n // Get or create position-group if it does not exist and\n // append it to konvaLayer\n let posGroup = this.getKonvaLayer().getChildren(\n isNodeWithId(posGroupId))[0];\n if (typeof posGroup === 'undefined') {\n posGroup = new Konva.Group({\n id: posGroupId,\n name: 'position-group',\n visible: visible\n });\n this.getKonvaLayer().add(posGroup);\n }\n if (!(posGroup instanceof Konva.Group)) {\n return;\n };\n\n const style = new Style();\n const stage = this.getKonvaStage();\n style.setZoomScale(stage.scale());\n\n // shape group (use first one since it will be removed from\n // the group when we change it)\n const factory = annotation.getFactory();\n const shapeGroup = factory.createShapeGroup(annotation, style);\n // add group to posGroup (switches its parent)\n posGroup.add(shapeGroup);\n\n // activate shape if possible\n if (visible &&\n typeof this.#shapeHandler !== 'undefined'\n ) {\n this.#shapeHandler.addShapeGroupListeners(shapeGroup, annotation, this);\n }\n // set label visibility\n this.setLabelVisibility(shapeGroup);\n }\n\n /**\n * Remove an annotation draw.\n *\n * @param {Annotation} annotation The annotation to remove.\n * @returns {boolean} True if the shape group has been found and removed.\n */\n #removeAnnotationDraw(annotation) {\n const shapeGroup = this.#findShapeGroup(annotation);\n if (!(shapeGroup instanceof Konva.Group)) {\n logger.debug('No shape group to remove');\n return false;\n };\n shapeGroup.remove();\n return true;\n }\n\n /**\n * Update an annotation draw.\n *\n * @param {Annotation} annotation The annotation to update.\n */\n #updateAnnotationDraw(annotation) {\n // update quantification after math shape update\n annotation.updateQuantification();\n // update draw if needed\n if (this.#removeAnnotationDraw(annotation)) {\n this.#addAnnotationDraw(annotation, true);\n }\n }\n\n /**\n * Fit the layer to its parent container.\n *\n * @param {Scalar2D} containerSize The container size as {x,y}.\n * @param {number} divToWorldSizeRatio The div to world size ratio.\n * @param {Scalar2D} fitOffset The fit offset as {x,y}.\n */\n fitToContainer(containerSize, divToWorldSizeRatio, fitOffset) {\n // update konva\n this.#konvaStage.width(containerSize.x);\n this.#konvaStage.height(containerSize.y);\n\n // fit scale\n const divToImageSizeRatio = {\n x: divToWorldSizeRatio * this.#baseSpacing.x,\n y: divToWorldSizeRatio * this.#baseSpacing.y\n };\n // #scale = inputScale * fitScale * flipScale\n // flipScale does not change here, we can omit it\n // newScale = (#scale / fitScale) * newFitScale\n const newScale = {\n x: this.#konvaStage.scale().x * divToImageSizeRatio.x / this.#fitScale.x,\n y: this.#konvaStage.scale().y * divToImageSizeRatio.y / this.#fitScale.y\n };\n\n // set scales if different from previous\n if (this.#konvaStage.scale().x !== newScale.x ||\n this.#konvaStage.scale().y !== newScale.y) {\n this.#fitScale = divToImageSizeRatio;\n this.#konvaStage.scale(newScale);\n }\n\n // view offset\n const newViewOffset = {\n x: fitOffset.x / divToImageSizeRatio.x,\n y: fitOffset.y / divToImageSizeRatio.y\n };\n // flip offset\n const scaledImageSize = {\n x: containerSize.x / divToImageSizeRatio.x,\n y: containerSize.y / divToImageSizeRatio.y\n };\n const newFlipOffset = {\n x: this.#flipOffset.x !== 0 ? scaledImageSize.x : 0,\n y: this.#flipOffset.y !== 0 ? scaledImageSize.y : 0,\n };\n\n // set offsets if different from previous\n if (this.#viewOffset.x !== newViewOffset.x ||\n this.#viewOffset.y !== newViewOffset.y ||\n this.#flipOffset.x !== newFlipOffset.x ||\n this.#flipOffset.y !== newFlipOffset.y) {\n // update global offset\n this.#konvaStage.offset({\n x: this.#konvaStage.offset().x +\n newViewOffset.x - this.#viewOffset.x +\n newFlipOffset.x - this.#flipOffset.x,\n y: this.#konvaStage.offset().y +\n newViewOffset.y - this.#viewOffset.y +\n newFlipOffset.y - this.#flipOffset.y,\n });\n // update private local offsets\n this.#flipOffset = newFlipOffset;\n this.#viewOffset = newViewOffset;\n }\n }\n\n /**\n * Check the visibility of an annotation.\n *\n * @param {string} id The id of the annotation.\n * @returns {boolean} True if the annotation is visible.\n */\n isAnnotationVisible(id) {\n // get the group (annotation and group have same id)\n const group = this.#getGroup(id);\n if (typeof group === 'undefined') {\n return false;\n }\n // get visibility\n return group.isVisible();\n }\n\n /**\n * Set the visibility of an annotation.\n *\n * @param {string} id The id of the annotation.\n * @param {boolean} [visible] True to set to visible,\n * will toggle visibility if not defined.\n * @returns {boolean} False if the annotation shape cannot be found.\n */\n setAnnotationVisibility(id, visible) {\n // get the group (annotation and group have same id)\n const group = this.#getGroup(id);\n if (typeof group === 'undefined') {\n return false;\n }\n // if not set, toggle visibility\n if (typeof visible === 'undefined') {\n visible = !group.isVisible();\n }\n group.visible(visible);\n\n // udpate\n this.draw();\n\n return true;\n }\n\n /**\n * Set the visibility of all labels.\n *\n * @param {boolean} [visible] True to set to visible,\n * will toggle visibility if not defined.\n */\n setLabelsVisibility(visible) {\n this.#visibleLabels = visible;\n\n const posGroups = this.getKonvaLayer().getChildren();\n for (const posGroup of posGroups) {\n if (posGroup instanceof Konva.Group) {\n const shapeGroups = posGroup.getChildren();\n for (const shapeGroup of shapeGroups) {\n if (shapeGroup instanceof Konva.Group) {\n this.#setLabelVisibility(shapeGroup, visible);\n }\n }\n }\n }\n }\n\n /**\n * Set a shape group label visibility.\n *\n * @param {Konva.Group} shapeGroup The shape group.\n * @param {boolean} [visible] True to set to visible,\n * will toggle visibility if not defined.\n */\n #setLabelVisibility(shapeGroup, visible) {\n const label = shapeGroup.getChildren(isNodeNameLabel)[0];\n if (!(label instanceof Konva.Label)) {\n return;\n }\n // if not set, toggle visibility\n if (typeof visible === 'undefined') {\n visible = !label.isVisible();\n }\n // set visible only for non empty text\n if (typeof label.getText() !== 'undefined' &&\n label.getText().text().length !== 0) {\n label.visible(visible);\n const connector = shapeGroup.getChildren(node =>\n (node.className === 'Line') && node.name() === 'connector')[0];\n if (connector) {\n connector.visible(visible);\n }\n }\n }\n\n /**\n * Set a shape group label visibility according to\n * this layer setting.\n *\n * @param {Konva.Group} shapeGroup The shape group.\n */\n setLabelVisibility(shapeGroup) {\n this.#setLabelVisibility(shapeGroup, this.#visibleLabels);\n }\n\n /**\n * Delete a Draw from the stage.\n *\n * @deprecated Since v0.34, please switch to `annotationGroup.remove`.\n * @param {string} _id The id of the group to delete.\n * @param {Function} _exeCallback The callback to call once the\n * DeleteCommand has been executed.\n */\n deleteDraw(_id, _exeCallback) {\n // does nothing\n }\n\n /**\n * Delete all Draws from the stage.\n *\n * @deprecated Since v0.34, please switch to `annotationGroup.remove`.\n * @param {Function} _exeCallback The callback to call once the\n * DeleteCommand has been executed.\n */\n deleteDraws(_exeCallback) {\n // does nothing\n }\n\n /**\n * Get the total number of draws of this layer\n * (at all positions).\n *\n * @returns {number|undefined} The total number of draws.\n */\n getNumberOfDraws() {\n const posGroups = this.getKonvaLayer().getChildren();\n let count = 0;\n for (const posGroup of posGroups) {\n if (posGroup instanceof Konva.Group) {\n count += posGroup.getChildren().length;\n }\n }\n return count;\n }\n\n /**\n * Enable and listen to container interaction events.\n */\n bindInteraction() {\n this.#konvaStage.listening(true);\n // allow pointer events\n this.#containerDiv.style.pointerEvents = 'auto';\n // interaction events\n const names = InteractionEventNames;\n for (let i = 0; i < names.length; ++i) {\n this.#containerDiv.addEventListener(names[i], this.#fireEvent);\n }\n }\n\n /**\n * Disable and stop listening to container interaction events.\n */\n unbindInteraction() {\n this.#konvaStage.listening(false);\n // disable pointer events\n this.#containerDiv.style.pointerEvents = 'none';\n // interaction events\n const names = InteractionEventNames;\n for (let i = 0; i < names.length; ++i) {\n this.#containerDiv.removeEventListener(names[i], this.#fireEvent);\n }\n }\n\n /**\n * Set the current position.\n *\n * @param {Point} position The new position.\n * @param {Index} [index] Optional coresponding index.\n * @returns {boolean} True if the position was updated.\n */\n setCurrentPosition(position, index) {\n if (typeof index === 'undefined') {\n index = this.#planeHelper.worldToIndex(position);\n }\n const planePoints = this.#planeHelper.getPlanePoints(position);\n let points;\n if (this.#planeHelper.isAquisitionOrientation()) {\n // just use plane origin\n points = [planePoints[0]];\n } else {\n // use plane points\n points = planePoints;\n }\n const posGroupId = this.#getPositionId(points);\n\n this.#activateDrawLayer(posGroupId);\n // TODO: add check\n this.#fireEvent({\n type: 'positionchange',\n value: [\n index.getValues(),\n position.getValues(),\n ],\n valid: true\n });\n\n return true;\n }\n\n /**\n * Activate the current draw layer.\n *\n * @param {string} posGroupId The position group ID.\n */\n #activateDrawLayer(posGroupId) {\n this.#currentPosGroupId = posGroupId;\n\n // get all position groups\n const posGroups = this.getKonvaLayer().getChildren(isPositionNode);\n // reset or set the visible property\n let visible;\n for (let i = 0, leni = posGroups.length; i < leni; ++i) {\n visible = false;\n if (typeof posGroupId !== 'undefined' &&\n posGroups[i].id() === posGroupId) {\n visible = true;\n }\n // group members inherit the visible property\n posGroups[i].visible(visible);\n }\n\n // show current draw layer\n this.getKonvaLayer().draw();\n }\n\n /**\n * Get the current position group.\n *\n * @returns {Konva.Group|undefined} The Konva group.\n */\n #getCurrentPosGroup() {\n if (typeof this.#currentPosGroupId === 'undefined') {\n return;\n }\n // get position groups\n const posGroups = this.getKonvaLayer().getChildren((node) => {\n return node.id() === this.#currentPosGroupId;\n });\n // if one group, use it\n // if no group, create one\n let posGroup;\n if (posGroups.length === 1) {\n if (posGroups[0] instanceof Konva.Group) {\n posGroup = posGroups[0];\n }\n } else if (posGroups.length === 0) {\n posGroup = new Konva.Group();\n posGroup.name('position-group');\n posGroup.id(this.#currentPosGroupId);\n posGroup.visible(true); // dont inherit\n // add new group to layer\n this.getKonvaLayer().add(posGroup);\n } else {\n logger.warn('Unexpected number of draw position groups');\n }\n // return\n return posGroup;\n }\n\n /**\n * Get a Konva group using its id.\n *\n * @param {string} id The group id.\n * @returns {Konva.Group|undefined} The Konva group.\n */\n #getGroup(id) {\n return this.getKonvaLayer().findOne('#' + id);\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n event.srclayerid = this.getId();\n event.dataid = this.#dataId;\n this.#listenerHandler.fireEvent(event);\n };\n\n // common layer methods [end] ---------------\n\n /**\n * Update label scale: compensate for it so\n * that label size stays visually the same.\n *\n * @param {Scalar2D} scale The scale to compensate for as {x,y}.\n */\n #updateLabelScale(scale) {\n // same formula as in labelFactory::create\n // compensate for scale and times 2 so that font 10 looks like a 10\n const ratioX = 2 / scale.x;\n const ratioY = 2 / scale.y;\n // compensate scale for labels\n const labels = this.#konvaStage.find('Label');\n for (let i = 0; i < labels.length; ++i) {\n labels[i].scale({x: ratioX, y: ratioY});\n }\n }\n\n} // DrawLayer class\n\n// *************************\n// legacy code to allow to convert old state into annotation\n// *************************\n\n/**\n * Draw meta data.\n */\nexport class DrawMeta {\n /**\n * Draw quantification.\n *\n * @type {object}\n */\n quantification;\n\n /**\n * Draw text expression. Can contain variables surrounded with '{}' that will\n * be extracted from the quantification object.\n *\n * @type {string}\n */\n textExpr;\n}\n\n/**\n * Draw details.\n */\nexport class DrawDetails {\n /**\n * The draw ID.\n *\n * @type {number}\n */\n id;\n\n /**\n * The draw position: an Index converted to string.\n *\n * @type {string}\n */\n position;\n\n /**\n * The draw type.\n *\n * @type {string}\n */\n type;\n\n /**\n * The draw color: for example 'green', '#00ff00' or 'rgb(0,255,0)'.\n *\n * @type {string}\n */\n color;\n\n /**\n * The draw meta.\n *\n * @type {DrawMeta}\n */\n meta;\n}\n\n/**\n * Convert a KonvaLayer object to a list of annotations.\n *\n * @param {Array} drawings An array of drawings stored\n * with 'KonvaLayer().toObject()'.\n * @param {DrawDetails[]} drawingsDetails An array of drawings details.\n * @returns {Annotation[]} The associated list of annotations.\n */\nexport function konvaToAnnotation(drawings, drawingsDetails) {\n const annotations = [];\n\n // regular Konva deserialize\n const stateLayer = Konva.Node.create(drawings);\n\n // get all position groups\n const statePosGroups = stateLayer.getChildren(isPositionNode);\n\n for (let i = 0, leni = statePosGroups.length; i < leni; ++i) {\n const statePosGroup = statePosGroups[i];\n const statePosKids = statePosGroup.getChildren();\n for (let j = 0, lenj = statePosKids.length; j < lenj; ++j) {\n const annotation = new Annotation();\n\n // shape group (use first one since it will be removed from\n // the group when we change it)\n const stateGroup = statePosKids[0];\n // annotation id\n annotation.id = stateGroup.id();\n\n // shape\n const shape = stateGroup.getChildren(isNodeNameShape)[0];\n // annotation colour\n annotation.colour = shape.stroke();\n\n if (stateGroup.name() === 'line-group') {\n const points = shape.points();\n annotation.mathShape = new Point2D(points[0], points[1]);\n annotation.referencePoints = [\n new Point2D(points[2], points[3])\n ];\n } else if (stateGroup.name() === 'ruler-group') {\n const points = shape.points();\n annotation.mathShape = new Line(\n new Point2D(points[0], points[1]),\n new Point2D(points[2], points[3])\n );\n } else if (stateGroup.name() === 'rectangle-group') {\n annotation.mathShape = new Rectangle(\n new Point2D(shape.x(), shape.y()),\n new Point2D(shape.x() + shape.width(), shape.y() + shape.height())\n );\n } else if (stateGroup.name() === 'roi-group') {\n const points = shape.points();\n const pointsArray = [];\n for (let i = 0; i < points.length; i = i + 2) {\n pointsArray.push(new Point2D(points[i], points[i + 1]));\n }\n annotation.mathShape = new ROI(pointsArray);\n } else if (stateGroup.name() === 'freeHand-group') {\n logger.warn('Converting freehand into ROI shape');\n const points = shape.points();\n const pointsArray = [];\n for (let i = 0; i < points.length; i = i + 2) {\n pointsArray.push(new Point2D(points[i], points[i + 1]));\n }\n annotation.mathShape = new ROI(pointsArray);\n } else if (stateGroup.name() === 'protractor-group') {\n const points = shape.points();\n annotation.mathShape = new Protractor([\n new Point2D(points[0], points[1]),\n new Point2D(points[2], points[3]),\n new Point2D(points[4], points[5])\n ]);\n } else if (stateGroup.name() === 'ellipse-group') {\n const absPosition = shape.absolutePosition();\n annotation.mathShape = new Ellipse(\n new Point2D(absPosition.x, absPosition.y),\n shape.radiusX(),\n shape.radiusY()\n );\n } else if (stateGroup.name() === 'circle-group') {\n const absPosition = shape.absolutePosition();\n annotation.mathShape = new Circle(\n new Point2D(absPosition.x, absPosition.y),\n shape.radius()\n );\n }\n\n // details\n if (drawingsDetails) {\n const details = drawingsDetails[stateGroup.id()];\n annotation.textExpr = details.meta.textExpr;\n annotation.quantification = details.meta.quantification;\n }\n\n annotations.push(annotation);\n }\n }\n\n return annotations;\n}\n","// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DrawLayer} from '../gui/drawLayer';\nimport {Annotation} from '../image/annotation';\nimport {DrawController} from '../app/drawController';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get the display name of the input shape.\n *\n * @param {Konva.Shape} shape The Konva shape.\n * @returns {string} The display name.\n */\nexport function getShapeDisplayName(shape) {\n let displayName = 'shape';\n if (shape instanceof Konva.Line) {\n if (shape.points().length === 4) {\n displayName = 'line';\n } else if (shape.points().length === 6) {\n displayName = 'protractor';\n } else {\n displayName = 'roi';\n }\n } else if (shape instanceof Konva.Rect) {\n displayName = 'rectangle';\n } else if (shape instanceof Konva.Ellipse) {\n displayName = 'ellipse';\n }\n // return\n return displayName;\n}\n\n/**\n * Add annotation command.\n */\nexport class AddAnnotationCommand {\n /**\n * @type {Annotation}\n */\n #annotation;\n\n /**\n * @type {DrawController}\n */\n #drawController;\n\n /**\n * @param {Annotation} annotation The annotation to add.\n * @param {DrawController} drawController The associated draw controller.\n */\n constructor(annotation, drawController) {\n this.#annotation = annotation;\n this.#drawController = drawController;\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'AddAnnotation-' + this.#annotation.id;\n }\n\n /**\n * Execute the command.\n */\n execute() {\n this.#drawController.addAnnotation(this.#annotation);\n }\n\n /**\n * Undo the command.\n */\n undo() {\n this.#drawController.removeAnnotation(this.#annotation.id);\n }\n}\n\n/**\n * Remove annotation command.\n */\nexport class RemoveAnnotationCommand {\n /**\n * @type {Annotation}\n */\n #annotation;\n\n /**\n * @type {DrawController}\n */\n #drawController;\n\n /**\n * @param {Annotation} annotation The annotation to remove.\n * @param {DrawController} drawController The associated draw controller.\n */\n constructor(annotation, drawController) {\n this.#annotation = annotation;\n this.#drawController = drawController;\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'RemoveAnnotation-' + this.#annotation.id;\n }\n\n /**\n * Execute the command.\n */\n execute() {\n this.#drawController.removeAnnotation(this.#annotation.id);\n }\n\n /**\n * Undo the command.\n */\n undo() {\n this.#drawController.addAnnotation(this.#annotation);\n }\n}\n\n/**\n * Update annotation command.\n */\nexport class UpdateAnnotationCommand {\n /**\n * @type {Annotation}\n */\n #annotation;\n\n /**\n * @type {DrawController}\n */\n #drawController;\n\n /**\n * Original annotation properties.\n *\n * @type {object}\n */\n #originalProps;\n\n /**\n * New annotation properties.\n *\n * @type {object}\n */\n #newProps;\n\n /**\n * @param {Annotation} annotation The annotation to update.\n * @param {object} originaProps The original annotation properties.\n * @param {object} newProps The new annotation properties.\n * @param {DrawController} drawController The associated draw controller.\n */\n constructor(annotation, originaProps, newProps, drawController) {\n this.#annotation = annotation;\n this.#drawController = drawController;\n this.#originalProps = originaProps;\n this.#newProps = newProps;\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'UpdateAnnotation-' + this.#annotation.id;\n }\n\n /**\n * Execute the command.\n */\n execute() {\n const keys = Object.keys(this.#newProps);\n for (const key of keys) {\n this.#annotation[key] = this.#newProps[key];\n }\n this.#drawController.updateAnnotation(this.#annotation, keys);\n }\n\n /**\n * Undo the command.\n */\n undo() {\n const keys = Object.keys(this.#originalProps);\n for (const key of keys) {\n this.#annotation[key] = this.#originalProps[key];\n }\n this.#drawController.updateAnnotation(this.#annotation, keys);\n }\n}\n/**\n * Draw group command.\n *\n * TODO: remove.\n */\nexport class DrawGroupCommand {\n\n /**\n * The group to draw.\n *\n * @type {Konva.Group}\n */\n #group;\n\n /**\n * The shape display name.\n *\n * @type {string}\n */\n #name;\n\n /**\n * The draw layer.\n *\n * @type {DrawLayer}\n */\n #layer;\n\n /**\n * Flag to send events.\n *\n * @type {boolean}\n */\n #isSilent;\n\n /**\n * The group parent.\n *\n * @type {object}\n */\n #parent;\n\n /**\n * @param {Konva.Group} group The group draw.\n * @param {string} name The shape display name.\n * @param {DrawLayer} layer The layer where to draw the group.\n * @param {boolean} [silent] Whether to send a creation event or not.\n */\n constructor(group, name, layer, silent) {\n this.#group = group;\n this.#name = name;\n this.#layer = layer;\n this.#isSilent = (typeof silent === 'undefined') ? false : silent;\n this.#parent = group.getParent();\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'Draw-' + this.#name;\n }\n\n /**\n * Execute the command.\n *\n * @fires DrawGroupCommand#drawcreate\n */\n execute() {\n // add the group to the parent (in case of undo/redo)\n this.#parent.add(this.#group);\n // draw\n this.#layer.getKonvaLayer().draw();\n // callback\n if (!this.#isSilent) {\n /**\n * Draw create event.\n *\n * @event DrawGroupCommand#drawcreate\n * @type {object}\n * @property {string} id The id of the created draw.\n * @property {string} srclayerid The id of the layer of the draw.\n * @property {string} dataid The associated data id.\n */\n this.onExecute({\n type: 'drawcreate',\n id: this.#group.id(),\n srclayerid: this.#layer.getId(),\n dataid: this.#layer.getDataId()\n });\n }\n }\n\n /**\n * Undo the command.\n *\n * @fires DeleteGroupCommand#drawdelete\n */\n undo() {\n // remove the group from the parent layer\n this.#group.remove();\n // draw\n this.#layer.getKonvaLayer().draw();\n // callback\n this.onUndo({\n type: 'drawdelete',\n id: this.#group.id(),\n srclayerid: this.#layer.getId(),\n dataid: this.#layer.getDataId()\n });\n }\n\n /**\n * Handle an execute event.\n *\n * @param {object} _event The execute event with type and id.\n */\n onExecute(_event) {\n // default does nothing.\n }\n\n /**\n * Handle an undo event.\n *\n * @param {object} _event The undo event with type and id.\n */\n onUndo(_event) {\n // default does nothing.\n }\n\n} // DrawGroupCommand class\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * Path shape.\n */\nexport class Path {\n\n /**\n * @param {Point2D[]} [inputPointArray] The list of Point2D that make\n * the path (optional).\n * @param {number[]} [inputControlPointIndexArray] The list of control\n * point of path, as indexes (optional).\n * Note: first and last point do not need to be equal.\n */\n constructor(inputPointArray, inputControlPointIndexArray) {\n /**\n * List of points.\n *\n * @type {Point2D[]}\n */\n this.pointArray = inputPointArray ? inputPointArray.slice() : [];\n /**\n * List of control points.\n *\n * @type {number[]}\n */\n this.controlPointIndexArray = inputControlPointIndexArray\n ? inputControlPointIndexArray.slice() : [];\n }\n\n /**\n * Get a point of the list.\n *\n * @param {number} index The index of the point\n * to get (beware, no size check).\n * @returns {Point2D} The Point2D at the given index.\n */\n getPoint(index) {\n return this.pointArray[index];\n }\n\n /**\n * Is the given point a control point.\n *\n * @param {Point2D} point The Point2D to check.\n * @returns {boolean} True if a control point.\n */\n isControlPoint(point) {\n const index = this.pointArray.indexOf(point);\n if (index !== -1) {\n return this.controlPointIndexArray.indexOf(index) !== -1;\n } else {\n throw new Error('Error: isControlPoint called with not in list point.');\n }\n }\n\n /**\n * Get the length of the path.\n *\n * @returns {number} The length of the path.\n */\n getLength() {\n return this.pointArray.length;\n }\n\n /**\n * Add a point to the path.\n *\n * @param {Point2D} point The Point2D to add.\n */\n addPoint(point) {\n this.pointArray.push(point);\n }\n\n /**\n * Add a control point to the path.\n *\n * @param {Point2D} point The Point2D to make a control point.\n */\n addControlPoint(point) {\n const index = this.pointArray.indexOf(point);\n if (index !== -1) {\n this.controlPointIndexArray.push(index);\n } else {\n throw new Error(\n 'Cannot mark a non registered point as control point.');\n }\n }\n\n /**\n * Add points to the path.\n *\n * @param {Point2D[]} newPointArray The list of Point2D to add.\n */\n addPoints(newPointArray) {\n this.pointArray = this.pointArray.concat(newPointArray);\n }\n\n /**\n * Append a Path to this one.\n *\n * @param {Path} other The Path to append.\n */\n appenPath(other) {\n const oldSize = this.pointArray.length;\n this.pointArray = this.pointArray.concat(other.pointArray);\n const indexArray = [];\n for (let i = 0; i < other.controlPointIndexArray.length; ++i) {\n indexArray[i] = other.controlPointIndexArray[i] + oldSize;\n }\n this.controlPointIndexArray =\n this.controlPointIndexArray.concat(indexArray);\n }\n\n} // Path class\n","/**\n * Circular Bucket Queue.\n *\n * Returns input'd points in sorted order. All operations run in roughly O(1)\n * time (for input with small cost values), but it has a strict requirement:\n *\n * If the most recent point had a cost of c, any points added should have a cost\n * c' in the range c <= c' <= c + (capacity - 1).\n */\nexport class BucketQueue {\n\n /**\n * @param {number} bits Number of bits.\n * @param {Function} cost_functor The cost functor.\n */\n constructor(bits, cost_functor) {\n this.bucketCount = 1 << bits; // # of buckets = 2^bits\n this.mask = this.bucketCount - 1; // 2^bits - 1 = index mask\n this.size = 0;\n\n this.loc = 0; // Current index in bucket list\n // Cost defaults to item value\n this.cost = (typeof (cost_functor) !== 'undefined')\n ? cost_functor : function (item) {\n return item;\n };\n this.buckets = this.buildArray(this.bucketCount);\n }\n\n push(item) {\n // Prepend item to the list in the appropriate bucket\n const bucket = this.getBucket(item);\n item.next = this.buckets[bucket];\n this.buckets[bucket] = item;\n\n this.size++;\n }\n\n pop() {\n if (this.size === 0) {\n throw new Error('Cannot pop, bucketQueue is empty.');\n }\n\n // Find first empty bucket\n while (this.buckets[this.loc] === null) {\n this.loc = (this.loc + 1) % this.bucketCount;\n }\n\n // All items in bucket have same cost, return the first one\n const ret = this.buckets[this.loc];\n this.buckets[this.loc] = ret.next;\n ret.next = null;\n\n this.size--;\n return ret;\n }\n\n // TODO: needs at least two items...\n remove(item) {\n // Tries to remove item from queue. Returns true on success, false otherwise\n if (!item) {\n return false;\n }\n\n // To find node, go to bucket and search through unsorted list.\n const bucket = this.getBucket(item);\n let node = this.buckets[bucket];\n\n while (node !== null &&\n !(node.next !== null &&\n item.x === node.next.x &&\n item.y === node.next.y)) {\n node = node.next;\n }\n\n if (node === null) {\n // Item not in list, ergo item not in queue\n return false;\n } else {\n // Found item, do standard list node deletion\n node.next = node.next.next;\n\n this.size--;\n return true;\n }\n }\n\n isEmpty() {\n return this.size === 0;\n }\n\n getBucket(item) {\n // Bucket index is the masked cost\n return this.cost(item) & this.mask;\n }\n\n buildArray(newSize) {\n // Create array and initialze pointers to null\n const buckets = new Array(newSize);\n\n for (let i = 0; i < buckets.length; i++) {\n buckets[i] = null;\n }\n\n return buckets;\n }\n\n} // class BucketQueue\n","import {BucketQueue} from './bucketQueue';\n\n// Pre-created to reduce allocation in inner loops\nconst __twothirdpi = (2 / (3 * Math.PI));\n\n/**\n * Compute grey scale.\n *\n * @param {Array} data The input data.\n * @param {number} width The width of the output.\n * @param {number} height The height of the output.\n * @returns {object} A greyscale object.\n */\nfunction computeGreyscale(data, width, height) {\n // Returns 2D augmented array containing greyscale data\n // Greyscale values found by averaging colour channels\n // Input should be in a flat RGBA array, with values between 0 and 255\n const greyscale = {\n data: []\n };\n\n // Compute actual values\n for (let y = 0; y < height; y++) {\n greyscale.data[y] = [];\n\n for (let x = 0; x < width; x++) {\n const p = (y * width + x) * 4;\n greyscale.data[y][x] = (data[p] + data[p + 1] + data[p + 2]) / (3 * 255);\n }\n }\n\n // Augment with convenience functions\n greyscale.dx = function (x, y) {\n if (x + 1 === this.data[y].length) {\n // If we're at the end, back up one\n x--;\n }\n return this.data[y][x + 1] - this.data[y][x];\n };\n\n greyscale.dy = function (x, y) {\n if (y + 1 === this.data.length) {\n // If we're at the end, back up one\n y--;\n }\n return this.data[y][x] - this.data[y + 1][x];\n };\n\n greyscale.gradMagnitude = function (x, y) {\n const dx = this.dx(x, y);\n const dy = this.dy(x, y);\n return Math.sqrt(dx * dx + dy * dy);\n };\n\n greyscale.laplace = function (x, y) {\n // Laplacian of Gaussian\n let lap = -16 * this.data[y][x];\n lap += this.data[y - 2][x];\n lap += this.data[y - 1][x - 1] +\n 2 * this.data[y - 1][x] +\n this.data[y - 1][x + 1];\n lap += this.data[y][x - 2] +\n 2 * this.data[y][x - 1] +\n 2 * this.data[y][x + 1] +\n this.data[y][x + 2];\n lap += this.data[y + 1][x - 1] +\n 2 * this.data[y + 1][x] +\n this.data[y + 1][x + 1];\n lap += this.data[y + 2][x];\n\n return lap;\n };\n\n return greyscale;\n}\n\n/**\n * Compute gradient.\n *\n * @param {object} greyscale The input greyscale.\n * @returns {object} A gradient object.\n */\nfunction computeGradient(greyscale) {\n // Returns a 2D array of gradient magnitude values for greyscale. The values\n // are scaled between 0 and 1, and then flipped, so that it works as a cost\n // function.\n const gradient = [];\n\n let max = 0; // Maximum gradient found, for scaling purposes\n\n let x = 0;\n let y = 0;\n\n for (y = 0; y < greyscale.data.length - 1; y++) {\n gradient[y] = [];\n\n for (x = 0; x < greyscale.data[y].length - 1; x++) {\n gradient[y][x] = greyscale.gradMagnitude(x, y);\n max = Math.max(gradient[y][x], max);\n }\n\n gradient[y][greyscale.data[y].length - 1] =\n gradient[y][greyscale.data.length - 2];\n }\n\n gradient[greyscale.data.length - 1] = [];\n for (let i = 0; i < gradient[0].length; i++) {\n gradient[greyscale.data.length - 1][i] =\n gradient[greyscale.data.length - 2][i];\n }\n\n // Flip and scale.\n for (y = 0; y < gradient.length; y++) {\n for (x = 0; x < gradient[y].length; x++) {\n // @ts-ignore\n gradient[y][x] = 1 - (gradient[y][x] / max);\n }\n }\n\n return gradient;\n}\n\n/**\n * @param {object} greyscale The input greyscale.\n * @returns {object} A laplace object.\n */\nfunction computeLaplace(greyscale) {\n // Returns a 2D array of Laplacian of Gaussian values\n const laplace = [];\n\n // Make the edges low cost here.\n\n laplace[0] = [];\n laplace[1] = [];\n for (let i = 1; i < greyscale.data.length; i++) {\n // Pad top, since we can't compute Laplacian\n laplace[0][i] = 1;\n laplace[1][i] = 1;\n }\n\n for (let y = 2; y < greyscale.data.length - 2; y++) {\n laplace[y] = [];\n // Pad left, ditto\n laplace[y][0] = 1;\n laplace[y][1] = 1;\n\n for (let x = 2; x < greyscale.data[y].length - 2; x++) {\n // Threshold needed to get rid of clutter.\n laplace[y][x] = (greyscale.laplace(x, y) > 0.33) ? 0 : 1;\n }\n\n // Pad right, ditto\n laplace[y][greyscale.data[y].length - 2] = 1;\n laplace[y][greyscale.data[y].length - 1] = 1;\n }\n\n laplace[greyscale.data.length - 2] = [];\n laplace[greyscale.data.length - 1] = [];\n for (let j = 1; j < greyscale.data.length; j++) {\n // Pad bottom, ditto\n laplace[greyscale.data.length - 2][j] = 1;\n laplace[greyscale.data.length - 1][j] = 1;\n }\n\n return laplace;\n}\n\n/**\n * Compute the X gradient.\n *\n * @param {object} greyscale The values.\n * @returns {Array} The gradient.\n */\nfunction computeGradX(greyscale) {\n // Returns 2D array of x-gradient values for greyscale\n const gradX = [];\n\n for (let y = 0; y < greyscale.data.length; y++) {\n gradX[y] = [];\n\n for (let x = 0; x < greyscale.data[y].length - 1; x++) {\n gradX[y][x] = greyscale.dx(x, y);\n }\n\n gradX[y][greyscale.data[y].length - 1] =\n gradX[y][greyscale.data[y].length - 2];\n }\n\n return gradX;\n}\n\n/**\n * Compute the Y gradient.\n *\n * @param {object} greyscale The values.\n * @returns {Array} The gradient.\n */\nfunction computeGradY(greyscale) {\n // Returns 2D array of y-gradient values for greyscale\n const gradY = [];\n\n for (let y = 0; y < greyscale.data.length - 1; y++) {\n gradY[y] = [];\n\n for (let x = 0; x < greyscale.data[y].length; x++) {\n gradY[y][x] = greyscale.dy(x, y);\n }\n }\n\n gradY[greyscale.data.length - 1] = [];\n for (let i = 0; i < greyscale.data[0].length; i++) {\n gradY[greyscale.data.length - 1][i] = gradY[greyscale.data.length - 2][i];\n }\n\n return gradY;\n}\n\n/**\n * Compute the gradient unit vector.\n *\n * @param {Array} gradX The X gradient.\n * @param {Array} gradY The Y gradient.\n * @param {number} px The point X.\n * @param {number} py The point Y.\n * @param {object} out The result.\n */\nfunction gradUnitVector(gradX, gradY, px, py, out) {\n // Returns the gradient vector at (px,py), scaled to a magnitude of 1\n const ox = gradX[py][px];\n const oy = gradY[py][px];\n\n let gvm = Math.sqrt(ox * ox + oy * oy);\n gvm = Math.max(gvm, 1e-100); // To avoid possible divide-by-0 errors\n\n out.x = ox / gvm;\n out.y = oy / gvm;\n}\n\n/**\n * Compute the gradient direction.\n *\n * @param {Array} gradX The X gradient.\n * @param {Array} gradY The Y gradient.\n * @param {number} px The point X.\n * @param {number} py The point Y.\n * @param {number} qx The q X.\n * @param {number} qy The q Y.\n * @returns {number} The direction.\n */\nfunction gradDirection(gradX, gradY, px, py, qx, qy) {\n const __dgpuv = {x: -1, y: -1};\n const __gdquv = {x: -1, y: -1};\n // Compute the gradiant direction, in radians, between to points\n gradUnitVector(gradX, gradY, px, py, __dgpuv);\n gradUnitVector(gradX, gradY, qx, qy, __gdquv);\n\n let dp = __dgpuv.y * (qx - px) - __dgpuv.x * (qy - py);\n let dq = __gdquv.y * (qx - px) - __gdquv.x * (qy - py);\n\n // Make sure dp is positive, to keep things consistant\n if (dp < 0) {\n dp = -dp;\n dq = -dq;\n }\n\n if (px !== qx && py !== qy) {\n // We're going diagonally between pixels\n dp *= Math.SQRT1_2;\n dq *= Math.SQRT1_2;\n }\n\n return __twothirdpi * (Math.acos(dp) + Math.acos(dq));\n}\n\n/**\n * Compute the sides.\n *\n * @param {number} dist The distance.\n * @param {Array} gradX The X gradient.\n * @param {Array} gradY The Y gradient.\n * @param {object} greyscale The value.\n * @returns {object} The sides.\n */\nfunction computeSides(dist, gradX, gradY, greyscale) {\n // Returns 2 2D arrays, containing inside and outside greyscale values.\n // These greyscale values are the intensity just a little bit along the\n // gradient vector, in either direction, from the supplied point. These\n // values are used when using active-learning Intelligent Scissors\n\n const sides = {};\n sides.inside = [];\n sides.outside = [];\n\n const guv = {x: -1, y: -1}; // Current gradient unit vector\n\n for (let y = 0; y < gradX.length; y++) {\n sides.inside[y] = [];\n sides.outside[y] = [];\n\n for (let x = 0; x < gradX[y].length; x++) {\n gradUnitVector(gradX, gradY, x, y, guv);\n\n //(x, y) rotated 90 = (y, -x)\n\n let ix = Math.round(x + dist * guv.y);\n let iy = Math.round(y - dist * guv.x);\n let ox = Math.round(x - dist * guv.y);\n let oy = Math.round(y + dist * guv.x);\n\n ix = Math.max(Math.min(ix, gradX[y].length - 1), 0);\n ox = Math.max(Math.min(ox, gradX[y].length - 1), 0);\n iy = Math.max(Math.min(iy, gradX.length - 1), 0);\n oy = Math.max(Math.min(oy, gradX.length - 1), 0);\n\n sides.inside[y][x] = greyscale.data[iy][ix];\n sides.outside[y][x] = greyscale.data[oy][ox];\n }\n }\n\n return sides;\n}\n\n/**\n * Gaussian blur an input buffer.\n *\n * @param {Array} buffer The input buffer.\n * @param {Array} out The result.\n */\nfunction gaussianBlur(buffer, out) {\n // Smooth values over to fill in gaps in the mapping\n out[0] = 0.4 * buffer[0] + 0.5 * buffer[1] + 0.1 * buffer[1];\n out[1] = 0.25 * buffer[0] + 0.4 * buffer[1] + 0.25 * buffer[2] +\n 0.1 * buffer[3];\n\n for (let i = 2; i < buffer.length - 2; i++) {\n out[i] = 0.05 * buffer[i - 2] + 0.25 * buffer[i - 1] +\n 0.4 * buffer[i] + 0.25 * buffer[i + 1] + 0.05 * buffer[i + 2];\n }\n\n const len = buffer.length;\n out[len - 2] = 0.25 * buffer[len - 1] + 0.4 * buffer[len - 2] +\n 0.25 * buffer[len - 3] + 0.1 * buffer[len - 4];\n out[len - 1] = 0.4 * buffer[len - 1] + 0.5 * buffer[len - 2] +\n 0.1 * buffer[len - 3];\n}\n\n/**\n * Scissors.\n *\n * Ref: Eric N. Mortensen, William A. Barrett, Interactive Segmentation with\n * Intelligent Scissors, Graphical Models and Image Processing, Volume 60,\n * Issue 5, September 1998, Pages 349-384, ISSN 1077-3169,\n * DOI: 10.1006/gmip.1998.0480.\n *\n * See: {@link http://www.sciencedirect.com/science/article/B6WG4-45JB8WN-9/2/6fe59d8089fd1892c2bfb82283065579}.\n *\n * Highly inspired from: {@link http://code.google.com/p/livewire-javascript/}.\n */\nexport class Scissors {\n\n constructor() {\n this.width = -1;\n this.height = -1;\n\n this.curPoint = null; // Corrent point we're searching on.\n this.searchGranBits = 8; // Bits of resolution for BucketQueue.\n this.searchGran = 1 << this.searchGranBits; //bits.\n this.pointsPerPost = 500;\n\n // Precomputed image data. All in ranges 0 >= x >= 1 and\n // all inverted (1 - x).\n this.greyscale = null; // Greyscale of image\n this.laplace = null; // Laplace zero-crossings (either 0 or 1).\n this.gradient = null; // Gradient magnitudes.\n this.gradX = null; // X-differences.\n this.gradY = null; // Y-differences.\n\n // Matrix mapping point => parent along shortest-path to root.\n this.parents = null;\n\n this.working = false; // Currently computing shortest paths?\n\n // Begin Training:\n this.trained = false;\n this.trainingPoints = null;\n\n this.edgeWidth = 2;\n this.trainingLength = 32;\n\n this.edgeGran = 256;\n this.edgeTraining = null;\n\n this.gradPointsNeeded = 32;\n this.gradGran = 1024;\n this.gradTraining = null;\n\n this.insideGran = 256;\n this.insideTraining = null;\n\n this.outsideGran = 256;\n this.outsideTraining = null;\n }\n // End Training\n\n\n // Begin training methods //\n getTrainingIdx(granularity, value) {\n return Math.round((granularity - 1) * value);\n }\n\n getTrainedEdge(edge) {\n return this.edgeTraining[this.getTrainingIdx(this.edgeGran, edge)];\n }\n\n getTrainedGrad(grad) {\n return this.gradTraining[this.getTrainingIdx(this.gradGran, grad)];\n }\n\n getTrainedInside(inside) {\n return this.insideTraining[this.getTrainingIdx(this.insideGran, inside)];\n }\n\n getTrainedOutside(outside) {\n return this.outsideTraining[this.getTrainingIdx(this.outsideGran, outside)];\n }\n // End training methods //\n\n setWorking(working) {\n // Sets working flag\n this.working = working;\n }\n\n setDimensions(width, height) {\n this.width = width;\n this.height = height;\n }\n\n setData(data) {\n if (this.width === -1 || this.height === -1) {\n // The width and height should have already been set\n throw new Error('Dimensions have not been set.');\n }\n\n this.greyscale = computeGreyscale(data, this.width, this.height);\n this.laplace = computeLaplace(this.greyscale);\n this.gradient = computeGradient(this.greyscale);\n this.gradX = computeGradX(this.greyscale);\n this.gradY = computeGradY(this.greyscale);\n\n const sides = computeSides(\n this.edgeWidth, this.gradX, this.gradY, this.greyscale);\n this.inside = sides.inside;\n this.outside = sides.outside;\n this.edgeTraining = [];\n this.gradTraining = [];\n this.insideTraining = [];\n this.outsideTraining = [];\n }\n\n findTrainingPoints(p) {\n // Grab the last handful of points for training\n const points = [];\n\n if (this.parents !== null) {\n for (let i = 0; i < this.trainingLength && p; i++) {\n points.push(p);\n p = this.parents[p.y][p.x];\n }\n }\n\n return points;\n }\n\n resetTraining() {\n this.trained = false; // Training is ignored with this flag set\n }\n\n doTraining(p) {\n // Compute training weights and measures\n this.trainingPoints = this.findTrainingPoints(p);\n\n if (this.trainingPoints.length < 8) {\n return; // Not enough points, I think. It might crash if length = 0.\n }\n\n const buffer = [];\n this.calculateTraining(\n buffer, this.edgeGran, this.greyscale, this.edgeTraining);\n this.calculateTraining(\n buffer, this.gradGran, this.gradient, this.gradTraining);\n this.calculateTraining(\n buffer, this.insideGran, this.inside, this.insideTraining);\n this.calculateTraining(\n buffer, this.outsideGran, this.outside, this.outsideTraining);\n\n if (this.trainingPoints.length < this.gradPointsNeeded) {\n // If we have two few training points, the gradient weight map might not\n // be smooth enough, so average with normal weights.\n this.addInStaticGrad(this.trainingPoints.length, this.gradPointsNeeded);\n }\n\n this.trained = true;\n }\n\n calculateTraining(\n buffer, granularity, input, output) {\n let i = 0;\n // Build a map of raw-weights to trained-weights by favoring input values\n buffer.length = granularity;\n for (i = 0; i < granularity; i++) {\n buffer[i] = 0;\n }\n\n let maxVal = 1;\n for (i = 0; i < this.trainingPoints.length; i++) {\n const p = this.trainingPoints[i];\n const idx = this.getTrainingIdx(granularity, input[p.y][p.x]);\n buffer[idx] += 1;\n\n maxVal = Math.max(maxVal, buffer[idx]);\n }\n\n // Invert and scale.\n for (i = 0; i < granularity; i++) {\n buffer[i] = 1 - buffer[i] / maxVal;\n }\n\n // Blur it, as suggested. Gets rid of static.\n gaussianBlur(buffer, output);\n }\n\n addInStaticGrad(have, need) {\n // Average gradient raw-weights to trained-weights map with standard weight\n // map so that we don't end up with something to spiky\n for (let i = 0; i < this.gradGran; i++) {\n this.gradTraining[i] = Math.min(\n this.gradTraining[i],\n 1 - i * (need - have) / (need * this.gradGran)\n );\n }\n }\n\n gradDirection(px, py, qx, qy) {\n return gradDirection(this.gradX, this.gradY, px, py, qx, qy);\n }\n\n dist(px, py, qx, qy) {\n // The grand culmunation of most of the code: the weighted distance function\n let grad = this.gradient[qy][qx];\n\n if (px === qx || py === qy) {\n // The distance is Euclidean-ish; non-diagonal edges should be shorter\n grad *= Math.SQRT1_2;\n }\n\n const lap = this.laplace[qy][qx];\n const dir = this.gradDirection(px, py, qx, qy);\n\n if (this.trained) {\n // Apply training magic\n const gradT = this.getTrainedGrad(grad);\n const edgeT = this.getTrainedEdge(this.greyscale.data[py][px]);\n const insideT = this.getTrainedInside(this.inside[py][px]);\n const outsideT = this.getTrainedOutside(this.outside[py][px]);\n\n return 0.3 * gradT + 0.3 * lap + 0.1 * (dir + edgeT + insideT + outsideT);\n } else {\n // Normal weights\n return 0.43 * grad + 0.43 * lap + 0.11 * dir;\n }\n }\n\n adj(p) {\n const list = [];\n\n const sx = Math.max(p.x - 1, 0);\n const sy = Math.max(p.y - 1, 0);\n const ex = Math.min(p.x + 1, this.greyscale.data[0].length - 1);\n const ey = Math.min(p.y + 1, this.greyscale.data.length - 1);\n\n let idx = 0;\n for (let y = sy; y <= ey; y++) {\n for (let x = sx; x <= ex; x++) {\n if (x !== p.x || y !== p.y) {\n list[idx++] = {x: x, y: y};\n }\n }\n }\n\n return list;\n }\n\n #costFunction = (p) => {\n return Math.round(this.searchGran * this.cost[p.y][p.x]);\n };\n\n setPoint(sp) {\n this.setWorking(true);\n\n this.curPoint = sp;\n\n let x = 0;\n let y = 0;\n\n this.visited = [];\n for (y = 0; y < this.height; y++) {\n this.visited[y] = [];\n for (x = 0; x < this.width; x++) {\n this.visited[y][x] = false;\n }\n }\n\n this.parents = [];\n for (y = 0; y < this.height; y++) {\n this.parents[y] = [];\n }\n\n this.cost = [];\n for (y = 0; y < this.height; y++) {\n this.cost[y] = [];\n for (x = 0; x < this.width; x++) {\n this.cost[y][x] = Number.MAX_VALUE;\n }\n }\n this.cost[sp.y][sp.x] = 0;\n\n this.pq = new BucketQueue(this.searchGranBits, this.#costFunction);\n this.pq.push(sp);\n }\n\n doWork() {\n if (!this.working) {\n return;\n }\n\n this.timeout = null;\n\n let pointCount = 0;\n const newPoints = [];\n while (!this.pq.isEmpty() && pointCount < this.pointsPerPost) {\n const p = this.pq.pop();\n newPoints.push(p);\n newPoints.push(this.parents[p.y][p.x]);\n\n this.visited[p.y][p.x] = true;\n\n const adjList = this.adj(p);\n for (let i = 0; i < adjList.length; i++) {\n const q = adjList[i];\n\n const pqCost = this.cost[p.y][p.x] + this.dist(p.x, p.y, q.x, q.y);\n\n if (pqCost < this.cost[q.y][q.x]) {\n if (this.cost[q.y][q.x] !== Number.MAX_VALUE) {\n // Already in PQ, must remove it so we can re-add it.\n this.pq.remove(q);\n }\n\n this.cost[q.y][q.x] = pqCost;\n this.parents[q.y][q.x] = p;\n this.pq.push(q);\n }\n }\n\n pointCount++;\n }\n\n return newPoints;\n }\n\n} // Scissors class\n","// linting 'type {Object.}' will give:\n// warning Use object shorthand or index signatures instead of `Object`,\n// e.g., `{[key: string]: string}` jsdoc/check-types\n// pb: jsdoc does not support the object shorthand\n// and ignoring will give vscode warning since the doc linting is not\n// activated by default.\n\n// Overridable default object.\nexport const defaults = {\n /**\n * List of default window level presets.\n *\n * @type {Object.>}\n */\n labelText: {\n arrow: {\n '*': ''\n },\n circle: {\n '*': '{surface}'\n },\n ellipse: {\n '*': '{surface}'\n },\n protractor: {\n '*': '{angle}'\n },\n rectangle: {\n '*': '{surface}'\n },\n roi: {\n '*': ''\n },\n ruler: {\n '*': '{length}'\n }\n }\n};\n","// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Label factory to create and update shape label.\n */\nexport class LabelFactory {\n\n /**\n * Default position getter.\n *\n * @type {Function}\n */\n #defaultPositionGetter;\n\n /**\n * @param {Function} positionGetter Default position getter.\n */\n constructor(positionGetter) {\n this.#defaultPositionGetter = positionGetter;\n }\n\n /**\n * Get the annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n getPosition(annotation) {\n let position = annotation.labelPosition;\n if (typeof position === 'undefined') {\n position = this.#defaultPositionGetter(annotation);\n }\n return position;\n }\n\n /**\n * Creates the konva label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Label} The Konva label.\n */\n create(annotation, style) {\n // konva text\n const ktext = new Konva.Text({\n fontSize: style.getFontSize(),\n fontFamily: style.getFontFamily(),\n fill: annotation.colour,\n padding: style.getTextPadding(),\n shadowColor: style.getShadowLineColour(),\n shadowOffset: style.getShadowOffset(),\n name: 'text'\n });\n const labelText = annotation.getText();\n ktext.setText(labelText);\n\n // times 2 so that the font size 10 looks like a 10...\n // (same logic as in the DrawController::updateLabelScale)\n const zoomScale = style.applyZoomScale(1);\n const labelScale = {\n x: 2 * zoomScale.x,\n y: 2 * zoomScale.y\n };\n\n // konva label\n const labelPosition = this.getPosition(annotation);\n const klabel = new Konva.Label({\n x: labelPosition.getX(),\n y: labelPosition.getY(),\n scale: labelScale,\n visible: labelText.length !== 0,\n name: 'label'\n });\n klabel.add(ktext);\n klabel.add(new Konva.Tag({\n fill: annotation.colour,\n opacity: style.getTagOpacity()\n }));\n\n return klabel;\n }\n\n /**\n * Update the shape label position.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n */\n updatePosition(annotation, group) {\n // associated label\n const klabel = group.getChildren(function (node) {\n return node.name() === 'label';\n })[0];\n if (!(klabel instanceof Konva.Label)) {\n return;\n }\n // update position\n const labelPosition = this.getPosition(annotation);\n klabel.position({\n x: labelPosition.getX(),\n y: labelPosition.getY()\n });\n }\n\n /**\n * Get the anchors positions for the label.\n *\n * @param {Konva.Label} label The label.\n * @returns {Point2D[]} The connectors positions.\n */\n getLabelAnchorsPosition(label) {\n const lx = label.x();\n const ly = label.y();\n const dx = label.width() * label.scale().x;\n const dy = label.height() * label.scale().y;\n return [\n new Point2D(lx + dx / 2, ly),\n new Point2D(lx, ly + dy / 2),\n new Point2D(lx + dx / 2, ly + dy),\n new Point2D(lx + dx, ly + dy / 2),\n ];\n }\n\n /**\n * Get the two closest points of two points lists.\n *\n * @param {Point2D[]} points1 The first point list.\n * @param {Point2D[]} points2 The second point list.\n * @returns {Point2D[]} The closests points.\n */\n getClosestPoints(points1, points2) {\n let minDist = points1[0].getDistance(points2[0]);\n let p1 = points1[0];\n let p2 = points2[0];\n for (const point1 of points1) {\n for (const point2 of points2) {\n const dist = point1.getDistance(point2);\n if (dist < minDist) {\n minDist = dist;\n p1 = point1;\n p2 = point2;\n }\n }\n }\n return [p1, p2];\n }\n\n /**\n * Get the connector between this label and its shape.\n *\n * @param {Point2D[]} connectorsPos The shape connectors positions.\n * @param {Konva.Label} label The label.\n * @param {Style} style The drawing style.\n * @returns {Konva.Line} The connector.\n */\n getConnector(connectorsPos, label, style) {\n const labelAnchorsPos = this.getLabelAnchorsPosition(label);\n const anchorPoints = this.getClosestPoints(\n connectorsPos, labelAnchorsPos);\n return new Konva.Line({\n points: [\n anchorPoints[0].getX(),\n anchorPoints[0].getY(),\n anchorPoints[1].getX(),\n anchorPoints[1].getY()\n ],\n stroke: label.getText().fill(),\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n visible: label.visible(),\n dash: [10, 7],\n name: 'connector'\n });\n }\n\n /**\n * Update the connector between a label and its shape.\n *\n * @param {Konva.Group} group The associated shape group.\n * @param {Point2D[]} connectorsPos The shape connectors positions.\n */\n updateConnector(group, connectorsPos) {\n // associated label\n const klabel = group.getChildren(function (node) {\n return node.name() === 'label';\n })[0];\n if (!(klabel instanceof Konva.Label)) {\n return;\n }\n\n const labelAnchorsPos = this.getLabelAnchorsPosition(klabel);\n\n const anchors = this.getClosestPoints(connectorsPos, labelAnchorsPos);\n\n const kconnect = group.getChildren(function (node) {\n return node.name() === 'connector';\n })[0];\n if (!(kconnect instanceof Konva.Line)) {\n return;\n }\n\n kconnect.points([\n anchors[0].getX(),\n anchors[0].getY(),\n anchors[1].getX(),\n anchors[1].getY()\n ]);\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n */\n updateContent(annotation, group) {\n // associated label\n const klabel = group.getChildren(function (node) {\n return node.name() === 'label';\n })[0];\n if (!(klabel instanceof Konva.Label)) {\n return;\n }\n // update text\n const text = annotation.getText();\n const ktext = klabel.getText();\n ktext.setText(text);\n // hide if visible and empty\n if (klabel.visible()) {\n klabel.visible(text.length !== 0);\n }\n }\n\n} // LabelFactory","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\n/* eslint-enable no-unused-vars */\n\n/**\n * Threshold an image between an input minimum and maximum.\n */\nexport class ThresholdFilter {\n /**\n * Threshold minimum.\n *\n * @type {number}\n */\n #min = 0;\n\n /**\n * Threshold maximum.\n *\n * @type {number}\n */\n #max = 0;\n\n /**\n * Get the threshold minimum.\n *\n * @returns {number} The threshold minimum.\n */\n getMin() {\n return this.#min;\n }\n\n /**\n * Set the threshold minimum.\n *\n * @param {number} val The threshold minimum.\n */\n setMin(val) {\n this.#min = val;\n }\n\n /**\n * Get the threshold maximum.\n *\n * @returns {number} The threshold maximum.\n */\n getMax() {\n return this.#max;\n }\n\n /**\n * Set the threshold maximum.\n *\n * @param {number} val The threshold maximum.\n */\n setMax(val) {\n this.#max = val;\n }\n\n /**\n * Get the name of the filter.\n *\n * @returns {string} The name of the filter.\n */\n getName() {\n return 'Threshold';\n }\n\n /**\n * Original image.\n *\n * @type {Image}\n */\n #originalImage = null;\n\n /**\n * Set the original image.\n *\n * @param {Image} image The original image.\n */\n setOriginalImage(image) {\n this.#originalImage = image;\n }\n\n /**\n * Get the original image.\n *\n * @returns {Image} The original image.\n */\n getOriginalImage() {\n return this.#originalImage;\n }\n\n /**\n * Transform the main image using this filter.\n *\n * @returns {Image} The transformed image.\n */\n update() {\n const image = this.getOriginalImage();\n const imageMin = image.getDataRange().min;\n const threshFunction = (value) => {\n if (value < this.getMin() || value > this.getMax()) {\n return imageMin;\n } else {\n return value;\n }\n };\n return image.transform(threshFunction);\n }\n\n} // class Threshold\n\n/**\n * Sharpen an image using a sharpen convolution matrix.\n */\nexport class SharpenFilter {\n /**\n * Get the name of the filter.\n *\n * @returns {string} The name of the filter.\n */\n getName() {\n return 'Sharpen';\n }\n\n /**\n * Original image.\n *\n * @type {Image}\n */\n #originalImage = null;\n\n /**\n * Set the original image.\n *\n * @param {Image} image The original image.\n */\n setOriginalImage(image) {\n this.#originalImage = image;\n }\n\n /**\n * Get the original image.\n *\n * @returns {Image} The original image.\n */\n getOriginalImage() {\n return this.#originalImage;\n }\n\n /**\n * Transform the main image using this filter.\n *\n * @returns {Image} The transformed image.\n */\n update() {\n const image = this.getOriginalImage();\n /* eslint-disable @stylistic/js/array-element-newline */\n return image.convolute2D([\n 0, -1, 0,\n -1, 5, -1,\n 0, -1, 0\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n }\n\n} // class Sharpen\n\n/**\n * Apply a Sobel filter to an image.\n */\nexport class SobelFilter {\n /**\n * Get the name of the filter.\n *\n * @returns {string} The name of the filter.\n */\n getName() {\n return 'Sobel';\n }\n\n /**\n * Original image.\n *\n * @type {Image}\n */\n #originalImage = null;\n\n /**\n * Set the original image.\n *\n * @param {Image} image The original image.\n */\n setOriginalImage(image) {\n this.#originalImage = image;\n }\n\n /**\n * Get the original image.\n *\n * @returns {Image} The original image.\n */\n getOriginalImage() {\n return this.#originalImage;\n }\n\n /**\n * Transform the main image using this filter.\n *\n * @returns {Image} The transformed image.\n */\n update() {\n const image = this.getOriginalImage();\n /* eslint-disable @stylistic/js/array-element-newline */\n const gradX = image.convolute2D([\n 1, 0, -1,\n 2, 0, -2,\n 1, 0, -1\n ]);\n const gradY = image.convolute2D([\n 1, 2, 1,\n 0, 0, 0,\n -1, -2, -1\n ]);\n /* eslint-enable @stylistic/js/array-element-newline */\n return gradX.compose(gradY, function (x, y) {\n return Math.sqrt(x * x + y * y);\n });\n }\n\n} // class Sobel\n","import {ListenerHandler} from '../utils/listen';\nimport {\n ThresholdFilter,\n SobelFilter,\n SharpenFilter\n} from '../image/filter';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Filter tool.\n */\nexport class Filter {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Filter list.\n *\n * @type {object}\n */\n #filterList = null;\n\n /**\n * Selected filter.\n *\n * @type {object}\n */\n #selectedFilter = 0;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Activate the tool.\n *\n * @param {boolean} bool Flag to activate or not.\n */\n activate(bool) {\n // setup event listening\n for (const key in this.#filterList) {\n if (bool) {\n this.#filterList[key].addEventListener('filterrun', this.#fireEvent);\n this.#filterList[key].addEventListener('filter-undo', this.#fireEvent);\n } else {\n this.#filterList[key].removeEventListener(\n 'filterrun', this.#fireEvent);\n this.#filterList[key].removeEventListener(\n 'filter-undo', this.#fireEvent);\n }\n }\n }\n\n /**\n * Set the tool options.\n *\n * @param {object} options The list of filter names amd classes.\n */\n setOptions(options) {\n this.#filterList = {};\n // try to instanciate filters from the options\n for (const key in options) {\n this.#filterList[key] = new options[key](this.#app);\n }\n }\n\n /**\n * Get the type of tool options: here 'instance' since the filter\n * list contains instances of each possible filter.\n *\n * @returns {string} The type.\n */\n getOptionsType() {\n return 'instance';\n }\n\n /**\n * Initialise the filter. Called once the image is loaded.\n */\n init() {\n // setup event listening\n for (const key in this.#filterList) {\n this.#filterList[key].init();\n }\n }\n\n /**\n * Handle keydown event.\n *\n * @param {object} event The keydown event.\n */\n keydown = (event) => {\n event.context = 'Filter';\n this.#app.onKeydown(event);\n };\n\n /**\n * Get the list of event names that this tool can fire.\n *\n * @returns {string[]} The list of event names.\n */\n getEventNames() {\n return ['filterrun', 'filterundo'];\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n /**\n * Get the selected filter.\n *\n * @returns {object} The selected filter.\n */\n getSelectedFilter() {\n return this.#selectedFilter;\n }\n\n /**\n * Set the tool live features: filter name.\n *\n * @param {object} features The list of features.\n */\n setFeatures(features) {\n if (typeof features.filterName !== 'undefined') {\n // check if we have it\n if (!this.hasFilter(features.filterName)) {\n throw new Error('Unknown filter: \\'' + features.filterName + '\\'');\n }\n // de-activate last selected\n if (this.#selectedFilter) {\n this.#selectedFilter.activate(false);\n }\n // enable new one\n this.#selectedFilter = this.#filterList[features.filterName];\n // activate the selected filter\n this.#selectedFilter.activate(true);\n }\n if (typeof features.run !== 'undefined' && features.run) {\n let args = {};\n if (typeof features.runArgs !== 'undefined') {\n args = features.runArgs;\n }\n this.getSelectedFilter().run(args);\n }\n }\n\n /**\n * Get the list of filters.\n *\n * @returns {Array} The list of filter objects.\n */\n getFilterList() {\n return this.#filterList;\n }\n\n /**\n * Check if a filter is in the filter list.\n *\n * @param {string} name The name to check.\n * @returns {string} The filter list element for the given name.\n */\n hasFilter(name) {\n return this.#filterList[name];\n }\n\n} // class Filter\n\n/**\n * Threshold filter tool.\n */\nexport class Threshold {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Associated filter.\n *\n * @type {object}\n */\n #filter = new ThresholdFilter();\n\n /**\n * Flag to know wether to reset the image or not.\n *\n * @type {boolean}\n */\n #resetImage = true;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Activate the filter.\n *\n * @param {boolean} bool Flag to activate or not.\n */\n activate(bool) {\n // reset the image when the tool is activated\n if (bool) {\n this.#resetImage = true;\n }\n }\n\n /**\n * Initialise the filter. Called once the image is loaded.\n */\n init() {\n // does nothing\n }\n\n /**\n * Run the filter.\n *\n * @param {*} args The filter arguments.\n */\n run(args) {\n if (typeof args.dataId === 'undefined') {\n throw new Error('No dataId to run threshod filter on.');\n }\n this.#filter.setMin(args.min);\n this.#filter.setMax(args.max);\n // reset the image if asked\n if (this.#resetImage) {\n const image = this.#app.getData(args.dataId).image;\n this.#filter.setOriginalImage(image);\n this.#resetImage = false;\n }\n const command = new RunFilterCommand(this.#filter, args.dataId, this.#app);\n command.onExecute = this.#fireEvent;\n command.onUndo = this.#fireEvent;\n command.execute();\n // save command in undo stack\n this.#app.addToUndoStack(command);\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n} // class Threshold\n\n/**\n * Sharpen filter tool.\n */\nexport class Sharpen {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Activate the filter.\n *\n * @param {boolean} _bool Flag to activate or not.\n */\n activate(_bool) {\n // does nothing\n }\n\n /**\n * Initialise the filter. Called once the image is loaded.\n */\n init() {\n // does nothing\n }\n\n /**\n * Run the filter.\n *\n * @param {*} args The filter arguments.\n */\n run(args) {\n if (typeof args.dataId === 'undefined') {\n throw new Error('No dataId to run sharpen filter on.');\n }\n const filter = new SharpenFilter();\n const image = this.#app.getData(args.dataId).image;\n filter.setOriginalImage(image);\n const command = new RunFilterCommand(filter, args.dataId, this.#app);\n command.onExecute = this.#fireEvent;\n command.onUndo = this.#fireEvent;\n command.execute();\n // save command in undo stack\n this.#app.addToUndoStack(command);\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n} // filter.Sharpen\n\n/**\n * Sobel filter tool.\n */\nexport class Sobel {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Activate the filter.\n *\n * @param {boolean} _bool Flag to activate or not.\n */\n activate(_bool) {\n // does nothing\n }\n\n /**\n * Initialise the filter. Called once the image is loaded.\n */\n init() {\n // does nothing\n }\n\n /**\n * Run the filter.\n *\n * @param {*} args The filter arguments.\n */\n run(args) {\n if (typeof args.dataId === 'undefined') {\n throw new Error('No dataId to run sobel filter on.');\n }\n const filter = new SobelFilter();\n const image = this.#app.getData(args.dataId).image;\n filter.setOriginalImage(image);\n const command = new RunFilterCommand(filter, args.dataId, this.#app);\n command.onExecute = this.#fireEvent;\n command.onUndo = this.#fireEvent;\n command.execute();\n // save command in undo stack\n this.#app.addToUndoStack(command);\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n} // class filter.Sobel\n\n/**\n * Run filter command.\n */\nexport class RunFilterCommand {\n\n /**\n * The filter to run.\n *\n * @type {object}\n */\n #filter;\n\n /**\n * Data id.\n *\n * @type {string}\n */\n #dataId;\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {object} filter The filter to run.\n * @param {string} dataId The data to filter.\n * @param {App} app The associated application.\n */\n constructor(filter, dataId, app) {\n this.#filter = filter;\n this.#dataId = dataId;\n this.#app = app;\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'Filter-' + this.#filter.getName();\n }\n\n /**\n * Execute the command.\n *\n * @fires RunFilterCommand#filterrun\n */\n execute() {\n // run filter and set app image\n this.#app.setImage(this.#dataId, this.#filter.update());\n // update display\n this.#app.render(this.#dataId);\n /**\n * Filter run event.\n *\n * @event RunFilterCommand#filterrun\n * @type {object}\n * @property {string} type The event type: filterrun.\n * @property {number} id The id of the run command.\n */\n const event = {\n type: 'filterrun',\n id: this.getName(),\n dataId: this.#dataId\n };\n // callback\n this.onExecute(event);\n }\n\n /**\n * Undo the command.\n *\n * @fires RunFilterCommand#filterundo\n */\n undo() {\n // reset the image\n this.#app.setImage(this.#dataId, this.#filter.getOriginalImage());\n // update display\n this.#app.render(this.#dataId);\n /**\n * Filter undo event.\n *\n * @event RunFilterCommand#filterundo\n * @type {object}\n * @property {string} type The event type: filterundo.\n * @property {number} id The id of the undone run command.\n */\n const event = {\n type: 'filterundo',\n id: this.getName(),\n dataid: this.#dataId\n }; // callback\n this.onUndo(event);\n }\n\n /**\n * Handle an execute event.\n *\n * @param {object} _event The execute event with type and id.\n */\n onExecute(_event) {\n // default does nothing.\n }\n\n /**\n * Handle an undo event.\n *\n * @param {object} _event The undo event with type and id.\n */\n onUndo(_event) {\n // default does nothing.\n }\n\n} // RunFilterCommand class\n","import {WindowLevel} from './windowLevel';\nimport {Scroll} from './scroll';\nimport {ZoomAndPan} from './zoomPan';\nimport {Opacity} from './opacity';\nimport {Draw} from './draw';\nimport {Floodfill} from './floodfill';\nimport {Livewire} from './livewire';\n\nimport {ArrowFactory} from './arrow';\nimport {CircleFactory} from './circle';\nimport {EllipseFactory} from './ellipse';\nimport {ProtractorFactory} from './protractor';\nimport {RectangleFactory} from './rectangle';\nimport {RoiFactory} from './roi';\nimport {RulerFactory} from './ruler';\n\nimport {Filter, Threshold, Sobel, Sharpen} from './filter';\n\n/**\n * List of client provided tools to be added to\n * the default ones.\n *\n * @example\n * // custom tool\n * class AlertTool {\n * mousedown() {alert('AlertTool mousedown');}\n * init() {}\n * activate() {}\n * }\n * // pass it to dwv tool list\n * dwv.toolList['Alert'] = AlertTool;\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Alert: {}};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n * app.setTool('Alert');\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n *\n * @type {Object}\n */\nexport const toolList = {};\n\n/**\n * List of client provided tool options to be added to\n * the default ones.\n *\n * @example\n * // custom factory\n * class LoveFactory {\n * getName() {return 'love';}\n * static supports(mathShape) {return mathShape instanceof ROI;}\n * getNPoints() {return 1;}\n * getTimeout() {return 0;}\n * setAnnotationMathShape(annotation, points) {\n * const px = points[0].getX();\n * const py = points[0].getY();\n * annotation.mathShape = new dwv.ROI([\n * new dwv.Point2D(px+15,py), new dwv.Point2D(px+10,py-10),\n * new dwv.Point2D(px,py), new dwv.Point2D(px-10,py-10),\n * new dwv.Point2D(px-15,py), new dwv.Point2D(px,py+20)\n * ]);\n * annotation.getFactory = function () {return new LoveFactory();}\n * }\n * createShapeGroup(annotation, style) {\n * const roi = annotation.mathShape;\n * // konva line\n * const arr = [];\n * for (let i = 0; i < roi.getLength(); ++i) {\n * arr.push(roi.getPoint(i).getX());\n * arr.push(roi.getPoint(i).getY());\n * }\n * const shape = new Konva.Line({\n * name: 'shape', points: arr,\n * stroke: 'red', strokeWidth: 2,\n * closed: true\n * });\n * // konva group\n * const group = new Konva.Group();\n * group.name('love-group');\n * group.visible(true);\n * group.id(annotation.id);\n * group.add(shape);\n * return group;\n * }\n * }\n * // pass it to dwv option list\n * dwv.toolOptions['draw'] = {LoveFactory};\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Draw: {options: ['Love']}};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n * app.setTool('Draw');\n * app.setToolFeatures({shapeName: 'Love'});\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n *\n * @type {Object>}\n */\nexport const toolOptions = {};\n\n/**\n * Default tool list.\n *\n * @type {Object}\n */\nexport const defaultToolList = {\n WindowLevel,\n Scroll,\n ZoomAndPan,\n Opacity,\n Draw,\n Filter,\n Floodfill,\n Livewire\n};\n\n/**\n * Default tool options.\n *\n * @type {Object>}\n */\nexport const defaultToolOptions = {\n draw: {\n ArrowFactory,\n CircleFactory,\n EllipseFactory,\n ProtractorFactory,\n RectangleFactory,\n RoiFactory,\n RulerFactory\n },\n filter: {\n Threshold,\n Sobel,\n Sharpen\n }\n};","import {ScrollWheel} from './scrollWheel';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\nimport {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {\n validateWindowWidth,\n WindowLevel as WindowLevelValues\n} from '../image/windowLevel';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * WindowLevel tool: handle window/level related events.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {WindowLevel: new dwv.ToolConfig()};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n * app.setTool('WindowLevel');\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\nexport class WindowLevel {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #started = false;\n\n /**\n * Start point.\n *\n * @type {Point2D}\n */\n #startPoint;\n\n /**\n * Scroll wheel handler.\n *\n * @type {ScrollWheel}\n */\n #scrollWhell;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n this.#scrollWhell = new ScrollWheel(app);\n }\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n * @param {string} divId The layer group divId.\n */\n #start(point, divId) {\n // check if possible\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n if (!viewController.isMonochrome()) {\n return;\n }\n\n this.#started = true;\n this.#startPoint = point;\n }\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #update(point, divId) {\n // check start flag\n if (!this.#started) {\n return;\n }\n\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n\n // difference to last position\n const diffX = point.getX() - this.#startPoint.getX();\n const diffY = this.#startPoint.getY() - point.getY();\n // data range\n const range = viewController.getImageRescaledDataRange();\n // 1/1000 seems to give reasonable results...\n const pixelToIntensity = (range.max - range.min) * 0.01;\n\n // calculate new window level\n const center = viewController.getWindowLevel().center;\n const width = viewController.getWindowLevel().width;\n const windowCenter = center + Math.round(diffY * pixelToIntensity);\n let windowWidth = width + Math.round(diffX * pixelToIntensity);\n // bound window width\n windowWidth = validateWindowWidth(windowWidth);\n // set\n const wl = new WindowLevelValues(windowCenter, windowWidth);\n viewController.setWindowLevel(wl);\n\n // store position\n this.#startPoint = point;\n }\n\n /**\n * Finish tool interaction.\n */\n #finish() {\n if (this.#started) {\n this.#started = false;\n }\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} _event The mouse up event.\n */\n mouseup = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle mouse out event.\n *\n * @param {object} _event The mouse out event.\n */\n mouseout = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} _event The touch end event.\n */\n touchend = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle double click event.\n *\n * @param {object} event The double click event.\n */\n dblclick = (event) => {\n const layerDetails = getLayerDetailsFromEvent(event);\n const mousePoint = getMousePoint(event);\n\n const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const index = viewLayer.displayToPlaneIndex(mousePoint);\n const viewController = viewLayer.getViewController();\n // exit if not possible\n if (!viewController.isMonochrome()) {\n return;\n }\n\n // update view controller\n const image = this.#app.getData(viewLayer.getDataId()).image;\n const wl = new WindowLevelValues(\n image.getRescaledValueAtIndex(\n viewController.getCurrentIndex().getWithNew2D(\n index.get(0),\n index.get(1)\n )\n ),\n viewController.getWindowLevel().width\n );\n viewController.setWindowLevel(wl);\n };\n\n /**\n * Handle mouse wheel event.\n *\n * @param {WheelEvent} event The mouse wheel event.\n */\n wheel = (event) => {\n this.#scrollWhell.wheel(event);\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n event.context = 'WindowLevel';\n this.#app.onKeydown(event);\n };\n\n /**\n * Activate the tool.\n *\n * @param {boolean} _bool The flag to activate or not.\n */\n activate(_bool) {\n // does nothing\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n /**\n * Set the tool live features: does nothing.\n *\n * @param {object} _features The list of features.\n */\n setFeatures(_features) {\n // does nothing\n }\n\n} // WindowLevel class\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\nimport {ScrollWheel} from './scrollWheel';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * Scroll class.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Scroll: new dwv.ToolConfig()};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n * app.setTool('Scroll');\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm',\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323707.dcm',\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323563.dcm'\n * ]);\n * @example Example with slider\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Scroll: new dwv.ToolConfig()};\n * app.init(options);\n * // create range\n * const range = document.createElement('input');\n * range.type = 'range';\n * range.min = 0;\n * range.id = 'sliceRange';\n * document.body.appendChild(range);\n * // update app on slider change\n * range.oninput = function () {\n * const lg = app.getLayerGroupByDivId('layerGroup0');\n * const vc = lg.getActiveViewLayer().getViewController();\n * const index = vc.getCurrentIndex();\n * const values = index.getValues();\n * values[2] = this.value;\n * vc.setCurrentIndex(new dwv.Index(values));\n * }\n * // activate tool and update range max on load\n * app.addEventListener('load', function () {\n * app.setTool('Scroll');\n * const size = app.getData(0).image.getGeometry().getSize();\n * range.max = size.get(2) - 1;\n * });\n * // update slider on slice change (for ex via mouse wheel)\n * app.addEventListener('positionchange', function () {\n * const lg = app.getLayerGroupByDivId('layerGroup0');\n * const vc = lg.getActiveViewLayer().getViewController();\n * range.value = vc.getCurrentIndex().get(2);\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm',\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323707.dcm',\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323563.dcm'\n * ]);\n */\nexport class Scroll {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #started = false;\n\n /**\n * Start point.\n *\n * @type {Point2D}\n */\n #startPoint;\n\n /**\n * Scroll wheel handler.\n *\n * @type {ScrollWheel}\n */\n #scrollWhell;\n\n /**\n * Touch timer ID (created by setTimeout).\n *\n * @type {number}\n */\n #touchTimerID;\n\n /**\n * Option to show or not a value tooltip on mousemove.\n *\n * @type {boolean}\n */\n #displayTooltip = false;\n\n /**\n * Current layer group div id.\n *\n * @type {string}\n */\n #currentDivId;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n this.#scrollWhell = new ScrollWheel(app);\n }\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n * @param {string} divId The layer group divId.\n */\n #start(point, divId) {\n // optional tooltip\n this.#removeTooltipDiv();\n\n // stop viewer if playing\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n if (viewController.isPlaying()) {\n viewController.stop();\n }\n\n // start flag\n this.#started = true;\n this.#startPoint = point;\n\n // update controller position\n const planePos = viewLayer.displayToPlanePos(point);\n const position = viewController.getPositionFromPlanePoint(planePos);\n viewController.setCurrentPosition(position);\n }\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #update(point, divId) {\n if (!this.#started) {\n // optional tooltip\n if (this.#displayTooltip) {\n this.#showTooltip(point, divId);\n }\n return;\n }\n\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n\n let newPosition;\n\n // difference to last Y position\n const diffY = point.getY() - this.#startPoint.getY();\n const yMove = (Math.abs(diffY) > 15);\n // do not trigger for small moves\n if (yMove && layerGroup.canScroll()) {\n // update view controller\n if (diffY > 0) {\n newPosition = viewController.getDecrementScrollPosition();\n } else {\n newPosition = viewController.getIncrementScrollPosition();\n }\n }\n\n // difference to last X position\n const diffX = point.getX() - this.#startPoint.getX();\n const xMove = (Math.abs(diffX) > 15);\n // do not trigger for small moves\n if (xMove && layerGroup.moreThanOne(3)) {\n // update view controller\n if (diffX > 0) {\n newPosition = viewController.getIncrementPosition(3);\n } else {\n newPosition = viewController.getDecrementPosition(3);\n }\n }\n\n // set all layers if at least one can be set\n if (typeof newPosition !== 'undefined' &&\n layerGroup.isPositionInBounds(newPosition)) {\n viewController.setCurrentPosition(newPosition);\n }\n\n // reset origin point\n if (xMove || yMove) {\n this.#startPoint = point;\n }\n }\n\n /**\n * Finish tool interaction.\n */\n #finish() {\n if (this.#started) {\n this.#started = false;\n }\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} _event The mouse up event.\n */\n mouseup = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle mouse out event.\n *\n * @param {object} _event The mouse out event.\n */\n mouseout = (_event) => {\n this.#finish();\n // remove possible tooltip div\n this.#removeTooltipDiv();\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n // long touch triggers the dblclick\n // @ts-ignore\n this.#touchTimerID = setTimeout(() => {\n this.dblclick(event);\n }, 500);\n // call start\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n // abort timer if move\n if (this.#touchTimerID !== null) {\n clearTimeout(this.#touchTimerID);\n this.#touchTimerID = null;\n }\n // call update\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} _event The touch end event.\n */\n touchend = (_event) => {\n // abort timer\n if (this.#touchTimerID !== null) {\n clearTimeout(this.#touchTimerID);\n this.#touchTimerID = null;\n }\n // call mouse equivalent\n this.#finish();\n };\n\n /**\n * Handle mouse wheel event.\n *\n * @param {WheelEvent} event The mouse wheel event.\n */\n wheel = (event) => {\n this.#scrollWhell.wheel(event);\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n event.context = 'Scroll';\n this.#app.onKeydown(event);\n };\n\n /**\n * Handle double click.\n *\n * @param {object} event The key down event.\n */\n dblclick = (event) => {\n const layerDetails = getLayerDetailsFromEvent(event);\n\n const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n viewController.play();\n };\n\n /**\n * Display a tooltip at the given point.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #showTooltip(point, divId) {\n // get layer group\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n this.#currentDivId = divId;\n // show new tooltip\n layerGroup.showTooltip(point);\n }\n\n /**\n * Remove the last tooltip html div.\n */\n #removeTooltipDiv() {\n if (typeof this.#currentDivId !== 'undefined') {\n const layerGroup = this.#app.getLayerGroupByDivId(this.#currentDivId);\n layerGroup.removeTooltipDiv();\n this.#currentDivId = undefined;\n }\n }\n\n /**\n * Activate the tool.\n *\n * @param {boolean} _bool The flag to activate or not.\n */\n activate(_bool) {\n // remove tooltip html when deactivating\n if (!_bool) {\n this.#removeTooltipDiv();\n }\n }\n\n /**\n * Set the tool live features: disaply tooltip.\n *\n * @param {object} features The list of features.\n */\n setFeatures(features) {\n if (typeof features.displayTooltip !== 'undefined') {\n this.#displayTooltip = features.displayTooltip;\n }\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n} // Scroll class\n","import {Point2D} from '../math/point';\nimport {Line} from '../math/line';\nimport {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * ZoomAndPan class.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {ZoomAndPan: new dwv.ToolConfig()};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n * app.setTool('ZoomAndPan');\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\nexport class ZoomAndPan {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #started = false;\n\n /**\n * Start point.\n *\n * @type {Point2D}\n */\n #startPoint;\n\n /**\n * Move flag: true if mouse or touch move.\n *\n * @type {boolean}\n */\n #hasMoved;\n\n /**\n * Line between input points.\n *\n * @type {Line}\n */\n #pointsLine;\n\n /**\n * PointsLine midpoint.\n *\n * @type {Point2D}\n */\n #midPoint;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n */\n #start(point) {\n this.#started = true;\n this.#startPoint = point;\n this.#hasMoved = false;\n }\n\n /**\n * Two touch start.\n *\n * @param {Point2D[]} points The start points.\n */\n #twoTouchStart = (points) => {\n this.#started = true;\n this.#startPoint = points[0];\n this.#hasMoved = false;\n // points line\n this.#pointsLine = new Line(points[0], points[1]);\n this.#midPoint = this.#pointsLine.getMidpoint();\n };\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #update(point, divId) {\n if (!this.#started) {\n return;\n }\n this.#hasMoved = true;\n\n // calculate translation\n const tx = point.getX() - this.#startPoint.getX();\n const ty = point.getY() - this.#startPoint.getY();\n // apply translation\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n const planeOffset = viewLayer.displayToPlaneScale(\n new Point2D(tx, ty)\n );\n const offset3D = viewController.getOffset3DFromPlaneOffset({\n x: planeOffset.getX(),\n y: planeOffset.getY()\n });\n layerGroup.addTranslation({\n x: offset3D.getX(),\n y: offset3D.getY(),\n z: offset3D.getZ()\n });\n layerGroup.draw();\n // reset origin point\n this.#startPoint = point;\n }\n\n /**\n * Two touch update.\n *\n * @param {Point2D[]} points The update points.\n * @param {string} divId The layer group divId.\n */\n #twoTouchUpdate = (points, divId) => {\n if (!this.#started) {\n return;\n }\n this.#hasMoved = true;\n\n const newLine = new Line(points[0], points[1]);\n const lineRatio = newLine.getLength() / this.#pointsLine.getLength();\n\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n\n if (lineRatio === 1) {\n // scroll mode\n // difference to last position\n const diffY = points[0].getY() - this.#startPoint.getY();\n // do not trigger for small moves\n if (Math.abs(diffY) < 15) {\n return;\n }\n // update view controller\n if (layerGroup.canScroll()) {\n let newPosition;\n if (diffY > 0) {\n newPosition = viewController.getIncrementScrollPosition();\n } else {\n newPosition = viewController.getDecrementScrollPosition();\n }\n // set all layers if at least one can be set\n if (typeof newPosition !== 'undefined' &&\n layerGroup.isPositionInBounds(newPosition)) {\n viewController.setCurrentPosition(newPosition);\n }\n }\n } else {\n // zoom mode\n const zoom = (lineRatio - 1) / 10;\n if (Math.abs(zoom) % 0.1 <= 0.05 &&\n typeof this.#midPoint !== 'undefined') {\n const planePos = viewLayer.displayToMainPlanePos(this.#midPoint);\n const center = viewController.getPlanePositionFromPlanePoint(planePos);\n layerGroup.addScale(zoom, center);\n layerGroup.draw();\n }\n }\n };\n\n /**\n * Set the current position.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #setCurrentPosition(point, divId) {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n const planePos = viewLayer.displayToPlanePos(point);\n const position = viewController.getPositionFromPlanePoint(planePos);\n viewController.setCurrentPosition(position);\n }\n\n /**\n * Finish tool interaction.\n */\n #finish() {\n if (this.#started) {\n this.#started = false;\n }\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n const mousePoint = getMousePoint(event);\n this.#start(mousePoint);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} event The mouse up event.\n */\n mouseup = (event) => {\n // update position if no move\n if (!this.#hasMoved) {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#setCurrentPosition(mousePoint, layerDetails.groupDivId);\n }\n this.#finish();\n };\n\n /**\n * Handle mouse out event.\n *\n * @param {object} _event The mouse out event.\n */\n mouseout = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n const touchPoints = getTouchPoints(event);\n if (touchPoints.length === 1) {\n this.#start(touchPoints[0]);\n } else if (touchPoints.length === 2) {\n this.#twoTouchStart(touchPoints);\n }\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n if (touchPoints.length === 1) {\n this.#update(touchPoints[0], layerDetails.groupDivId);\n } else if (touchPoints.length === 2) {\n this.#twoTouchUpdate(touchPoints, layerDetails.groupDivId);\n }\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} event The touch end event.\n */\n touchend = (event) => {\n // update position if no move\n if (!this.#hasMoved) {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#setCurrentPosition(mousePoint, layerDetails.groupDivId);\n }\n this.#finish();\n };\n\n /**\n * Handle mouse wheel event.\n *\n * @param {object} event The mouse wheel event.\n */\n wheel = (event) => {\n // prevent default page scroll\n event.preventDefault();\n\n const step = -event.deltaY / 500;\n\n const layerDetails = getLayerDetailsFromEvent(event);\n const mousePoint = getMousePoint(event);\n\n const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n const planePos = viewLayer.displayToMainPlanePos(mousePoint);\n const center = viewController.getPlanePositionFromPlanePoint(planePos);\n layerGroup.addScale(step, center);\n layerGroup.draw();\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n event.context = 'ZoomAndPan';\n this.#app.onKeydown(event);\n };\n\n /**\n * Activate the tool.\n *\n * @param {boolean} _bool The flag to activate or not.\n */\n activate(_bool) {\n // does nothing\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n /**\n * Set the tool live features: does nothing.\n *\n * @param {object} _features The list of features.\n */\n setFeatures(_features) {\n // does nothing\n }\n\n} // ZoomAndPan class\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {ScrollWheel} from './scrollWheel';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * Opacity class.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Opacity: new dwv.ToolConfig()};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n * app.setTool('Opacity');\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\nexport class Opacity {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #started = false;\n\n /**\n * Start point.\n *\n * @type {Point2D}\n */\n #startPoint;\n\n /**\n * Scroll wheel handler.\n *\n * @type {ScrollWheel}\n */\n #scrollWhell;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n this.#scrollWhell = new ScrollWheel(app);\n }\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n */\n #start(point) {\n this.#started = true;\n this.#startPoint = point;\n }\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #update(point, divId) {\n if (!this.#started) {\n return;\n }\n\n // difference to last X position\n const diffX = point.getX() - this.#startPoint.getX();\n const xMove = (Math.abs(diffX) > 15);\n // do not trigger for small moves\n if (xMove) {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const op = viewLayer.getOpacity();\n viewLayer.setOpacity(op + (diffX / 200));\n viewLayer.draw();\n\n // reset origin point\n this.#startPoint = point;\n }\n }\n\n /**\n * Finish tool interaction.\n */\n #finish() {\n if (this.#started) {\n this.#started = false;\n }\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n const mousePoint = getMousePoint(event);\n this.#start(mousePoint);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} _event The mouse up event.\n */\n mouseup = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle mouse out event.\n *\n * @param {object} _event The mouse out event.\n */\n mouseout = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n const touchPoints = getTouchPoints(event);\n this.#start(touchPoints[0]);\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} _event The touch end event.\n */\n touchend = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle mouse wheel event.\n *\n * @param {object} event The mouse wheel event.\n */\n wheel = (event) => {\n this.#scrollWhell.wheel(event);\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n event.context = 'Opacity';\n this.#app.onKeydown(event);\n };\n\n /**\n * Activate the tool.\n *\n * @param {boolean} _bool The flag to activate or not.\n */\n activate(_bool) {\n // does nothing\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n /**\n * Set the tool live features: does nothing.\n *\n * @param {object} _features The list of features.\n */\n setFeatures(_features) {\n // does nothing\n }\n\n} // Opacity class\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\nimport {guid} from '../math/stats';\nimport {logger} from '../utils/logger';\nimport {\n AddAnnotationCommand,\n RemoveAnnotationCommand\n} from './drawCommands';\nimport {\n isNodeNameShape,\n} from './drawBounds';\nimport {Annotation} from '../image/annotation';\nimport {ScrollWheel} from './scrollWheel';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {Style} from '../gui/style';\nimport {LayerGroup} from '../gui/layerGroup';\nimport {Point2D} from '../math/point';\nimport {DrawLayer} from '../gui/drawLayer';\nimport {DrawShapeHandler} from './drawShapeHandler';\n/* eslint-enable no-unused-vars */\n\n/**\n * Drawing tool.\n *\n * This tool is responsible for the draw of layer group structure.\n *\n * ```\n * drawLayer\n * |_ positionGroup: {name=\"position-group\", id=\"#2-0#_#3-1\"}\n * |_ shapeGroup: {name=\"{shape name}-group\", id=\"#\"}\n * |_ shape: {name=\"shape\"},\n * |_ label: {name=\"label\"},\n * |_ extra: line tick, protractor arc...\n * ```\n *\n * Discussion:\n * - posGroup > shapeGroup:\n * (pro) slice/frame display: 1 loop -\n * (cons) multi-slice shape splitted in positionGroups.\n * - shapeGroup > posGroup:\n * (pros) more logical -\n * (cons) slice/frame display: 2 loops.\n */\nexport class Draw {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Scroll wheel handler.\n *\n * @type {ScrollWheel}\n */\n #scrollWhell;\n\n /**\n * Drawing style.\n *\n * @type {Style}\n */\n #style;\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #isDrawing = false;\n\n /**\n * Shape factory list.\n *\n * @type {object}\n */\n #shapeFactoryList = null;\n\n /**\n * Current shape factory.\n *\n * @type {object}\n */\n #currentFactory = null;\n\n /**\n * Current shape group.\n *\n * @type {object}\n */\n #tmpShapeGroup = null;\n\n /**\n * Shape name.\n *\n * @type {string}\n */\n #shapeName;\n\n /**\n * List of points.\n *\n * @type {Point2D[]}\n */\n #points = [];\n\n /**\n * Last selected point.\n *\n * @type {Point2D}\n */\n #lastPoint = null;\n\n /**\n * With scroll flag.\n *\n * @type {boolean}\n */\n #withScroll = true;\n\n /**\n * Black list: list of dataIds for which draw layer creation\n * is forbidden.\n */\n #blacklist = [];\n\n /**\n * Shape handler: activate listeners on existing shape.\n *\n * @type {DrawShapeHandler}\n */\n #shapeHandler;\n\n /**\n * Auto shape colour: will use defaults colours and\n * vary them according to the layer.\n *\n * @type {boolean}\n */\n #autoShapeColour = false;\n\n /**\n * Event listeners.\n */\n #listeners = {};\n\n /**\n * Flag to know if the last added point was made by mouse move.\n *\n * @type {boolean}\n */\n #lastIsMouseMovePoint = false;\n\n /**\n * Callback store to allow attach/detach.\n *\n * @type {Array}\n */\n #callbackStore = [];\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n this.#scrollWhell = new ScrollWheel(app);\n this.#shapeHandler = new DrawShapeHandler(app, this.#fireEvent);\n\n this.#style = app.getStyle();\n }\n\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n * @param {string} divId The layer group divId.\n */\n #switchEditOrCreateShapeGroup(point, divId) {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n let drawLayer = layerGroup.getActiveDrawLayer();\n\n if (typeof drawLayer === 'undefined') {\n const viewLayer = layerGroup.getActiveViewLayer();\n const refDataId = viewLayer.getDataId();\n const refData = this.#app.getData(refDataId);\n const refMeta = refData.image.getMeta();\n const seriesInstanceUID = refMeta.SeriesInstanceUID;\n // check black list\n if (this.#blacklist.includes(seriesInstanceUID)) {\n /**\n * Warn event.\n *\n * @event Draw#warn\n * @type {object}\n * @property {string} type The event type.\n * @property {string} message The warning message.\n */\n this.#fireEvent({\n type: 'warn',\n message: 'Cannot create draw layer, data is in black list'\n });\n return;\n }\n // create new data\n const data = this.#app.createAnnotationData(refDataId);\n // render (will create draw layer)\n this.#app.addAndRenderAnnotationData(data, divId, refDataId);\n // get draw layer\n drawLayer = layerGroup.getActiveDrawLayer();\n // set the layer shape handler\n drawLayer.setShapeHandler(this.#shapeHandler);\n // set active to bind to toolboxController\n layerGroup.setActiveDrawLayerByDataId(drawLayer.getDataId());\n }\n\n // data should exist / be created\n const data = drawLayer.getDrawController().getAnnotationGroup();\n\n const stage = drawLayer.getKonvaStage();\n\n // update scale\n this.#style.setZoomScale(stage.scale());\n\n if (data.isEditable()) {\n // determine if the click happened on an existing shape or not\n const kshape = stage.getIntersection({\n x: point.getX(),\n y: point.getY()\n });\n if (kshape) {\n // select shape for edition\n this.#selectShapeGroup(drawLayer, kshape);\n } else {\n // create new shape\n this.#startShapeGroupCreation(layerGroup, point);\n }\n }\n }\n\n /**\n * Initializes the new shape creation:\n * - Updates the started variable,\n * - Gets the factory,\n * - Initializes the points array.\n *\n * @param {LayerGroup} layerGroup The layer group where the user clicks.\n * @param {Point2D} point The start point where the user clicks.\n */\n #startShapeGroupCreation(layerGroup, point) {\n // disable edition\n this.#shapeHandler.disableAndResetEditor();\n this.#setToDrawingState();\n // store point\n const viewLayer = layerGroup.getActiveViewLayer();\n this.#lastPoint = viewLayer.displayToPlanePos(point);\n this.#points.push(this.#lastPoint);\n }\n\n /**\n * Sets the variables to drawing state:\n * - Updates is drawing variable,\n * - Initializes the current factory,\n * - Resets points.\n */\n #setToDrawingState() {\n // start storing points\n this.#isDrawing = true;\n // set factory\n this.#currentFactory = new this.#shapeFactoryList[this.#shapeName]();\n // clear array\n this.#points = [];\n }\n\n /**\n * Resets the variables to not drawing state:\n * - Destroys tmp shape group,\n * - Updates is drawing variable,\n * - Resets points.\n */\n #setToNotDrawingState() {\n this.#isDrawing = false;\n this.#points = [];\n }\n\n /**\n * Selects a shape group.\n *\n * @param {DrawLayer} drawLayer The draw layer where to draw.\n * @param {Konva.Shape} kshape The shape that has been selected.\n */\n #selectShapeGroup(drawLayer, kshape) {\n let group = kshape.getParent();\n // kshape: Konva.Tag -> parent: Konva.Label -> parent: Konva.Group\n if (kshape instanceof Konva.Tag) {\n group = group.getParent();\n }\n const selectedShape = group.find('.shape')[0];\n if (!(selectedShape instanceof Konva.Shape)) {\n return;\n }\n /**\n * Annotation select event.\n *\n * @event Draw#annotationselect\n * @type {object}\n * @property {string} type The event type.\n * @property {string} annotationid The annotation id.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'annotationselect',\n annotationid: group.id(),\n dataid: drawLayer.getDataId()\n });\n this.#shapeHandler.setEditorShape(selectedShape, drawLayer);\n }\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #updateShapeGroupCreation(point, divId) {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const pos = viewLayer.displayToPlanePos(point);\n\n // draw line to current pos\n if (Math.abs(pos.getX() - this.#lastPoint.getX()) > 0 ||\n Math.abs(pos.getY() - this.#lastPoint.getY()) > 0) {\n // clear last mouse move point\n if (this.#lastIsMouseMovePoint) {\n this.#points.pop();\n }\n // current point\n this.#lastPoint = pos;\n // mark it as temporary\n this.#lastIsMouseMovePoint = true;\n // add it to the list\n this.#points.push(this.#lastPoint);\n // update points\n this.#onNewPoints(this.#points, layerGroup);\n }\n }\n\n /**\n * Finish tool interaction.\n *\n * @param {string} divId The layer group divId.\n */\n #finishShapeGroupCreation(divId) {\n // exit if no points\n if (this.#points.length === 0) {\n logger.warn('Draw mouseup but no points...');\n return;\n }\n\n // do we have all the needed points\n if (this.#points.length === this.#currentFactory.getNPoints()) {\n // store points\n const layerGroup =\n this.#app.getLayerGroupByDivId(divId);\n this.#onFinalPoints(this.#points, layerGroup);\n this.#setToNotDrawingState();\n }\n\n // reset mouse move point flag\n this.#lastIsMouseMovePoint = false;\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n // exit if not started draw\n if (this.#isDrawing) {\n return;\n }\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#switchEditOrCreateShapeGroup(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n // exit if not started draw\n if (!this.#isDrawing) {\n return;\n }\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#updateShapeGroupCreation(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} event The mouse up event.\n */\n mouseup = (event) => {\n // exit if not started draw\n if (!this.#isDrawing) {\n return;\n }\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#finishShapeGroupCreation(layerDetails.groupDivId);\n };\n\n /**\n * Handle double click event: some tools use it to finish interaction.\n *\n * @param {object} event The double click event.\n */\n dblclick = (event) => {\n // only end by double click undefined NPoints\n if (this.#currentFactory &&\n typeof this.#currentFactory.getNPoints() !== 'undefined') {\n return;\n }\n // exit if not started draw\n if (!this.#isDrawing) {\n return;\n }\n // exit if no points\n if (this.#points.length === 0) {\n logger.warn('Draw dblclick but no points...');\n return;\n }\n\n // store points\n const layerDetails = getLayerDetailsFromEvent(event);\n const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n this.#onFinalPoints(this.#points, layerGroup);\n this.#setToNotDrawingState();\n };\n\n /**\n * Handle mouse out event.\n *\n * @param {object} event The mouse out event.\n */\n mouseout = (event) => {\n // exit if not started draw\n if (!this.#isDrawing) {\n return;\n }\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#finishShapeGroupCreation(layerDetails.groupDivId);\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n // exit if not started draw\n if (this.#isDrawing) {\n return;\n }\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#switchEditOrCreateShapeGroup(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n // exit if not started draw\n if (!this.#isDrawing) {\n return;\n }\n\n const layerDetails = getLayerDetailsFromEvent(event);\n const touchPoints = getTouchPoints(event);\n\n const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const pos = viewLayer.displayToPlanePos(touchPoints[0]);\n\n if (Math.abs(pos.getX() - this.#lastPoint.getX()) > 0 ||\n Math.abs(pos.getY() - this.#lastPoint.getY()) > 0) {\n // clear last added point from the list (but not the first one)\n if (this.#points.length !== 1) {\n this.#points.pop();\n }\n // current point\n this.#lastPoint = pos;\n // add current one to the list\n this.#points.push(this.#lastPoint);\n // allow for anchor points\n if (this.#points.length < this.#currentFactory.getNPoints()) {\n clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.#points.push(this.#lastPoint);\n }, this.#currentFactory.getTimeout());\n }\n // update points\n this.#onNewPoints(this.#points, layerGroup);\n }\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} event The touch end event.\n */\n touchend = (event) => {\n this.dblclick(event);\n };\n\n /**\n * Handle mouse wheel event.\n *\n * @param {WheelEvent} event The mouse wheel event.\n */\n wheel = (event) => {\n if (this.#withScroll) {\n this.#scrollWhell.wheel(event);\n }\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n // call app handler if we are not in the middle of a draw\n if (!this.#isDrawing) {\n event.context = 'Draw';\n this.#app.onKeydown(event);\n }\n\n // press delete or backspace key\n const annotation = this.#shapeHandler.getEditorAnnotation();\n if ((event.key === 'Delete' ||\n event.key === 'Backspace') &&\n typeof annotation !== 'undefined') {\n const layerGroup = this.#app.getActiveLayerGroup();\n const drawLayer = layerGroup.getActiveDrawLayer();\n const drawController = drawLayer.getDrawController();\n\n // create remove annotation command\n const command = new RemoveAnnotationCommand(annotation, drawController);\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // execute command: triggers draw remove\n command.execute();\n\n // reset cursor\n this.#shapeHandler.onMouseOutShapeGroup();\n }\n\n // escape key: exit shape creation\n if (event.key === 'Escape' && this.#tmpShapeGroup !== null) {\n const konvaLayer = this.#tmpShapeGroup.getLayer();\n // reset temporary shape group\n this.#tmpShapeGroup.destroy();\n this.#tmpShapeGroup = null;\n // set state\n this.#setToNotDrawingState();\n // redraw\n konvaLayer.draw();\n }\n };\n\n /**\n * Update the current draw with new points.\n *\n * @param {Point2D[]} tmpPoints The array of new points.\n * @param {LayerGroup} layerGroup The origin layer group.\n */\n #onNewPoints(tmpPoints, layerGroup) {\n // remove temporary shape draw\n if (this.#tmpShapeGroup) {\n this.#tmpShapeGroup.destroy();\n this.#tmpShapeGroup = null;\n }\n\n const drawLayer = layerGroup.getActiveDrawLayer();\n const drawController = drawLayer.getDrawController();\n const konvaLayer = drawLayer.getKonvaLayer();\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n\n // auto mode: vary shape colour with layer id\n if (this.#autoShapeColour) {\n const colours = [\n '#ffff80', '#ff80ff', '#80ffff', '#80ff80', '8080ff', 'ff8080'\n ];\n // warning: depends on layer id nomenclature\n const drawLayerId = drawLayer.getId();\n const layerId = drawLayerId.substring(drawLayerId.length - 1);\n const layerIndex = parseInt(layerId, 10) - 1;\n const colour = colours[layerIndex];\n if (typeof colour !== 'undefined') {\n this.#style.setLineColour(colour);\n }\n }\n\n // create tmp annotation\n const annotation = new Annotation();\n // use group colour if defined\n const groupColour = drawController.getAnnotationGroup().getColour();\n if (typeof groupColour !== 'undefined') {\n annotation.colour = groupColour;\n } else {\n annotation.colour = this.#style.getLineColour();\n }\n annotation.init(viewController);\n // set annotation shape\n this.#currentFactory.setAnnotationMathShape(annotation, tmpPoints);\n // create shape group\n this.#tmpShapeGroup =\n this.#currentFactory.createShapeGroup(annotation, this.#style);\n // set the label visibility\n drawLayer.setLabelVisibility(this.#tmpShapeGroup);\n\n // do not listen during creation\n const shape = this.#tmpShapeGroup.getChildren(isNodeNameShape)[0];\n shape.listening(false);\n konvaLayer.listening(false);\n // draw shape\n konvaLayer.add(this.#tmpShapeGroup);\n konvaLayer.draw();\n }\n\n /**\n * Create the final shape from a point list.\n *\n * @param {Point2D[]} finalPoints The array of points.\n * @param {LayerGroup} layerGroup The origin layer group.\n */\n #onFinalPoints(finalPoints, layerGroup) {\n // remove temporary shape draw\n // (has to be done before sending add event)\n if (this.#tmpShapeGroup) {\n this.#tmpShapeGroup.destroy();\n this.#tmpShapeGroup = null;\n }\n\n const drawLayer = layerGroup.getActiveDrawLayer();\n const konvaLayer = drawLayer.getKonvaLayer();\n const drawController = drawLayer.getDrawController();\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n\n // create final annotation\n const annotation = new Annotation();\n // use group colour if defined\n const groupColour = drawController.getAnnotationGroup().getColour();\n if (typeof groupColour !== 'undefined') {\n annotation.colour = groupColour;\n } else {\n annotation.colour = this.#style.getLineColour();\n }\n annotation.id = guid();\n annotation.init(viewController);\n // set annotation shape\n this.#currentFactory.setAnnotationMathShape(annotation, finalPoints);\n\n // create add annotation command\n const command = new AddAnnotationCommand(annotation, drawController);\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // execute command: triggers draw creation\n command.execute();\n\n // re-activate layer\n konvaLayer.listening(true);\n }\n\n /**\n * Get a DrawLayer position callback.\n *\n * TODO: check need for store item removal.\n *\n * @param {DrawLayer} layer The layer to update.\n * @returns {Function} The callback.\n */\n #getPositionCallback(layer) {\n const layerId = layer.getId();\n if (typeof this.#callbackStore[layerId] === 'undefined') {\n this.#callbackStore[layerId] = () => {\n layer.activateCurrentPositionShapes(true);\n };\n }\n return this.#callbackStore[layerId];\n }\n\n /**\n * Activate a draw layer.\n *\n * @param {DrawLayer} drawLayer The layer to update.\n * @param {boolean} flag The flag to activate or not.\n */\n #activateLayer(drawLayer, flag) {\n drawLayer.setShapeHandler(this.#shapeHandler);\n drawLayer.activateCurrentPositionShapes(flag);\n // update on position change\n if (flag) {\n this.#app.addEventListener('positionchange',\n this.#getPositionCallback(drawLayer)\n );\n } else {\n this.#app.removeEventListener('positionchange',\n this.#getPositionCallback(drawLayer)\n );\n }\n }\n\n /**\n * Activate the tool.\n *\n * @param {boolean} flag The flag to activate or not.\n */\n activate(flag) {\n // force cursor if deactivate\n if (!flag) {\n this.#shapeHandler.onMouseOutShapeGroup();\n }\n // update draw layers\n const drawLayers = this.#app.getDrawLayers();\n for (const drawLayer of drawLayers) {\n if (typeof drawLayer !== 'undefined') {\n this.#activateLayer(drawLayer, flag);\n }\n }\n // activate newly added layers\n this.#app.addEventListener('drawlayeradd', (event) => {\n const drawLayers = this.#app.getDrawLayers(function (item) {\n return item.getId() === event.layerid;\n });\n // should be just one\n if (drawLayers.length === 1) {\n this.#activateLayer(drawLayers[0], flag);\n }\n });\n\n }\n\n /**\n * Set the tool configuration options.\n *\n * @param {object} options The list of shape names amd classes.\n */\n setOptions(options) {\n // save the options as the shape factory list\n this.#shapeFactoryList = options;\n }\n\n /**\n * Get the type of tool options: here 'factory' since the shape\n * list contains factories to create each possible shape.\n *\n * @returns {string} The type.\n */\n getOptionsType() {\n return 'factory';\n }\n\n /**\n * Set the tool live features: shape colour and shape name.\n *\n * @param {object} features The list of features.\n */\n setFeatures(features) {\n if (typeof features.autoShapeColour !== 'undefined') {\n this.#autoShapeColour = features.autoShapeColour;\n }\n if (typeof features.shapeColour !== 'undefined') {\n this.#style.setLineColour(features.shapeColour);\n this.#autoShapeColour = false;\n }\n if (typeof features.shapeName !== 'undefined') {\n // check if we have it\n if (!this.hasShape(features.shapeName)) {\n throw new Error('Unknown shape: \\'' + features.shapeName + '\\'');\n }\n this.#shapeName = features.shapeName;\n }\n if (typeof features.mouseOverCursor !== 'undefined') {\n this.#shapeHandler.storeMouseOverCursor(features.mouseOverCursor);\n }\n if (typeof features.withScroll !== 'undefined') {\n this.#withScroll = features.withScroll;\n }\n if (typeof features.blacklist !== 'undefined') {\n this.#blacklist = features.blacklist;\n }\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n /**\n * Get the list of event names that this tool can fire.\n *\n * @returns {string[]} The list of event names.\n */\n getEventNames() {\n return [\n 'annotationupdate', 'annotationselect', 'warn'\n ];\n }\n\n /**\n * Add an event listener on the app.\n *\n * @param {string} type The event type.\n * @param {Function} listener The function associated with the provided\n * event type.\n */\n addEventListener(type, listener) {\n if (typeof this.#listeners[type] === 'undefined') {\n this.#listeners[type] = [];\n }\n this.#listeners[type].push(listener);\n }\n\n /**\n * Remove an event listener from the app.\n *\n * @param {string} type The event type.\n * @param {Function} listener The function associated with the provided\n * event type.\n */\n removeEventListener(type, listener) {\n if (typeof this.#listeners[type] === 'undefined') {\n return;\n }\n for (let i = 0; i < this.#listeners[type].length; ++i) {\n if (this.#listeners[type][i] === listener) {\n this.#listeners[type].splice(i, 1);\n }\n }\n }\n\n // Private Methods -----------------------------------------------------------\n\n /**\n * Fire an event: call all associated listeners.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n if (typeof this.#listeners[event.type] === 'undefined') {\n return;\n }\n for (let i = 0; i < this.#listeners[event.type].length; ++i) {\n this.#listeners[event.type][i](event);\n }\n };\n\n /**\n * Check if the shape is in the shape list.\n *\n * @param {string} name The name of the shape.\n * @returns {boolean} True if there is a factory for the shape.\n */\n hasShape(name) {\n return typeof this.#shapeFactoryList[name] !== 'undefined';\n }\n\n} // Draw class\n","import {Annotation} from '../image/annotation';\nimport {\n AddAnnotationCommand,\n UpdateAnnotationCommand\n} from '../tools/drawCommands';\n//import {RoiFactory} from '../tools/roi';\nimport {ROI} from '../math/roi';\nimport {guid} from '../math/stats';\nimport {Point2D} from '../math/point';\nimport {Style} from '../gui/style';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\nimport {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {ListenerHandler} from '../utils/listen';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {LayerGroup} from '../gui/layerGroup';\nimport {Scalar2D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * The magic wand namespace.\n *\n * Ref: {@link https://github.com/Tamersoul/magic-wand-js}.\n *\n * @external MagicWand\n */\nimport MagicWand from 'magic-wand-tool';\n\n/**\n * Floodfill painting tool.\n */\nexport class Floodfill {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Original variables from external library. Used as in the lib example.\n *\n * @type {number}\n */\n #blurRadius = 5;\n /**\n * Original variables from external library. Used as in the lib example.\n *\n * @type {number}\n */\n #simplifyTolerant = 0;\n\n /**\n * Original variables from external library. Used as in the lib example.\n *\n * @type {number}\n */\n #simplifyCount = 2000;\n\n /**\n * Canvas info.\n *\n * @type {object}\n */\n #imageInfo = null;\n\n /**\n * Object created by MagicWand lib containing border points.\n *\n * @type {object}\n */\n #mask = null;\n\n /**\n * Threshold default tolerance of the tool border.\n *\n * @type {number}\n */\n #initialthreshold = 10;\n\n /**\n * Threshold tolerance of the tool border.\n *\n * @type {number}\n */\n #currentthreshold = null;\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #started = false;\n\n /**\n * Current annotation.\n *\n * @type {Annotation}\n */\n #annotation;\n\n /**\n * Coordinates of the fist mousedown event.\n *\n * @type {object}\n */\n #initialpoint;\n\n /**\n * Floodfill border.\n *\n * @type {object}\n */\n #border = null;\n\n /**\n * List of parent points.\n *\n * @type {Point2D[]}\n */\n #parentPoints = [];\n\n /**\n * Assistant variable to paint border on all slices.\n *\n * @type {boolean}\n */\n #extender = false;\n\n /**\n * Drawing style.\n *\n * @type {Style}\n */\n #style = new Style();\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Set extend option for painting border on all slices.\n *\n * @param {boolean} bool The option to set.\n */\n setExtend(bool) {\n this.#extender = bool;\n }\n\n /**\n * Get extend option for painting border on all slices.\n *\n * @returns {boolean} The actual value of of the variable to use Floodfill\n * on museup.\n */\n getExtend() {\n return this.#extender;\n }\n\n /**\n * Get (x, y) coordinates referenced to the canvas.\n *\n * @param {Point2D} point The start point.\n * @param {string} divId The layer group divId.\n * @returns {Scalar2D} The coordinates as a {x,y}.\n */\n #getIndex = (point, divId) => {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const index = viewLayer.displayToPlaneIndex(point);\n return {\n x: index.get(0),\n y: index.get(1)\n };\n };\n\n /**\n * Calculate border.\n *\n * @param {object} points The input points.\n * @param {number} threshold The threshold of the floodfill.\n * @param {boolean} simple Return first points or a list.\n * @returns {Point2D[]} The parent points.\n */\n #calcBorder(points, threshold, simple) {\n\n this.#parentPoints = [];\n const image = {\n data: this.#imageInfo.data,\n width: this.#imageInfo.width,\n height: this.#imageInfo.height,\n bytes: 4\n };\n\n this.#mask = MagicWand.floodFill(image, points.x, points.y, threshold);\n this.#mask = MagicWand.gaussBlurOnlyBorder(this.#mask, this.#blurRadius);\n\n let cs = MagicWand.traceContours(this.#mask);\n cs = MagicWand.simplifyContours(\n cs, this.#simplifyTolerant, this.#simplifyCount);\n\n if (cs.length > 0 && cs[0].points[0].x) {\n if (simple) {\n return cs[0].points;\n }\n for (let j = 0, icsl = cs[0].points.length; j < icsl; j++) {\n this.#parentPoints.push(new Point2D(\n cs[0].points[j].x,\n cs[0].points[j].y\n ));\n }\n return this.#parentPoints;\n } else {\n return [];\n }\n }\n\n /**\n * Paint Floodfill.\n *\n * @param {object} point The start point.\n * @param {number} threshold The border threshold.\n * @param {LayerGroup} layerGroup The origin layer group.\n * @returns {boolean} False if no border.\n */\n #paintBorder(point, threshold, layerGroup) {\n // Calculate the border\n this.#border = this.#calcBorder(point, threshold, false);\n // Paint the border\n if (this.#border.length !== 0) {\n const drawLayer = layerGroup.getActiveDrawLayer();\n const drawController = drawLayer.getDrawController();\n\n const newMathShape = new ROI(this.#border);\n\n let command;\n if (typeof this.#annotation === 'undefined') {\n // create annotation\n this.#annotation = new Annotation();\n this.#annotation.colour = this.#style.getLineColour();\n this.#annotation.id = guid();\n\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n this.#annotation.init(viewController);\n\n this.#annotation.mathShape = newMathShape;\n command = new AddAnnotationCommand(\n this.#annotation,\n drawController\n );\n } else {\n // update annotation\n const originalMathShape = this.#annotation.mathShape;\n command = new UpdateAnnotationCommand(\n this.#annotation,\n {mathShape: originalMathShape},\n {mathShape: newMathShape},\n drawController\n );\n }\n\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // execute command: triggers draw creation\n command.execute();\n }\n\n return this.#border.length !== 0;\n }\n\n /**\n * Create Floodfill in all the prev and next slices while border is found.\n *\n * @param {number} ini The first slice to extend to.\n * @param {number} end The last slice to extend to.\n * @param {object} layerGroup The origin layer group.\n */\n extend(ini, end, layerGroup) {\n //avoid errors\n if (!this.#initialpoint) {\n throw '\\'initialpoint\\' not found. User must click before use extend!';\n }\n\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n\n const pos = viewController.getCurrentIndex();\n const imageSize = viewController.getImageSize();\n const threshold = this.#currentthreshold || this.#initialthreshold;\n\n // Iterate over the next images and paint border on each slice.\n for (let i = pos.get(2),\n len = end\n ? end : imageSize.get(2);\n i < len; i++) {\n if (!this.#paintBorder(this.#initialpoint, threshold, layerGroup)) {\n break;\n }\n viewController.incrementIndex(2);\n }\n viewController.setCurrentPosition(pos);\n\n // Iterate over the prev images and paint border on each slice.\n for (let j = pos.get(2), jl = ini ? ini : 0; j > jl; j--) {\n if (!this.#paintBorder(this.#initialpoint, threshold, layerGroup)) {\n break;\n }\n viewController.decrementIndex(2);\n }\n viewController.setCurrentPosition(pos);\n }\n\n /**\n * Event fired when threshold change.\n *\n * @param {number} _value Current threshold.\n */\n onThresholdChange(_value) {\n // Defaults do nothing\n }\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n * @param {string} divId The layer group divId.\n */\n #start(point, divId) {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n let drawLayer = layerGroup.getActiveDrawLayer();\n\n if (typeof drawLayer === 'undefined') {\n const viewLayer = layerGroup.getActiveViewLayer();\n const refDataId = viewLayer.getDataId();\n // create new data\n const data = this.#app.createAnnotationData(refDataId);\n // render (will create draw layer)\n this.#app.addAndRenderAnnotationData(data, divId, refDataId);\n // get draw layer\n drawLayer = layerGroup.getActiveDrawLayer();\n // set active to bind to toolboxController\n layerGroup.setActiveDrawLayerByDataId(drawLayer.getDataId());\n }\n\n this.#imageInfo = viewLayer.getImageData();\n if (!this.#imageInfo) {\n logger.error('No image found');\n return;\n }\n\n // update zoom scale\n this.#style.setZoomScale(\n drawLayer.getKonvaLayer().getAbsoluteScale());\n\n this.#started = true;\n this.#initialpoint = this.#getIndex(point, divId);\n this.#paintBorder(this.#initialpoint, this.#initialthreshold, layerGroup);\n this.onThresholdChange(this.#initialthreshold);\n }\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #update(point, divId) {\n if (!this.#started) {\n return;\n }\n\n const movedpoint = this.#getIndex(point, divId);\n this.#currentthreshold = Math.round(Math.sqrt(\n Math.pow((this.#initialpoint.x - movedpoint.x), 2) +\n Math.pow((this.#initialpoint.y - movedpoint.y), 2)) / 2);\n this.#currentthreshold = this.#currentthreshold < this.#initialthreshold\n ? this.#initialthreshold\n : this.#currentthreshold - this.#initialthreshold;\n\n this.#paintBorder(\n this.#initialpoint,\n this.#currentthreshold,\n this.#app.getLayerGroupByDivId(divId)\n );\n\n this.onThresholdChange(this.#currentthreshold);\n }\n\n /**\n * Finish tool interaction.\n */\n #finish() {\n if (this.#started) {\n this.#started = false;\n }\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} _event The mouse up event.\n */\n mouseup = (_event) => {\n this.#finish();\n // TODO: re-activate\n // if (this.#extender) {\n // const layerDetails = getLayerDetailsFromEvent(event);\n // const layerGroup =\n // this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n // this.extend(layerGroup);\n // }\n };\n\n /**\n * Handle mouse out event.\n *\n * @param {object} _event The mouse out event.\n */\n mouseout = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} _event The touch end event.\n */\n touchend = (_event) => {\n this.#finish();\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n event.context = 'Floodfill';\n this.#app.onKeydown(event);\n };\n\n /**\n * Activate the tool.\n *\n * @param {boolean} bool The flag to activate or not.\n */\n activate(bool) {\n if (bool) {\n // init with the app window scale\n this.#style.setBaseScale(this.#app.getBaseScale());\n // set the default to the first in the list\n this.setFeatures({shapeColour: this.#style.getLineColour()});\n }\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n /**\n * Get the list of event names that this tool can fire.\n *\n * @returns {Array} The list of event names.\n */\n getEventNames() {\n return ['drawcreate', 'drawchange', 'drawmove', 'drawdelete'];\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n // #fireEvent = (event) => {\n // this.#listenerHandler.fireEvent(event);\n // };\n\n /**\n * Set the tool live features: shape colour.\n *\n * @param {object} features The list of features.\n */\n setFeatures(features) {\n if (typeof features.shapeColour !== 'undefined') {\n this.#style.setLineColour(features.shapeColour);\n }\n }\n\n} // Floodfill class\n","import {Style} from '../gui/style';\nimport {\n getMousePoint,\n getTouchPoints\n} from '../gui/generic';\nimport {Point2D} from '../math/point';\nimport {Path} from '../math/path';\nimport {Scissors} from '../math/scissors';\nimport {guid} from '../math/stats';\nimport {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {ListenerHandler} from '../utils/listen';\nimport {ROI} from '../math/roi';\nimport {Annotation} from '../image/annotation';\nimport {\n AddAnnotationCommand,\n UpdateAnnotationCommand\n} from '../tools/drawCommands';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Livewire painting tool.\n */\nexport class Livewire {\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * @param {App} app The associated application.\n */\n constructor(app) {\n this.#app = app;\n }\n\n /**\n * Interaction start flag.\n *\n * @type {boolean}\n */\n #started = false;\n\n /**\n * Start point.\n *\n * @type {Point2D}\n */\n #startPoint;\n\n /**\n * Current annotation.\n *\n * @type {Annotation}\n */\n #annotation;\n\n /**\n * Drawing style.\n *\n * @type {Style}\n */\n #style = new Style();\n\n /**\n * Path storage. Paths are stored in reverse order.\n *\n * @type {Path}\n */\n #path = new Path();\n\n /**\n * Current path storage. Paths are stored in reverse order.\n *\n * @type {Path}\n */\n #currentPath = new Path();\n\n /**\n * List of parent points.\n *\n * @type {Array}\n */\n #parentPoints = [];\n\n /**\n * Tolerance.\n *\n * @type {number}\n */\n #tolerance = 5;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Clear the parent points list.\n *\n * @param {object} imageSize The image size.\n */\n #clearParentPoints(imageSize) {\n const nrows = imageSize.get(1);\n for (let i = 0; i < nrows; ++i) {\n this.#parentPoints[i] = [];\n }\n }\n\n /**\n * Clear the stored paths.\n */\n #clearPaths() {\n this.#path = new Path();\n this.#currentPath = new Path();\n }\n\n /**\n * Scissor representation.\n *\n * @type {Scissors}\n */\n #scissors = new Scissors();\n\n /**\n * Start tool interaction.\n *\n * @param {Point2D} point The start point.\n * @param {string} divId The layer group divId.\n */\n #start(point, divId) {\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const imageSize = viewLayer.getViewController().getImageSize();\n const index = viewLayer.displayToPlaneIndex(point);\n\n // first time\n if (!this.#started) {\n this.#started = true;\n this.#startPoint = new Point2D(index.get(0), index.get(1));\n // clear vars\n this.#clearPaths();\n this.#clearParentPoints(imageSize);\n // get draw layer\n let drawLayer = layerGroup.getActiveDrawLayer();\n if (typeof drawLayer === 'undefined') {\n const viewLayer = layerGroup.getActiveViewLayer();\n const refDataId = viewLayer.getDataId();\n // create new data\n const data = this.#app.createAnnotationData(refDataId);\n // render (will create draw layer)\n this.#app.addAndRenderAnnotationData(data, divId, refDataId);\n // get draw layer\n drawLayer = layerGroup.getActiveDrawLayer();\n // set active to bind to toolboxController\n layerGroup.setActiveDrawLayerByDataId(drawLayer.getDataId());\n }\n // update zoom scale\n this.#style.setZoomScale(\n drawLayer.getKonvaLayer().getAbsoluteScale());\n // do the training from the first point\n const p = {x: index.get(0), y: index.get(1)};\n this.#scissors.doTraining(p);\n // add the initial point to the path\n const p0 = new Point2D(index.get(0), index.get(1));\n this.#path.addPoint(p0);\n this.#path.addControlPoint(p0);\n } else {\n const diffX = Math.abs(index.get(0) - this.#startPoint.getX());\n const diffY = Math.abs(index.get(1) - this.#startPoint.getY());\n // final point: at 'tolerance' of the initial point\n if (diffX < this.#tolerance &&\n diffY < this.#tolerance) {\n // finish\n this.#finishShape();\n } else {\n // anchor point\n this.#path = this.#currentPath;\n this.#clearParentPoints(imageSize);\n const pn = {x: index.get(0), y: index.get(1)};\n this.#scissors.doTraining(pn);\n this.#path.addControlPoint(this.#currentPath.getPoint(0));\n }\n }\n }\n\n /**\n * Update tool interaction.\n *\n * @param {Point2D} point The update point.\n * @param {string} divId The layer group divId.\n */\n #update(point, divId) {\n if (!this.#started) {\n return;\n }\n const layerGroup = this.#app.getLayerGroupByDivId(divId);\n const viewLayer = layerGroup.getActiveViewLayer();\n const index = viewLayer.displayToPlaneIndex(point);\n\n // set the point to find the path to\n let p = {x: index.get(0), y: index.get(1)};\n this.#scissors.setPoint(p);\n // do the work\n let results = [];\n let stop = false;\n while (!this.#parentPoints[p.y][p.x] && !stop) {\n results = this.#scissors.doWork();\n\n if (results.length === 0) {\n stop = true;\n } else {\n // fill parents\n for (let i = 0; i < results.length - 1; i += 2) {\n const _p = results[i];\n const _q = results[i + 1];\n this.#parentPoints[_p.y][_p.x] = _q;\n }\n }\n }\n\n // get the path\n this.#currentPath = new Path();\n stop = false;\n while (p && !stop) {\n this.#currentPath.addPoint(new Point2D(p.x, p.y));\n if (!this.#parentPoints[p.y]) {\n stop = true;\n } else {\n if (!this.#parentPoints[p.y][p.x]) {\n stop = true;\n } else {\n p = this.#parentPoints[p.y][p.x];\n }\n }\n }\n this.#currentPath.appenPath(this.#path);\n\n const drawLayer = layerGroup.getActiveDrawLayer();\n const drawController = drawLayer.getDrawController();\n\n const newMathShape = new ROI(this.#currentPath.pointArray);\n\n let command;\n if (typeof this.#annotation === 'undefined') {\n // create annotation\n this.#annotation = new Annotation();\n this.#annotation.colour = this.#style.getLineColour();\n this.#annotation.id = guid();\n\n const viewLayer = layerGroup.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n this.#annotation.init(viewController);\n\n this.#annotation.mathShape = newMathShape;\n command = new AddAnnotationCommand(\n this.#annotation,\n drawController\n );\n } else {\n // update annotation\n const originalMathShape = this.#annotation.mathShape;\n command = new UpdateAnnotationCommand(\n this.#annotation,\n {mathShape: originalMathShape},\n {mathShape: newMathShape},\n drawController\n );\n }\n\n // add command to undo stack\n this.#app.addToUndoStack(command);\n // execute command: triggers draw creation\n command.execute();\n }\n\n /**\n * Finish a livewire (roi) shape.\n */\n #finishShape() {\n // set flag\n this.#started = false;\n }\n\n /**\n * Handle mouse down event.\n *\n * @param {object} event The mouse down event.\n */\n mousedown = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse move event.\n *\n * @param {object} event The mouse move event.\n */\n mousemove = (event) => {\n const mousePoint = getMousePoint(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(mousePoint, layerDetails.groupDivId);\n };\n\n /**\n * Handle mouse up event.\n *\n * @param {object} _event The mouse up event.\n */\n mouseup(_event) {\n // nothing to do\n }\n\n /**\n * Handle mouse out event.\n *\n * @param {object} _event The mouse out event.\n */\n mouseout = (_event) => {\n // nothing to do\n };\n\n /**\n * Handle double click event.\n *\n * @param {object} _event The double click event.\n */\n dblclick = (_event) => {\n this.#finishShape();\n };\n\n /**\n * Handle touch start event.\n *\n * @param {object} event The touch start event.\n */\n touchstart = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#start(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch move event.\n *\n * @param {object} event The touch move event.\n */\n touchmove = (event) => {\n const touchPoints = getTouchPoints(event);\n const layerDetails = getLayerDetailsFromEvent(event);\n this.#update(touchPoints[0], layerDetails.groupDivId);\n };\n\n /**\n * Handle touch end event.\n *\n * @param {object} _event The touch end event.\n */\n touchend = (_event) => {\n // nothing to do\n };\n\n /**\n * Handle key down event.\n *\n * @param {object} event The key down event.\n */\n keydown = (event) => {\n event.context = 'Livewire';\n this.#app.onKeydown(event);\n };\n\n /**\n * Activate the tool.\n *\n * @param {boolean} bool The flag to activate or not.\n */\n activate(bool) {\n // start scissors if displayed\n if (bool) {\n const layerGroup = this.#app.getActiveLayerGroup();\n const viewLayer = layerGroup.getActiveViewLayer();\n\n //scissors = new Scissors();\n const imageSize = viewLayer.getViewController().getImageSize();\n this.#scissors.setDimensions(\n imageSize.get(0),\n imageSize.get(1));\n this.#scissors.setData(viewLayer.getImageData().data);\n\n // init with the app window scale\n this.#style.setBaseScale(this.#app.getBaseScale());\n // set the default to the first in the list\n this.setFeatures({shapeColour: this.#style.getLineColour()});\n }\n }\n\n /**\n * Initialise the tool.\n */\n init() {\n // does nothing\n }\n\n /**\n * Get the list of event names that this tool can fire.\n *\n * @returns {Array} The list of event names.\n */\n getEventNames() {\n return ['drawcreate', 'drawchange', 'drawmove', 'drawdelete'];\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n // #fireEvent = (event) => {\n // this.#listenerHandler.fireEvent(event);\n // };\n\n /**\n * Set the tool live features: shape colour.\n *\n * @param {object} features The list of features.\n */\n setFeatures(features) {\n if (typeof features.shapeColour !== 'undefined') {\n this.#style.setLineColour(features.shapeColour);\n }\n }\n\n} // Livewire class\n","import {\n Line,\n getPerpendicularLine,\n getPerpendicularLineAtDistance\n} from '../math/line';\nimport {Point2D} from '../math/point';\nimport {defaults} from '../app/defaults';\nimport {logger} from '../utils/logger';\nimport {\n getLineShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorShape\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Arrow factory.\n */\nexport class ArrowFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'arrow';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof Point2D;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number} The number of points.\n */\n getNPoints() {\n return 2;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 0;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.referencePoints = [points[1]];\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create a line shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(shape);\n // extras\n const extras = this.#createShapeExtras(annotation, style);\n for (const extra of extras) {\n group.add(extra);\n }\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(label);\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n return group;\n }\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n const centerX = (points[0] + points[2]) / 2 + sx;\n const centerY = (points[1] + points[3]) / 2 + sy;\n return [new Point2D(centerX, centerY)];\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n return [\n new Point2D(points[0] + sx, points[1] + sy),\n new Point2D(points[2] + sx, points[3] + sy)\n ];\n }\n\n /**\n * Get anchors to update a line shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} _anchor The active anchor.\n */\n constrainAnchorMove(_anchor) {\n // no constraints\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kline = this.#getShape(group);\n // find anchors\n const begin = getAnchorShape(group, 0);\n const end = getAnchorShape(group, 1);\n\n // math shape\n // compensate for possible shape drag\n const pointBegin = new Point2D(\n begin.x() - kline.x(),\n begin.y() - kline.y()\n );\n const pointEnd = new Point2D(\n end.x() - kline.x(),\n end.y() - kline.y()\n );\n annotation.mathShape = pointBegin;\n annotation.referencePoints = [pointEnd];\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const point = annotation.mathShape;\n const endPoint = annotation.referencePoints[0];\n const line = new Line(point, endPoint);\n\n const begin = line.getBegin();\n const newBegin = new Point2D(\n begin.getX() + translation.x,\n begin.getY() + translation.y\n );\n const end = line.getEnd();\n const newEnd = new Point2D(\n end.getX() + translation.x,\n end.getY() + translation.y\n );\n annotation.mathShape = newBegin;\n annotation.referencePoints = [newEnd];\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {Point2D} The mathematical shape.\n */\n #calculateMathShape(points) {\n return points[0];\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.arrow;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Line} The konva shape.\n */\n #createShape(annotation, style) {\n const point = annotation.mathShape;\n const endPoint = annotation.referencePoints[0];\n const line = new Line(point, endPoint);\n\n // konva line\n const kshape = new Konva.Line({\n points: [\n point.getX(),\n point.getY(),\n endPoint.getX(),\n endPoint.getY()\n ],\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape'\n });\n\n // larger hitfunc\n const tickLen = 20;\n const linePerp0 = getPerpendicularLine(\n line, point, tickLen, style.getZoomScale());\n const linePerp1 = getPerpendicularLine(\n line, endPoint, tickLen, style.getZoomScale());\n kshape.hitFunc(function (context) {\n context.beginPath();\n context.moveTo(linePerp0.getBegin().getX(), linePerp0.getBegin().getY());\n context.lineTo(linePerp0.getEnd().getX(), linePerp0.getEnd().getY());\n context.lineTo(linePerp1.getEnd().getX(), linePerp1.getEnd().getY());\n context.lineTo(linePerp1.getBegin().getX(), linePerp1.getBegin().getY());\n context.closePath();\n context.fillStrokeShape(kshape);\n });\n\n return kshape;\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Line|undefined} The shape.\n */\n #getShape(group) {\n return getLineShape(group);\n }\n\n /**\n * Creates the konva shape extras.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Array} The konva shape extras.\n */\n #createShapeExtras(annotation, style) {\n const point = annotation.mathShape;\n const endPoint = annotation.referencePoints[0];\n const line = new Line(point, endPoint);\n\n const tickLen = 20;\n // perpendicular line at 2*tickLen\n const perpLine = getPerpendicularLineAtDistance(\n line, 2 * tickLen, tickLen, style.getZoomScale());\n\n // triangle\n const ktriangle = new Konva.Line({\n points: [\n line.getBegin().getX(),\n line.getBegin().getY(),\n perpLine.getBegin().getX(),\n perpLine.getBegin().getY(),\n perpLine.getEnd().getX(),\n perpLine.getEnd().getY(),\n ],\n fill: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n closed: true,\n name: 'shape-triangle'\n });\n\n return [ktriangle];\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const point = annotation.mathShape;\n return point;\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n #updateShape(annotation, anchor, style) {\n const point = annotation.mathShape;\n const endPoint = annotation.referencePoints[0];\n const line = new Line(point, endPoint);\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kline = this.#getShape(group);\n\n // reset position after possible shape drag\n kline.position({x: 0, y: 0});\n // update shape\n kline.points([\n point.getX(),\n point.getY(),\n endPoint.getX(),\n endPoint.getY(),\n ]);\n\n // associated triangle shape\n const ktriangle = group.getChildren(function (node) {\n return node.name() === 'shape-triangle';\n })[0];\n if (!(ktriangle instanceof Konva.Line)) {\n return;\n }\n // find anchors\n const begin = getAnchorShape(group, 0);\n const end = getAnchorShape(group, 1);\n\n // update 'self' (undo case)\n switch (anchor.id()) {\n case 'anchor0':\n begin.x(anchor.x());\n begin.y(anchor.y());\n break;\n case 'anchor1':\n end.x(anchor.x());\n end.y(anchor.y());\n break;\n default:\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n\n const tickLen = 20;\n\n // triangle\n const perpLine = getPerpendicularLineAtDistance(\n line, 2 * tickLen, tickLen, style.getZoomScale());\n ktriangle.position({x: 0, y: 0});\n ktriangle.points([\n line.getBegin().getX(),\n line.getBegin().getY(),\n perpLine.getBegin().getX(),\n perpLine.getBegin().getY(),\n perpLine.getEnd().getX(),\n perpLine.getEnd().getY(),\n ]);\n\n // larger hitfunc\n const linePerp0 = getPerpendicularLine(\n line, point, tickLen, style.getZoomScale());\n const linePerp1 = getPerpendicularLine(\n line, endPoint, tickLen, style.getZoomScale());\n kline.hitFunc(function (context) {\n context.beginPath();\n context.moveTo(linePerp0.getBegin().getX(), linePerp0.getBegin().getY());\n context.lineTo(linePerp0.getEnd().getX(), linePerp0.getEnd().getY());\n context.lineTo(linePerp1.getEnd().getX(), linePerp1.getEnd().getY());\n context.lineTo(linePerp1.getBegin().getX(), linePerp1.getBegin().getY());\n context.closePath();\n context.fillStrokeShape(kline);\n });\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} [_group] The associated group.\n * @returns {Konva.Group|undefined} The shadow konva group.\n */\n #getDebugShadow(_annotation, _group) {\n return;\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} _group The associated group.\n */\n #updateDebugShadow(_annotation, _group) {\n // does nothing\n }\n\n} // class ArrowFactory\n","import {Circle} from '../math/circle';\nimport {Point2D} from '../math/point';\nimport {logger} from '../utils/logger';\nimport {defaults} from '../app/defaults';\nimport {\n isNodeNameShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorShape\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Circle factory.\n */\nexport class CircleFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'circle';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof Circle;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number} The number of points.\n */\n getNPoints() {\n return 2;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 0;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create a circle shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(this.#createShape(annotation, style));\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(this.#labelFactory.create(annotation, style));\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n return group;\n }\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Circle} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const centerX = shape.x();\n const centerY = shape.y();\n const radius = shape.radius() * Math.sqrt(2) / 2;\n return [\n new Point2D(centerX - radius, centerY - radius),\n new Point2D(centerX + radius, centerY - radius),\n new Point2D(centerX - radius, centerY + radius),\n new Point2D(centerX + radius, centerY + radius),\n ];\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Circle} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const centerX = shape.x();\n const centerY = shape.y();\n const radius = shape.radius();\n return [\n new Point2D(centerX - radius, centerY),\n new Point2D(centerX + radius, centerY),\n new Point2D(centerX, centerY + radius),\n new Point2D(centerX, centerY - radius),\n ];\n }\n\n /**\n * Get anchors to update a circle shape.\n *\n * @param {Konva.Circle} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} anchor The active anchor.\n */\n constrainAnchorMove(anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // find special points\n const left = getAnchorShape(group, 0);\n const right = getAnchorShape(group, 1);\n const bottom = getAnchorShape(group, 2);\n const top = getAnchorShape(group, 3);\n\n // update 'self' (undo case) and special points\n switch (anchor.id()) {\n case 'anchor0':\n // block y\n left.y(right.y());\n break;\n case 'anchor1':\n // block y\n right.y(left.y());\n break;\n case 'anchor2':\n // block x\n bottom.x(top.x());\n break;\n case 'anchor3':\n // block x\n top.x(bottom.x());\n break;\n default :\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // math shape\n const circle = annotation.mathShape;\n const center = new Point2D(\n circle.getCenter().getX(),\n circle.getCenter().getY()\n );\n const anchorPoint = new Point2D(anchor.x(), anchor.y());\n const newRadius = center.getDistance(anchorPoint);\n annotation.mathShape = new Circle(center, newRadius);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const circle = annotation.mathShape;\n const center = circle.getCenter();\n const newCenter = new Point2D(\n center.getX() + translation.x,\n center.getY() + translation.y\n );\n annotation.mathShape = new Circle(newCenter, circle.getRadius());\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {Circle} The mathematical shape.\n */\n #calculateMathShape(points) {\n // calculate radius\n const a = Math.abs(points[0].getX() - points[1].getX());\n const b = Math.abs(points[0].getY() - points[1].getY());\n const radius = Math.round(Math.sqrt(a * a + b * b));\n // physical shape\n return new Circle(points[0], radius);\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.circle;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Circle} The konva shape.\n */\n #createShape(annotation, style) {\n const circle = annotation.mathShape;\n // konva circle\n return new Konva.Circle({\n x: circle.getCenter().getX(),\n y: circle.getCenter().getY(),\n radius: circle.getRadius(),\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape'\n });\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Circle|undefined} The shape.\n */\n #getShape(group) {\n const kshape = group.getChildren(isNodeNameShape)[0];\n if (!(kshape instanceof Konva.Circle)) {\n return;\n }\n return kshape;\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const circle = annotation.mathShape;\n const center = circle.getCenter();\n const radius = circle.getRadius();\n return new Point2D(\n center.getX() - radius,\n center.getY() + radius,\n );\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} _style The application style.\n */\n #updateShape(annotation, anchor, _style) {\n const circle = annotation.mathShape;\n const center = circle.getCenter();\n const radius = circle.getRadius();\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kcircle = this.#getShape(group);\n // update shape: just update the radius\n kcircle.radius(radius);\n\n // find anchors\n const left = getAnchorShape(group, 0);\n const right = getAnchorShape(group, 1);\n const bottom = getAnchorShape(group, 2);\n const top = getAnchorShape(group, 3);\n\n const swapX = right.x() < left.x() ? -1 : 1;\n const swapY = top.y() < bottom.y() ? 1 : -1;\n\n // update 'self' (undo case) and other anchors\n switch (anchor.id()) {\n case 'anchor0':\n // update self\n left.x(anchor.x());\n // update others\n right.x(center.getX() + swapX * radius);\n bottom.y(center.getY() + radius);\n top.y(center.getY() - radius);\n break;\n case 'anchor1':\n // update self\n right.x(anchor.x());\n // update others\n left.x(center.getX() - swapX * radius);\n bottom.y(center.getY() + radius);\n top.y(center.getY() - radius);\n break;\n case 'anchor2':\n // update self\n bottom.y(anchor.y());\n // update others\n left.x(center.getX() - radius);\n right.x(center.getX() + radius);\n top.y(center.getY() - swapY * radius);\n break;\n case 'anchor3':\n // update self\n top.y(anchor.y());\n // update others\n left.x(center.getX() - radius);\n right.x(center.getX() + radius);\n bottom.y(center.getY() + swapY * radius);\n break;\n default :\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} annotation The annotation to shadow.\n * @param {Konva.Group} [group] The associated group.\n * @returns {Konva.Group|undefined} The shadow konva group.\n */\n #getDebugShadow(annotation, group) {\n const circle = annotation.mathShape;\n\n // possible group offset\n let offsetX = 0;\n let offsetY = 0;\n if (typeof group !== 'undefined') {\n offsetX = group.x();\n offsetY = group.y();\n }\n const kshadow = new Konva.Group();\n kshadow.name('shadow');\n const regions = circle.getRound();\n for (let i = 0; i < regions.length; ++i) {\n const region = regions[i];\n const minX = region[0][0];\n const minY = region[0][1];\n const maxX = region[1][0];\n const pixelLine = new Konva.Rect({\n x: minX - offsetX,\n y: minY - offsetY,\n width: maxX - minX,\n height: 1,\n fill: 'grey',\n strokeWidth: 0,\n strokeScaleEnabled: false,\n opacity: 0.3,\n name: 'shadow-element'\n });\n kshadow.add(pixelLine);\n }\n return kshadow;\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} annotation The annotation to shadow.\n * @param {Konva.Group} group The associated group.\n */\n #updateDebugShadow(annotation, group) {\n const kshadow = group.getChildren(function (node) {\n return node.name() === 'shadow';\n })[0];\n if (typeof kshadow !== 'undefined') {\n // remove previous\n kshadow.destroy();\n // add new\n group.add(this.#getDebugShadow(annotation, group));\n }\n }\n\n} // class CircleFactory\n","import {Ellipse} from '../math/ellipse';\nimport {Point2D} from '../math/point';\nimport {logger} from '../utils/logger';\nimport {defaults} from '../app/defaults';\nimport {\n isNodeNameShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorShape\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Ellipse factory.\n */\nexport class EllipseFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'ellipse';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof Ellipse;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number} The number of points.\n */\n getNPoints() {\n return 2;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 0;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create an ellipse shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(this.#createShape(annotation, style));\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(this.#labelFactory.create(annotation, style));\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n return group;\n }\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Ellipse} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const centerX = shape.x();\n const centerY = shape.y();\n const radiusX = shape.radiusX() * Math.sqrt(2) / 2;\n const radiusY = shape.radiusY() * Math.sqrt(2) / 2;\n return [\n new Point2D(centerX - radiusX, centerY - radiusY),\n new Point2D(centerX + radiusX, centerY - radiusY),\n new Point2D(centerX - radiusX, centerY + radiusY),\n new Point2D(centerX + radiusX, centerY + radiusY),\n ];\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Ellipse} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const centerX = shape.x();\n const centerY = shape.y();\n const radius = shape.radius();\n return [\n new Point2D(centerX - radius.x, centerY),\n new Point2D(centerX + radius.x, centerY),\n new Point2D(centerX, centerY + radius.y),\n new Point2D(centerX, centerY - radius.y),\n ];\n }\n\n /**\n * Get anchors to update a ellipse shape.\n *\n * @param {Konva.Ellipse} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} anchor The active anchor.\n */\n constrainAnchorMove(anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // find special points\n const left = getAnchorShape(group, 0);\n const right = getAnchorShape(group, 1);\n const bottom = getAnchorShape(group, 2);\n const top = getAnchorShape(group, 3);\n\n // update 'self' (undo case) and special points\n switch (anchor.id()) {\n case 'anchor0':\n // block y\n left.y(right.y());\n break;\n case 'anchor1':\n // block y\n right.y(left.y());\n break;\n case 'anchor2':\n // block x\n bottom.x(top.x());\n break;\n case 'anchor3':\n // block x\n top.x(bottom.x());\n break;\n default :\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // math shape\n const ellipse = annotation.mathShape;\n const center = ellipse.getCenter();\n let radiusX = ellipse.getA();\n let radiusY = ellipse.getB();\n\n // update 'self' (undo case) and special points\n switch (anchor.id()) {\n case 'anchor0':\n radiusX = center.getX() - anchor.x();\n break;\n case 'anchor1':\n radiusX = anchor.x() - center.getX();\n break;\n case 'anchor2':\n radiusY = anchor.y() - center.getY();\n break;\n case 'anchor3':\n radiusY = center.getY() - anchor.y();\n break;\n default :\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n\n annotation.mathShape = new Ellipse(\n center, Math.abs(radiusX), Math.abs(radiusY));\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const ellipse = annotation.mathShape;\n const center = ellipse.getCenter();\n const newCenter = new Point2D(\n center.getX() + translation.x,\n center.getY() + translation.y\n );\n annotation.mathShape = new Ellipse(\n newCenter, ellipse.getA(), ellipse.getB());\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {Ellipse} The mathematical shape.\n */\n #calculateMathShape(points) {\n // calculate radius\n const a = Math.abs(points[0].getX() - points[1].getX());\n const b = Math.abs(points[0].getY() - points[1].getY());\n // physical shape\n return new Ellipse(points[0], a, b);\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.ellipse;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Ellipse} The konva shape.\n */\n #createShape(annotation, style) {\n const ellipse = annotation.mathShape;\n const center = ellipse.getCenter();\n const radius = {\n x: ellipse.getA(),\n y: ellipse.getB()\n };\n // konva circle\n return new Konva.Ellipse({\n x: center.getX(),\n y: center.getY(),\n radius: radius,\n radiusX: radius.x,\n radiusY: radius.y,\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape'\n });\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Ellipse|undefined} The shape.\n */\n #getShape(group) {\n const kshape = group.getChildren(isNodeNameShape)[0];\n if (!(kshape instanceof Konva.Ellipse)) {\n return;\n }\n return kshape;\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const ellipse = annotation.mathShape;\n const center = ellipse.getCenter();\n return new Point2D(\n center.getX() - ellipse.getA(),\n center.getY() + ellipse.getB()\n );\n }\n\n /**\n * Update shape on anchor move.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} _style The application style.\n */\n #updateShape(annotation, anchor, _style) {\n const ellipse = annotation.mathShape;\n const center = ellipse.getCenter();\n const radiusX = ellipse.getA();\n const radiusY = ellipse.getB();\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kellipse = this.#getShape(group);\n // update shape: just update radius\n kellipse.radius({\n x: radiusX,\n y: radiusY\n });\n\n // find anchors\n const left = getAnchorShape(group, 0);\n const right = getAnchorShape(group, 1);\n const bottom = getAnchorShape(group, 2);\n const top = getAnchorShape(group, 3);\n\n const swapX = right.x() < left.x() ? -1 : 1;\n const swapY = top.y() < bottom.y() ? 1 : -1;\n\n // update 'self' (undo case) and other anchors\n switch (anchor.id()) {\n case 'anchor0':\n // update self\n left.x(anchor.x());\n // update others\n right.x(center.getX() + swapX * radiusX);\n bottom.y(center.getY() + radiusY);\n top.y(center.getY() - radiusY);\n break;\n case 'anchor1':\n // update self\n right.x(anchor.x());\n // update others\n left.x(center.getX() - swapX * radiusX);\n bottom.y(center.getY() + radiusY);\n top.y(center.getY() - radiusY);\n break;\n case 'anchor2':\n // update self\n bottom.y(anchor.y());\n // update others\n left.x(center.getX() - radiusX);\n right.x(center.getX() + radiusX);\n top.y(center.getY() - swapY * radiusY);\n break;\n case 'anchor3':\n // update self\n top.y(anchor.y());\n // update others\n left.x(center.getX() - radiusX);\n right.x(center.getX() + radiusX);\n bottom.y(center.getY() + swapY * radiusY);\n break;\n default :\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} annotation The annotation to shadow.\n * @param {Konva.Group} [group] The associated group.\n * @returns {Konva.Group|undefined} The shadow konva group.\n */\n #getDebugShadow(annotation, group) {\n const ellipse = annotation.mathShape;\n\n // possible group offset\n let offsetX = 0;\n let offsetY = 0;\n if (typeof group !== 'undefined') {\n offsetX = group.x();\n offsetY = group.y();\n }\n const kshadow = new Konva.Group();\n kshadow.name('shadow');\n const regions = ellipse.getRound();\n for (let i = 0; i < regions.length; ++i) {\n const region = regions[i];\n const minX = region[0][0];\n const minY = region[0][1];\n const maxX = region[1][0];\n const pixelLine = new Konva.Rect({\n x: minX - offsetX,\n y: minY - offsetY,\n width: maxX - minX,\n height: 1,\n fill: 'grey',\n strokeWidth: 0,\n strokeScaleEnabled: false,\n opacity: 0.3,\n name: 'shadow-element'\n });\n kshadow.add(pixelLine);\n }\n return kshadow;\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} annotation The annotation to shadow.\n * @param {Konva.Group} group The associated group.\n */\n #updateDebugShadow(annotation, group) {\n const kshadow = group.getChildren(function (node) {\n return node.name() === 'shadow';\n })[0];\n if (typeof kshadow !== 'undefined') {\n // remove previous\n kshadow.destroy();\n // add new\n group.add(this.#getDebugShadow(annotation, group));\n }\n }\n\n} // class EllipseFactory\n","import {Line, getAngle} from '../math/line';\nimport {Protractor} from '../math/protractor';\nimport {Point2D} from '../math/point';\nimport {defaults} from '../app/defaults';\nimport {\n getLineShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorShape\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Protractor factory.\n */\nexport class ProtractorFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'protractor';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof Protractor;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number} The number of points.\n */\n getNPoints() {\n return 3;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 500;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create a line shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n const protractor = annotation.mathShape;\n\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(this.#createShape(annotation, style));\n\n if (protractor.getLength() === this.getNPoints()) {\n // extras\n const extras = this.#createShapeExtras(annotation, style);\n for (const extra of extras) {\n group.add(extra);\n }\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(this.#labelFactory.create(annotation, style));\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n }\n return group;\n }\n\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n return [\n new Point2D(points[2] + sx, points[3] + sy)\n ];\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n return [\n new Point2D(points[0] + sx, points[1] + sy),\n new Point2D(points[2] + sx, points[3] + sy),\n new Point2D(points[4] + sx, points[5] + sy)\n ];\n }\n\n /**\n * Get anchors to update a line shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} _anchor The active anchor.\n */\n constrainAnchorMove(_anchor) {\n // no constraints\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kline = this.#getShape(group);\n // find special points\n const begin = getAnchorShape(group, 0);\n const mid = getAnchorShape(group, 1);\n const end = getAnchorShape(group, 2);\n\n // math shape\n // compensate for possible shape drag\n const pointBegin = new Point2D(\n begin.x() - kline.x(),\n begin.y() - kline.y()\n );\n const pointMid = new Point2D(\n mid.x() - kline.x(),\n mid.y() - kline.y()\n );\n const pointEnd = new Point2D(\n end.x() - kline.x(),\n end.y() - kline.y()\n );\n annotation.mathShape = new Protractor([pointBegin, pointMid, pointEnd]);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const protractor = annotation.mathShape;\n const newPointList = [];\n for (let i = 0; i < 3; ++i) {\n newPointList.push(new Point2D(\n protractor.getPoint(i).getX() + translation.x,\n protractor.getPoint(i).getY() + translation.y\n ));\n }\n annotation.mathShape = new Protractor(newPointList);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {Protractor} The mathematical shape.\n */\n #calculateMathShape(points) {\n return new Protractor(points);\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.protractor;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Line} The konva shape.\n */\n #createShape(annotation, style) {\n const protractor = annotation.mathShape;\n const points = [];\n for (let i = 0; i < protractor.getLength(); ++i) {\n points.push(protractor.getPoint(i).getX());\n points.push(protractor.getPoint(i).getY());\n }\n\n // konva line\n const kshape = new Konva.Line({\n points: points,\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape'\n });\n\n if (protractor.getLength() === this.getNPoints()) {\n // larger hitfunc\n kshape.hitFunc(function (context) {\n context.beginPath();\n context.moveTo(\n protractor.getPoint(0).getX(), protractor.getPoint(0).getY());\n context.lineTo(\n protractor.getPoint(1).getX(), protractor.getPoint(1).getY());\n context.lineTo(\n protractor.getPoint(2).getX(), protractor.getPoint(2).getY());\n context.closePath();\n context.fillStrokeShape(kshape);\n });\n }\n\n return kshape;\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Line|undefined} The shape.\n */\n #getShape(group) {\n return getLineShape(group);\n }\n\n /**\n * Creates the konva shape extras.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Array} The konva shape extras.\n */\n #createShapeExtras(annotation, style) {\n const protractor = annotation.mathShape;\n const line0 = new Line(\n protractor.getPoint(0), protractor.getPoint(1));\n const line1 = new Line(\n protractor.getPoint(1), protractor.getPoint(2));\n\n let angle = getAngle(line0, line1);\n let inclination = line0.getInclination();\n if (angle > 180) {\n angle = 360 - angle;\n inclination += angle;\n }\n\n const radius = Math.min(line0.getLength(), line1.getLength()) * 33 / 100;\n const karc = new Konva.Arc({\n innerRadius: radius,\n outerRadius: radius,\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n angle: angle,\n rotation: -inclination,\n x: protractor.getPoint(1).getX(),\n y: protractor.getPoint(1).getY(),\n name: 'shape-arc'\n });\n\n return [karc];\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const protractor = annotation.mathShape;\n const line0 = new Line(\n protractor.getPoint(0), protractor.getPoint(1));\n const line1 = new Line(\n protractor.getPoint(1), protractor.getPoint(2));\n\n const midX =\n (line0.getMidpoint().getX() + line1.getMidpoint().getX()) / 2;\n const midY =\n (line0.getMidpoint().getY() + line1.getMidpoint().getY()) / 2;\n\n return new Point2D(\n midX,\n midY\n );\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} _style The application style.\n */\n #updateShape(annotation, anchor, _style) {\n const protractor = annotation.mathShape;\n const line0 = new Line(\n protractor.getPoint(0), protractor.getPoint(1));\n const line1 = new Line(\n protractor.getPoint(1), protractor.getPoint(2));\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kline = this.#getShape(group);\n\n // reset position after possible shape drag\n kline.position({x: 0, y: 0});\n // update shape\n kline.points([\n protractor.getPoint(0).getX(),\n protractor.getPoint(0).getY(),\n protractor.getPoint(1).getX(),\n protractor.getPoint(1).getY(),\n protractor.getPoint(2).getX(),\n protractor.getPoint(2).getY()\n ]);\n\n // associated arc\n const karc = group.getChildren(function (node) {\n return node.name() === 'shape-arc';\n })[0];\n if (!(karc instanceof Konva.Arc)) {\n return;\n }\n\n // find special points\n const begin = getAnchorShape(group, 0);\n const mid = getAnchorShape(group, 1);\n const end = getAnchorShape(group, 2);\n\n // update special points\n switch (anchor.id()) {\n case 'anchor0':\n begin.x(anchor.x());\n begin.y(anchor.y());\n break;\n case 'anchor1':\n mid.x(anchor.x());\n mid.y(anchor.y());\n break;\n case 'anchor2':\n end.x(anchor.x());\n end.y(anchor.y());\n break;\n }\n\n // angle\n let angle = getAngle(line0, line1);\n let inclination = line0.getInclination();\n if (angle > 180) {\n angle = 360 - angle;\n inclination += angle;\n }\n\n // arc\n const radius = Math.min(line0.getLength(), line1.getLength()) * 33 / 100;\n karc.innerRadius(radius);\n karc.outerRadius(radius);\n karc.angle(angle);\n karc.rotation(-inclination);\n const arcPos = {x: mid.x(), y: mid.y()};\n karc.position(arcPos);\n\n // larger hitfunc\n kline.hitFunc(function (context) {\n context.beginPath();\n context.moveTo(\n protractor.getPoint(0).getX(), protractor.getPoint(0).getY());\n context.lineTo(\n protractor.getPoint(1).getX(), protractor.getPoint(1).getY());\n context.lineTo(\n protractor.getPoint(2).getX(), protractor.getPoint(2).getY());\n context.closePath();\n context.fillStrokeShape(kline);\n });\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} [_group] The associated group.\n * @returns {Konva.Group|undefined} The shadow konva group.\n */\n #getDebugShadow(_annotation, _group) {\n return;\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} _group The associated group.\n */\n #updateDebugShadow(_annotation, _group) {\n // does nothing\n }\n\n} // class ProtractorFactory\n","import {Rectangle} from '../math/rectangle';\nimport {Point2D} from '../math/point';\nimport {logger} from '../utils/logger';\nimport {defaults} from '../app/defaults';\nimport {\n isNodeNameShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorShape\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Rectangle factory.\n */\nexport class RectangleFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'rectangle';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof Rectangle;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number} The number of points.\n */\n getNPoints() {\n return 2;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 0;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create a rectangle shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(shape);\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(label);\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n return group;\n }\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Rect} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const sx = shape.x();\n const sy = shape.y();\n const width = shape.width();\n const height = shape.height();\n return [\n new Point2D(sx + width / 2, sy),\n new Point2D(sx, sy + height / 2),\n new Point2D(sx + width / 2, sy + height),\n new Point2D(sx + width, sy + height / 2),\n ];\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Rect} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const sx = shape.x();\n const sy = shape.y();\n const width = shape.width();\n const height = shape.height();\n return [\n new Point2D(sx, sy),\n new Point2D(sx + width, sy),\n new Point2D(sx + width, sy + height),\n new Point2D(sx, sy + height),\n ];\n }\n\n /**\n * Get anchors to update a rectangle shape.\n *\n * @param {Konva.Rect} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} _anchor The active anchor.\n */\n constrainAnchorMove(_anchor) {\n // no constraints\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // find anchors\n const topLeft = getAnchorShape(group, 0);\n const bottomRight = getAnchorShape(group, 2);\n\n const pointTopLeft = new Point2D(\n topLeft.x(),\n topLeft.y()\n );\n const pointBottomRight = new Point2D(\n bottomRight.x(),\n bottomRight.y()\n );\n // new rect\n annotation.mathShape = new Rectangle(pointTopLeft, pointBottomRight);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const rectangle = annotation.mathShape;\n const begin = rectangle.getBegin();\n const newBegin = new Point2D(\n begin.getX() + translation.x,\n begin.getY() + translation.y\n );\n const end = rectangle.getEnd();\n const newEnd = new Point2D(\n end.getX() + translation.x,\n end.getY() + translation.y\n );\n annotation.mathShape = new Rectangle(newBegin, newEnd);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label content.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {Rectangle} The mathematical shape.\n */\n #calculateMathShape(points) {\n return new Rectangle(points[0], points[1]);\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.rectangle;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Rect} The konva shape.\n */\n #createShape(annotation, style) {\n const rectangle = annotation.mathShape;\n // konva rect\n return new Konva.Rect({\n x: rectangle.getBegin().getX(),\n y: rectangle.getBegin().getY(),\n width: rectangle.getWidth(),\n height: rectangle.getHeight(),\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape'\n });\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Rect|undefined} The shape.\n */\n #getShape(group) {\n const kshape = group.getChildren(isNodeNameShape)[0];\n if (!(kshape instanceof Konva.Rect)) {\n return;\n }\n return kshape;\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const rectangle = annotation.mathShape;\n return new Point2D(\n rectangle.getBegin().getX(),\n rectangle.getEnd().getY(),\n );\n }\n\n /**\n * Update shape on anchor move.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} _style The application style.\n */\n #updateShape(annotation, anchor, _style) {\n const rectangle = annotation.mathShape;\n const begin = rectangle.getBegin();\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const krect = this.#getShape(group);\n // update shape\n krect.position({\n x: begin.getX(),\n y: begin.getY()\n });\n krect.size({\n width: rectangle.getWidth(),\n height: rectangle.getHeight()\n });\n\n // find anchors\n const topLeft = getAnchorShape(group, 0);\n const topRight = getAnchorShape(group, 1);\n const bottomRight = getAnchorShape(group, 2);\n const bottomLeft = getAnchorShape(group, 3);\n\n // update 'self' (undo case) and other anchors\n switch (anchor.id()) {\n case 'anchor0':\n // update self\n topLeft.x(anchor.x());\n topLeft.y(anchor.y());\n // update others\n topRight.y(anchor.y());\n bottomLeft.x(anchor.x());\n break;\n case 'anchor1':\n // update self\n topRight.x(anchor.x());\n topRight.y(anchor.y());\n // update others\n topLeft.y(anchor.y());\n bottomRight.x(anchor.x());\n break;\n case 'anchor2':\n // update self\n bottomRight.x(anchor.x());\n bottomRight.y(anchor.y());\n // update others\n bottomLeft.y(anchor.y());\n topRight.x(anchor.x());\n break;\n case 'anchor3':\n // update self\n bottomLeft.x(anchor.x());\n bottomLeft.y(anchor.y());\n // update others\n bottomRight.y(anchor.y());\n topLeft.x(anchor.x());\n break;\n default :\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} annotation The anootation to shadow.\n * @param {Konva.Group} [_group] The associated group.\n * @returns {Konva.Rect} The shadow konva rect.\n */\n #getDebugShadow(annotation, _group) {\n const rectangle = annotation.mathShape;\n const round = rectangle.getRound();\n const rWidth = round.max.getX() - round.min.getX();\n const rHeight = round.max.getY() - round.min.getY();\n return new Konva.Rect({\n x: round.min.getX(),\n y: round.min.getY(),\n width: rWidth,\n height: rHeight,\n fill: 'grey',\n strokeWidth: 0,\n strokeScaleEnabled: false,\n opacity: 0.3,\n name: 'shadow'\n });\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} annotation The annotation to shadow.\n * @param {Konva.Group} group The associated group.\n */\n #updateDebugShadow(annotation, group) {\n const kshadow = group.getChildren(function (node) {\n return node.name() === 'shadow';\n })[0];\n if (typeof kshadow !== 'undefined') {\n // remove previous\n kshadow.destroy();\n // add new\n group.add(this.#getDebugShadow(annotation, group));\n }\n }\n\n} // class RectangleFactory\n","import {ROI} from '../math/roi';\nimport {Point2D} from '../math/point';\nimport {defaults} from '../app/defaults';\nimport {\n getLineShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorIndex\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * ROI factory.\n */\nexport class RoiFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'roi';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof ROI;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number|undefined} The number of points.\n */\n getNPoints() {\n // undefined to end with double click\n return undefined;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 100;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create a roi shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(this.#createShape(annotation, style));\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(this.#labelFactory.create(annotation, style));\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n return group;\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n const positions = [];\n for (let i = 0; i < points.length; i = i + 2) {\n positions.push(new Point2D(\n points[i] + sx,\n points[i + 1] + sy\n ));\n }\n return positions;\n }\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n const positions = [];\n for (let i = 0; i < points.length; i += 2) {\n const nextIndex = (i + 2) % points.length;\n const midX = (points[i] + points[nextIndex]) / 2 + sx;\n const midY = (points[i + 1] + points[nextIndex + 1]) / 2 + sy;\n positions.push(new Point2D(midX, midY));\n }\n return positions;\n }\n\n /**\n * Get anchors to update a roi shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} _anchor The active anchor.\n */\n constrainAnchorMove(_anchor) {\n // no constraints\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kroi = this.#getShape(group);\n\n // update the roi point and compensate for possible drag\n // (the anchor id is the index of the point in the main list)\n const roi = annotation.mathShape;\n const points = roi.getPoints().slice();\n const newPoint = new Point2D(\n anchor.x() - kroi.x(),\n anchor.y() - kroi.y()\n );\n const index = getAnchorIndex(anchor.id());\n points[index] = newPoint;\n\n // new math shape\n annotation.mathShape = new ROI(points);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const roi = annotation.mathShape;\n const newPoints = [];\n for (let i = 0; i < roi.getLength(); ++i) {\n newPoints.push(new Point2D(\n roi.getPoint(i).getX() + translation.x,\n roi.getPoint(i).getY() + translation.y\n ));\n }\n annotation.mathShape = new ROI(newPoints);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {ROI} The mathematical shape.\n */\n #calculateMathShape(points) {\n return new ROI(points);\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.roi;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Line} The konva shape.\n */\n #createShape(annotation, style) {\n const roi = annotation.mathShape;\n // konva line\n const arr = [];\n for (let i = 0; i < roi.getLength(); ++i) {\n arr.push(roi.getPoint(i).getX());\n arr.push(roi.getPoint(i).getY());\n }\n return new Konva.Line({\n points: arr,\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape',\n closed: true\n });\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Line|undefined} The shape.\n */\n #getShape(group) {\n return getLineShape(group);\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const roi = annotation.mathShape;\n return new Point2D(\n roi.getPoint(0).getX(),\n roi.getPoint(0).getY()\n );\n }\n\n /**\n * Update shape on anchor move.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} _style The application style.\n */\n #updateShape(annotation, anchor, _style) {\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kroi = this.#getShape(group);\n // update the roi point and compensate for possible drag\n // (the anchor id is the index of the point in the main list)\n const points = kroi.points();\n const index = getAnchorIndex(anchor.id()) * 2;\n points[index] = anchor.x() - kroi.x();\n points[index + 1] = anchor.y() - kroi.y();\n kroi.points(points);\n\n // update self\n const point = group.getChildren(function (node) {\n return node.id() === anchor.id();\n })[0];\n\n point.x(anchor.x());\n point.y(anchor.y());\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} _annotation The anootation to shadow.\n * @param {Konva.Group} [_group] The associated group.\n * @returns {Konva.Line} The shadow konva line.\n */\n #getDebugShadow(_annotation, _group) {\n // does nothing\n return undefined;\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} _group The associated group.\n */\n #updateDebugShadow(_annotation, _group) {\n // does nothing\n }\n\n} // class RoiFactory\n","import {Line, getPerpendicularLine} from '../math/line';\nimport {Point2D} from '../math/point';\nimport {logger} from '../utils/logger';\nimport {defaults} from '../app/defaults';\nimport {\n getLineShape,\n DRAW_DEBUG,\n getDefaultAnchor,\n getAnchorShape\n} from './drawBounds';\nimport {LabelFactory} from './labelFactory';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * Ruler factory.\n */\nexport class RulerFactory {\n\n /**\n * The name of the factory.\n *\n * @type {string}\n */\n #name = 'ruler';\n\n /**\n * The associated label factory.\n *\n * @type {LabelFactory}\n */\n #labelFactory = new LabelFactory(this.#getDefaultLabelPosition);\n\n /**\n * Does this factory support the input math shape.\n *\n * @param {object} mathShape The mathematical shape.\n * @returns {boolean} True if supported.\n */\n static supports(mathShape) {\n return mathShape instanceof Line;\n }\n\n /**\n * Get the name of the factory.\n *\n * @returns {string} The name.\n */\n getName() {\n return this.#name;\n }\n\n /**\n * Get the name of the shape group.\n *\n * @returns {string} The name.\n */\n getGroupName() {\n return this.#name + '-group';\n }\n\n /**\n * Get the number of points needed to build the shape.\n *\n * @returns {number} The number of points.\n */\n getNPoints() {\n return 2;\n }\n\n /**\n * Get the timeout between point storage.\n *\n * @returns {number} The timeout in milliseconds.\n */\n getTimeout() {\n return 0;\n }\n\n /**\n * Set an annotation math shape from input points.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Point2D[]} points The points.\n */\n setAnnotationMathShape(annotation, points) {\n annotation.mathShape = this.#calculateMathShape(points);\n annotation.setTextExpr(this.#getDefaultLabel());\n annotation.updateQuantification();\n }\n\n /**\n * Create a line shape to be displayed.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Group} The Konva group.\n */\n createShapeGroup(annotation, style) {\n // konva group\n const group = new Konva.Group();\n group.name(this.getGroupName());\n group.visible(true);\n group.id(annotation.id);\n // konva shape\n const shape = this.#createShape(annotation, style);\n group.add(this.#createShape(annotation, style));\n // extras\n const extras = this.#createShapeExtras(annotation, style);\n for (const extra of extras) {\n group.add(extra);\n }\n // konva label\n const label = this.#labelFactory.create(annotation, style);\n group.add(this.#labelFactory.create(annotation, style));\n // label-shape connector\n const connectorsPos = this.#getConnectorsPositions(shape);\n group.add(this.#labelFactory.getConnector(connectorsPos, label, style));\n // konva shadow (if debug)\n if (DRAW_DEBUG) {\n group.add(this.#getDebugShadow(annotation));\n }\n return group;\n }\n\n /**\n * Get the connectors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The connectors positions.\n */\n #getConnectorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n const centerX = (points[0] + points[2]) / 2 + sx;\n const centerY = (points[1] + points[3]) / 2 + sy;\n return [new Point2D(centerX, centerY)];\n }\n\n /**\n * Get the anchors positions for the shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @returns {Point2D[]} The anchor positions.\n */\n #getAnchorsPositions(shape) {\n const points = shape.points();\n const sx = shape.x();\n const sy = shape.y();\n return [\n new Point2D(points[0] + sx, points[1] + sy),\n new Point2D(points[2] + sx, points[3] + sy)\n ];\n }\n\n /**\n * Get anchors to update a line shape.\n *\n * @param {Konva.Line} shape The associated shape.\n * @param {Style} style The application style.\n * @returns {Konva.Ellipse[]} A list of anchors.\n */\n getAnchors(shape, style) {\n const positions = this.#getAnchorsPositions(shape);\n const anchors = [];\n for (let i = 0; i < positions.length; ++i) {\n anchors.push(getDefaultAnchor(\n positions[i].getX(),\n positions[i].getY(),\n 'anchor' + i,\n style\n ));\n }\n return anchors;\n }\n\n /**\n * Constrain anchor movement.\n *\n * @param {Konva.Ellipse} _anchor The active anchor.\n */\n constrainAnchorMove(_anchor) {\n // no constraints\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n updateShapeGroupOnAnchorMove(annotation, anchor, style) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n\n // update shape and anchors\n this.#updateShape(annotation, anchor, style);\n // update label\n this.updateLabelContent(annotation, group, style);\n // label position\n if (typeof annotation.labelPosition === 'undefined') {\n // update label position if default position\n this.#labelFactory.updatePosition(annotation, group);\n } else {\n // update connector if not default position\n this.updateConnector(group);\n }\n // update shadow\n if (DRAW_DEBUG) {\n this.#updateDebugShadow(annotation, group);\n }\n }\n\n /**\n * Update an annotation on anchor move.\n *\n * @param {Annotation} annotation The annotation.\n * @param {Konva.Shape} anchor The anchor.\n */\n updateAnnotationOnAnchorMove(annotation, anchor) {\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kline = this.#getShape(group);\n // find anchors\n const begin = getAnchorShape(group, 0);\n const end = getAnchorShape(group, 1);\n\n // math shape\n // compensate for possible shape drag\n const pointBegin = new Point2D(\n begin.x() - kline.x(),\n begin.y() - kline.y()\n );\n const pointEnd = new Point2D(\n end.x() - kline.x(),\n end.y() - kline.y()\n );\n annotation.mathShape = new Line(pointBegin, pointEnd);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update an annotation on translation (shape move).\n *\n * @param {Annotation} annotation The annotation.\n * @param {object} translation The translation.\n */\n updateAnnotationOnTranslation(annotation, translation) {\n // math shape\n const line = annotation.mathShape;\n const begin = line.getBegin();\n const newBegin = new Point2D(\n begin.getX() + translation.x,\n begin.getY() + translation.y\n );\n const end = line.getEnd();\n const newEnd = new Point2D(\n end.getX() + translation.x,\n end.getY() + translation.y\n );\n annotation.mathShape = new Line(newBegin, newEnd);\n // quantification\n annotation.updateQuantification();\n }\n\n /**\n * Update the shape label.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Group} group The shape group.\n * @param {Style} _style The application style.\n */\n updateLabelContent(annotation, group, _style) {\n this.#labelFactory.updateContent(annotation, group);\n }\n\n /**\n * Update the shape connector.\n *\n * @param {Konva.Group} group The shape group.\n */\n updateConnector(group) {\n const kshape = this.#getShape(group);\n const connectorsPos = this.#getConnectorsPositions(kshape);\n this.#labelFactory.updateConnector(group, connectorsPos);\n }\n\n /**\n * Calculate the mathematical shape from a list of points.\n *\n * @param {Point2D[]} points The points that define the shape.\n * @returns {Line} The mathematical shape.\n */\n #calculateMathShape(points) {\n return new Line(points[0], points[1]);\n }\n\n /**\n * Get the default labels.\n *\n * @returns {object} The label list.\n */\n #getDefaultLabel() {\n return defaults.labelText.ruler;\n }\n\n /**\n * Creates the konva shape.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Konva.Line} The konva shape.\n */\n #createShape(annotation, style) {\n const line = annotation.mathShape;\n\n // konva line\n const kshape = new Konva.Line({\n points: [\n line.getBegin().getX(),\n line.getBegin().getY(),\n line.getEnd().getX(),\n line.getEnd().getY()\n ],\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape'\n });\n\n // larger hitfunc\n const tickLen = 20;\n const linePerp0 = getPerpendicularLine(\n line, line.getBegin(), tickLen, style.getZoomScale());\n const linePerp1 = getPerpendicularLine(\n line, line.getEnd(), tickLen, style.getZoomScale());\n kshape.hitFunc(function (context) {\n context.beginPath();\n context.moveTo(linePerp0.getBegin().getX(), linePerp0.getBegin().getY());\n context.lineTo(linePerp0.getEnd().getX(), linePerp0.getEnd().getY());\n context.lineTo(linePerp1.getEnd().getX(), linePerp1.getEnd().getY());\n context.lineTo(linePerp1.getBegin().getX(), linePerp1.getBegin().getY());\n context.closePath();\n context.fillStrokeShape(kshape);\n });\n\n return kshape;\n }\n\n /**\n * Get the associated shape from a group.\n *\n * @param {Konva.Group} group The group to look into.\n * @returns {Konva.Line|undefined} The shape.\n */\n #getShape(group) {\n return getLineShape(group);\n }\n\n /**\n * Creates the konva shape extras.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Style} style The drawing style.\n * @returns {Array} The konva shape extras.\n */\n #createShapeExtras(annotation, style) {\n const line = annotation.mathShape;\n\n const tickLen = 20;\n\n // tick begin\n const linePerp0 = getPerpendicularLine(\n line, line.getBegin(), tickLen, style.getZoomScale());\n const ktick0 = new Konva.Line({\n points: [\n linePerp0.getBegin().getX(),\n linePerp0.getBegin().getY(),\n linePerp0.getEnd().getX(),\n linePerp0.getEnd().getY()\n ],\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape-tick0'\n });\n\n // tick end\n const linePerp1 = getPerpendicularLine(\n line, line.getEnd(), tickLen, style.getZoomScale());\n const ktick1 = new Konva.Line({\n points: [\n linePerp1.getBegin().getX(),\n linePerp1.getBegin().getY(),\n linePerp1.getEnd().getX(),\n linePerp1.getEnd().getY()\n ],\n stroke: annotation.colour,\n strokeWidth: style.getStrokeWidth(),\n strokeScaleEnabled: false,\n name: 'shape-tick1'\n });\n\n return [ktick0, ktick1];\n }\n\n /**\n * Get the default annotation label position.\n *\n * @param {Annotation} annotation The annotation.\n * @returns {Point2D} The position.\n */\n #getDefaultLabelPosition(annotation) {\n const line = annotation.mathShape;\n const begin = line.getBegin();\n const end = line.getEnd();\n // lowest point\n let res = begin;\n if (begin.getY() < end.getY()) {\n res = end;\n }\n return res;\n }\n\n /**\n * Update shape and label on anchor move taking the updated\n * annotation as input.\n *\n * @param {Annotation} annotation The associated annotation.\n * @param {Konva.Ellipse} anchor The active anchor.\n * @param {Style} style The application style.\n */\n #updateShape(annotation, anchor, style) {\n const line = annotation.mathShape;\n\n // parent group\n const group = anchor.getParent();\n if (!(group instanceof Konva.Group)) {\n return;\n }\n // associated shape\n const kline = this.#getShape(group);\n\n // reset position after possible shape drag\n kline.position({x: 0, y: 0});\n // update shape\n kline.points([\n line.getBegin().getX(),\n line.getBegin().getY(),\n line.getEnd().getX(),\n line.getEnd().getY(),\n ]);\n\n // associated tick0\n const ktick0 = group.getChildren(function (node) {\n return node.name() === 'shape-tick0';\n })[0];\n if (!(ktick0 instanceof Konva.Line)) {\n return;\n }\n // associated tick1\n const ktick1 = group.getChildren(function (node) {\n return node.name() === 'shape-tick1';\n })[0];\n if (!(ktick1 instanceof Konva.Line)) {\n return;\n }\n // find anchors\n const begin = getAnchorShape(group, 0);\n const end = getAnchorShape(group, 1);\n\n // update 'self' (undo case)\n switch (anchor.id()) {\n case 'anchor0':\n begin.x(anchor.x());\n begin.y(anchor.y());\n break;\n case 'anchor1':\n end.x(anchor.x());\n end.y(anchor.y());\n break;\n default:\n logger.error('Unhandled anchor id: ' + anchor.id());\n break;\n }\n\n // tick\n const tickLen = 20;\n const linePerp0 = getPerpendicularLine(\n line, line.getBegin(), tickLen, style.getZoomScale());\n ktick0.position({x: 0, y: 0});\n ktick0.points([linePerp0.getBegin().getX(),\n linePerp0.getBegin().getY(),\n linePerp0.getEnd().getX(),\n linePerp0.getEnd().getY()]);\n const linePerp1 = getPerpendicularLine(\n line, line.getEnd(), tickLen, style.getZoomScale());\n ktick1.position({x: 0, y: 0});\n ktick1.points([linePerp1.getBegin().getX(),\n linePerp1.getBegin().getY(),\n linePerp1.getEnd().getX(),\n linePerp1.getEnd().getY()]);\n\n // larger hitfunc\n kline.hitFunc(function (context) {\n context.beginPath();\n context.moveTo(linePerp0.getBegin().getX(), linePerp0.getBegin().getY());\n context.lineTo(linePerp0.getEnd().getX(), linePerp0.getEnd().getY());\n context.lineTo(linePerp1.getEnd().getX(), linePerp1.getEnd().getY());\n context.lineTo(linePerp1.getBegin().getX(), linePerp1.getBegin().getY());\n context.closePath();\n context.fillStrokeShape(kline);\n });\n }\n\n /**\n * Get the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} [_group] The associated group.\n * @returns {Konva.Group|undefined} The shadow konva group.\n */\n #getDebugShadow(_annotation, _group) {\n return;\n }\n\n /**\n * Update the debug shadow.\n *\n * @param {Annotation} _annotation The annotation to shadow.\n * @param {Konva.Group} _group The associated group.\n */\n #updateDebugShadow(_annotation, _group) {\n // does nothing\n }\n\n} // class RulerFactory\n","import {logger} from '../utils/logger';\nimport {getFlags, replaceFlags} from '../utils/string';\nimport {Point} from '../math/point';\nimport {getOrientationName} from '../math/orientation';\nimport {defaultToolOptions, toolOptions} from '../tools/index';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D, Point3D} from '../math/point';\nimport {ViewController} from '../app/viewController';\nimport {PlaneHelper} from './planeHelper';\n/* eslint-enable no-unused-vars */\n\n/**\n * Image annotation.\n */\nexport class Annotation {\n /**\n * The ID.\n *\n * @type {string}\n */\n id;\n\n /**\n * The reference image SOP UID.\n *\n * @type {string}\n */\n referenceSopUID;\n\n /**\n * The mathematical shape.\n *\n * @type {object}\n */\n mathShape;\n\n /**\n * Additional points used to define the annotation.\n *\n * @type {Point2D[]|undefined}\n */\n referencePoints;\n\n /**\n * The color: for example 'green', '#00ff00' or 'rgb(0,255,0)'.\n *\n * @type {string|undefined}\n */\n colour;\n\n /**\n * Annotation quantification.\n *\n * @type {object|undefined}\n */\n quantification;\n\n /**\n * Text expression. Can contain variables surrounded with '{}' that will\n * be extracted from the quantification object.\n *\n * @type {string|undefined}\n */\n textExpr;\n\n /**\n * Label position. If undefined, the default shape\n * label position will be used.\n *\n * @type {Point2D|undefined}\n */\n labelPosition;\n\n /**\n * The plane origin, the 3D position of index [0, 0, k].\n *\n * @type {Point3D|undefined}\n */\n planeOrigin;\n\n /**\n * A couple of points that help define the annotation plane.\n *\n * @type {Point3D[]|undefined}\n */\n planePoints;\n\n /**\n * Associated view controller: needed for quantification and label.\n *\n * @type {ViewController|undefined}\n */\n #viewController;\n\n /**\n * Get the orientation name for this annotation.\n *\n * @returns {string|undefined} The orientation name,\n * undefined if same as reference data.\n */\n getOrientationName() {\n let res;\n if (typeof this.planePoints !== 'undefined') {\n const cosines = this.planePoints[1].getValues().concat(\n this.planePoints[2].getValues()\n );\n res = getOrientationName(cosines);\n }\n return res;\n }\n\n /**\n * Initialise the annotation.\n *\n * @param {ViewController} viewController The associated view controller.\n */\n init(viewController) {\n if (typeof this.referenceSopUID !== 'undefined') {\n logger.debug('Cannot initialise annotation twice');\n return;\n }\n\n this.#viewController = viewController;\n // set UID\n this.referenceSopUID = viewController.getCurrentImageUid();\n // set plane origin (not saved with file)\n this.planeOrigin =\n viewController.getOriginForImageUid(this.referenceSopUID);\n // set plane points if not aquisition orientation\n // (planePoints are saved with file if present)\n if (!viewController.isAquisitionOrientation()) {\n this.planePoints = viewController.getPlanePoints(\n viewController.getCurrentPosition()\n );\n }\n }\n\n /**\n * Check if an input view is compatible with the annotation.\n *\n * @param {PlaneHelper} planeHelper The input view to check.\n * @returns {boolean} True if compatible view.\n */\n isCompatibleView(planeHelper) {\n let res = false;\n\n // TODO: add check for referenceSopUID\n\n if (typeof this.planePoints === 'undefined') {\n // non oriented view\n if (planeHelper.isAquisitionOrientation()) {\n res = true;\n }\n } else {\n // oriented view: compare cosines (independent of slice index)\n const cosines = planeHelper.getCosines();\n const cosine1 = new Point3D(cosines[0], cosines[1], cosines[2]);\n const cosine2 = new Point3D(cosines[3], cosines[4], cosines[5]);\n\n if (cosine1.equals(this.planePoints[1]) &&\n cosine2.equals(this.planePoints[2])) {\n res = true;\n }\n }\n return res;\n }\n\n /**\n * Set the associated view controller if it is compatible.\n *\n * @param {ViewController} viewController The view controller.\n */\n setViewController(viewController) {\n // check uid\n if (!viewController.includesImageUid(this.referenceSopUID)) {\n return;\n }\n // check if same view\n if (!this.isCompatibleView(viewController.getPlaneHelper())) {\n return;\n }\n this.#viewController = viewController;\n\n // set plane origin (not saved with file)\n this.planeOrigin =\n viewController.getOriginForImageUid(this.referenceSopUID);\n }\n\n /**\n * Get the centroid of the math shape.\n *\n * @returns {Point|undefined} The 3D centroid point.\n */\n getCentroid() {\n let res;\n if (typeof this.#viewController !== 'undefined' &&\n typeof this.mathShape.getCentroid !== 'undefined') {\n // find the slice index of the annotation origin\n let origin = this.planeOrigin;\n if (typeof this.planePoints !== 'undefined') {\n origin = this.planePoints[0];\n }\n const originPoint =\n new Point([origin.getX(), origin.getY(), origin.getZ()]);\n const originIndex =\n this.#viewController.getIndexFromPosition(originPoint);\n const scrollIndex = this.#viewController.getScrollIndex();\n const k = originIndex.getValues()[scrollIndex];\n\n // shape center converted to 3D\n const planePoint = this.mathShape.getCentroid();\n res = this.#viewController.getPositionFromPlanePoint(planePoint, k);\n }\n return res;\n }\n\n /**\n * Set the annotation text expression.\n *\n * @param {Object.} labelText The list of label\n * texts indexed by modality.\n */\n setTextExpr(labelText) {\n if (typeof this.#viewController !== 'undefined') {\n const modality = this.#viewController.getModality();\n\n if (typeof labelText[modality] !== 'undefined') {\n this.textExpr = labelText[modality];\n } else {\n this.textExpr = labelText['*'];\n }\n } else {\n logger.warn('Cannot set text expr without a view controller');\n }\n }\n\n /**\n * Get the annotation label text by applying the\n * text expression on the current quantification.\n *\n * @returns {string} The resulting text.\n */\n getText() {\n return replaceFlags(this.textExpr, this.quantification);\n }\n\n /**\n * Update the annotation quantification.\n */\n updateQuantification() {\n if (typeof this.#viewController !== 'undefined' &&\n typeof this.mathShape.quantify !== 'undefined') {\n this.quantification = this.mathShape.quantify(\n this.#viewController,\n getFlags(this.textExpr));\n }\n }\n\n /**\n * Get the math shape associated draw factory.\n *\n * @returns {object} The factory.\n */\n getFactory() {\n let fac;\n // check in user provided factories\n if (typeof toolOptions.draw !== 'undefined') {\n for (const factoryName in toolOptions.draw) {\n const factory = toolOptions.draw[factoryName];\n if (factory.supports(this.mathShape)) {\n fac = new factory();\n break;\n }\n }\n }\n // check in default factories\n if (typeof fac === 'undefined') {\n for (const factoryName in defaultToolOptions.draw) {\n const factory = defaultToolOptions.draw[factoryName];\n if (factory.supports(this.mathShape)) {\n fac = new factory();\n break;\n }\n }\n }\n if (typeof fac === 'undefined') {\n logger.warn('No shape factory found for math shape');\n }\n return fac;\n }\n}\n","import {logger} from '../utils/logger';\nimport {Point2D} from '../math/point';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Annotation} from '../image/annotation';\n/* eslint-enable no-unused-vars */\n\n/**\n * List of interaction event names.\n */\nexport const InteractionEventNames = [\n 'mousedown',\n 'mousemove',\n 'mouseup',\n 'mouseout',\n 'wheel',\n 'dblclick',\n 'touchstart',\n 'touchmove',\n 'touchend'\n];\n\n/**\n * Overridalbe custom UI object for client defined UI.\n */\nexport const customUI = {\n /**\n * Open a dialogue to edit roi data. Defaults to window.prompt.\n *\n * @param {Annotation} annotation The roi data.\n * @param {Function} callback The callback to launch on dialogue exit.\n */\n openRoiDialog(annotation, callback) {\n const textExpr = prompt('Label', annotation.textExpr);\n if (textExpr !== null) {\n annotation.textExpr = textExpr;\n callback(annotation);\n }\n }\n};\n\n/**\n * Get the positions (without the parent offset) of a list of touch events.\n *\n * @param {Array} touches The list of touch events.\n * @returns {Point2D[]} The list of positions of the touch events.\n */\nfunction getTouchesPositions(touches) {\n // get the touch offset from all its parents\n let offsetLeft = 0;\n let offsetTop = 0;\n if (touches.length !== 0 &&\n typeof touches[0].target !== 'undefined') {\n let offsetParent = touches[0].target.offsetParent;\n while (offsetParent) {\n if (!isNaN(offsetParent.offsetLeft)) {\n offsetLeft += offsetParent.offsetLeft;\n }\n if (!isNaN(offsetParent.offsetTop)) {\n offsetTop += offsetParent.offsetTop;\n }\n offsetParent = offsetParent.offsetParent;\n }\n } else {\n logger.debug('No touch target offset parent.');\n }\n // set its position\n const positions = [];\n for (let i = 0; i < touches.length; ++i) {\n positions.push(new Point2D(\n touches[i].pageX - offsetLeft,\n touches[i].pageY - offsetTop\n ));\n }\n return positions;\n}\n\n/**\n * Get the offsets of an input touch event.\n *\n * @param {object} event The event to get the offset from.\n * @returns {Point2D[]} The array of points.\n */\nexport function getTouchPoints(event) {\n let positions = [];\n if (typeof event.targetTouches !== 'undefined' &&\n event.targetTouches.length !== 0) {\n // see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/targetTouches\n positions = getTouchesPositions(event.targetTouches);\n } else if (typeof event.changedTouches !== 'undefined' &&\n event.changedTouches.length !== 0) {\n // see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/changedTouches\n positions = getTouchesPositions(event.changedTouches);\n }\n return positions;\n}\n\n/**\n * Get the offset of an input mouse event.\n *\n * @param {object} event The event to get the offset from.\n * @returns {Point2D} The 2D point.\n */\nexport function getMousePoint(event) {\n // offsetX/Y: the offset in the X coordinate of the mouse pointer\n // between that event and the padding edge of the target node\n // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/offsetX\n // https://caniuse.com/mdn-api_mouseevent_offsetx\n return new Point2D(\n event.offsetX,\n event.offsetY\n );\n}\n\n/**\n * Test if a canvas with the input size can be created.\n *\n * Ref:\n * - {@link https://github.com/ivmartel/dwv/issues/902},\n * - {@link https://github.com/jhildenbiddle/canvas-size/blob/v1.2.4/src/canvas-test.js}.\n *\n * @param {number} width The canvas width.\n * @param {number} height The canvas height.\n * @returns {boolean} True is the canvas can be created.\n */\nexport function canCreateCanvas(width, height) {\n // test canvas with input size\n const testCvs = document.createElement('canvas');\n testCvs.width = width;\n testCvs.height = height;\n // crop canvas to speed up test\n const cropCvs = document.createElement('canvas');\n cropCvs.width = 1;\n cropCvs.height = 1;\n // contexts\n const testCtx = testCvs.getContext('2d');\n const cropCtx = cropCvs.getContext('2d');\n // set data\n if (testCtx) {\n testCtx.fillRect(width - 1, height - 1, 1, 1);\n // Render the test pixel in the bottom-right corner of the\n // test canvas in the top-left of the 1x1 crop canvas. This\n // dramatically reducing the time for getImageData to complete.\n cropCtx.drawImage(testCvs, width - 1, height - 1, 1, 1, 0, 0, 1, 1);\n }\n // Verify image data (alpha component, Pass = 255, Fail = 0)\n return cropCtx && cropCtx.getImageData(0, 0, 1, 1).data[3] !== 0;\n}\n","import {Index} from '../math/index';\nimport {ListenerHandler} from '../utils/listen';\nimport {viewEventNames} from '../image/view';\nimport {ViewController} from '../app/viewController';\nimport {Point2D} from '../math/point';\nimport {\n canCreateCanvas,\n InteractionEventNames\n} from './generic';\nimport {getScaledOffset} from './layerGroup';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Vector3D} from '../math/vector';\nimport {Point, Point3D} from '../math/point';\nimport {Scalar2D, Scalar3D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * View layer.\n */\nexport class ViewLayer {\n\n /**\n * Container div.\n *\n * @type {HTMLElement}\n */\n #containerDiv;\n\n /**\n * The view controller.\n *\n * @type {ViewController}\n */\n #viewController = null;\n\n /**\n * The main display canvas.\n *\n * @type {object}\n */\n #canvas = null;\n\n /**\n * The offscreen canvas: used to store the raw, unscaled pixel data.\n *\n * @type {object}\n */\n #offscreenCanvas = null;\n\n /**\n * The associated CanvasRenderingContext2D.\n *\n * @type {object}\n */\n #context = null;\n\n /**\n * Flag to know if the current position is valid.\n *\n * @type {boolean}\n */\n #isValidPosition = true;\n\n /**\n * The image data array.\n *\n * @type {ImageData}\n */\n #imageData = null;\n\n /**\n * The layer base size as {x,y}.\n *\n * @type {Scalar2D}\n */\n #baseSize;\n\n /**\n * The layer base spacing as {x,y}.\n *\n * @type {Scalar2D}\n */\n #baseSpacing;\n\n /**\n * The layer opacity.\n *\n * @type {number}\n */\n #opacity = 1;\n\n /**\n * The layer scale.\n *\n * @type {Scalar2D}\n */\n #scale = {x: 1, y: 1};\n\n /**\n * The layer fit scale.\n *\n * @type {Scalar2D}\n */\n #fitScale = {x: 1, y: 1};\n\n /**\n * The layer flip scale.\n *\n * @type {Scalar3D}\n */\n #flipScale = {x: 1, y: 1, z: 1};\n\n /**\n * The layer offset.\n *\n * @type {Scalar2D}\n */\n #offset = {x: 0, y: 0};\n\n /**\n * The base layer offset.\n *\n * @type {Scalar2D}\n */\n #baseOffset = {x: 0, y: 0};\n\n /**\n * The view offset.\n *\n * @type {Scalar2D}\n */\n #viewOffset = {x: 0, y: 0};\n\n /**\n * The zoom offset.\n *\n * @type {Scalar2D}\n */\n #zoomOffset = {x: 0, y: 0};\n\n /**\n * The flip offset.\n *\n * @type {Scalar2D}\n */\n #flipOffset = {x: 0, y: 0};\n\n /**\n * Data update flag.\n *\n * @type {boolean}\n */\n #needsDataUpdate = null;\n\n /**\n * The associated data id.\n *\n * @type {string}\n */\n #dataId;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Image smoothing flag.\n *\n * See: {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingEnabled}.\n *\n * @type {boolean}\n */\n #imageSmoothing = false;\n\n /**\n * Layer group origin.\n *\n * @type {Point3D}\n */\n #layerGroupOrigin;\n\n /**\n * Layer group first origin.\n *\n * @type {Point3D}\n */\n #layerGroupOrigin0;\n\n /**\n * @param {HTMLElement} containerDiv The layer div, its id will be used\n * as this layer id.\n */\n constructor(containerDiv) {\n this.#containerDiv = containerDiv;\n // specific css class name\n this.#containerDiv.className += ' viewLayer';\n }\n\n /**\n * Get the associated data id.\n *\n * @returns {string} The data id.\n */\n getDataId() {\n return this.#dataId;\n }\n\n /**\n * Get the layer scale.\n *\n * @returns {Scalar2D} The scale as {x,y}.\n */\n getScale() {\n return this.#scale;\n }\n\n /**\n * Get the layer zoom offset without the fit scale.\n *\n * @returns {Scalar2D} The offset as {x,y}.\n */\n getAbsoluteZoomOffset() {\n return {\n x: this.#zoomOffset.x * this.#fitScale.x,\n y: this.#zoomOffset.y * this.#fitScale.y\n };\n }\n\n /**\n * Set the imageSmoothing flag value.\n *\n * @param {boolean} flag True to enable smoothing.\n */\n setImageSmoothing(flag) {\n this.#imageSmoothing = flag;\n }\n\n /**\n * Set the associated view.\n *\n * @param {object} view The view.\n * @param {string} dataId The associated data id.\n */\n setView(view, dataId) {\n this.#dataId = dataId;\n // local listeners\n view.addEventListener('wlchange', this.#onWLChange);\n view.addEventListener('colourmapchange', this.#onColourMapChange);\n view.addEventListener('positionchange', this.#onPositionChange);\n view.addEventListener('alphafuncchange', this.#onAlphaFuncChange);\n // view events\n for (let j = 0; j < viewEventNames.length; ++j) {\n view.addEventListener(viewEventNames[j], this.#fireEvent);\n }\n // create view controller\n this.#viewController = new ViewController(view);\n // bind layer and image\n this.bindImage();\n }\n\n /**\n * Get the view controller.\n *\n * @returns {ViewController} The controller.\n */\n getViewController() {\n return this.#viewController;\n }\n\n /**\n * Get the canvas image data.\n *\n * @returns {object} The image data.\n */\n getImageData() {\n return this.#imageData;\n }\n\n /**\n * Handle an image set event.\n *\n * @param {object} event The event.\n * @function\n */\n onimageset = (event) => {\n // event.value = [index, image]\n if (this.#dataId === event.dataid) {\n this.#viewController.setImage(event.value[0]);\n this.#setBaseSize(this.#viewController.getImageSize().get2D());\n this.#needsDataUpdate = true;\n }\n };\n\n /**\n * Bind this layer to the view image.\n */\n bindImage() {\n if (this.#viewController) {\n this.#viewController.bindImageAndLayer(this);\n }\n }\n\n /**\n * Unbind this layer to the view image.\n */\n unbindImage() {\n if (this.#viewController) {\n this.#viewController.unbindImageAndLayer(this);\n }\n }\n\n /**\n * Handle an image content change event.\n *\n * @param {object} event The event.\n * @function\n */\n onimagecontentchange = (event) => {\n // event.value = [index]\n if (this.#dataId === event.dataid) {\n this.#isValidPosition = this.#viewController.isPositionInBounds();\n // flag update and draw\n this.#needsDataUpdate = true;\n this.draw();\n }\n };\n\n /**\n * Handle an image change event.\n *\n * @param {object} event The event.\n * @function\n */\n onimagegeometrychange = (event) => {\n // event.value = [index]\n if (this.#dataId === event.dataid) {\n const vcSize = this.#viewController.getImageSize().get2D();\n if (this.#baseSize.x !== vcSize.x ||\n this.#baseSize.y !== vcSize.y) {\n // size changed, recalculate base offset\n // in case origin changed\n if (typeof this.#layerGroupOrigin !== 'undefined' &&\n typeof this.#layerGroupOrigin0 !== 'undefined') {\n const origin0 = this.#viewController.getOrigin();\n const scrollOffset = this.#layerGroupOrigin0.minus(origin0);\n const origin = this.#viewController.getOrigin(\n this.#viewController.getCurrentPosition()\n );\n const planeOffset = this.#layerGroupOrigin.minus(origin);\n this.setBaseOffset(scrollOffset, planeOffset);\n }\n // update base size\n this.#setBaseSize(vcSize);\n // flag update and draw\n this.#needsDataUpdate = true;\n this.draw();\n }\n }\n };\n\n // common layer methods [start] ---------------\n\n /**\n * Get the id of the layer.\n *\n * @returns {string} The string id.\n */\n getId() {\n return this.#containerDiv.id;\n }\n\n /**\n * Remove the HTML element from the DOM.\n */\n removeFromDOM() {\n this.#containerDiv.remove();\n }\n\n /**\n * Get the layer base size (without scale).\n *\n * @returns {Scalar2D} The size as {x,y}.\n */\n getBaseSize() {\n return this.#baseSize;\n }\n\n /**\n * Get the image world (mm) 2D size.\n *\n * @returns {Scalar2D} The 2D size as {x,y}.\n */\n getImageWorldSize() {\n return this.#viewController.getImageWorldSize();\n }\n\n /**\n * Get the layer opacity.\n *\n * @returns {number} The opacity ([0:1] range).\n */\n getOpacity() {\n return this.#opacity;\n }\n\n /**\n * Set the layer opacity.\n *\n * @param {number} alpha The opacity ([0:1] range).\n */\n setOpacity(alpha) {\n if (alpha === this.#opacity) {\n return;\n }\n\n this.#opacity = Math.min(Math.max(alpha, 0), 1);\n\n /**\n * Opacity change event.\n *\n * @event App#opacitychange\n * @type {object}\n * @property {string} type The event type.\n */\n const event = {\n type: 'opacitychange',\n value: [this.#opacity]\n };\n this.#fireEvent(event);\n }\n\n /**\n * Add a flip offset along the layer X axis.\n */\n addFlipOffsetX() {\n this.#flipOffset.x += this.#canvas.width / this.#scale.x;\n this.#offset.x += this.#flipOffset.x;\n }\n\n /**\n * Add a flip offset along the layer Y axis.\n */\n addFlipOffsetY() {\n this.#flipOffset.y += this.#canvas.height / this.#scale.y;\n this.#offset.y += this.#flipOffset.y;\n }\n\n /**\n * Flip the scale along the layer X axis.\n */\n flipScaleX() {\n this.#flipScale.x *= -1;\n }\n\n /**\n * Flip the scale along the layer Y axis.\n */\n flipScaleY() {\n this.#flipScale.y *= -1;\n }\n\n /**\n * Flip the scale along the layer Z axis.\n */\n flipScaleZ() {\n this.#flipScale.z *= -1;\n }\n\n /**\n * Set the layer scale.\n *\n * @param {Scalar3D} newScale The scale as {x,y,z}.\n * @param {Point3D} [center] The scale center.\n */\n setScale(newScale, center) {\n const helper = this.#viewController.getPlaneHelper();\n const orientedNewScale = helper.getTargetOrientedPositiveXYZ({\n x: newScale.x * this.#flipScale.x,\n y: newScale.y * this.#flipScale.y,\n z: newScale.z * this.#flipScale.z,\n });\n const finalNewScale = {\n x: this.#fitScale.x * orientedNewScale.x,\n y: this.#fitScale.y * orientedNewScale.y\n };\n\n if (Math.abs(newScale.x) === 1 &&\n Math.abs(newScale.y) === 1 &&\n Math.abs(newScale.z) === 1) {\n // reset zoom offset for scale=1\n const resetOffset = {\n x: this.#offset.x - this.#zoomOffset.x,\n y: this.#offset.y - this.#zoomOffset.y\n };\n // store new offset\n this.#zoomOffset = {x: 0, y: 0};\n this.#offset = resetOffset;\n } else {\n if (typeof center !== 'undefined') {\n let worldCenter = helper.getPlaneOffsetFromOffset3D({\n x: center.getX(),\n y: center.getY(),\n z: center.getZ()\n });\n // center was obtained with viewLayer.displayToMainPlanePos\n // compensated for baseOffset\n // TODO: justify...\n worldCenter = {\n x: worldCenter.x + this.#baseOffset.x,\n y: worldCenter.y + this.#baseOffset.y\n };\n\n const newOffset = getScaledOffset(\n this.#offset, this.#scale, finalNewScale, worldCenter);\n\n const newZoomOffset = {\n x: this.#zoomOffset.x + newOffset.x - this.#offset.x,\n y: this.#zoomOffset.y + newOffset.y - this.#offset.y\n };\n // store new offset\n this.#zoomOffset = newZoomOffset;\n this.#offset = newOffset;\n }\n }\n\n // store new scale\n this.#scale = finalNewScale;\n }\n\n /**\n * Initialise the layer scale.\n *\n * @param {Scalar3D} newScale The scale as {x,y,z}.\n * @param {Scalar2D} absoluteZoomOffset The zoom offset as {x,y}\n * without the fit scale (as provided by getAbsoluteZoomOffset).\n */\n initScale(newScale, absoluteZoomOffset) {\n const helper = this.#viewController.getPlaneHelper();\n const orientedNewScale = helper.getTargetOrientedPositiveXYZ({\n x: newScale.x * this.#flipScale.x,\n y: newScale.y * this.#flipScale.y,\n z: newScale.z * this.#flipScale.z,\n });\n const finalNewScale = {\n x: this.#fitScale.x * orientedNewScale.x,\n y: this.#fitScale.y * orientedNewScale.y\n };\n this.#scale = finalNewScale;\n\n this.#zoomOffset = {\n x: absoluteZoomOffset.x / this.#fitScale.x,\n y: absoluteZoomOffset.y / this.#fitScale.y\n };\n this.#offset = {\n x: this.#offset.x + this.#zoomOffset.x,\n y: this.#offset.y + this.#zoomOffset.y\n };\n }\n\n /**\n * Set the base layer offset. Updates the layer offset.\n *\n * @param {Vector3D} scrollOffset The scroll offset vector.\n * @param {Vector3D} planeOffset The plane offset vector.\n * @param {Point3D} [layerGroupOrigin] The layer group origin.\n * @param {Point3D} [layerGroupOrigin0] The layer group first origin.\n * @returns {boolean} True if the offset was updated.\n */\n setBaseOffset(\n scrollOffset, planeOffset,\n layerGroupOrigin, layerGroupOrigin0) {\n const helper = this.#viewController.getPlaneHelper();\n const scrollIndex = helper.getNativeScrollIndex();\n const newOffset = helper.getPlaneOffsetFromOffset3D({\n x: scrollIndex === 0 ? scrollOffset.getX() : planeOffset.getX(),\n y: scrollIndex === 1 ? scrollOffset.getY() : planeOffset.getY(),\n z: scrollIndex === 2 ? scrollOffset.getZ() : planeOffset.getZ(),\n });\n const needsUpdate = this.#baseOffset.x !== newOffset.x ||\n this.#baseOffset.y !== newOffset.y;\n // store layer group origins\n if (typeof layerGroupOrigin !== 'undefined' &&\n typeof layerGroupOrigin0 !== 'undefined') {\n this.#layerGroupOrigin = layerGroupOrigin;\n this.#layerGroupOrigin0 = layerGroupOrigin0;\n }\n // reset offset if needed\n if (needsUpdate) {\n this.#offset = {\n x: this.#offset.x - this.#baseOffset.x + newOffset.x,\n y: this.#offset.y - this.#baseOffset.y + newOffset.y\n };\n this.#baseOffset = newOffset;\n }\n return needsUpdate;\n }\n\n /**\n * Set the layer offset.\n *\n * @param {Scalar3D} newOffset The offset as {x,y,z}.\n */\n setOffset(newOffset) {\n const helper = this.#viewController.getPlaneHelper();\n const planeNewOffset = helper.getPlaneOffsetFromOffset3D(newOffset);\n this.#offset = {\n x: planeNewOffset.x +\n this.#viewOffset.x +\n this.#baseOffset.x +\n this.#zoomOffset.x +\n this.#flipOffset.x,\n y: planeNewOffset.y +\n this.#viewOffset.y +\n this.#baseOffset.y +\n this.#zoomOffset.y +\n this.#flipOffset.y\n };\n }\n\n /**\n * Transform a display position to a 2D index.\n *\n * @param {Point2D} point2D The input point.\n * @returns {Index} The equivalent 2D index.\n */\n displayToPlaneIndex(point2D) {\n const planePos = this.displayToPlanePos(point2D);\n return new Index([\n Math.floor(planePos.getX()),\n Math.floor(planePos.getY())\n ]);\n }\n\n /**\n * Remove scale from a display position.\n *\n * @param {Point2D} point2D The input point.\n * @returns {Point2D} The de-scaled point.\n */\n displayToPlaneScale(point2D) {\n return new Point2D(\n point2D.getX() / this.#scale.x,\n point2D.getY() / this.#scale.y\n );\n }\n\n /**\n * Get a plane position from a display position.\n *\n * @param {Point2D} point2D The input point.\n * @returns {Point2D} The plane position.\n */\n displayToPlanePos(point2D) {\n const deScaled = this.displayToPlaneScale(point2D);\n return new Point2D(\n deScaled.getX() + this.#offset.x,\n deScaled.getY() + this.#offset.y\n );\n }\n\n /**\n * Get a display position from a plane position.\n *\n * @param {Point2D} point2D The input point.\n * @returns {Point2D} The display position, can be individually\n * undefined if out of bounds.\n */\n planePosToDisplay(point2D) {\n let posX =\n (point2D.getX() - this.#offset.x + this.#baseOffset.x) * this.#scale.x;\n let posY =\n (point2D.getY() - this.#offset.y + this.#baseOffset.y) * this.#scale.y;\n // check if in bounds\n if (posX < 0 || posX >= this.#canvas.width) {\n posX = undefined;\n }\n if (posY < 0 || posY >= this.#canvas.height) {\n posY = undefined;\n }\n return new Point2D(posX, posY);\n }\n\n /**\n * Get a main plane position from a display position.\n *\n * @param {Point2D} point2D The input point.\n * @returns {Point2D} The main plane position.\n */\n displayToMainPlanePos(point2D) {\n const planePos = this.displayToPlanePos(point2D);\n return new Point2D(\n planePos.getX() - this.#baseOffset.x,\n planePos.getY() - this.#baseOffset.y\n );\n }\n\n /**\n * Display the layer.\n *\n * @param {boolean} flag Whether to display the layer or not.\n */\n display(flag) {\n this.#containerDiv.style.display = flag ? '' : 'none';\n }\n\n /**\n * Check if the layer is visible.\n *\n * @returns {boolean} True if the layer is visible.\n */\n isVisible() {\n return this.#containerDiv.style.display === '';\n }\n\n /**\n * Draw the content (imageData) of the layer.\n * The imageData variable needs to be set.\n *\n * @fires App#renderstart\n * @fires App#renderend\n */\n draw() {\n // skip for non valid position\n if (!this.#isValidPosition) {\n return;\n }\n\n /**\n * Render start event.\n *\n * @event App#renderstart\n * @type {object}\n * @property {string} type The event type.\n */\n let event = {\n type: 'renderstart',\n layerid: this.getId(),\n dataid: this.getDataId()\n };\n this.#fireEvent(event);\n\n // update data if needed\n if (this.#needsDataUpdate) {\n this.#updateImageData();\n }\n\n // context opacity\n this.#context.globalAlpha = this.#opacity;\n\n // clear context\n this.clear();\n\n // draw the cached canvas on the context\n // transform takes as input a, b, c, d, e, f to create\n // the transform matrix (column-major order):\n // [ a c e ]\n // [ b d f ]\n // [ 0 0 1 ]\n this.#context.setTransform(\n this.#scale.x,\n 0,\n 0,\n this.#scale.y,\n -1 * this.#offset.x * this.#scale.x,\n -1 * this.#offset.y * this.#scale.y\n );\n\n // disable smoothing (set just before draw, could be reset by resize)\n this.#context.imageSmoothingEnabled = this.#imageSmoothing;\n // draw image\n this.#context.drawImage(this.#offscreenCanvas, 0, 0);\n\n /**\n * Render end event.\n *\n * @event App#renderend\n * @type {object}\n * @property {string} type The event type.\n */\n event = {\n type: 'renderend',\n layerid: this.getId(),\n dataid: this.getDataId()\n };\n this.#fireEvent(event);\n }\n\n /**\n * Initialise the layer: set the canvas and context.\n *\n * @param {Scalar2D} size The image size as {x,y}.\n * @param {Scalar2D} spacing The image spacing as {x,y}.\n * @param {number} alpha The initial data opacity.\n */\n initialise(size, spacing, alpha) {\n // set locals\n this.#baseSpacing = spacing;\n this.#opacity = Math.min(Math.max(alpha, 0), 1);\n\n // create canvas\n // (canvas size is set in fitToContainer)\n this.#canvas = document.createElement('canvas');\n this.#containerDiv.appendChild(this.#canvas);\n\n // check that the getContext method exists\n if (!this.#canvas.getContext) {\n alert('Error: no canvas.getContext method.');\n return;\n }\n // get the 2D context\n this.#context = this.#canvas.getContext('2d');\n if (!this.#context) {\n alert('Error: failed to get the 2D context.');\n return;\n }\n\n // off screen canvas\n this.#offscreenCanvas = document.createElement('canvas');\n\n // set base size: needs an existing context and off screen canvas\n this.#setBaseSize(size);\n\n // update data on first draw\n this.#needsDataUpdate = true;\n }\n\n /**\n * Set the base size of the layer.\n *\n * @param {Scalar2D} size The size as {x,y}.\n */\n #setBaseSize(size) {\n // check canvas creation\n if (!canCreateCanvas(size.x, size.y)) {\n throw new Error('Cannot create canvas with size ' +\n size.x + ', ' + size.y);\n }\n\n // set local\n this.#baseSize = size;\n\n // off screen canvas\n this.#offscreenCanvas.width = this.#baseSize.x;\n this.#offscreenCanvas.height = this.#baseSize.y;\n // original empty image data array\n this.#context.clearRect(0, 0, this.#baseSize.x, this.#baseSize.y);\n this.#imageData = this.#context.createImageData(\n this.#baseSize.x, this.#baseSize.y);\n }\n\n /**\n * Fit the layer to its parent container.\n *\n * @param {Scalar2D} containerSize The fit size as {x,y}.\n * @param {number} divToWorldSizeRatio The div to world size ratio.\n * @param {Scalar2D} fitOffset The fit offset as {x,y}.\n */\n fitToContainer(containerSize, divToWorldSizeRatio, fitOffset) {\n let needsDraw = false;\n\n // set canvas size if different from previous\n if (this.#canvas.width !== containerSize.x ||\n this.#canvas.height !== containerSize.y) {\n if (!canCreateCanvas(containerSize.x, containerSize.y)) {\n throw new Error('Cannot resize canvas ' +\n containerSize.x + ', ' + containerSize.y);\n }\n // canvas size change triggers canvas reset\n this.#canvas.width = containerSize.x;\n this.#canvas.height = containerSize.y;\n // update draw flag\n needsDraw = true;\n }\n\n // fit scale\n const divToImageSizeRatio = {\n x: divToWorldSizeRatio * this.#baseSpacing.x,\n y: divToWorldSizeRatio * this.#baseSpacing.y\n };\n // #scale = inputScale * fitScale * flipScale\n // flipScale does not change here, we can omit it\n // newScale = (#scale / fitScale) * newFitScale\n const newScale = {\n x: this.#scale.x * divToImageSizeRatio.x / this.#fitScale.x,\n y: this.#scale.y * divToImageSizeRatio.y / this.#fitScale.y\n };\n\n // set scales if different from previous\n if (this.#scale.x !== newScale.x ||\n this.#scale.y !== newScale.y) {\n this.#fitScale = divToImageSizeRatio;\n this.#scale = newScale;\n // update draw flag\n needsDraw = true;\n }\n\n // view offset\n const newViewOffset = {\n x: fitOffset.x / divToImageSizeRatio.x,\n y: fitOffset.y / divToImageSizeRatio.y\n };\n // flip offset\n const scaledImageSize = {\n x: containerSize.x / divToImageSizeRatio.x,\n y: containerSize.y / divToImageSizeRatio.y\n };\n const newFlipOffset = {\n x: this.#flipOffset.x !== 0 ? scaledImageSize.x : 0,\n y: this.#flipOffset.y !== 0 ? scaledImageSize.y : 0,\n };\n\n // set offsets if different from previous\n if (this.#viewOffset.x !== newViewOffset.x ||\n this.#viewOffset.y !== newViewOffset.y ||\n this.#flipOffset.x !== newFlipOffset.x ||\n this.#flipOffset.y !== newFlipOffset.y) {\n // update global offset\n this.#offset = {\n x: this.#offset.x +\n newViewOffset.x - this.#viewOffset.x +\n newFlipOffset.x - this.#flipOffset.x,\n y: this.#offset.y +\n newViewOffset.y - this.#viewOffset.y +\n newFlipOffset.y - this.#flipOffset.y,\n };\n // update private local offsets\n this.#flipOffset = newFlipOffset;\n this.#viewOffset = newViewOffset;\n // update draw flag\n needsDraw = true;\n }\n\n // draw if needed\n if (needsDraw) {\n this.draw();\n }\n }\n\n /**\n * Enable and listen to container interaction events.\n */\n bindInteraction() {\n // allow pointer events\n this.#containerDiv.style.pointerEvents = 'auto';\n // interaction events\n const names = InteractionEventNames;\n for (let i = 0; i < names.length; ++i) {\n const eventName = names[i];\n const passive = eventName !== 'wheel';\n this.#containerDiv.addEventListener(\n eventName, this.#fireEvent, {passive: passive});\n }\n }\n\n /**\n * Disable and stop listening to container interaction events.\n */\n unbindInteraction() {\n // disable pointer events\n this.#containerDiv.style.pointerEvents = 'none';\n // interaction events\n const names = InteractionEventNames;\n for (let i = 0; i < names.length; ++i) {\n this.#containerDiv.removeEventListener(names[i], this.#fireEvent);\n }\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n event.srclayerid = this.getId();\n event.dataid = this.#dataId;\n this.#listenerHandler.fireEvent(event);\n };\n\n // common layer methods [end] ---------------\n\n /**\n * Update the canvas image data.\n */\n #updateImageData() {\n // generate image data\n this.#viewController.generateImageData(this.#imageData);\n // pass the data to the off screen canvas\n this.#offscreenCanvas.getContext('2d').putImageData(this.#imageData, 0, 0);\n // update data flag\n this.#needsDataUpdate = false;\n }\n\n /**\n * Handle window/level change.\n *\n * @param {object} event The event fired when changing the window/level.\n */\n #onWLChange = (event) => {\n // generate and draw if no skip flag\n const skip = typeof event.skipGenerate !== 'undefined' &&\n event.skipGenerate === true;\n if (!skip) {\n this.#needsDataUpdate = true;\n this.draw();\n }\n };\n\n /**\n * Handle colour map change.\n *\n * @param {object} event The event fired when changing the colour map.\n */\n #onColourMapChange = (event) => {\n const skip = typeof event.skipGenerate !== 'undefined' &&\n event.skipGenerate === true;\n if (!skip) {\n this.#needsDataUpdate = true;\n this.draw();\n }\n };\n\n /**\n * Handle position change.\n *\n * @param {object} event The event fired when changing the position.\n */\n #onPositionChange = (event) => {\n const skip = typeof event.skipGenerate !== 'undefined' &&\n event.skipGenerate === true;\n if (!skip) {\n let valid = true;\n if (typeof event.valid !== 'undefined') {\n valid = event.valid;\n }\n // clear for non valid events\n if (!valid) {\n // clear only once\n if (this.#isValidPosition) {\n this.#isValidPosition = false;\n this.clear();\n }\n } else {\n // 3D dimensions\n const dims3D = [0, 1, 2];\n // remove scroll index\n const indexScrollIndex =\n dims3D.indexOf(this.#viewController.getScrollIndex());\n dims3D.splice(indexScrollIndex, 1);\n // remove non scroll index from diff dims\n const diffDims = event.diffDims.filter(function (item) {\n return dims3D.indexOf(item) === -1;\n });\n // update if we have something left\n if (diffDims.length !== 0 || !this.#isValidPosition) {\n // reset valid flag\n this.#isValidPosition = true;\n // reset update flag\n this.#needsDataUpdate = true;\n this.draw();\n }\n }\n }\n };\n\n /**\n * Handle alpha function change.\n *\n * @param {object} event The event fired when changing the function.\n */\n #onAlphaFuncChange = (event) => {\n const skip = typeof event.skipGenerate !== 'undefined' &&\n event.skipGenerate === true;\n if (!skip) {\n this.#needsDataUpdate = true;\n this.draw();\n }\n };\n\n /**\n * Set the current position.\n *\n * @param {Point} position The new position.\n * @param {Index} _index The new index.\n * @returns {boolean} True if the position was updated.\n */\n setCurrentPosition(position, _index) {\n return this.#viewController.setCurrentPosition(position);\n }\n\n /**\n * Clear the context.\n */\n clear() {\n // clear the context: reset the transform first\n // store the current transformation matrix\n this.#context.save();\n // use the identity matrix while clearing the canvas\n this.#context.setTransform(1, 0, 0, 1, 0, 0);\n this.#context.clearRect(0, 0, this.#canvas.width, this.#canvas.height);\n // restore the transform\n this.#context.restore();\n }\n\n} // ViewLayer class\n","import {Index} from '../math/index';\nimport {Point} from '../math/point';\nimport {Vector3D} from '../math/vector';\nimport {viewEventNames} from '../image/view';\nimport {ListenerHandler} from '../utils/listen';\nimport {logger} from '../utils/logger';\nimport {precisionRound} from '../utils/string';\nimport {ViewLayer} from './viewLayer';\nimport {DrawLayer} from './drawLayer';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Matrix33} from '../math/matrix';\nimport {Point2D, Point3D} from '../math/point';\nimport {Scalar2D, Scalar3D} from '../math/scalar';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get the layer div id.\n *\n * @param {string} groupDivId The layer group div id.\n * @param {number} layerIndex The layer index.\n * @returns {string} A string id.\n */\nexport function getLayerDivId(groupDivId, layerIndex) {\n return groupDivId + '-layer-' + layerIndex;\n}\n\n/**\n * Get the layer details from a div id.\n *\n * @param {string} idString The layer div id.\n * @returns {object} The layer details as {groupDivId, layerIndex, layerId}.\n */\nexport function getLayerDetailsFromLayerDivId(idString) {\n const split = idString.split('-layer-');\n if (split.length !== 2) {\n logger.warn('Not the expected layer div id format...');\n }\n return {\n groupDivId: split[0],\n layerIndex: split[1],\n layerId: idString,\n };\n}\n\n/**\n * Get the layer details from a mouse event.\n *\n * @param {object} event The event to get the layer div id from. Expecting\n * an event origininating from a canvas inside a layer HTML div\n * with the 'layer' class and id generated with `getLayerDivId`.\n * @returns {object} The layer details as {groupDivId, layerIndex, layerId}.\n */\nexport function getLayerDetailsFromEvent(event) {\n let res = null;\n // get the closest element from the event target and with the 'layer' class\n const layerDiv = event.target.closest('.layer');\n if (layerDiv && typeof layerDiv.id !== 'undefined') {\n res = getLayerDetailsFromLayerDivId(layerDiv.id);\n }\n return res;\n}\n\n/**\n * Get a scaled offset to adapt to new scale and such as the input center\n * stays at the same position.\n *\n * @param {Scalar2D} offset The previous offset as {x,y}.\n * @param {Scalar2D} scale The previous scale as {x,y}.\n * @param {Scalar2D} newScale The new scale as {x,y}.\n * @param {Scalar2D} center The scale center as {x,y}.\n * @returns {Scalar2D} The scaled offset as {x,y}.\n */\nexport function getScaledOffset(offset, scale, newScale, center) {\n // worldPoint = indexPoint / scale + offset\n //=> indexPoint = (worldPoint - offset ) * scale\n\n // plane center should stay the same:\n // indexCenter / newScale + newOffset =\n // indexCenter / oldScale + oldOffset\n //=> newOffset = indexCenter / oldScale + oldOffset -\n // indexCenter / newScale\n //=> newOffset = worldCenter - indexCenter / newScale\n const indexCenter = {\n x: (center.x - offset.x) * scale.x,\n y: (center.y - offset.y) * scale.y\n };\n return {\n x: center.x - (indexCenter.x / newScale.x),\n y: center.y - (indexCenter.y / newScale.y)\n };\n}\n\n/**\n * Layer group.\n *\n * - Display position: {x,y},\n * - Plane position: Index (access: get(i)),\n * - (world) Position: Point3D (access: getX, getY, getZ).\n *\n * Display -> World:\n * - planePos = viewLayer.displayToPlanePos(displayPos)\n * -> compensate for layer scale and offset,\n * - pos = viewController.getPositionFromPlanePoint(planePos).\n *\n * World -> Display:\n * - planePos = viewController.getOffset3DFromPlaneOffset(pos)\n * no need yet for a planePos to displayPos...\n */\nexport class LayerGroup {\n\n /**\n * The container div.\n *\n * @type {HTMLElement}\n */\n #containerDiv;\n\n // jsdoc does not like\n // @type {(ViewLayer|DrawLayer)[]}\n\n /**\n * List of layers.\n *\n * @type {Array}\n */\n #layers = [];\n\n /**\n * The layer scale as {x,y,z}.\n *\n * @type {Scalar3D}\n */\n #scale = {x: 1, y: 1, z: 1};\n\n /**\n * The base scale as {x,y,z}: all posterior scale will be on top of this one.\n *\n * @type {Scalar3D}\n */\n #baseScale = {x: 1, y: 1, z: 1};\n\n /**\n * The layer offset as {x,y,z}.\n *\n * @type {Scalar3D}\n */\n #offset = {x: 0, y: 0, z: 0};\n\n /**\n * Active view layer index.\n *\n * @type {number}\n */\n #activeViewLayerIndex = undefined;\n\n /**\n * Active draw layer index.\n *\n * @type {number}\n */\n #activeDrawLayerIndex = undefined;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Flag to activate crosshair or not.\n *\n * @type {boolean}\n */\n #showCrosshair = false;\n\n /**\n * Crosshair HTML elements.\n *\n * @type {HTMLElement[]}\n */\n #crosshairHtmlElements = [];\n\n /**\n * Tooltip HTML element.\n *\n * @type {HTMLElement}\n */\n #tooltipHtmlElement;\n\n /**\n * The current position used for the crosshair.\n *\n * @type {Point}\n */\n #currentPosition;\n\n /**\n * Image smoothing flag.\n *\n * @type {boolean}\n */\n #imageSmoothing = false;\n\n /**\n * @param {HTMLElement} containerDiv The associated HTML div.\n */\n constructor(containerDiv) {\n this.#containerDiv = containerDiv;\n }\n\n /**\n * Get the showCrosshair flag.\n *\n * @returns {boolean} True to display the crosshair.\n */\n getShowCrosshair() {\n return this.#showCrosshair;\n }\n\n /**\n * Set the showCrosshair flag.\n *\n * @param {boolean} flag True to display the crosshair.\n */\n setShowCrosshair(flag) {\n this.#showCrosshair = flag;\n if (flag) {\n // listen to offset and zoom change\n this.addEventListener('offsetchange', this.#updateCrosshairOnChange);\n this.addEventListener('zoomchange', this.#updateCrosshairOnChange);\n // show crosshair div\n this.#showCrosshairDiv();\n } else {\n // listen to offset and zoom change\n this.removeEventListener('offsetchange', this.#updateCrosshairOnChange);\n this.removeEventListener('zoomchange', this.#updateCrosshairOnChange);\n // remove crosshair div\n this.#removeCrosshairDiv();\n }\n }\n\n /**\n * Set the imageSmoothing flag value.\n *\n * @param {boolean} flag True to enable smoothing.\n */\n setImageSmoothing(flag) {\n this.#imageSmoothing = flag;\n // set for existing layers\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer) {\n layer.setImageSmoothing(flag);\n }\n }\n }\n\n /**\n * Update crosshair on offset or zoom change.\n *\n * @param {object} _event The change event.\n */\n #updateCrosshairOnChange = (_event) => {\n this.#showCrosshairDiv();\n };\n\n /**\n * Get the Id of the container div.\n *\n * @returns {string} The id of the div.\n */\n getDivId() {\n return this.#containerDiv.id;\n }\n\n /**\n * Get the layer scale.\n *\n * @returns {Scalar3D} The scale as {x,y,z}.\n */\n getScale() {\n return this.#scale;\n }\n\n /**\n * Get the base scale.\n *\n * @returns {Scalar3D} The scale as {x,y,z}.\n */\n getBaseScale() {\n return this.#baseScale;\n }\n\n\n /**\n * Get the added scale: the scale added to the base scale.\n *\n * @returns {Scalar3D} The scale as {x,y,z}.\n */\n getAddedScale() {\n return {\n x: this.#scale.x / this.#baseScale.x,\n y: this.#scale.y / this.#baseScale.y,\n z: this.#scale.z / this.#baseScale.z\n };\n }\n\n /**\n * Get the layer offset.\n *\n * @returns {Scalar3D} The offset as {x,y,z}.\n */\n getOffset() {\n return this.#offset;\n }\n\n /**\n * Get the number of layers handled by this class.\n *\n * @returns {number} The number of layers.\n */\n getNumberOfLayers() {\n let count = 0;\n this.#layers.forEach(item => {\n if (typeof item !== 'undefined') {\n count++;\n }\n });\n return count;\n }\n\n /**\n * Check if this layerGroup contains a layer with the input id.\n *\n * @param {string} id The layer id to look for.\n * @returns {boolean} True if this group contains\n * a layer with the input id.\n */\n includes(id) {\n if (typeof id === 'undefined') {\n return false;\n }\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined' &&\n layer.getId() === id) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get a list of view layers according to an input callback function.\n *\n * @param {Function} [callbackFn] A function that takes\n * a ViewLayer as input and returns a boolean. If undefined,\n * returns all view layers.\n * @returns {ViewLayer[]} The layers that\n * satisfy the callbackFn.\n */\n getViewLayers(callbackFn) {\n if (typeof callbackFn === 'undefined') {\n callbackFn = function () {\n return true;\n };\n }\n const res = [];\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer &&\n callbackFn(layer)) {\n res.push(layer);\n }\n }\n return res;\n }\n\n /**\n * Test if one of the view layers satisfies an input callbackFn.\n *\n * @param {Function} callbackFn A function that takes\n * a ViewLayer as input and returns a boolean.\n * @returns {boolean} True if one of the ViewLayers\n * satisfies the callbackFn.\n */\n someViewLayer(callbackFn) {\n let hasOne = false;\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer &&\n callbackFn(layer)) {\n hasOne = true;\n break;\n }\n }\n return hasOne;\n }\n\n /**\n * Get a list of draw layers according to an input callback function.\n *\n * @param {Function} [callbackFn] A function that takes\n * a DrawLayer as input and returns a boolean. If undefined,\n * returns all draw layers.\n * @returns {DrawLayer[]} The layers that\n * satisfy the callbackFn.\n */\n getDrawLayers(callbackFn) {\n if (typeof callbackFn === 'undefined') {\n callbackFn = function () {\n return true;\n };\n }\n const res = [];\n for (const layer of this.#layers) {\n if (layer instanceof DrawLayer &&\n callbackFn(layer)) {\n res.push(layer);\n }\n }\n return res;\n }\n\n /**\n * Get the number of view layers handled by this class.\n *\n * @returns {number} The number of layers.\n */\n getNumberOfViewLayers() {\n let count = 0;\n this.#layers.forEach(item => {\n if (typeof item !== 'undefined' &&\n item instanceof ViewLayer) {\n count++;\n }\n });\n return count;\n }\n\n /**\n * Get the active image layer.\n *\n * @returns {ViewLayer|undefined} The layer.\n */\n getActiveViewLayer() {\n let layer;\n if (typeof this.#activeViewLayerIndex !== 'undefined') {\n const tmpLayer = this.#layers[this.#activeViewLayerIndex];\n if (tmpLayer instanceof ViewLayer) {\n layer = tmpLayer;\n }\n }\n return layer;\n }\n\n /**\n * Get the base view layer.\n *\n * @returns {ViewLayer|undefined} The layer.\n */\n getBaseViewLayer() {\n // use first layer as base for calculating position and\n // line sizes\n let baseLayer;\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer) {\n baseLayer = layer;\n break;\n }\n }\n if (typeof baseLayer === 'undefined') {\n logger.warn('No layer found');\n return;\n }\n return baseLayer;\n }\n\n /**\n * Get the view layers associated to a data id.\n *\n * @param {string} dataId The data id.\n * @returns {ViewLayer[]} The layers.\n */\n getViewLayersByDataId(dataId) {\n const callbackFn = function (layer) {\n return layer.getDataId() === dataId;\n };\n return this.getViewLayers(callbackFn);\n }\n\n /**\n * Search view layers for equal imae meta data.\n *\n * @param {object} meta The meta data to find.\n * @returns {ViewLayer[]} The list of view layers that contain matched data.\n */\n searchViewLayers(meta) {\n const res = [];\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer) {\n if (layer.getViewController().equalImageMeta(meta)) {\n res.push(layer);\n }\n }\n }\n return res;\n }\n\n /**\n * Get the view layers data indices.\n *\n * @returns {string[]} The list of indices.\n */\n getViewDataIndices() {\n const res = [];\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer) {\n res.push(layer.getDataId());\n }\n }\n return res;\n }\n\n /**\n * Get the active draw layer.\n *\n * @returns {DrawLayer|undefined} The layer.\n */\n getActiveDrawLayer() {\n let layer;\n if (typeof this.#activeDrawLayerIndex !== 'undefined') {\n const tmpLayer = this.#layers[this.#activeDrawLayerIndex];\n if (tmpLayer instanceof DrawLayer) {\n layer = tmpLayer;\n }\n }\n return layer;\n }\n\n /**\n * Get the draw layers associated to a data id.\n *\n * @param {string} dataId The data id.\n * @returns {DrawLayer[]} The layers.\n */\n getDrawLayersByDataId(dataId) {\n const callbackFn = function (layer) {\n return layer.getDataId() === dataId;\n };\n return this.getDrawLayers(callbackFn);\n }\n\n /**\n * Set the active view layer.\n *\n * @param {number} index The index of the layer to set as active.\n */\n setActiveViewLayer(index) {\n if (this.#layers[index] instanceof ViewLayer) {\n this.#activeViewLayerIndex = index;\n /**\n * Active layer change event.\n *\n * @event LayerGroup#activelayerchange\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} value The changed value.\n */\n this.#fireEvent({\n type: 'activelayerchange',\n value: [this.#layers[index]]\n });\n } else {\n logger.warn('No view layer to set as active with index: ' +\n index);\n }\n }\n\n /**\n * Set the active view layer with a data id.\n *\n * @param {string} dataId The data id.\n */\n setActiveViewLayerByDataId(dataId) {\n let index;\n for (let i = 0; i < this.#layers.length; ++i) {\n if (this.#layers[i] instanceof ViewLayer &&\n this.#layers[i].getDataId() === dataId) {\n // stop at first one\n index = i;\n break;\n }\n }\n if (typeof index !== 'undefined') {\n this.setActiveViewLayer(index);\n } else {\n logger.warn('No view layer to set as active with dataId: ' +\n dataId);\n }\n }\n\n /**\n * Set the active draw layer.\n *\n * @param {number|undefined} index The index of the layer to set as active\n * or undefined to not set any.\n */\n setActiveDrawLayer(index) {\n this.#activeDrawLayerIndex = index;\n this.#fireEvent({\n type: 'activelayerchange',\n value: [this.#layers[index]]\n });\n }\n\n /**\n * Set the active draw layer with a data id.\n *\n * @param {string} dataId The data id.\n */\n setActiveDrawLayerByDataId(dataId) {\n let index;\n for (let i = 0; i < this.#layers.length; ++i) {\n if (this.#layers[i] instanceof DrawLayer &&\n this.#layers[i].getDataId() === dataId) {\n // stop at first one\n index = i;\n break;\n }\n }\n if (typeof index !== 'undefined') {\n this.setActiveDrawLayer(index);\n } else {\n logger.warn('No draw layer to set as active with dataId: ' +\n dataId);\n }\n }\n\n /**\n * Add a view layer.\n *\n * The new layer will be marked as the active view layer.\n *\n * @returns {ViewLayer} The created layer.\n */\n addViewLayer() {\n // layer index\n const viewLayerIndex = this.#layers.length;\n // create div\n const div = this.#getNextLayerDiv();\n // prepend to container\n this.#containerDiv.append(div);\n // view layer\n const layer = new ViewLayer(div);\n layer.setImageSmoothing(this.#imageSmoothing);\n // add layer\n this.#layers.push(layer);\n // mark it as active\n this.setActiveViewLayer(viewLayerIndex);\n // bind view layer events\n this.#bindViewLayer(layer);\n // return\n return layer;\n }\n\n /**\n * Add a draw layer.\n *\n * The new layer will be marked as the active draw layer.\n *\n * @returns {DrawLayer} The created layer.\n */\n addDrawLayer() {\n // store active index\n this.#activeDrawLayerIndex = this.#layers.length;\n // create div\n const div = this.#getNextLayerDiv();\n // prepend to container\n this.#containerDiv.append(div);\n // draw layer\n const layer = new DrawLayer(div);\n // add layer\n this.#layers.push(layer);\n // bind draw layer events\n this.#bindDrawLayer(layer);\n // return\n return layer;\n }\n\n /**\n * Bind view layer events to this.\n *\n * @param {ViewLayer} viewLayer The view layer to bind.\n */\n #bindViewLayer(viewLayer) {\n // listen to position change to update other group layers\n viewLayer.addEventListener(\n 'positionchange', this.updateLayersToPositionChange);\n // propagate view viewLayer-layer events\n for (const eventName of viewEventNames) {\n viewLayer.addEventListener(eventName, this.#fireEvent);\n }\n // propagate viewLayer events\n viewLayer.addEventListener('renderstart', this.#fireEvent);\n viewLayer.addEventListener('renderend', this.#fireEvent);\n }\n\n /**\n * Un-bind a view layer events to this.\n *\n * @param {ViewLayer} viewLayer The view layer to unbind.\n */\n #unbindViewLayer(viewLayer) {\n // stop listening to position change to update other group layers\n viewLayer.removeEventListener(\n 'positionchange', this.updateLayersToPositionChange);\n // stop propagating view viewLayer-layer events\n for (const eventName of viewEventNames) {\n viewLayer.removeEventListener(eventName, this.#fireEvent);\n }\n // stop propagating viewLayer events\n viewLayer.removeEventListener('renderstart', this.#fireEvent);\n viewLayer.removeEventListener('renderend', this.#fireEvent);\n\n // stop view layer - image binding\n // (binding is done in layer.setView)\n viewLayer.unbindImage();\n }\n\n /**\n * Bind draw layer events to this.\n *\n * @param {DrawLayer} drawLayer The draw layer to bind.\n */\n #bindDrawLayer(drawLayer) {\n // listen to position change to update other group layers\n drawLayer.addEventListener(\n 'positionchange', this.updateLayersToPositionChange);\n drawLayer.addEventListener(\n 'positionchange', this.#fireEvent);\n // propagate drawLayer events\n drawLayer.addEventListener('drawcreate', this.#fireEvent);\n drawLayer.addEventListener('drawdelete', this.#fireEvent);\n }\n\n /**\n * Un-bind a draw layer events to this.\n *\n * @param {DrawLayer} drawLayer The draw layer to unbind.\n */\n #unbindDrawLayer(drawLayer) {\n // stop listening to position change to update other group layers\n drawLayer.removeEventListener(\n 'positionchange', this.updateLayersToPositionChange);\n drawLayer.removeEventListener(\n 'positionchange', this.#fireEvent);\n // propagate drawLayer events\n drawLayer.removeEventListener('drawcreate', this.#fireEvent);\n drawLayer.removeEventListener('drawdelete', this.#fireEvent);\n }\n\n /**\n * Get the next layer DOM div.\n *\n * @returns {HTMLDivElement} A DOM div.\n */\n #getNextLayerDiv() {\n const div = document.createElement('div');\n div.id = getLayerDivId(this.getDivId(), this.#layers.length);\n div.className = 'layer';\n div.style.pointerEvents = 'none';\n return div;\n }\n\n /**\n * Empty the layer list.\n */\n empty() {\n this.#layers = [];\n // reset active indices\n this.#activeViewLayerIndex = undefined;\n this.#activeDrawLayerIndex = undefined;\n // remove possible crosshair\n this.#removeCrosshairDiv();\n // clean container div\n const previous = this.#containerDiv.getElementsByClassName('layer');\n if (previous) {\n while (previous.length > 0) {\n previous[0].remove();\n }\n }\n }\n\n /**\n * Remove all layers for a specific data.\n *\n * @param {string} dataId The data to remove its layers.\n */\n removeLayersByDataId(dataId) {\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined' &&\n layer.getDataId() === dataId) {\n this.removeLayer(layer);\n }\n }\n }\n\n /**\n * Remove a layer from this layer group.\n * Warning: if current active layer, the index will\n * be set to `undefined`. Call one of the setActive\n * methods to define the active index.\n *\n * @param {ViewLayer | DrawLayer} layer The layer to remove.\n */\n removeLayer(layer) {\n // find layer\n const index = this.#layers.findIndex((item) => item === layer);\n if (index === -1) {\n throw new Error('Cannot find layer to remove');\n }\n // unbind and update active index\n if (layer instanceof ViewLayer) {\n this.#unbindViewLayer(layer);\n if (this.#activeViewLayerIndex === index) {\n this.#activeViewLayerIndex = undefined;\n }\n } else {\n this.#unbindDrawLayer(layer);\n if (this.#activeDrawLayerIndex === index) {\n this.#activeDrawLayerIndex = undefined;\n }\n }\n // reset in storage\n this.#layers[index] = undefined;\n // update html\n layer.removeFromDOM();\n }\n\n /**\n * Show a crosshair at a given position.\n *\n * @param {Point} [position] The position where to show the crosshair,\n * defaults to current position.\n */\n #showCrosshairDiv(position) {\n if (typeof position === 'undefined') {\n position = this.#currentPosition;\n }\n\n // remove previous\n this.#removeCrosshairDiv();\n\n // use first layer as base for calculating position and\n // line sizes\n let baseLayer;\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer) {\n baseLayer = layer;\n break;\n }\n }\n if (typeof baseLayer === 'undefined') {\n logger.warn('No layer to show crosshair');\n return;\n }\n\n const vc = baseLayer.getViewController();\n const planePos = vc.getPlanePositionFromPosition(position);\n const displayPos = baseLayer.planePosToDisplay(planePos);\n\n // horizontal line\n if (typeof displayPos.getY() !== 'undefined') {\n const lineH = document.createElement('hr');\n lineH.id = this.getDivId() + '-scroll-crosshair-horizontal';\n lineH.className = 'horizontal';\n lineH.style.width = this.#containerDiv.offsetWidth + 'px';\n lineH.style.left = '0px';\n lineH.style.top = displayPos.getY() + 'px';\n // add to local array\n this.#crosshairHtmlElements.push(lineH);\n // add to html\n this.#containerDiv.appendChild(lineH);\n }\n\n // vertical line\n if (typeof displayPos.getX() !== 'undefined') {\n const lineV = document.createElement('hr');\n lineV.id = this.getDivId() + '-scroll-crosshair-vertical';\n lineV.className = 'vertical';\n lineV.style.width = this.#containerDiv.offsetHeight + 'px';\n lineV.style.left = (displayPos.getX()) + 'px';\n lineV.style.top = '0px';\n // add to local array\n this.#crosshairHtmlElements.push(lineV);\n // add to html\n this.#containerDiv.appendChild(lineV);\n }\n }\n\n /**\n * Remove crosshair divs.\n */\n #removeCrosshairDiv() {\n for (const element of this.#crosshairHtmlElements) {\n element.remove();\n }\n this.#crosshairHtmlElements = [];\n }\n\n /**\n * Displays a tooltip in a temporary `span`.\n * Works with css to hide/show the span only on mouse hover.\n *\n * @param {Point2D} point The update point.\n */\n showTooltip(point) {\n // remove previous div\n this.removeTooltipDiv();\n\n const viewLayer = this.getActiveViewLayer();\n const viewController = viewLayer.getViewController();\n const planePos = viewLayer.displayToPlanePos(point);\n const position = viewController.getPositionFromPlanePoint(planePos);\n const value = viewController.getRescaledImageValue(position);\n\n // create\n if (typeof value !== 'undefined') {\n const span = document.createElement('span');\n span.id = 'scroll-tooltip';\n // tooltip position\n span.style.left = (point.getX() + 10) + 'px';\n span.style.top = (point.getY() + 10) + 'px';\n let text = precisionRound(value, 3).toString();\n if (typeof viewController.getPixelUnit() !== 'undefined') {\n text += ' ' + viewController.getPixelUnit();\n }\n span.appendChild(document.createTextNode(text));\n // add to local var\n this.#tooltipHtmlElement = span;\n // add to html\n this.#containerDiv.appendChild(span);\n }\n }\n\n /**\n * Remove the tooltip html div.\n */\n removeTooltipDiv() {\n if (typeof this.#tooltipHtmlElement !== 'undefined') {\n this.#tooltipHtmlElement.remove();\n this.#tooltipHtmlElement = undefined;\n }\n }\n\n /**\n * Can the input position be set on one of the view layers.\n *\n * @param {Point} position The input position.\n * @returns {boolean} True if one view layer accepts the input position.\n */\n isPositionInBounds(position) {\n return this.someViewLayer(function (layer) {\n return layer.getViewController().isPositionInBounds(position);\n });\n }\n\n /**\n * Can one of the view layers be scrolled.\n *\n * @returns {boolean} True if one view layer can be scrolled.\n */\n canScroll() {\n return this.someViewLayer(function (layer) {\n return layer.getViewController().canScroll();\n });\n }\n\n /**\n * Does one of the view layer have more than one slice in the\n * given dimension.\n *\n * @param {number} dim The input dimension.\n * @returns {boolean} True if one view layer has more than one slice.\n */\n moreThanOne(dim) {\n return this.someViewLayer(function (layer) {\n return layer.getViewController().moreThanOne(dim);\n });\n }\n\n /**\n * Update layers (but not the active view layer) to a position change.\n *\n * @param {object} event The position change event.\n * @function\n */\n updateLayersToPositionChange = (event) => {\n // pause positionchange listeners\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.removeEventListener(\n 'positionchange', this.updateLayersToPositionChange);\n layer.removeEventListener('positionchange', this.#fireEvent);\n }\n }\n\n const index = new Index(event.value[0]);\n const position = new Point(event.value[1]);\n\n // store current position\n this.#currentPosition = position;\n\n if (this.#showCrosshair) {\n this.#showCrosshairDiv(position);\n }\n\n // origin of the first view layer\n const viewLayerOffsets = {};\n let baseViewLayerOrigin0;\n let baseViewLayerOrigin;\n // update position for all layers except the source one\n for (const layer of this.#layers) {\n if (typeof layer === 'undefined') {\n continue;\n }\n let hasSetOffset = false;\n\n // view layer case: define and set offsets\n if (layer instanceof ViewLayer) {\n const vc = layer.getViewController();\n // origin0 should always be there\n const origin0 = vc.getOrigin();\n // depending on position, origin could be undefined\n const origin = vc.getOrigin(position);\n\n let scrollOffset;\n let planeOffset;\n\n if (typeof baseViewLayerOrigin === 'undefined') {\n // first view layer, store origins\n baseViewLayerOrigin0 = origin0;\n baseViewLayerOrigin = origin;\n // no offset\n scrollOffset = new Vector3D(0, 0, 0);\n planeOffset = new Vector3D(0, 0, 0);\n } else {\n if (vc.isPositionInBounds(position) &&\n typeof origin !== 'undefined') {\n // TODO: compensate for possible different orientation between views\n const scrollDiff = baseViewLayerOrigin0.minus(origin0);\n scrollOffset = new Vector3D(\n scrollDiff.getX(), scrollDiff.getY(), scrollDiff.getZ());\n const planeDiff = baseViewLayerOrigin.minus(origin);\n planeOffset = new Vector3D(\n planeDiff.getX(), planeDiff.getY(), planeDiff.getZ());\n }\n }\n\n // set and store offsets\n if (typeof scrollOffset !== 'undefined' &&\n typeof planeOffset !== 'undefined') {\n hasSetOffset =\n layer.setBaseOffset(\n scrollOffset, planeOffset,\n baseViewLayerOrigin, baseViewLayerOrigin0\n );\n // store\n viewLayerOffsets[layer.getId()] = {\n scroll: scrollOffset,\n plane: planeOffset\n };\n }\n }\n\n // draw layer case: use associated view layer offsets\n if (layer instanceof DrawLayer) {\n const refOffsets = viewLayerOffsets[layer.getReferenceLayerId()];\n if (typeof refOffsets !== 'undefined') {\n hasSetOffset =\n layer.setBaseOffset(refOffsets.scroll, refOffsets.plane);\n }\n }\n\n // update position (triggers redraw)\n let hasSetPos = false;\n if (layer.getId() !== event.srclayerid) {\n hasSetPos = layer.setCurrentPosition(position, index);\n }\n\n // force redraw if needed\n if (!hasSetPos && hasSetOffset) {\n layer.draw();\n }\n }\n\n // re-start positionchange listeners\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.addEventListener(\n 'positionchange', this.updateLayersToPositionChange);\n layer.addEventListener('positionchange', this.#fireEvent);\n }\n }\n };\n\n /**\n * Calculate the div to world size ratio needed to fit\n * the largest data.\n *\n * @returns {number|undefined} The ratio.\n */\n getDivToWorldSizeRatio() {\n // check container\n if (this.#containerDiv.offsetWidth === 0 &&\n this.#containerDiv.offsetHeight === 0) {\n throw new Error('Cannot fit to zero sized container.');\n }\n // get max world size\n const maxWorldSize = this.getMaxWorldSize();\n if (typeof maxWorldSize === 'undefined') {\n return undefined;\n }\n // if the container has a width but no height,\n // resize it to follow the same ratio to completely\n // fill the div with the image\n if (this.#containerDiv.offsetHeight === 0) {\n const ratioX = this.#containerDiv.offsetWidth / maxWorldSize.x;\n const height = maxWorldSize.y * ratioX;\n this.#containerDiv.style.height = height + 'px';\n }\n // return best fit\n return Math.min(\n this.#containerDiv.offsetWidth / maxWorldSize.x,\n this.#containerDiv.offsetHeight / maxWorldSize.y\n );\n }\n\n /**\n * Fit to container: set the layers div to world size ratio.\n *\n * @param {number} divToWorldSizeRatio The ratio.\n */\n fitToContainer(divToWorldSizeRatio) {\n // get maximum world size\n const maxWorldSize = this.getMaxWorldSize();\n // exit if none\n if (typeof maxWorldSize === 'undefined') {\n return;\n }\n\n const containerSize = {\n x: this.#containerDiv.offsetWidth,\n y: this.#containerDiv.offsetHeight\n };\n // offset to keep data centered\n const fitOffset = {\n x: -0.5 *\n (containerSize.x - Math.floor(maxWorldSize.x * divToWorldSizeRatio)),\n y: -0.5 *\n (containerSize.y - Math.floor(maxWorldSize.y * divToWorldSizeRatio))\n };\n\n // apply to layers\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.fitToContainer(containerSize, divToWorldSizeRatio, fitOffset);\n }\n }\n\n // update crosshair\n if (this.#showCrosshair) {\n this.#showCrosshairDiv();\n }\n }\n\n /**\n * Get the largest data world (mm) size.\n *\n * @returns {Scalar2D|undefined} The largest size as {x,y}.\n */\n getMaxWorldSize() {\n let maxSize = {x: 0, y: 0};\n for (const layer of this.#layers) {\n if (layer instanceof ViewLayer) {\n const size = layer.getImageWorldSize();\n if (size.x > maxSize.x) {\n maxSize.x = size.x;\n }\n if (size.y > maxSize.y) {\n maxSize.y = size.y;\n }\n }\n }\n if (maxSize.x === 0 && maxSize.y === 0) {\n maxSize = undefined;\n }\n return maxSize;\n }\n\n /**\n * Flip all layers along the Z axis without offset compensation.\n */\n flipScaleZ() {\n this.#baseScale.z *= -1;\n this.setScale(this.#baseScale);\n }\n\n /**\n * Add scale to the layers. Scale cannot go lower than 0.1.\n *\n * @param {number} scaleStep The scale to add.\n * @param {Point3D} center The scale center Point3D.\n */\n addScale(scaleStep, center) {\n const newScale = {\n x: this.#scale.x * (1 + scaleStep),\n y: this.#scale.y * (1 + scaleStep),\n z: this.#scale.z * (1 + scaleStep)\n };\n this.setScale(newScale, center);\n }\n\n /**\n * Set the layers' scale.\n *\n * @param {Scalar3D} newScale The scale to apply as {x,y,z}.\n * @param {Point3D} [center] The scale center Point3D.\n * @fires LayerGroup#zoomchange\n */\n setScale(newScale, center) {\n this.#scale = newScale;\n // apply to layers\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.setScale(this.#scale, center);\n }\n }\n\n // event value\n const value = [\n newScale.x,\n newScale.y,\n newScale.z\n ];\n if (typeof center !== 'undefined') {\n value.push(center.getX());\n value.push(center.getY());\n value.push(center.getZ());\n }\n\n /**\n * Zoom change event.\n *\n * @event LayerGroup#zoomchange\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} value The changed value.\n */\n this.#fireEvent({\n type: 'zoomchange',\n value: value\n });\n }\n\n /**\n * Add translation to the layers.\n *\n * @param {Scalar3D} translation The translation as {x,y,z}.\n */\n addTranslation(translation) {\n this.setOffset({\n x: this.#offset.x - translation.x,\n y: this.#offset.y - translation.y,\n z: this.#offset.z - translation.z\n });\n }\n\n /**\n * Set the layers' offset.\n *\n * @param {Scalar3D} newOffset The offset as {x,y,z}.\n * @fires LayerGroup#offsetchange\n */\n setOffset(newOffset) {\n // store\n this.#offset = newOffset;\n // apply to layers\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.setOffset(this.#offset);\n }\n }\n\n /**\n * Offset change event.\n *\n * @event LayerGroup#offsetchange\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} value The changed value.\n */\n this.#fireEvent({\n type: 'offsetchange',\n value: [\n this.#offset.x,\n this.#offset.y,\n this.#offset.z\n ]\n });\n }\n\n /**\n * Reset the stage to its initial scale and no offset.\n */\n reset() {\n this.setScale(this.#baseScale);\n this.setOffset({x: 0, y: 0, z: 0});\n }\n\n /**\n * Draw the layer.\n */\n draw() {\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.draw();\n }\n }\n }\n\n /**\n * Display the layer.\n *\n * @param {boolean} flag Whether to display the layer or not.\n */\n display(flag) {\n for (const layer of this.#layers) {\n if (typeof layer !== 'undefined') {\n layer.display(flag);\n }\n }\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n} // LayerGroup class\n","import {Point, Point3D} from '../math/point';\nimport {WindowLevel} from '../image/windowLevel';\nimport {LayerGroup} from './layerGroup';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {ViewLayer} from '../gui/viewLayer';\nimport {DrawLayer} from '../gui/drawLayer';\n/* eslint-enable no-unused-vars */\n\n/**\n * Window/level binder.\n */\nexport class WindowLevelBinder {\n getEventType = function () {\n return 'wlchange';\n };\n getCallback = function (layerGroup) {\n return function (event) {\n const viewLayers = layerGroup.getViewLayersByDataId(event.dataid);\n if (viewLayers.length !== 0) {\n const vc = viewLayers[0].getViewController();\n if (event.value.length === 2) {\n const wl = new WindowLevel(event.value[0], event.value[1]);\n vc.setWindowLevel(wl);\n }\n if (event.value.length === 3) {\n vc.setWindowLevelPreset(event.value[2]);\n }\n }\n };\n };\n}\n\n/**\n * Colour map binder.\n */\nexport class ColourMapBinder {\n getEventType = function () {\n return 'colourmapchange';\n };\n getCallback = function (layerGroup) {\n return function (event) {\n const viewLayers = layerGroup.getViewLayersByDataId(event.dataid);\n if (viewLayers.length !== 0) {\n const vc = viewLayers[0].getViewController();\n vc.setColourMap(event.value[0]);\n }\n };\n };\n}\n\n/**\n * Position binder.\n */\nexport class PositionBinder {\n getEventType = function () {\n return 'positionchange';\n };\n getCallback = function (layerGroup) {\n return function (event) {\n const pointValues = event.value[1];\n const vc = layerGroup.getActiveViewLayer().getViewController();\n // handle different number of dimensions\n const currentPos = vc.getCurrentPosition();\n const currentDims = currentPos.length();\n const inputDims = pointValues.length;\n if (inputDims !== currentDims) {\n if (inputDims === currentDims - 1) {\n // add missing dim, for ex: input 3D -> current 4D\n pointValues.push(currentPos.get(currentDims - 1));\n } else if (inputDims === currentDims + 1) {\n // remove extra dim, for ex: input 4D -> current 3D\n pointValues.pop();\n }\n }\n vc.setCurrentPosition(new Point(pointValues));\n };\n };\n}\n\n/**\n * Zoom binder.\n */\nexport class ZoomBinder {\n getEventType = function () {\n return 'zoomchange';\n };\n getCallback = function (layerGroup) {\n return function (event) {\n const scale = {\n x: event.value[0],\n y: event.value[1],\n z: event.value[2]\n };\n let center;\n if (event.value.length === 6) {\n center = new Point3D(\n event.value[3],\n event.value[4],\n event.value[5]\n );\n }\n layerGroup.setScale(scale, center);\n layerGroup.draw();\n };\n };\n}\n\n/**\n * Offset binder.\n */\nexport class OffsetBinder {\n getEventType = function () {\n return 'offsetchange';\n };\n getCallback = function (layerGroup) {\n return function (event) {\n layerGroup.setOffset({\n x: event.value[0],\n y: event.value[1],\n z: event.value[2]\n });\n layerGroup.draw();\n };\n };\n}\n\n/**\n * Opacity binder. Only propagates to view layers of the same data.\n */\nexport class OpacityBinder {\n getEventType = function () {\n return 'opacitychange';\n };\n getCallback = function (layerGroup) {\n return function (event) {\n // exit if no data id\n if (typeof event.dataid === 'undefined') {\n return;\n }\n // propagate to first view layer if it is not base layer\n const viewLayers = layerGroup.getViewLayersByDataId(event.dataid);\n const baseLayer = layerGroup.getBaseViewLayer();\n if (viewLayers.length !== 0 && baseLayer !== viewLayers[0]) {\n viewLayers[0].setOpacity(event.value);\n viewLayers[0].draw();\n }\n };\n };\n}\n\n/**\n * List of binders.\n */\nexport const binderList = {\n WindowLevelBinder,\n PositionBinder,\n ZoomBinder,\n OffsetBinder,\n OpacityBinder,\n ColourMapBinder\n};\n\n/**\n * Stage: controls a list of layer groups and their\n * synchronisation.\n */\nexport class Stage {\n\n /**\n * Associated layer groups.\n *\n * @type {LayerGroup[]}\n */\n #layerGroups = [];\n\n /**\n * Active layer group index.\n *\n * @type {number|undefined}\n */\n #activeLayerGroupIndex;\n\n /**\n * Image smoothing flag.\n *\n * @type {boolean}\n */\n #imageSmoothing = false;\n\n // layer group binders\n #binders = [];\n // binder callbacks\n #callbackStore = null;\n\n /**\n * Get the layer group at the given index.\n *\n * @param {number} index The index.\n * @returns {LayerGroup|undefined} The layer group.\n */\n getLayerGroup(index) {\n return this.#layerGroups[index];\n }\n\n /**\n * Get the number of layer groups that form the stage.\n *\n * @returns {number} The number of layer groups.\n */\n getNumberOfLayerGroups() {\n return this.#layerGroups.length;\n }\n\n /**\n * Get the active layer group.\n *\n * @returns {LayerGroup|undefined} The layer group.\n */\n getActiveLayerGroup() {\n return this.getLayerGroup(this.#activeLayerGroupIndex);\n }\n\n /**\n * Set the active layer group.\n *\n * @param {number} index The layer group index.\n */\n setActiveLayerGroup(index) {\n if (typeof this.getLayerGroup(index) !== 'undefined') {\n this.#activeLayerGroupIndex = index;\n } else {\n logger.warn('No layer group to set as active with index: ' +\n index);\n }\n }\n\n /**\n * Get the view layers associated to a data id.\n *\n * @param {string} dataId The data id.\n * @returns {ViewLayer[]} The layers.\n */\n getViewLayersByDataId(dataId) {\n let res = [];\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n res = res.concat(this.#layerGroups[i].getViewLayersByDataId(dataId));\n }\n return res;\n }\n\n /**\n * Get a list of view layers according to an input callback function.\n *\n * @param {Function} [callbackFn] A function that takes\n * a ViewLayer as input and returns a boolean. If undefined,\n * returns all view layers.\n * @returns {ViewLayer[]} The layers that\n * satisfy the callbackFn.\n */\n getViewLayers(callbackFn) {\n let res = [];\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n res = res.concat(this.#layerGroups[i].getViewLayers(callbackFn));\n }\n return res;\n }\n\n /**\n * Get the draw layers associated to a data id.\n *\n * @param {string} dataId The data id.\n * @returns {DrawLayer[]} The layers.\n */\n getDrawLayersByDataId(dataId) {\n let res = [];\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n res = res.concat(this.#layerGroups[i].getDrawLayersByDataId(dataId));\n }\n return res;\n }\n\n /**\n * Get a list of draw layers according to an input callback function.\n *\n * @param {Function} [callbackFn] A function that takes\n * a DrawLayer as input and returns a boolean. If undefined,\n * returns all draw layers.\n * @returns {DrawLayer[]} The layers that\n * satisfy the callbackFn.\n */\n getDrawLayers(callbackFn) {\n let res = [];\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n res = res.concat(this.#layerGroups[i].getDrawLayers(callbackFn));\n }\n return res;\n }\n\n /**\n * Add a layer group to the list.\n *\n * The new layer group will be marked as the active layer group.\n *\n * @param {object} htmlElement The HTML element of the layer group.\n * @returns {LayerGroup} The newly created layer group.\n */\n addLayerGroup(htmlElement) {\n this.#activeLayerGroupIndex = this.#layerGroups.length;\n const layerGroup = new LayerGroup(htmlElement);\n layerGroup.setImageSmoothing(this.#imageSmoothing);\n // add to storage\n const isBound = this.#callbackStore && this.#callbackStore.length !== 0;\n if (isBound) {\n this.unbindLayerGroups();\n }\n this.#layerGroups.push(layerGroup);\n if (isBound) {\n this.bindLayerGroups();\n }\n // return created group\n return layerGroup;\n }\n\n /**\n * Get a layer group from an HTML element id.\n *\n * @param {string} id The element id to find.\n * @returns {LayerGroup} The layer group.\n */\n getLayerGroupByDivId(id) {\n return this.#layerGroups.find(function (item) {\n return item.getDivId() === id;\n });\n }\n\n /**\n * Set the layer groups binders.\n *\n * @param {Array} list The list of binder objects.\n */\n setBinders(list) {\n if (typeof list === 'undefined' || list === null) {\n throw new Error('Cannot set null or undefined binders');\n }\n if (this.#binders.length !== 0) {\n this.unbindLayerGroups();\n }\n this.#binders = list.slice();\n this.bindLayerGroups();\n }\n\n /**\n * Empty the layer group list.\n */\n empty() {\n this.unbindLayerGroups();\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n this.#layerGroups[i].empty();\n }\n this.#layerGroups = [];\n this.#activeLayerGroupIndex = undefined;\n }\n\n /**\n * Remove all layers for a specific data.\n *\n * @param {string} dataId The data to remove its layers.\n */\n removeLayersByDataId(dataId) {\n for (const layerGroup of this.#layerGroups) {\n layerGroup.removeLayersByDataId(dataId);\n }\n }\n\n /**\n * Remove a layer group from this stage.\n *\n * @param {LayerGroup} layerGroup The layer group to remove.\n */\n removeLayerGroup(layerGroup) {\n // find layer\n const index = this.#layerGroups.findIndex((item) => item === layerGroup);\n if (index === -1) {\n throw new Error('Cannot find layerGroup to remove');\n }\n // unbind\n this.unbindLayerGroups();\n // empty layer group\n layerGroup.empty();\n // remove from storage\n this.#layerGroups.splice(index, 1);\n // update active index\n if (this.#activeLayerGroupIndex === index) {\n this.#activeLayerGroupIndex = undefined;\n }\n // bind\n this.bindLayerGroups();\n }\n\n /**\n * Reset the stage: calls reset on all layer groups.\n */\n reset() {\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n this.#layerGroups[i].reset();\n }\n }\n\n /**\n * Draw the stage: calls draw on all layer groups.\n */\n draw() {\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n this.#layerGroups[i].draw();\n }\n }\n\n /**\n * Fit to container: synchronise the div to world size ratio\n * of the group layers.\n */\n fitToContainer() {\n // find the minimum ratio\n let minRatio;\n const hasRatio = [];\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n const ratio = this.#layerGroups[i].getDivToWorldSizeRatio();\n if (typeof ratio !== 'undefined') {\n hasRatio.push(i);\n if (typeof minRatio === 'undefined' || ratio < minRatio) {\n minRatio = ratio;\n }\n }\n }\n // exit if no ratio\n if (typeof minRatio === 'undefined') {\n return;\n }\n // apply min ratio to layers\n for (let j = 0; j < this.#layerGroups.length; ++j) {\n if (hasRatio.includes(j)) {\n this.#layerGroups[j].fitToContainer(minRatio);\n }\n }\n }\n\n /**\n * Bind the layer groups of the stage.\n */\n bindLayerGroups() {\n if (this.#layerGroups.length === 0 ||\n this.#layerGroups.length === 1 ||\n this.#binders.length === 0) {\n return;\n }\n // create callback store\n this.#callbackStore = new Array(this.#layerGroups.length);\n // add listeners\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n for (let j = 0; j < this.#binders.length; ++j) {\n this.#addEventListeners(i, this.#binders[j]);\n }\n }\n }\n\n /**\n * Unbind the layer groups of the stage.\n */\n unbindLayerGroups() {\n if (this.#layerGroups.length === 0 ||\n this.#layerGroups.length === 1 ||\n this.#binders.length === 0 ||\n !this.#callbackStore) {\n return;\n }\n // remove listeners\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n for (let j = 0; j < this.#binders.length; ++j) {\n this.#removeEventListeners(i, this.#binders[j]);\n }\n }\n // clear callback store\n this.#callbackStore = null;\n }\n\n /**\n * Set the imageSmoothing flag value.\n *\n * @param {boolean} flag True to enable smoothing.\n */\n setImageSmoothing(flag) {\n this.#imageSmoothing = flag;\n // set for existing layer groups\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n this.#layerGroups[i].setImageSmoothing(flag);\n }\n }\n\n /**\n * Get the binder callback function for a given layer group index.\n * The function is created if not yet stored.\n *\n * @param {object} binder The layer binder.\n * @param {number} index The index of the associated layer group.\n * @returns {Function} The binder function.\n */\n #getBinderCallback(binder, index) {\n if (typeof this.#callbackStore[index] === 'undefined') {\n this.#callbackStore[index] = [];\n }\n const store = this.#callbackStore[index];\n let binderObj = store.find(function (elem) {\n return elem.binder === binder;\n });\n if (typeof binderObj === 'undefined') {\n // create new callback object\n binderObj = {\n binder: binder,\n callback: (event) => {\n // stop listeners\n this.#removeEventListeners(index, binder);\n // apply binder\n binder.getCallback(this.#layerGroups[index])(event);\n // re-start listeners\n this.#addEventListeners(index, binder);\n }\n };\n this.#callbackStore[index].push(binderObj);\n }\n return binderObj.callback;\n }\n\n /**\n * Add event listeners for a given layer group index and binder.\n *\n * @param {number} index The index of the associated layer group.\n * @param {object} binder The layer binder.\n */\n #addEventListeners(index, binder) {\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n if (i !== index) {\n this.#layerGroups[index].addEventListener(\n binder.getEventType(),\n this.#getBinderCallback(binder, i)\n );\n }\n }\n }\n\n /**\n * Remove event listeners for a given layer group index and binder.\n *\n * @param {number} index The index of the associated layer group.\n * @param {object} binder The layer binder.\n */\n #removeEventListeners(index, binder) {\n for (let i = 0; i < this.#layerGroups.length; ++i) {\n if (i !== index) {\n this.#layerGroups[index].removeEventListener(\n binder.getEventType(),\n this.#getBinderCallback(binder, i)\n );\n }\n }\n }\n\n} // class Stage\n","import {Index} from '../math/index';\nimport {colourNameToHex} from '../utils/colour';\nimport {WindowLevel} from '../image/windowLevel';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * State class.\n * Saves: data url/path, display info.\n *\n * History:\n * - v0.5 (dwv 0.30.0, 12/2021):\n * - store position as array,\n * - new draw position group key.\n * - v0.4 (dwv 0.29.0, 06/2021):\n * - move drawing details into meta property,\n * - remove scale center and translation, add offset.\n * - v0.3 (dwv v0.23.0, 03/2018):\n * - new drawing structure, drawings are now the full layer object and\n * using toObject to avoid saving a string representation,\n * - new details structure: simple array of objects referenced by draw ids.\n * - v0.2 (dwv v0.17.0, 12/2016):\n * - adds draw details: array [nslices][nframes] of detail objects.\n * - v0.1 (dwv v0.15.0, 07/2016):\n * - adds version,\n * - drawings: array [nslices][nframes] with all groups.\n * - initial release (dwv v0.10.0, 05/2015), no version number:\n * - content: window-center, window-width, position, scale,\n * scaleCenter, translation, drawings,\n * - drawings: array [nslices] with all groups.\n */\nexport class State {\n /**\n * The state data id.\n *\n * @type {string}\n */\n #dataId;\n\n /**\n * @param {string} dataId The associated data id.\n */\n constructor(dataId) {\n this.#dataId = dataId;\n }\n\n /**\n * Load an application state from JSON.\n *\n * @param {string} json The state as a JSON string.\n * @returns {object} The state object.\n */\n fromJSON(json) {\n const data = JSON.parse(json);\n let res = null;\n if (data.version === '0.1') {\n res = this.#readV01(data);\n } else if (data.version === '0.2') {\n res = this.#readV02(data);\n } else if (data.version === '0.3') {\n res = this.#readV03(data);\n } else if (data.version === '0.4') {\n res = this.#readV04(data);\n } else if (data.version === '0.5') {\n res = this.#readV05(data);\n } else {\n throw new Error('Unknown state file format version: \\'' +\n data.version + '\\'.');\n }\n return res;\n }\n\n /**\n * Load an application state from JSON.\n *\n * @param {App} app The app to apply the state to.\n * @param {object} data The state data.\n */\n apply(app, data) {\n const layerGroup = app.getActiveLayerGroup();\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n // display\n const wl = new WindowLevel(data['window-center'], data['window-width']);\n viewController.setWindowLevel(wl);\n // position is index...\n viewController.setCurrentIndex(new Index(data.position));\n // apply saved scale on top of current base one\n const baseScale = app.getActiveLayerGroup().getBaseScale();\n let scale = null;\n let offset = null;\n if (typeof data.scaleCenter !== 'undefined') {\n scale = {\n x: data.scale * baseScale.x,\n y: data.scale * baseScale.y,\n z: 1\n };\n // ---- transform translation (now) ----\n // Tx = -offset.x * scale.x\n // => offset.x = -Tx / scale.x\n // ---- transform translation (before) ----\n // origin.x = centerX - (centerX - origin.x) * (newZoomX / zoom.x);\n // (zoom.x -> initial zoom = base scale, origin.x = 0)\n // Tx = origin.x + (trans.x * zoom.x)\n const originX = data.scaleCenter.x - data.scaleCenter.x * data.scale;\n const originY = data.scaleCenter.y - data.scaleCenter.y * data.scale;\n const oldTx = originX + data.translation.x * scale.x;\n const oldTy = originY + data.translation.y * scale.y;\n offset = {\n x: -oldTx / scale.x,\n y: -oldTy / scale.y,\n z: 0\n };\n } else {\n scale = {\n x: data.scale.x * baseScale.x,\n y: data.scale.y * baseScale.y,\n z: baseScale.z\n };\n offset = {\n x: data.offset.x,\n y: data.offset.y,\n z: 0\n };\n }\n app.getActiveLayerGroup().setScale(scale);\n app.getActiveLayerGroup().setOffset(offset);\n // drawings (will draw the draw layer)\n app.setDrawings(data.drawings, data.drawingsDetails, this.#dataId);\n }\n\n /**\n * Read an application state from an Object in v0.1 format.\n *\n * @param {object} data The Object representation of the state.\n * @returns {object} The state object.\n */\n #readV01(data) {\n // v0.1 -> v0.2\n const v02DAndD = v01Tov02DrawingsAndDetails(data.drawings);\n // v0.2 -> v0.3, v0.4\n data.drawings = v02Tov03Drawings(v02DAndD.drawings).toObject();\n data.drawingsDetails = v03Tov04DrawingsDetails(\n v02DAndD.drawingsDetails);\n // v0.4 -> v0.5\n data = v04Tov05Data(data);\n data.drawings = v04Tov05Drawings(data.drawings);\n return data;\n }\n\n /**\n * Read an application state from an Object in v0.2 format.\n *\n * @param {object} data The Object representation of the state.\n * @returns {object} The state object.\n */\n #readV02(data) {\n // v0.2 -> v0.3, v0.4\n data.drawings = v02Tov03Drawings(data.drawings).toObject();\n data.drawingsDetails = v03Tov04DrawingsDetails(\n v02Tov03DrawingsDetails(data.drawingsDetails));\n // v0.4 -> v0.5\n data = v04Tov05Data(data);\n data.drawings = v04Tov05Drawings(data.drawings);\n return data;\n }\n\n /**\n * Read an application state from an Object in v0.3 format.\n *\n * @param {object} data The Object representation of the state.\n * @returns {object} The state object.\n */\n #readV03(data) {\n // v0.3 -> v0.4\n data.drawingsDetails = v03Tov04DrawingsDetails(data.drawingsDetails);\n // v0.4 -> v0.5\n data = v04Tov05Data(data);\n data.drawings = v04Tov05Drawings(data.drawings);\n return data;\n }\n\n /**\n * Read an application state from an Object in v0.4 format.\n *\n * @param {object} data The Object representation of the state.\n * @returns {object} The state object.\n */\n #readV04(data) {\n // v0.4 -> v0.5\n data = v04Tov05Data(data);\n data.drawings = v04Tov05Drawings(data.drawings);\n return data;\n }\n /**\n * Read an application state from an Object in v0.5 format.\n *\n * @param {object} data The Object representation of the state.\n * @returns {object} The state object.\n */\n #readV05(data) {\n return data;\n }\n\n} // State class\n\n/**\n * Convert drawings from v0.2 to v0.3:\n * - v0.2: one layer per slice/frame,\n * - v0.3: one layer, one group per slice. `setDrawing` expects the full stage.\n *\n * @param {Array} drawings An array of drawings.\n * @returns {object} The layer with the converted drawings.\n */\nfunction v02Tov03Drawings(drawings) {\n // Auxiliar variables\n let group, groupShapes, parentGroup;\n // Avoid errors when dropping multiple states\n //drawLayer.getChildren().each(function(node){\n // node.visible(false);\n //});\n\n /**\n * Get the draw group id for a given position.\n *\n * @param {Index} currentPosition The current position.\n * @returns {string} The group id.\n */\n function getDrawPositionGroupId(currentPosition) {\n const sliceNumber = currentPosition.get(2);\n const frameNumber = currentPosition.length() === 4\n ? currentPosition.get(3) : 0;\n return 'slice-' + sliceNumber + '_frame-' + frameNumber;\n }\n\n const drawLayer = new Konva.Layer({\n listening: false,\n visible: true\n });\n\n // Get the positions-groups data\n const groupDrawings = typeof drawings === 'string'\n ? JSON.parse(drawings) : drawings;\n // Iterate over each position-groups\n for (let k = 0, lenk = groupDrawings.length; k < lenk; ++k) {\n // Iterate over each frame\n for (let f = 0, lenf = groupDrawings[k].length; f < lenf; ++f) {\n groupShapes = groupDrawings[k][f];\n if (groupShapes.length !== 0) {\n // Create position-group set as visible and append it to drawLayer\n parentGroup = new Konva.Group({\n id: getDrawPositionGroupId(new Index([1, 1, k, f])),\n name: 'position-group',\n visible: false\n });\n\n // Iterate over shapes-group\n for (let g = 0, leng = groupShapes.length; g < leng; ++g) {\n // create the konva group\n group = Konva.Node.create(groupShapes[g]);\n // enforce draggable: only the shape was draggable in v0.2,\n // now the whole group is.\n group.draggable(true);\n group.getChildren().forEach(function (gnode) {\n gnode.draggable(false);\n });\n // add to position group\n parentGroup.add(group);\n }\n // add to layer\n drawLayer.add(parentGroup);\n }\n }\n }\n\n return drawLayer;\n}\n\n/**\n * Convert drawings from v0.1 to v0.2:\n * - v0.1: text on its own,\n * - v0.2: text as part of label.\n *\n * @param {Array} inputDrawings An array of drawings.\n * @returns {object} The converted drawings.\n */\nfunction v01Tov02DrawingsAndDetails(inputDrawings) {\n const newDrawings = [];\n const drawingsDetails = {};\n\n let drawGroups;\n let drawGroup;\n // loop over each slice\n for (let k = 0, lenk = inputDrawings.length; k < lenk; ++k) {\n // loop over each frame\n newDrawings[k] = [];\n for (let f = 0, lenf = inputDrawings[k].length; f < lenf; ++f) {\n // draw group\n drawGroups = inputDrawings[k][f];\n const newFrameDrawings = [];\n // Iterate over shapes-group\n for (let g = 0, leng = drawGroups.length; g < leng; ++g) {\n // create konva group from input\n drawGroup = Konva.Node.create(drawGroups[g]);\n // force visible (not set in state)\n drawGroup.visible(true);\n // label position\n let pos = {x: 0, y: 0};\n // update shape colour\n const kshape = drawGroup.getChildren(function (node) {\n return node.name() === 'shape';\n })[0];\n kshape.stroke(colourNameToHex(kshape.stroke()));\n // special line case\n if (drawGroup.name() === 'line-group') {\n // update name\n drawGroup.name('ruler-group');\n // add ticks\n const ktick0 = new Konva.Line({\n points: [kshape.points()[0],\n kshape.points()[1],\n kshape.points()[0],\n kshape.points()[1]],\n name: 'shape-tick0'\n });\n drawGroup.add(ktick0);\n const ktick1 = new Konva.Line({\n points: [kshape.points()[2],\n kshape.points()[3],\n kshape.points()[2],\n kshape.points()[3]],\n name: 'shape-tick1'\n });\n drawGroup.add(ktick1);\n }\n // special protractor case: update arc name\n const karcs = drawGroup.getChildren(function (node) {\n return node.name() === 'arc';\n });\n if (karcs.length === 1) {\n karcs[0].name('shape-arc');\n }\n // get its text\n const ktexts = drawGroup.getChildren(function (node) {\n return node.name() === 'text';\n });\n // update text: move it into a label\n let ktext = new Konva.Text({\n name: 'text',\n text: ''\n });\n if (ktexts.length === 1) {\n pos.x = ktexts[0].x();\n pos.y = ktexts[0].y();\n // remove it from the group\n ktexts[0].remove();\n // use it\n ktext = ktexts[0];\n } else {\n // use shape position if no text\n if (kshape.points().length !== 0) {\n pos = {x: kshape.points()[0],\n y: kshape.points()[1]};\n }\n }\n // create new label with text and tag\n const klabel = new Konva.Label({\n x: pos.x,\n y: pos.y,\n name: 'label'\n });\n klabel.add(ktext);\n klabel.add(new Konva.Tag());\n // add label to group\n drawGroup.add(klabel);\n // add group to list\n newFrameDrawings.push(JSON.stringify(drawGroup.toObject()));\n\n // create details (v0.3 format)\n let textExpr = ktext.text();\n const txtLen = textExpr.length;\n let quant = null;\n // adapt to text with flag\n if (drawGroup.name() === 'ruler-group') {\n quant = {\n length: {\n value: parseFloat(textExpr.substring(0, txtLen - 2)),\n unit: textExpr.substring(-2)\n }\n };\n textExpr = '{length}';\n } else if (drawGroup.name() === 'ellipse-group' ||\n drawGroup.name() === 'rectangle-group') {\n quant = {\n surface: {\n value: parseFloat(textExpr.substring(0, txtLen - 3)),\n unit: textExpr.substring(-3)\n }\n };\n textExpr = '{surface}';\n } else if (drawGroup.name() === 'protractor-group' ||\n drawGroup.name() === 'rectangle-group') {\n quant = {\n angle: {\n value: parseFloat(textExpr.substring(0, txtLen - 1)),\n unit: textExpr.substring(-1)\n }\n };\n textExpr = '{angle}';\n }\n // set details\n drawingsDetails[drawGroup.id()] = {\n textExpr: textExpr,\n longText: '',\n quant: quant\n };\n\n }\n newDrawings[k].push(newFrameDrawings);\n }\n }\n\n return {drawings: newDrawings, drawingsDetails: drawingsDetails};\n}\n\n/**\n * Convert drawing details from v0.2 to v0.3:\n * - v0.2: array [nslices][nframes] with all,\n * - v0.3: simple array of objects referenced by draw ids.\n *\n * @param {Array} details An array of drawing details.\n * @returns {object} The converted drawings.\n */\nfunction v02Tov03DrawingsDetails(details) {\n const res = {};\n // Get the positions-groups data\n const groupDetails = typeof details === 'string'\n ? JSON.parse(details) : details;\n // Iterate over each position-groups\n for (let k = 0, lenk = groupDetails.length; k < lenk; ++k) {\n // Iterate over each frame\n for (let f = 0, lenf = groupDetails[k].length; f < lenf; ++f) {\n // Iterate over shapes-group\n for (let g = 0, leng = groupDetails[k][f].length; g < leng; ++g) {\n const group = groupDetails[k][f][g];\n res[group.id] = {\n textExpr: group.textExpr,\n longText: group.longText,\n quant: group.quant\n };\n }\n }\n }\n return res;\n}\n\n/**\n * Convert drawing details from v0.3 to v0.4:\n * - v0.3: properties at group root,\n * - v0.4: properties in group meta object.\n *\n * @param {Array} details An array of drawing details.\n * @returns {object} The converted drawings.\n */\nfunction v03Tov04DrawingsDetails(details) {\n const res = {};\n const keys = Object.keys(details);\n // Iterate over each position-groups\n for (let k = 0, lenk = keys.length; k < lenk; ++k) {\n const detail = details[keys[k]];\n res[keys[k]] = {\n meta: {\n textExpr: detail.textExpr,\n longText: detail.longText,\n quantification: detail.quant\n }\n };\n }\n return res;\n}\n\n/**\n * Convert drawing from v0.4 to v0.5:\n * - v0.4: position as object,\n * - v0.5: position as array.\n *\n * @param {object} data An array of drawing.\n * @returns {object} The converted drawings.\n */\nfunction v04Tov05Data(data) {\n const pos = data.position;\n data.position = [pos.i, pos.j, pos.k];\n return data;\n}\n\n/**\n * Convert drawing from v0.4 to v0.5:\n * - v0.4: draw id as 'slice-0_frame-1',\n * - v0.5: draw id as '#2-0_#3-1'.\n *\n * @param {object} inputDrawings An array of drawing.\n * @returns {object} The converted drawings.\n */\nfunction v04Tov05Drawings(inputDrawings) {\n // Iterate over each position-groups\n const posGroups = inputDrawings.children;\n for (let k = 0, lenk = posGroups.length; k < lenk; ++k) {\n const posGroup = posGroups[k];\n const id = posGroup.attrs.id;\n const ids = id.split('_');\n const sliceNumber = parseInt(ids[0].substring(6), 10); // 'slice-0'\n const frameNumber = parseInt(ids[1].substring(6), 10); // 'frame-0'\n let newId = '#2-';\n if (sliceNumber === 0 && frameNumber !== 0) {\n newId += frameNumber;\n } else {\n newId += sliceNumber;\n }\n posGroup.attrs.id = newId;\n }\n return inputDrawings;\n}\n","import {logger} from './logger';\nimport {splitKeyValueString} from './string';\n\n/**\n * Get an full object URL from a string uri.\n *\n * @param {string} uri A string representing the url.\n * @returns {URL} A URL object.\n */\nexport function getUrlFromUri(uri) {\n // add base to allow for relative urls\n // (base is not used for absolute urls)\n let base;\n if (window.location.origin !== 'null') {\n base = window.location.origin;\n }\n return new URL(uri, base);\n}\n\n/**\n * Split an input URI:\n * 'root?key0=val00&key0=val01&key1=val10' returns\n * { base : root, query : [ key0 : [val00, val01], key1 : val1 ] }\n * Returns an empty object if the input string is not correct (null, empty...)\n * or if it is not a query string (no question mark).\n *\n * @param {string} uri The string to split.\n * @returns {object} The split string.\n */\nexport function splitUri(uri) {\n // result\n const result = {};\n // check if query string\n let sepIndex = null;\n if (uri && (sepIndex = uri.indexOf('?')) !== -1) {\n // base: before the '?'\n result.base = uri.substring(0, sepIndex);\n // query : after the '?' and until possible '#'\n let hashIndex = uri.indexOf('#');\n if (hashIndex === -1) {\n hashIndex = uri.length;\n }\n const query = uri.substring(sepIndex + 1, hashIndex);\n // split key/value pairs of the query\n result.query = splitKeyValueString(query);\n }\n // return\n return result;\n}\n\n/**\n * Get the query part, split into an array, of an input URI.\n * The URI scheme is: `base?query#fragment`.\n *\n * @param {string} uri The input URI.\n * @returns {object} The query part, split into an array, of the input URI.\n */\nexport function getUriQuery(uri) {\n // split\n const parts = splitUri(uri);\n // check not empty\n if (Object.keys(parts).length === 0) {\n return null;\n }\n // return query\n return parts.query;\n}\n\n/**\n * Generic URI query decoder.\n * Supports manifest:\n * `[dwv root]?input=encodeURIComponent('[manifest file]')&type=manifest`.\n * Or encoded URI with base and key value/pairs:\n * `[dwv root]?input=encodeURIComponent([root]?key0=value0&key1=value1)`.\n *\n * @param {object} query The query part to the input URI.\n * @param {Function} callback The function to call with the decoded file urls.\n * @param {object} options Optional url request options.\n */\nexport function decodeQuery(query, callback, options) {\n // manifest\n if (query.type && query.type === 'manifest') {\n decodeManifestQuery(query, callback);\n } else {\n // default case: encoded URI with base and key/value pairs\n callback(\n decodeKeyValueUri(query.input, query.dwvReplaceMode),\n options);\n }\n}\n\n/**\n * Decode a Key/Value pair URI. If a key is repeated, the result\n * be an array of base + each key.\n *\n * @param {string} uri The URI to decode.\n * @param {string} replaceMode The key replace mode. Can be:\n * - key (default): keep the key\n * - other than key: do not use the key\n * 'file' is a special case where the '?' of the query is not kept.\n * @returns {string[]} The list of input file urls.\n */\nexport function decodeKeyValueUri(uri, replaceMode) {\n const result = [];\n\n // repeat key replace mode (default to keep key)\n let repeatKeyReplaceMode = 'key';\n if (replaceMode) {\n repeatKeyReplaceMode = replaceMode;\n }\n\n // decode input URI\n const queryUri = decodeURIComponent(uri);\n // get key/value pairs from input URI\n const inputQueryPairs = splitUri(queryUri);\n if (Object.keys(inputQueryPairs).length === 0) {\n result.push(queryUri);\n } else {\n const keys = Object.keys(inputQueryPairs.query);\n // find repeat key\n let repeatKey = null;\n for (let i = 0; i < keys.length; ++i) {\n if (inputQueryPairs.query[keys[i]] instanceof Array) {\n repeatKey = keys[i];\n break;\n }\n }\n\n if (!repeatKey) {\n result.push(queryUri);\n } else {\n const repeatList = inputQueryPairs.query[repeatKey];\n // build base uri\n let baseUrl = inputQueryPairs.base;\n // add '?' when:\n // - base is not empty\n // - the repeatKey is not 'file'\n // root/path/to/?file=0.jpg&file=1.jpg\n if (baseUrl !== '' && repeatKey !== 'file') {\n baseUrl += '?';\n }\n let gotOneArg = false;\n for (let j = 0; j < keys.length; ++j) {\n if (keys[j] !== repeatKey) {\n if (gotOneArg) {\n baseUrl += '&';\n }\n baseUrl += keys[j] + '=' + inputQueryPairs.query[keys[j]];\n gotOneArg = true;\n }\n }\n // append built urls to result\n let url;\n for (let k = 0; k < repeatList.length; ++k) {\n url = baseUrl;\n if (gotOneArg) {\n url += '&';\n }\n if (repeatKeyReplaceMode === 'key') {\n url += repeatKey + '=';\n }\n // other than 'key' mode: do nothing\n url += repeatList[k];\n result.push(url);\n }\n }\n }\n // return\n return result;\n}\n\n/**\n * Decode a manifest query.\n *\n * @external XMLHttpRequest\n * @param {object} query The manifest query: {input, nslices},\n * with input the input URI and nslices the number of slices.\n * @param {Function} callback The function to call with the decoded urls.\n */\nfunction decodeManifestQuery(query, callback) {\n let uri = '';\n if (query.input[0] === '/') {\n uri = window.location.protocol + '//' + window.location.host;\n }\n // TODO: needs to be decoded (decodeURIComponent?\n uri += query.input;\n\n /**\n * Handle error.\n *\n * @param {object} event The error event.\n */\n function onError(event) {\n logger.warn('RequestError while receiving manifest: ' +\n event.target.status);\n }\n\n /**\n * Handle load.\n *\n * @param {object} event The load event.\n */\n function onLoad(event) {\n callback(decodeManifest(event.target.responseXML, query.nslices));\n }\n\n const request = new XMLHttpRequest();\n request.open('GET', decodeURIComponent(uri), true);\n request.responseType = 'document';\n request.onload = onLoad;\n request.onerror = onError;\n request.send(null);\n}\n\n/**\n * Decode an XML manifest.\n *\n * @param {object} manifest The manifest to decode.\n * @param {number} nslices The number of slices to load.\n * @returns {string[]} The decoded manifest.\n */\nexport function decodeManifest(manifest, nslices) {\n const result = [];\n // wado url\n const wadoElement = manifest.getElementsByTagName('wado_query');\n const wadoURL = wadoElement[0].getAttribute('wadoURL');\n const rootURL = wadoURL + '?requestType=WADO&contentType=application/dicom&';\n // patient list\n const patientList = manifest.getElementsByTagName('Patient');\n if (patientList.length > 1) {\n logger.warn('More than one patient, loading first one.');\n }\n // study list\n const studyList = patientList[0].getElementsByTagName('Study');\n if (studyList.length > 1) {\n logger.warn('More than one study, loading first one.');\n }\n const studyUID = studyList[0].getAttribute('StudyInstanceUID');\n // series list\n const seriesList = studyList[0].getElementsByTagName('Series');\n if (seriesList.length > 1) {\n logger.warn('More than one series, loading first one.');\n }\n const seriesUID = seriesList[0].getAttribute('SeriesInstanceUID');\n // instance list\n const instanceList = seriesList[0].getElementsByTagName('Instance');\n // loop on instances and push links\n let max = instanceList.length;\n if (nslices < max) {\n max = nslices;\n }\n for (let i = 0; i < max; ++i) {\n const sopInstanceUID = instanceList[i].getAttribute('SOPInstanceUID');\n const link = rootURL +\n '&studyUID=' + studyUID +\n '&seriesUID=' + seriesUID +\n '&objectUID=' + sopInstanceUID;\n result.push(link);\n }\n // return\n return result;\n}\n","import {ListenerHandler} from './listen';\n\n/**\n * UndoStack class.\n */\nexport class UndoStack {\n /**\n * Array of commands.\n *\n * @type {Array}\n */\n #stack = [];\n\n /**\n * Current command index.\n *\n * @type {number}\n */\n #curCmdIndex = 0;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Get the stack size.\n *\n * @returns {number} The size of the stack.\n */\n getStackSize() {\n return this.#stack.length;\n }\n\n /**\n * Get the current stack index.\n *\n * @returns {number} The stack index.\n */\n getCurrentStackIndex() {\n return this.#curCmdIndex;\n }\n\n /**\n * Add a command to the stack.\n *\n * @param {object} cmd The command to add.\n * @fires UndoStack#undoadd\n */\n add(cmd) {\n // clear commands after current index\n this.#stack = this.#stack.slice(0, this.#curCmdIndex);\n // store command\n this.#stack.push(cmd);\n // increment index\n ++this.#curCmdIndex;\n /**\n * Command add to undo stack event.\n *\n * @event UndoStack#undoadd\n * @type {object}\n * @property {string} type The event type.\n * @property {string} command The name of the command added to the\n * undo stack.\n */\n this.#fireEvent({\n type: 'undoadd',\n command: cmd.getName()\n });\n }\n\n /**\n * Remove a command to the stack.\n *\n * @param {string} name The name of the command to remove.\n * @returns {boolean} True if the command was found and removed.\n * @fires UndoStack#undoremove\n */\n remove(name) {\n let res = false;\n const hasInputName = function (element) {\n return element.getName() === name;\n };\n const index = this.#stack.findIndex(hasInputName);\n if (index !== -1) {\n // remove command\n this.#stack.splice(index, 1);\n // decrement index\n --this.#curCmdIndex;\n // result\n res = true;\n /**\n * Command remove from undo stack event.\n *\n * @event UndoStack#undoremove\n * @type {object}\n * @property {string} type The event type.\n * @property {string} command The name of the command added to the\n * undo stack.\n */\n this.#fireEvent({\n type: 'undoremove',\n command: name\n });\n }\n return res;\n }\n\n /**\n * Undo the last command.\n *\n * @fires UndoStack#undo\n */\n undo() {\n // a bit inefficient...\n if (this.#curCmdIndex > 0) {\n // decrement command index\n --this.#curCmdIndex;\n // undo last command\n this.#stack[this.#curCmdIndex].undo();\n /**\n * Command undo event.\n *\n * @event UndoStack#undo\n * @type {object}\n * @property {string} type The event type.\n * @property {string} command The name of the undone command.\n */\n this.#fireEvent({\n type: 'undo',\n command: this.#stack[this.#curCmdIndex].getName()\n });\n }\n }\n\n /**\n * Redo the last command.\n *\n * @fires UndoStack#redo\n */\n redo() {\n if (this.#curCmdIndex < this.#stack.length) {\n // run last command\n this.#stack[this.#curCmdIndex].execute();\n /**\n * Command redo event.\n *\n * @event UndoStack#redo\n * @type {object}\n * @property {string} type The event type.\n * @property {string} command The name of the redone command.\n */\n this.#fireEvent({\n type: 'redo',\n command: this.#stack[this.#curCmdIndex].getName()\n });\n // increment command index\n ++this.#curCmdIndex;\n }\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n} // UndoStack class\n","import {InteractionEventNames} from '../gui/generic';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {LayerGroup} from '../gui/layerGroup';\nimport {ViewLayer} from '../gui/viewLayer';\nimport {DrawLayer} from '../gui/drawLayer';\n/* eslint-enable no-unused-vars */\n\n/**\n * Toolbox controller.\n */\nexport class ToolboxController {\n\n /**\n * List of tools to control.\n *\n * @type {object}\n */\n #toolList;\n\n /**\n * Selected tool.\n *\n * @type {object}\n */\n #selectedTool = null;\n\n /**\n * Callback store to allow attach/detach.\n *\n * @type {Array}\n */\n #callbackStore = [];\n\n /**\n * Current layers bound to tool.\n *\n * @type {object}\n */\n #boundLayers = {};\n\n /**\n * @param {object} toolList The list of tool objects.\n */\n constructor(toolList) {\n this.#toolList = toolList;\n }\n\n /**\n * Initialise.\n */\n init() {\n for (const key in this.#toolList) {\n this.#toolList[key].init();\n }\n // enable shortcuts\n this.enableShortcuts(true);\n }\n\n /**\n * Enable or disable shortcuts. The 'init' methods enables shortcuts\n * by default. Call this method after init to disable shortcuts.\n *\n * @param {boolean} flag True to enable shortcuts.\n */\n enableShortcuts(flag) {\n if (flag) {\n window.addEventListener('keydown',\n this.#getCallback('window', 'keydown'), true);\n } else {\n window.removeEventListener('keydown',\n this.#getCallback('window', 'keydown'), true);\n }\n }\n\n /**\n * Get the tool list.\n *\n * @returns {Array} The list of tool objects.\n */\n getToolList() {\n return this.#toolList;\n }\n\n /**\n * Check if a tool is in the tool list.\n *\n * @param {string} name The name to check.\n * @returns {boolean} The tool list element for the given name.\n */\n hasTool(name) {\n return typeof this.getToolList()[name] !== 'undefined';\n }\n\n /**\n * Get the selected tool.\n *\n * @returns {object} The selected tool.\n */\n getSelectedTool() {\n return this.#selectedTool;\n }\n\n /**\n * Get the selected tool event handler.\n *\n * @param {string} eventType The event type, for example\n * mousedown, touchstart...\n * @returns {Function} The event handler.\n */\n getSelectedToolEventHandler(eventType) {\n return this.getSelectedTool()[eventType];\n }\n\n /**\n * Set the selected tool.\n *\n * @param {string} name The name of the tool.\n */\n setSelectedTool(name) {\n // check if we have it\n if (!this.hasTool(name)) {\n throw new Error('Unknown tool: \\'' + name + '\\'');\n }\n // de-activate previous\n if (this.#selectedTool) {\n this.#selectedTool.activate(false);\n }\n // set internal var\n this.#selectedTool = this.#toolList[name];\n // activate new tool\n this.#selectedTool.activate(true);\n }\n\n /**\n * Set the selected tool live features.\n *\n * @param {object} list The list of features.\n */\n setToolFeatures(list) {\n if (this.getSelectedTool()) {\n this.getSelectedTool().setFeatures(list);\n }\n }\n\n /**\n * Listen to layer interaction events.\n *\n * @param {LayerGroup} layerGroup The associated layer group.\n * @param {ViewLayer|DrawLayer} layer The layer to listen to.\n */\n bindLayerGroup(layerGroup, layer) {\n const divId = layerGroup.getDivId();\n // listen to active layer changes\n layerGroup.addEventListener(\n 'activelayerchange', this.#getActiveLayerChangeHandler(divId));\n // bind the layer\n this.#internalBindLayerGroup(divId, layer);\n }\n\n /**\n * Bind a layer group to this controller.\n *\n * @param {string} layerGroupDivId The layer group div id.\n * @param {ViewLayer|DrawLayer} layer The layer.\n */\n #internalBindLayerGroup(layerGroupDivId, layer) {\n // remove from local list if preset\n if (typeof this.#boundLayers[layerGroupDivId] !== 'undefined') {\n this.#unbindLayer(this.#boundLayers[layerGroupDivId]);\n }\n // replace layer in local list\n this.#boundLayers[layerGroupDivId] = layer;\n // bind layer\n this.#bindLayer(layer);\n }\n\n /**\n * Get an active layer change handler.\n *\n * @param {string} divId The associated layer group div id.\n * @returns {Function} The event handler.\n */\n #getActiveLayerChangeHandler(divId) {\n return (event) => {\n const layer = event.value[0];\n if (typeof layer !== 'undefined') {\n this.#internalBindLayerGroup(divId, layer);\n }\n };\n }\n\n /**\n * Add canvas mouse and touch listeners to a layer.\n *\n * @param {ViewLayer|DrawLayer} layer The layer to start listening to.\n */\n #bindLayer(layer) {\n layer.bindInteraction();\n // interaction events\n const names = InteractionEventNames;\n for (let i = 0; i < names.length; ++i) {\n layer.addEventListener(names[i],\n this.#getCallback(layer.getId(), names[i]));\n }\n }\n\n /**\n * Remove canvas mouse and touch listeners to a layer.\n *\n * @param {ViewLayer|DrawLayer} layer The layer to stop listening to.\n */\n #unbindLayer(layer) {\n layer.unbindInteraction();\n // interaction events\n const names = InteractionEventNames;\n for (let i = 0; i < names.length; ++i) {\n layer.removeEventListener(names[i],\n this.#getCallback(layer.getId(), names[i]));\n }\n }\n\n /**\n * Mou(se) and (T)ouch event handler. This function just determines\n * the mouse/touch position relative to the canvas element.\n * It then passes it to the current tool.\n *\n * @param {string} layerId The layer id.\n * @param {string} eventType The event type.\n * @returns {object} A callback for the provided layer and event.\n */\n #getCallback(layerId, eventType) {\n if (typeof this.#callbackStore[layerId] === 'undefined') {\n this.#callbackStore[layerId] = [];\n }\n\n if (typeof this.#callbackStore[layerId][eventType] === 'undefined') {\n const applySelectedTool = (event) => {\n // make sure we have a tool\n if (this.#selectedTool) {\n const func = this.#selectedTool[event.type];\n if (func) {\n func(event);\n }\n }\n };\n // store callback\n this.#callbackStore[layerId][eventType] = applySelectedTool;\n }\n\n return this.#callbackStore[layerId][eventType];\n }\n\n} // class ToolboxController\n","/**\n * Multiple progresses handler.\n * Stores a multi dimensional list of progresses to allow to\n * calculate a global progress.\n *\n */\nexport class MultiProgressHandler {\n\n /**\n * List of progresses.\n * First dimension is a list of item for which the progress is recorded,\n * for example file names.\n * Second dimension is a list of possible progresses, for example\n * the progress of the download and the progress of the decoding.\n *\n * @type {Array}\n */\n #progresses = [];\n\n /**\n * Number of dimensions.\n *\n * @type {number}\n */\n #numberOfDimensions = 2;\n\n /**\n * Progress callback.\n *\n * @type {Function}\n */\n #callback;\n\n /**\n * @param {Function} callback The function to pass the global progress to.\n */\n constructor(callback) {\n this.#callback = callback;\n }\n\n /**\n * Set the number of dimensions.\n *\n * @param {number} num The number.\n */\n setNumberOfDimensions(num) {\n this.#numberOfDimensions = num;\n }\n\n /**\n * Set the number of data to load.\n *\n * @param {number} n The number of data to load.\n */\n setNToLoad(n) {\n for (let i = 0; i < n; ++i) {\n this.#progresses[i] = [];\n for (let j = 0; j < this.#numberOfDimensions; ++j) {\n this.#progresses[i][j] = 0;\n }\n }\n }\n\n /**\n * Handle a load progress.\n * Call the member callback with a global event.\n *\n * @param {object} event The progress event.\n */\n onprogress = (event) => {\n // check event\n if (!event.lengthComputable) {\n return;\n }\n if (typeof event.subindex === 'undefined') {\n return;\n }\n if (typeof event.index === 'undefined') {\n return;\n }\n // calculate percent\n const percent = (event.loaded * 100) / event.total;\n // set percent for index\n this.#progresses[event.index][event.subindex] = percent;\n\n // item progress\n let item = null;\n if (typeof event.item !== 'undefined') {\n item = event.item;\n } else {\n item = {\n loaded: this.#getItemProgress(event.index),\n total: 100,\n source: event.source\n };\n }\n\n // call callback with a global event\n this.#callback({\n lengthComputable: true,\n loaded: this.#getGlobalPercent(),\n total: 100,\n item: item\n });\n };\n\n /**\n * Get the item load percent.\n *\n * @param {number} index The index of the item.\n * @returns {number} The load percentage.\n */\n #getItemProgress(index) {\n let sum = 0;\n for (let j = 0; j < this.#numberOfDimensions; ++j) {\n sum += this.#progresses[index][j];\n }\n return sum / this.#numberOfDimensions;\n }\n\n /**\n * Get the global load percent including the provided one.\n *\n * @returns {number} The accumulated percentage.\n */\n #getGlobalPercent() {\n let sum = 0;\n const lenprog = this.#progresses.length;\n for (let i = 0; i < lenprog; ++i) {\n sum += this.#getItemProgress(i);\n }\n return Math.round(sum / lenprog);\n }\n\n\n /**\n * @callback eventFn\n * @param {object} event The event.\n */\n\n /**\n * Create a mono progress event handler.\n *\n * @param {number} index The index of the data.\n * @param {number} subindex The sub-index of the data.\n * @returns {eventFn} A progress handler function.\n */\n getMonoProgressHandler(index, subindex) {\n return (event) => {\n event.index = index;\n event.subindex = subindex;\n this.onprogress(event);\n };\n }\n\n /**\n * Create a mono progress event handler with an undefined index.\n * Warning: The caller handles the progress index.\n *\n * @param {number} subindex The sub-index of the data.\n * @returns {eventFn} A progress handler function.\n */\n getUndefinedMonoProgressHandler(subindex) {\n return (event) => {\n event.subindex = subindex;\n this.onprogress(event);\n };\n }\n}\n","import {endsWith, getRootPath} from '../utils/string';\nimport {MultiProgressHandler} from '../utils/progress';\nimport {getFileListFromDicomDir} from '../dicom/dicomElementsWrapper';\nimport {loaderList} from './loaderList';\n\n// url content types\nexport const urlContentTypes = {\n Text: 0,\n ArrayBuffer: 1\n};\n\n/**\n * Urls loader.\n */\nexport class UrlsLoader {\n\n /**\n * Input data.\n *\n * @type {string[]}\n */\n #inputData = null;\n\n /**\n * Array of launched requests.\n *\n * @type {XMLHttpRequest[]}\n */\n #requests = [];\n\n /**\n * Data loader.\n *\n * @type {object}\n */\n #runningLoader = null;\n\n /**\n * Number of loaded data.\n *\n * @type {number}\n */\n #nLoad = 0;\n\n /**\n * Number of load end events.\n *\n * @type {number}\n */\n #nLoadend = 0;\n\n /**\n * Flag to know if the load is aborting.\n *\n * @type {boolean}\n */\n #aborting;\n\n /**\n * The default character set (optional).\n *\n * @type {string}\n */\n #defaultCharacterSet;\n\n /**\n * Get the default character set.\n *\n * @returns {string} The default character set.\n */\n getDefaultCharacterSet() {\n return this.#defaultCharacterSet;\n }\n\n /**\n * Set the default character set.\n *\n * @param {string} characterSet The character set.\n */\n setDefaultCharacterSet(characterSet) {\n this.#defaultCharacterSet = characterSet;\n }\n\n /**\n * Store the current input.\n *\n * @param {string[]} data The input data.\n */\n #storeInputData(data) {\n this.#inputData = data;\n // reset counters\n this.#nLoad = 0;\n this.#nLoadend = 0;\n // reset flag\n this.#aborting = false;\n // clear storage\n this.#clearStoredRequests();\n this.#clearStoredLoader();\n }\n\n /**\n * Store a launched request.\n *\n * @param {XMLHttpRequest} request The launched request.\n */\n #storeRequest(request) {\n this.#requests.push(request);\n }\n\n /**\n * Clear the stored requests.\n *\n */\n #clearStoredRequests() {\n this.#requests = [];\n }\n\n /**\n * Store the launched loader.\n *\n * @param {object} loader The launched loader.\n */\n #storeLoader(loader) {\n this.#runningLoader = loader;\n }\n\n /**\n * Clear the stored loader.\n *\n */\n #clearStoredLoader() {\n this.#runningLoader = null;\n }\n\n /**\n * Increment the number of loaded data\n * and call onload if loaded all data.\n *\n * @param {object} _event The load data event.\n */\n #addLoad = (_event) => {\n this.#nLoad++;\n // call onload when all is loaded\n // (not using the input event since it is\n // an individual load)\n if (this.#nLoad === this.#inputData.length) {\n this.onload({\n source: this.#inputData\n });\n }\n };\n\n /**\n * Increment the counter of load end events\n * and run callbacks when all done, erroneus or not.\n *\n * @param {object} _event The load end event.\n */\n #addLoadend = (_event) => {\n this.#nLoadend++;\n // call onloadend when all is run\n // (not using the input event since it is\n // an individual load end)\n if (this.#nLoadend === this.#inputData.length) {\n this.onloadend({\n source: this.#inputData\n });\n }\n };\n\n /**\n * @callback eventFn\n * @param {object} event The event.\n */\n\n /**\n * Augment a callback event with a srouce.\n *\n * @param {object} callback The callback to augment its event.\n * @param {object} source The source to add to the event.\n * @returns {eventFn} The augmented callback.\n */\n #augmentCallbackEvent(callback, source) {\n return (event) => {\n event.source = source;\n callback(event);\n };\n }\n\n /**\n * Load a list of URLs or a DICOMDIR.\n *\n * @param {string[]} data The list of urls to load.\n * @param {object} [options] Load options.\n */\n load(data, options) {\n // send start event\n this.onloadstart({\n source: data\n });\n\n // check if DICOMDIR case\n if (data.length === 1 &&\n (endsWith(data[0], 'DICOMDIR') ||\n endsWith(data[0], '.dcmdir'))) {\n this.#loadDicomDir(data[0], options);\n } else {\n this.#loadUrls(data, options);\n }\n }\n\n /**\n * Get a load handler for a data element.\n *\n * @param {object} loader The associated loader.\n * @param {string} dataElement The data element.\n * @param {number} i The index of the element.\n * @returns {eventFn} A load handler.\n */\n #getLoadHandler(loader, dataElement, i) {\n return (event) => {\n // check response status\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Response_codes\n // status 200: \"OK\"; status 0: \"debug\"\n const status = event.target.status;\n if (status !== 200 && status !== 0) {\n this.onerror({\n source: dataElement,\n error: 'GET ' + event.target.responseURL +\n ' ' + event.target.status +\n ' (' + event.target.statusText + ')',\n target: event.target\n });\n this.#addLoadend();\n } else {\n loader.load(event.target.response, dataElement, i);\n }\n };\n }\n\n /**\n * Load a list of urls.\n *\n * @param {string[]} data The list of urls to load.\n * @param {object} [options] The options object, can contain:\n * - requestHeaders: an array of {name, value} to use as request headers,\n * - withCredentials: boolean xhr.withCredentials flag to pass\n * to the request,\n * - batchSize: the size of the request url batch.\n */\n #loadUrls(data, options) {\n // check input\n if (typeof data === 'undefined' || data.length === 0) {\n return;\n }\n this.#storeInputData(data);\n\n // create prgress handler\n const mproghandler = new MultiProgressHandler(this.onprogress);\n mproghandler.setNToLoad(data.length);\n\n // create loaders\n const loaders = [];\n for (let m = 0; m < loaderList.length; ++m) {\n loaders.push(new loaderList[m]());\n }\n\n // find an appropriate loader\n let dataElement = data[0];\n let loader = null;\n let foundLoader = false;\n for (let l = 0; l < loaders.length; ++l) {\n loader = loaders[l];\n if (loader.canLoadUrl(dataElement, options)) {\n foundLoader = true;\n // load options\n loader.setOptions({\n numberOfFiles: data.length,\n defaultCharacterSet: this.getDefaultCharacterSet()\n });\n // set loader callbacks\n // loader.onloadstart: nothing to do\n loader.onprogress = mproghandler.getUndefinedMonoProgressHandler(1);\n loader.onloaditem = this.onloaditem;\n loader.onload = this.#addLoad;\n loader.onloadend = this.#addLoadend;\n loader.onerror = this.onerror;\n loader.onabort = this.onabort;\n\n // store loader\n this.#storeLoader(loader);\n // exit\n break;\n }\n }\n if (!foundLoader) {\n throw new Error('No loader found for url: ' + dataElement);\n }\n\n // store last run request index\n let lastRunRequestIndex = 0;\n const requestOnLoadEnd = () => {\n // launch next in queue\n if (lastRunRequestIndex < this.#requests.length - 1 && !this.#aborting) {\n ++lastRunRequestIndex;\n this.#requests[lastRunRequestIndex].send(null);\n }\n };\n\n // loop on I/O elements\n for (let i = 0; i < data.length; ++i) {\n dataElement = data[i];\n\n // check loader\n if (!loader.canLoadUrl(dataElement, options)) {\n throw new Error('Input url of different type: ' + dataElement);\n }\n /**\n * The http request.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest}.\n *\n * @external XMLHttpRequest\n */\n const request = new XMLHttpRequest();\n request.open('GET', dataElement, true);\n\n // request options\n if (typeof options !== 'undefined') {\n // optional request headers\n if (typeof options.requestHeaders !== 'undefined') {\n const requestHeaders = options.requestHeaders;\n for (let j = 0; j < requestHeaders.length; ++j) {\n if (typeof requestHeaders[j].name !== 'undefined' &&\n typeof requestHeaders[j].value !== 'undefined') {\n request.setRequestHeader(\n requestHeaders[j].name, requestHeaders[j].value);\n }\n }\n }\n // optional withCredentials\n // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials\n if (typeof options.withCredentials !== 'undefined') {\n request.withCredentials = options.withCredentials;\n }\n }\n\n // set request callbacks\n // request.onloadstart: nothing to do\n request.onprogress = this.#augmentCallbackEvent(\n mproghandler.getMonoProgressHandler(i, 0), dataElement);\n request.onload = this.#getLoadHandler(loader, dataElement, i);\n request.onloadend = requestOnLoadEnd;\n const errorCallback =\n this.#augmentCallbackEvent(this.onerror, dataElement);\n request.onerror = (event) => {\n this.#addLoadend();\n errorCallback(event);\n };\n const abortCallback =\n this.#augmentCallbackEvent(this.onabort, dataElement);\n request.onabort = (event) => {\n this.#addLoadend();\n abortCallback(event);\n };\n // response type (default is 'text')\n if (loader.loadUrlAs() === urlContentTypes.ArrayBuffer) {\n request.responseType = 'arraybuffer';\n }\n\n // store request\n this.#storeRequest(request);\n }\n\n // launch requests in batch\n let batchSize = this.#requests.length;\n if (typeof options !== 'undefined') {\n // optional request batch size\n if (typeof options.batchSize !== 'undefined' && batchSize !== 0) {\n batchSize = Math.min(options.batchSize, this.#requests.length);\n }\n }\n for (let r = 0; r < batchSize; ++r) {\n if (!this.#aborting) {\n lastRunRequestIndex = r;\n this.#requests[lastRunRequestIndex].send(null);\n }\n }\n }\n\n /**\n * Load a DICOMDIR.\n *\n * @param {string} dicomDirUrl The DICOMDIR url.\n * @param {object} [options] Load options.\n */\n #loadDicomDir(dicomDirUrl, options) {\n // read DICOMDIR\n const request = new XMLHttpRequest();\n request.open('GET', dicomDirUrl, true);\n request.responseType = 'arraybuffer';\n // request.onloadstart: nothing to do\n /**\n * @param {object} event The load event.\n */\n request.onload = (event) => {\n // check status\n const status = event.target.status;\n if (status !== 200 && status !== 0) {\n this.onerror({\n source: dicomDirUrl,\n error: 'GET ' + event.target.responseURL +\n ' ' + event.target.status +\n ' (' + event.target.statusText + ')',\n target: event.target\n });\n this.onloadend({});\n } else {\n // get the file list\n const list = getFileListFromDicomDir(event.target.response);\n // use the first list\n const urls = list[0][0];\n // append root url\n const rootUrl = getRootPath(dicomDirUrl);\n const fullUrls = [];\n for (let i = 0; i < urls.length; ++i) {\n fullUrls.push(rootUrl + '/' + urls[i]);\n }\n // load urls\n this.#loadUrls(fullUrls, options);\n }\n };\n request.onerror = (event) => {\n this.#augmentCallbackEvent(this.onerror, dicomDirUrl)(event);\n this.onloadend({});\n };\n request.onabort = (event) => {\n this.#augmentCallbackEvent(this.onabort, dicomDirUrl)(event);\n this.onloadend({});\n };\n // request.onloadend: nothing to do\n // send request\n request.send(null);\n }\n\n /**\n * Abort a load.\n */\n abort() {\n this.#aborting = true;\n // abort non finished requests\n for (let i = 0; i < this.#requests.length; ++i) {\n // 0: UNSENT, 1: OPENED, 2: HEADERS_RECEIVED (send()), 3: LOADING, 4: DONE\n if (this.#requests[i].readyState !== 4) {\n this.#requests[i].abort();\n }\n }\n // abort loader\n if (this.#runningLoader && this.#runningLoader.isLoading()) {\n this.#runningLoader.abort();\n }\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle a load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class UrlsLoader\n","/**\n * Thread Pool.\n *\n * Highly inspired from {@link http://www.smartjava.org/content/html5-easily-parallelize-jobs-using-web-workers-and-threadpool}.\n */\nexport class ThreadPool {\n\n /**\n * @param {number} poolSize The size of the pool.\n */\n constructor(poolSize) {\n this.poolSize = poolSize;\n // task queue\n this.taskQueue = [];\n // lsit of available threads\n this.freeThreads = [];\n // create 'poolSize' number of worker threads\n for (let i = 0; i < poolSize; ++i) {\n this.freeThreads.push(new WorkerThread(this));\n }\n // list of running threads (unsed in abort)\n this.runningThreads = [];\n }\n\n /**\n * Add a worker task to the queue.\n * Will be run when a thread is made available.\n *\n * @param {object} workerTask The task to add to the queue.\n */\n addWorkerTask(workerTask) {\n // send work start if first task\n if (this.freeThreads.length === this.poolSize) {\n this.onworkstart({type: 'work-start'});\n }\n // launch task or queue\n if (this.freeThreads.length > 0) {\n // get the first free worker thread\n const workerThread = this.freeThreads.shift();\n // add the thread to the runnning list\n this.runningThreads.push(workerThread);\n // run the input task\n workerThread.run(workerTask);\n } else {\n // no free thread, add task to queue\n this.taskQueue.push(workerTask);\n }\n }\n\n /**\n * Abort all threads.\n */\n abort() {\n // stop all threads\n this.#stop();\n // callback\n this.onabort({type: 'work-abort'});\n this.onworkend({type: 'work-end'});\n }\n\n /**\n * Handle a task end.\n *\n * @param {object} workerThread The thread to free.\n */\n onTaskEnd(workerThread) {\n // launch next task in queue or finish\n if (this.taskQueue.length > 0) {\n // get waiting task\n const workerTask = this.taskQueue.shift();\n // use input thread to run the waiting task\n workerThread.run(workerTask);\n } else {\n // stop the worker\n workerThread.stop();\n // no task to run, add to free list\n this.freeThreads.push(workerThread);\n // remove from running list\n for (let i = 0; i < this.runningThreads.length; ++i) {\n if (this.runningThreads[i].getId() === workerThread.getId()) {\n this.runningThreads.splice(i, 1);\n }\n }\n // the work is done when the queue is back to its initial size\n if (this.freeThreads.length === this.poolSize) {\n this.onwork({type: 'work'});\n this.onworkend({type: 'work-end'});\n }\n }\n }\n\n /**\n * Handle an error message from a worker.\n *\n * @param {object} event The error event.\n */\n handleWorkerError = (event) => {\n // stop all threads\n this.#stop();\n // callback\n this.onerror({error: event});\n this.onworkend({type: 'work-end'});\n };\n\n // private ----------------------------------------------------------------\n\n /**\n * Stop the pool: stop all running threads.\n *\n */\n #stop() {\n // clear tasks\n this.taskQueue = [];\n // cancel running workers\n for (let i = 0; i < this.runningThreads.length; ++i) {\n this.runningThreads[i].stop();\n }\n this.runningThreads = [];\n }\n\n\n /**\n * Handle a work start event.\n * Default does nothing.\n *\n * @param {object} _event The work start event.\n */\n onworkstart(_event) {}\n\n /**\n * Handle a work item event.\n * Default does nothing.\n *\n * @param {object} _event The work item event fired\n * when a work item ended successfully.\n */\n onworkitem(_event) {}\n\n /**\n * Handle a work event.\n * Default does nothing.\n *\n * @param {object} _event The work event fired\n * when a work ended successfully.\n */\n onwork(_event) {}\n\n /**\n * Handle a work end event.\n * Default does nothing.\n *\n * @param {object} _event The work end event fired\n * when a work has completed, successfully or not.\n */\n onworkend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // ThreadPool\n\n/**\n * Worker background task.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/API/Worker}.\n *\n * @external Worker\n */\n\n/**\n * Worker thread.\n */\nclass WorkerThread {\n\n /**\n * @param {object} parentPool The parent pool.\n */\n constructor(parentPool) {\n this.parentPool = parentPool;\n // thread ID\n this.id = Math.random().toString(36).substring(2, 15);\n // running task\n this.runningTask = null;\n // worker used to run task\n this.worker;\n }\n\n /**\n * Get the thread ID.\n *\n * @returns {string} The thread ID (alphanumeric).\n */\n getId() {\n return this.id;\n }\n\n /**\n * Run a worker task.\n *\n * @param {object} workerTask The task to run.\n */\n run(workerTask) {\n // store task\n this.runningTask = workerTask;\n // create a new web worker if not done yet\n if (typeof this.worker === 'undefined') {\n this.worker = new Worker(this.runningTask.script);\n // set callbacks\n this.worker.onmessage = this.onmessage;\n this.worker.onerror = this.onerror;\n }\n // launch the worker\n this.worker.postMessage(this.runningTask.startMessage);\n }\n\n /**\n * Finish a task and tell the parent.\n */\n stop() {\n // stop the worker\n if (typeof this.worker !== 'undefined') {\n this.worker.terminate();\n // force create at next run\n this.worker = undefined;\n }\n }\n\n /**\n * Message event handler.\n * For now assume we only get a single callback from a worker\n * which also indicates the end of this worker.\n *\n * @param {object} event The message event.\n */\n onmessage = (event) => {\n // augment event\n event.itemNumber = this.runningTask.info.itemNumber;\n event.numberOfItems = this.runningTask.info.numberOfItems;\n event.index = this.runningTask.info.index;\n // send event\n this.parentPool.onworkitem(event);\n // tell the parent pool the task is done\n this.parentPool.onTaskEnd(this);\n };\n\n /**\n * Error event handler.\n *\n * @param {object} event The error event.\n */\n onerror = (event) => {\n // augment event\n event.itemNumber = this.runningTask.info.itemNumber;\n event.numberOfItems = this.runningTask.info.numberOfItems;\n event.index = this.runningTask.info.index;\n // pass to parent\n this.parentPool.handleWorkerError(event);\n // stop the worker and free the thread\n this.stop();\n };\n} // class WorkerThread\n\n/**\n * Worker task.\n */\nexport class WorkerTask {\n /**\n * @param {string} script The worker script.\n * @param {object} message The data to pass to the worker.\n * @param {object} info Information object about the input data.\n */\n constructor(script, message, info) {\n // worker script\n this.script = script;\n // worker start message\n this.startMessage = message;\n // information about the work data\n this.info = info;\n }\n}\n","import {ThreadPool, WorkerTask} from '../utils/thread';\n\n/**\n * The JPEG baseline decoder.\n *\n * Ref: {@link https://github.com/mozilla/pdf.js/blob/master/src/core/jpg.js}.\n *\n * @external JpegImage\n */\n/* global JpegImage */\n// @ts-ignore\nconst hasJpegBaselineDecoder = (typeof JpegImage !== 'undefined');\n\n/**\n * The JPEG decoder namespace.\n *\n * Ref: {@link https://github.com/rii-mango/JPEGLosslessDecoderJS}.\n *\n * @external jpeg\n */\n/* global jpeg */\nconst hasJpegLosslessDecoder =\n // @ts-ignore\n (typeof jpeg !== 'undefined') && (typeof jpeg.lossless !== 'undefined');\n\n/**\n * The JPEG 2000 decoder.\n *\n * Ref: {@link https://github.com/jpambrun/jpx-medical/blob/master/jpx.js}.\n *\n * @external JpxImage\n */\n/* global JpxImage */\n// @ts-ignore\nconst hasJpeg2000Decoder = (typeof JpxImage !== 'undefined');\n\n/* global dwvdecoder */\n\n/**\n * Decoder scripts to be passed to web workers for image decoding.\n */\nexport const decoderScripts = {\n jpeg2000: '',\n 'jpeg-lossless': '',\n 'jpeg-baseline': '',\n rle: ''\n};\n\n/**\n * Asynchronous pixel buffer decoder.\n */\nclass AsynchPixelBufferDecoder {\n\n /**\n * The associated worker script.\n *\n * @type {string}\n */\n #script;\n\n /**\n * Associated thread pool.\n *\n * @type {ThreadPool}\n */\n #pool = new ThreadPool(10);\n\n /**\n * Flag to know if callbacks are set.\n *\n * @type {boolean}\n */\n #areCallbacksSet = false;\n\n /**\n * @param {string} script The path to the decoder script to be used\n * by the web worker.\n * @param {number} _numberOfData The anticipated number of data to decode.\n */\n constructor(script, _numberOfData) {\n this.#script = script;\n }\n\n /**\n * Decode a pixel buffer.\n *\n * @param {Array} pixelBuffer The pixel buffer.\n * @param {object} pixelMeta The input meta data.\n * @param {object} info Information object about the input data.\n */\n decode(pixelBuffer, pixelMeta, info) {\n if (!this.#areCallbacksSet) {\n this.#areCallbacksSet = true;\n // set event handlers\n this.#pool.onworkstart = this.ondecodestart;\n this.#pool.onworkitem = this.ondecodeditem;\n this.#pool.onwork = this.ondecoded;\n this.#pool.onworkend = this.ondecodeend;\n this.#pool.onerror = this.onerror;\n this.#pool.onabort = this.onabort;\n }\n // create worker task\n const workerTask = new WorkerTask(\n this.#script,\n {\n buffer: pixelBuffer,\n meta: pixelMeta\n },\n info\n );\n // add it the queue and run it\n this.#pool.addWorkerTask(workerTask);\n }\n\n /**\n * Abort decoding.\n */\n abort() {\n // abort the thread pool, will trigger pool.onabort\n this.#pool.abort();\n }\n\n /**\n * Handle a decode start event.\n * Default does nothing.\n *\n * @param {object} _event The decode start event.\n */\n ondecodestart(_event) {}\n\n /**\n * Handle a decode item event.\n * Default does nothing.\n *\n * @param {object} _event The decode item event fired\n * when a decode item ended successfully.\n */\n ondecodeditem(_event) {}\n\n /**\n * Handle a decode event.\n * Default does nothing.\n *\n * @param {object} _event The decode event fired\n * when a file has been decoded successfully.\n */\n ondecoded(_event) {}\n\n /**\n * Handle a decode end event.\n * Default does nothing.\n *\n * @param {object} _event The decode end event fired\n * when a file decoding has completed, successfully or not.\n */\n ondecodeend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class AsynchPixelBufferDecoder\n\n/**\n * Synchronous pixel buffer decoder.\n */\nclass SynchPixelBufferDecoder {\n\n /**\n * Name of the compression algorithm.\n *\n * @type {string}\n */\n #algoName;\n\n /**\n * Number of data.\n *\n * @type {number}\n */\n #numberOfData;\n\n /**\n * @param {string} algoName The decompression algorithm name.\n * @param {number} numberOfData The anticipated number of data to decode.\n */\n constructor(algoName, numberOfData) {\n this.#algoName = algoName;\n this.#numberOfData = numberOfData;\n }\n\n // decode count\n #decodeCount = 0;\n\n /**\n * Decode a pixel buffer.\n *\n * @param {Array} pixelBuffer The pixel buffer.\n * @param {object} pixelMeta The input meta data.\n * @param {object} info Information object about the input data.\n * @external jpeg\n * @external JpegImage\n * @external JpxImage\n */\n decode(pixelBuffer, pixelMeta, info) {\n ++this.#decodeCount;\n\n let decoder = null;\n let decodedBuffer = null;\n if (this.#algoName === 'jpeg-lossless') {\n if (!hasJpegLosslessDecoder) {\n throw new Error('No JPEG Lossless decoder provided');\n }\n // bytes per element\n const bpe = pixelMeta.bitsAllocated / 8;\n const buf = new Uint8Array(pixelBuffer);\n // @ts-ignore\n decoder = new jpeg.lossless.Decoder();\n const decoded = decoder.decode(buf.buffer, 0, buf.buffer.byteLength, bpe);\n if (pixelMeta.bitsAllocated === 8) {\n if (pixelMeta.isSigned) {\n decodedBuffer = new Int8Array(decoded.buffer);\n } else {\n decodedBuffer = new Uint8Array(decoded.buffer);\n }\n } else if (pixelMeta.bitsAllocated === 16) {\n if (pixelMeta.isSigned) {\n decodedBuffer = new Int16Array(decoded.buffer);\n } else {\n decodedBuffer = new Uint16Array(decoded.buffer);\n }\n }\n } else if (this.#algoName === 'jpeg-baseline') {\n if (!hasJpegBaselineDecoder) {\n throw new Error('No JPEG Baseline decoder provided');\n }\n // @ts-ignore\n decoder = new JpegImage();\n decoder.parse(pixelBuffer);\n decodedBuffer = decoder.getData(decoder.width, decoder.height);\n } else if (this.#algoName === 'jpeg2000') {\n if (!hasJpeg2000Decoder) {\n throw new Error('No JPEG 2000 decoder provided');\n }\n // decompress pixel buffer into Int16 image\n // @ts-ignore\n decoder = new JpxImage();\n decoder.parse(pixelBuffer);\n // set the pixel buffer\n decodedBuffer = decoder.tiles[0].items;\n } else if (this.#algoName === 'rle') {\n // decode DICOM buffer\n // @ts-ignore\n decoder = new dwvdecoder.RleDecoder();\n // set the pixel buffer\n decodedBuffer = decoder.decode(\n pixelBuffer,\n pixelMeta.bitsAllocated,\n pixelMeta.isSigned,\n pixelMeta.sliceSize,\n pixelMeta.samplesPerPixel,\n pixelMeta.planarConfiguration);\n }\n // send decode events\n this.ondecodeditem({\n data: [decodedBuffer],\n index: info.index,\n numberOfItems: info.numberOfItems,\n itemNumber: info.itemNumber\n });\n // decode end?\n if (this.#decodeCount === this.#numberOfData) {\n this.ondecoded({});\n this.ondecodeend({});\n }\n }\n\n /**\n * Abort decoding.\n */\n abort() {\n // nothing to do in the synchronous case.\n // callback\n this.onabort({});\n this.ondecodeend({});\n }\n\n /**\n * Handle a decode start event.\n * Default does nothing.\n *\n * @param {object} _event The decode start event.\n */\n ondecodestart(_event) {}\n\n /**\n * Handle a decode item event.\n * Default does nothing.\n *\n * @param {object} _event The decode item event fired\n * when a decode item ended successfully.\n */\n ondecodeditem(_event) {}\n\n /**\n * Handle a decode event.\n * Default does nothing.\n *\n * @param {object} _event The decode event fired\n * when a file has been decoded successfully.\n */\n ondecoded(_event) {}\n\n /**\n * Handle a decode end event.\n * Default does nothing.\n *\n * @param {object} _event The decode end event fired\n * when a file decoding has completed, successfully or not.\n */\n ondecodeend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class SynchPixelBufferDecoder\n\n/**\n * Decode a pixel buffer.\n *\n * If the 'decoderScripts' variable does not contain the desired,\n * algorythm the decoder will switch to the synchronous mode.\n */\nexport class PixelBufferDecoder {\n\n /**\n * Flag to know if callbacks are set.\n *\n * @type {boolean}\n */\n #areCallbacksSet = false;\n\n /**\n * Pixel decoder.\n * Defined only once.\n *\n * @type {object}\n */\n #pixelDecoder = null;\n\n /**\n * @param {string} algoName The decompression algorithm name.\n * @param {number} numberOfData The anticipated number of data to decode.\n */\n constructor(algoName, numberOfData) {\n // initialise the asynch decoder (if possible)\n if (typeof decoderScripts !== 'undefined' &&\n typeof decoderScripts[algoName] !== 'undefined') {\n this.#pixelDecoder = new AsynchPixelBufferDecoder(\n decoderScripts[algoName], numberOfData);\n } else {\n this.#pixelDecoder = new SynchPixelBufferDecoder(\n algoName, numberOfData);\n }\n }\n\n /**\n * Get data from an input buffer using a DICOM parser.\n *\n * @param {Array} pixelBuffer The input data buffer.\n * @param {object} pixelMeta The input meta data.\n * @param {object} info Information object about the input data.\n */\n decode(pixelBuffer, pixelMeta, info) {\n if (!this.#areCallbacksSet) {\n this.#areCallbacksSet = true;\n // set callbacks\n this.#pixelDecoder.ondecodestart = this.ondecodestart;\n this.#pixelDecoder.ondecodeditem = this.ondecodeditem;\n this.#pixelDecoder.ondecoded = this.ondecoded;\n this.#pixelDecoder.ondecodeend = this.ondecodeend;\n this.#pixelDecoder.onerror = this.onerror;\n this.#pixelDecoder.onabort = this.onabort;\n }\n // decode and call the callback\n this.#pixelDecoder.decode(pixelBuffer, pixelMeta, info);\n }\n\n /**\n * Abort decoding.\n */\n abort() {\n // decoder classes should define an abort\n this.#pixelDecoder.abort();\n }\n\n /**\n * Handle a decode start event.\n * Default does nothing.\n *\n * @param {object} _event The decode start event.\n */\n ondecodestart(_event) {}\n\n /**\n * Handle a decode item event.\n * Default does nothing.\n *\n * @param {object} _event The decode item event fired\n * when a decode item ended successfully.\n */\n ondecodeditem(_event) {}\n\n /**\n * Handle a decode event.\n * Default does nothing.\n *\n * @param {object} _event The decode event fired\n * when a file has been decoded successfully.\n */\n ondecoded(_event) {}\n\n /**\n * Handle a decode end event.\n * Default does nothing.\n *\n * @param {object} _event The decode end event fired\n * when a file decoding has completed, successfully or not.\n */\n ondecodeend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class PixelBufferDecoder\n","import {\n getCode,\n getDicomCodeItem\n} from './dicomCode';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\nimport {DicomCode} from './dicomCode';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n NumericValue: '0040A30A',\n FloatingPointValue: '0040A161',\n RationalNumeratorValue: '0040A162',\n RationalDenominatorValue: '0040A163',\n MeasurementUnitsCodeSequence: '004008EA'\n};\n\n/**\n * DICOM measured value: property of a numeric measurement.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.html#table_C.18.1-1}.\n */\nexport class MeasuredValue {\n /**\n * @type {number}\n */\n numericValue;\n\n /**\n * @type {number}\n */\n floatingPointValue;\n\n /**\n * @type {number}\n */\n rationalNumeratorValue;\n\n /**\n * @type {number}\n */\n rationalDenominatorValue;\n\n /**\n * @type {DicomCode}\n */\n measurementUnitsCode;\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The object as string.\n */\n toString() {\n return this.numericValue + ' ' +\n this.measurementUnitsCode.toString();\n };\n\n};\n\n/**\n * Get a measured value object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {MeasuredValue} A measured value object.\n */\nexport function getMeasuredValue(dataElements) {\n const value = new MeasuredValue();\n\n if (typeof dataElements[TagKeys.NumericValue] !== 'undefined') {\n value.numericValue = dataElements[TagKeys.NumericValue].value[0];\n }\n if (typeof dataElements[TagKeys.FloatingPointValue] !== 'undefined') {\n value.floatingPointValue =\n dataElements[TagKeys.FloatingPointValue].value[0];\n }\n if (typeof dataElements[TagKeys.RationalNumeratorValue] !== 'undefined') {\n value.rationalNumeratorValue =\n dataElements[TagKeys.RationalNumeratorValue].value[0];\n }\n if (typeof dataElements[TagKeys.RationalDenominatorValue] !== 'undefined') {\n value.rationalDenominatorValue =\n dataElements[TagKeys.RationalDenominatorValue].value[0];\n }\n if (typeof dataElements[TagKeys.MeasurementUnitsCodeSequence] !==\n 'undefined') {\n value.measurementUnitsCode = getCode(\n dataElements[TagKeys.MeasurementUnitsCodeSequence].value[0]);\n }\n\n return value;\n};\n\n/**\n * Get a simple dicom element item from a measured value object.\n *\n * @param {MeasuredValue} value The measured value object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomMeasuredValueItem(value) {\n // dicom item (tags are in group/element order)\n const item = {};\n\n if (typeof value.measurementUnitsCode !== 'undefined') {\n item.MeasurementUnitsCodeSequence = {\n value: [getDicomCodeItem(value.measurementUnitsCode)]\n };\n }\n if (typeof value.floatingPointValue !== 'undefined') {\n item.FloatingPointValue = value.floatingPointValue;\n }\n if (typeof value.rationalNumeratorValue !== 'undefined') {\n item.RationalNumeratorValue = value.rationalNumeratorValue;\n }\n if (typeof value.rationalDenominatorValue !== 'undefined') {\n item.RationalDenominatorValue = value.rationalDenominatorValue;\n }\n if (typeof value.numericValue !== 'undefined') {\n item.NumericValue = value.numericValue;\n }\n\n // return\n return item;\n}\n","import {\n getCode,\n getDicomCodeItem\n} from './dicomCode';\nimport {\n getMeasuredValue,\n getDicomMeasuredValueItem\n} from './dicomMeasuredValue';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\nimport {MeasuredValue} from './dicomMeasuredValue';\nimport {DicomCode} from './dicomCode';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n MeasuredValueSequence: '0040A300',\n NumericValueQualifierCodeSequence: '0040A301'\n};\n\n/**\n * DICOM numeric measurement: item of a SR content sequence.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.html#table_C.18.1-1}.\n */\nexport class NumericMeasurement {\n /**\n * @type {MeasuredValue}\n */\n measuredValue;\n\n /**\n * @type {DicomCode}\n */\n numericValueQualifierCode;\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The object as string.\n */\n toString() {\n let res = this.measuredValue.toString();\n if (typeof this.numericValueQualifierCode !== 'undefined') {\n res += ' ' + this.numericValueQualifierCode.toString();\n }\n return res;\n }\n};\n\n/**\n * Get a measurement object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {NumericMeasurement} A measurement object.\n */\nexport function getNumericMeasurement(dataElements) {\n const measurement = new NumericMeasurement();\n\n if (typeof dataElements[TagKeys.MeasuredValueSequence] !== 'undefined') {\n measurement.measuredValue = getMeasuredValue(\n dataElements[TagKeys.MeasuredValueSequence].value[0]);\n }\n if (typeof dataElements[TagKeys.NumericValueQualifierCodeSequence] !==\n 'undefined') {\n measurement.numericValueQualifierCode = getCode(\n dataElements[TagKeys.NumericValueQualifierCodeSequence].value[0]);\n }\n\n return measurement;\n};\n\n/**\n * Get a simple dicom element item from a measurement object.\n *\n * @param {NumericMeasurement} measurement The measurement object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomNumericMeasurementItem(measurement) {\n // dicom item (tags are in group/element order)\n const item = {};\n\n if (typeof measurement.measuredValue !== 'undefined') {\n item.MeasuredValueSequence = {\n value: [getDicomMeasuredValueItem(measurement.measuredValue)]\n };\n }\n if (typeof measurement.numericValueQualifierCode !== 'undefined') {\n item.NumericValueQualifierCodeSequence = {\n value: [getDicomCodeItem(measurement.numericValueQualifierCode)]\n };\n }\n\n // return\n return item;\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n ReferencedSOPClassUID: '00081150',\n ReferencedSOPInstanceUID: '00081155'\n};\n\n/**\n * DICOM sop instance reference.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_10.8.html#table_10-11}.\n */\nexport class SopInstanceReference {\n /**\n * @type {string}\n */\n referencedSOPClassUID;\n\n /**\n * @type {string}\n */\n referencedSOPInstanceUID;\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The object as string.\n */\n toString() {\n return this.referencedSOPInstanceUID + ' (class: ' +\n this.referencedSOPClassUID + ')';\n };\n};\n\n/**\n * Get a SOP reference object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {SopInstanceReference} A SOP reference object.\n */\nexport function getSopInstanceReference(dataElements) {\n const ref = new SopInstanceReference();\n\n if (typeof dataElements[TagKeys.ReferencedSOPClassUID] !== 'undefined') {\n ref.referencedSOPClassUID =\n dataElements[TagKeys.ReferencedSOPClassUID].value[0];\n }\n if (typeof dataElements[TagKeys.ReferencedSOPInstanceUID] !== 'undefined') {\n ref.referencedSOPInstanceUID =\n dataElements[TagKeys.ReferencedSOPInstanceUID].value[0];\n }\n\n return ref;\n};\n\n/**\n * Get a simple dicom element item from a SOP reference object.\n *\n * @param {SopInstanceReference} ref The SOP reference object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomSopInstanceReferenceItem(ref) {\n // dicom item (tags are in group/element order)\n const item = {};\n\n if (typeof ref.referencedSOPClassUID !== 'undefined') {\n item.ReferencedSOPClassUID = ref.referencedSOPClassUID;\n }\n if (typeof ref.referencedSOPInstanceUID !== 'undefined') {\n item.ReferencedSOPInstanceUID = ref.referencedSOPInstanceUID;\n }\n\n // return\n return item;\n}\n","import {\n getSopInstanceReference,\n getDicomSopInstanceReferenceItem\n} from './dicomSopInstanceReference';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n ReferencedFrameNumber: '00081160',\n ReferencedSOPSequence: '00081199',\n ReferencedSegmentNumber: '0062000B'\n};\n\n/**\n * DICOM image reference: item of a SR content sequence.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.4.html#table_C.18.4-1}.\n */\nexport class ImageReference {\n /**\n * @type {object}\n */\n referencedSOPSequence;\n\n /**\n * @type {object}\n */\n referencedFrameNumber;\n\n /**\n * @type {string}\n */\n referencedSegmentNumber;\n\n /**\n * @type {string}\n */\n fiducialUID;\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The object as string.\n */\n toString() {\n return this.referencedSOPSequence.toString();\n };\n};\n\n/**\n * Get a reference object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {ImageReference} A reference object.\n */\nexport function getImageReference(dataElements) {\n const ref = new ImageReference();\n\n if (typeof dataElements[TagKeys.ReferencedFrameNumber] !== 'undefined') {\n ref.referencedFrameNumber =\n dataElements[TagKeys.ReferencedFrameNumber].value[0];\n }\n if (typeof dataElements[TagKeys.ReferencedSOPSequence] !== 'undefined') {\n ref.referencedSOPSequence = getSopInstanceReference(\n dataElements[TagKeys.ReferencedSOPSequence].value[0]);\n }\n if (typeof dataElements[TagKeys.ReferencedSegmentNumber] !== 'undefined') {\n ref.referencedSegmentNumber =\n dataElements[TagKeys.ReferencedSegmentNumber].value[0];\n }\n\n return ref;\n};\n\n/**\n * Get a simple dicom element item from a reference object.\n *\n * @param {ImageReference} ref The reference object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomImageReferenceItem(ref) {\n // dicom item (tags are in group/element order)\n const item = {};\n\n if (typeof ref.referencedFrameNumber !== 'undefined') {\n item.ReferencedFrameNumber = ref.referencedFrameNumber;\n }\n if (typeof ref.referencedSOPSequence !== 'undefined') {\n item.ReferencedSOPSequence = {\n value: [getDicomSopInstanceReferenceItem(ref.referencedSOPSequence)]\n };\n }\n if (typeof ref.referencedSegmentNumber !== 'undefined') {\n item.ReferencedSegmentNumber =\n ref.referencedSegmentNumber;\n }\n\n // return\n return item;\n}\n","import {Point2D} from '../math/point';\nimport {Line, areOrthogonal} from '../math/line';\nimport {Protractor} from '../math/protractor';\nimport {ROI} from '../math/roi';\nimport {Circle} from '../math/circle';\nimport {Ellipse} from '../math/ellipse';\nimport {Rectangle} from '../math/rectangle';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n PixelOriginInterpretation: '00480301',\n GraphicData: '00700022',\n GraphicType: '00700023',\n FiducialUID: '0070031A'\n};\n\n/**\n * DICOM graphic types.\n */\nexport const GraphicTypes = {\n point: 'POINT',\n multipoint: 'MULTIPOINT',\n polyline: 'POLYLINE',\n circle: 'CIRCLE',\n ellipse: 'ELLIPSE'\n};\n\n/**\n * DICOM spatial coordinate (SCOORD): item of a SR content sequence.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.6.html#table_C.18.6-1}.\n */\nexport class SpatialCoordinate {\n /**\n * @type {string[]}\n */\n graphicData;\n\n /**\n * @type {string}\n */\n graphicType;\n\n /**\n * @type {string}\n */\n pixelOriginInterpretation;\n\n /**\n * @type {string}\n */\n fiducialUID;\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The object as string.\n */\n toString() {\n return this.graphicType +\n ' {' + this.graphicData + '}';\n };\n};\n\n/**\n * Get a scoord object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {SpatialCoordinate} A scoord object.\n */\nexport function getSpatialCoordinate(dataElements) {\n const scoord = new SpatialCoordinate();\n\n if (typeof dataElements[TagKeys.GraphicData] !== 'undefined') {\n scoord.graphicData = dataElements[TagKeys.GraphicData].value;\n }\n if (typeof dataElements[TagKeys.GraphicType] !== 'undefined') {\n scoord.graphicType = dataElements[TagKeys.GraphicType].value[0];\n }\n if (typeof dataElements[TagKeys.PixelOriginInterpretation] !== 'undefined') {\n scoord.pixelOriginInterpretation =\n dataElements[TagKeys.PixelOriginInterpretation].value[0];\n }\n if (typeof dataElements[TagKeys.FiducialUID] !== 'undefined') {\n scoord.fiducialUID = dataElements[TagKeys.FiducialUID].value[0];\n }\n return scoord;\n};\n\n/**\n * Get a simple dicom element item from a scoord object.\n *\n * @param {SpatialCoordinate} scoord The scoord object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomSpatialCoordinateItem(scoord) {\n // dicom item (tags are in group/element order)\n const item = {};\n\n if (typeof scoord.pixelOriginInterpretation !== 'undefined') {\n item.PixelOriginInterpretation = scoord.pixelOriginInterpretation;\n }\n if (typeof scoord.graphicData !== 'undefined') {\n item.GraphicData = scoord.graphicData;\n }\n if (typeof scoord.graphicType !== 'undefined') {\n item.GraphicType = scoord.graphicType;\n }\n if (typeof scoord.fiducialUID !== 'undefined') {\n item.FiducialUID = scoord.fiducialUID;\n }\n\n // return\n return item;\n}\n\n/**\n * Get a DICOM spatial coordinate (SCOORD) from a mathematical shape.\n *\n * @param {Point2D|Line|Protractor|ROI|Circle|Ellipse|Rectangle} shape\n * The math shape.\n * @returns {SpatialCoordinate} The DICOM scoord.\n */\nexport function getScoordFromShape(shape) {\n const scoord = new SpatialCoordinate();\n\n if (shape instanceof Point2D) {\n scoord.graphicData = [\n shape.getX().toString(),\n shape.getY().toString(),\n ];\n scoord.graphicType = GraphicTypes.point;\n } else if (shape instanceof Line) {\n scoord.graphicData = [\n shape.getBegin().getX().toString(),\n shape.getBegin().getY().toString(),\n shape.getEnd().getX().toString(),\n shape.getEnd().getY().toString(),\n ];\n scoord.graphicType = GraphicTypes.polyline;\n } else if (shape instanceof Protractor) {\n scoord.graphicData = [];\n for (let i = 0; i < 3; ++i) {\n scoord.graphicData.push(shape.getPoint(i).getX().toString());\n scoord.graphicData.push(shape.getPoint(i).getY().toString());\n }\n scoord.graphicType = GraphicTypes.polyline;\n } else if (shape instanceof ROI) {\n scoord.graphicData = [];\n for (let i = 0; i < shape.getLength(); ++i) {\n scoord.graphicData.push(shape.getPoint(i).getX().toString());\n scoord.graphicData.push(shape.getPoint(i).getY().toString());\n }\n // repeat first point to close shape\n const firstPoint = shape.getPoint(0);\n scoord.graphicData.push(firstPoint.getX().toString());\n scoord.graphicData.push(firstPoint.getY().toString());\n\n scoord.graphicType = GraphicTypes.polyline;\n } else if (shape instanceof Circle) {\n const center = shape.getCenter();\n const pointPerimeter = new Point2D(\n center.getX() + shape.getRadius(), center.getY()\n );\n scoord.graphicData = [\n center.getX().toString(),\n center.getY().toString(),\n pointPerimeter.getX().toString(),\n pointPerimeter.getY().toString(),\n ];\n scoord.graphicType = GraphicTypes.circle;\n } else if (shape instanceof Ellipse) {\n const center = shape.getCenter();\n const radiusX = shape.getA();\n const radiusY = shape.getB();\n scoord.graphicData = [\n (center.getX() - radiusX).toString(),\n center.getY().toString(),\n (center.getX() + radiusX).toString(),\n center.getY().toString(),\n center.getX().toString(),\n (center.getY() - radiusY).toString(),\n center.getX().toString(),\n (center.getY() + radiusY).toString()\n ];\n scoord.graphicType = GraphicTypes.ellipse;\n } else if (shape instanceof Rectangle) {\n const begin = shape.getBegin();\n const end = shape.getEnd();\n // begin as first and last point to close shape\n scoord.graphicData = [\n begin.getX().toString(),\n begin.getY().toString(),\n begin.getX().toString(),\n end.getY().toString(),\n end.getX().toString(),\n end.getY().toString(),\n end.getX().toString(),\n begin.getY().toString(),\n begin.getX().toString(),\n begin.getY().toString()\n ];\n scoord.graphicType = GraphicTypes.polyline;\n }\n\n return scoord;\n};\n\n/**\n * Get a mathematical shape from a DICOM spatial coordinate (SCOORD).\n *\n * @param {SpatialCoordinate} scoord The DICOM scoord.\n * @returns {Point2D|Line|Protractor|ROI|Circle|Ellipse|Rectangle}\n * The math shape.\n */\nexport function getShapeFromScoord(scoord) {\n // extract points\n const dataLength = scoord.graphicData.length;\n if (dataLength % 2 !== 0) {\n throw new Error('Expecting even number of coordinates in scroord data');\n }\n const points = [];\n for (let i = 0; i < dataLength; i += 2) {\n points.push(new Point2D(\n parseFloat(scoord.graphicData[i]),\n parseFloat(scoord.graphicData[i + 1])\n ));\n }\n let isClosed = false;\n const numberOfPoints = points.length;\n if (numberOfPoints > 2) {\n const firstPoint = points[0];\n const lastPoint = points[numberOfPoints - 1];\n isClosed = firstPoint.equals(lastPoint);\n }\n\n // create math shape\n let shape;\n if (scoord.graphicType === GraphicTypes.point) {\n if (points.length !== 1) {\n throw new Error('Expecting 1 point for point');\n }\n shape = points[0];\n } else if (scoord.graphicType === GraphicTypes.circle) {\n if (points.length !== 2) {\n throw new Error('Expecting 2 points for circles');\n }\n const center = points[0];\n const pointPerimeter = points[1];\n const radius = pointPerimeter.getDistance(center);\n shape = new Circle(center, radius);\n } else if (scoord.graphicType === GraphicTypes.ellipse) {\n if (points.length !== 4) {\n throw new Error('Expecting 4 points for ellipses');\n }\n // TODO: make more generic\n const radiusX = points[0].getDistance(points[1]) / 2;\n const radiusY = points[2].getDistance(points[3]) / 2;\n const center = new Point2D(\n points[0].getX() + radiusX,\n points[0].getY()\n );\n shape = new Ellipse(center, radiusX, radiusY);\n } else if (scoord.graphicType === GraphicTypes.polyline) {\n if (!isClosed) {\n if (points.length === 2) {\n shape = new Line(points[0], points[1]);\n } else if (points.length === 3) {\n shape = new Protractor([points[0], points[1], points[2]]);\n }\n } else {\n if (points.length === 5) {\n const line0 = new Line(points[0], points[1]);\n const line1 = new Line(points[1], points[2]);\n const line2 = new Line(points[2], points[3]);\n const line3 = new Line(points[3], points[4]);\n if (areOrthogonal(line0, line1) &&\n areOrthogonal(line1, line2) &&\n areOrthogonal(line2, line3)) {\n shape = new Rectangle(points[0], points[2]);\n } else {\n // remove last=first point for closed shape\n shape = new ROI(points.slice(0, -1));\n }\n } else {\n // remove last=first point for closed shape\n shape = new ROI(points.slice(0, -1));\n }\n }\n }\n\n return shape;\n};","// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n GraphicData: '00700022',\n GraphicType: '00700023',\n ReferencedFrameofReferenceUID: '30060024',\n FiducialUID: '0070031A'\n};\n\n/**\n * DICOM spatial coordinate 3D (SCOORD3D): item of a SR content sequence.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.9.html#table_C.18.9-1}.\n */\nexport class SpatialCoordinate3D {\n /**\n * @type {string[]}\n */\n graphicData;\n\n /**\n * @type {string}\n */\n graphicType;\n\n /**\n * @type {string}\n */\n referencedFrameofReferenceUID;\n\n /**\n * @type {string}\n */\n fiducialUID;\n\n /**\n * Get a string representation of this object.\n *\n * @returns {string} The object as string.\n */\n toString() {\n return this.graphicType +\n '{' + this.graphicData + '}';\n };\n};\n\n/**\n * Get a scoord3d object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {SpatialCoordinate3D} A scoord3d object.\n */\nexport function getSpatialCoordinate3D(dataElements) {\n const scoord = new SpatialCoordinate3D();\n\n if (typeof dataElements[TagKeys.GraphicData] !== 'undefined') {\n scoord.graphicData = dataElements[TagKeys.GraphicData].value;\n }\n if (typeof dataElements[TagKeys.GraphicType] !== 'undefined') {\n scoord.graphicType = dataElements[TagKeys.GraphicType].value[0];\n }\n if (typeof dataElements[TagKeys.ReferencedFrameofReferenceUID] !==\n 'undefined') {\n scoord.referencedFrameofReferenceUID =\n dataElements[TagKeys.ReferencedFrameofReferenceUID].value[0];\n }\n if (typeof dataElements[TagKeys.FiducialUID] !== 'undefined') {\n scoord.fiducialUID = dataElements[TagKeys.FiducialUID].value[0];\n }\n return scoord;\n};\n\n/**\n * Get a simple dicom element item from a scoord3d object.\n *\n * @param {SpatialCoordinate3D} scoord The scoord3d object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomSpatialCoordinate3DItem(scoord) {\n // dicom item (tags are in group/element order)\n const item = {};\n\n if (typeof scoord.graphicData !== 'undefined') {\n item.GraphicData = scoord.graphicData;\n }\n if (typeof scoord.graphicType !== 'undefined') {\n item.GraphicType = scoord.graphicType;\n }\n if (typeof scoord.referencedFrameofReferenceUID !== 'undefined') {\n item.ReferencedFrameofReferenceUID =\n scoord.referencedFrameofReferenceUID;\n }\n if (typeof scoord.fiducialUID !== 'undefined') {\n item.FiducialUID = scoord.fiducialUID;\n }\n\n // return\n return item;\n}","import {\n NumericMeasurement,\n getNumericMeasurement,\n getDicomNumericMeasurementItem\n} from './dicomNumericMeasurement';\nimport {\n getCode,\n getDicomCodeItem,\n getConceptNameCode,\n getMeasurementUnitsCode\n} from './dicomCode';\nimport {\n getImageReference,\n getDicomImageReferenceItem\n} from './dicomImageReference';\nimport {\n getSopInstanceReference,\n getDicomSopInstanceReferenceItem\n} from './dicomSopInstanceReference';\nimport {\n getSpatialCoordinate,\n getDicomSpatialCoordinateItem\n} from './dicomSpatialCoordinate';\nimport {\n getSpatialCoordinate3D,\n getDicomSpatialCoordinate3DItem\n} from './dicomSpatialCoordinate3D';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from './dataElement';\nimport {DicomCode} from './dicomCode';\nimport {MeasuredValue} from './dicomMeasuredValue';\n/* eslint-enable no-unused-vars */\n\n/**\n * Related DICOM tag keys.\n */\nconst TagKeys = {\n ReferencedSOPSequence: '00081199',\n RelationshipType: '0040A010',\n ValueType: '0040A040',\n ConceptNameCodeSequence: '0040A043',\n ConceptCodeSequence: '0040A168',\n ContentSequence: '0040A730',\n DateTime: '0040A120',\n Date: '0040A121',\n Time: '0040A122',\n UID: '0040A124',\n PersonName: '0040A123',\n TextValue: '0040A160',\n ContinuityOfContent: '0040A050'\n};\n\n/**\n * DICOM relationship types.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.17.3.2.4.html#sect_C.17.3.2.4}.\n */\nexport const RelationshipTypes = {\n contains: 'CONTAINS',\n hasProperties: 'HAS PROPERTIES',\n hasObsContext: 'HAS OBS CONTEXT',\n hasAcqContext: 'HAS ACQ CONTEXT',\n inferredFrom: 'INFERRED FROM',\n selectedFrom: 'SELECTED FROM',\n hasConceptMod: 'HAS CONCEPT MOD'\n};\n\n/**\n * DICOM value types.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.17.3.2.html#sect_C.17.3.2.1}.\n */\nexport const ValueTypes = {\n text: 'TEXT',\n num: 'NUM',\n code: 'CODE',\n date: 'DATE',\n time: 'TIME',\n datetime: 'DATETIME',\n uidref: 'UIDREF',\n pname: 'PNAME',\n composite: 'COMPOSITE',\n image: 'IMAGE',\n waveform: 'WAVEFORM',\n scoord: 'SCOORD',\n scoord3d: 'SCOORD3D',\n tcoord: 'TCOORD',\n container: 'CONTAINER',\n table: 'TABLE',\n};\n\n/**\n * DICOM value type to associated tag name.\n */\nexport const ValueTypeValueTagName = {\n TEXT: 'TextValue',\n DATE: 'Date',\n TIME: 'Time',\n DATETIME: 'DateTime',\n UIDREF: 'UID',\n PNAME: 'PersonName',\n CONTAINER: 'ContinuityOfContent',\n};\n\n/**\n * DICOM SR content: item of a SR content sequence.\n *\n * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.17.3.html}.\n */\nexport class DicomSRContent {\n /**\n * Value type.\n *\n * @type {string}\n */\n valueType;\n /**\n * Concept name code.\n *\n * @type {DicomCode|undefined}\n */\n conceptNameCode;\n /**\n * Relationship Type.\n *\n * @type {string}\n */\n relationshipType;\n\n /**\n * Content sequence (0040,A730).\n *\n * @type {DicomSRContent[]|undefined}\n */\n contentSequence;\n\n /**\n * Value.\n *\n * @type {object}\n */\n value;\n\n /**\n * @param {string} valueType The content item value type.\n */\n constructor(valueType) {\n this.valueType = valueType;\n }\n\n /**\n * Get a string representation of this object.\n *\n * @param {string} [prefix] An optional prefix for recursive content.\n * @returns {string} The object as string.\n */\n toString(prefix) {\n if (typeof prefix === 'undefined') {\n prefix = '';\n }\n\n let res = '';\n\n if (typeof this.relationshipType !== 'undefined') {\n res += '(' + this.relationshipType + ') ';\n }\n\n res += this.valueType + ': ';\n\n if (typeof this.conceptNameCode !== 'undefined') {\n res += this.conceptNameCode.toString();\n }\n\n res += ' = ' + this.value.toString();\n\n if (typeof this.contentSequence !== 'undefined') {\n for (const item of this.contentSequence) {\n res += '\\n' + prefix + '- ' + item.toString(prefix + ' ');\n }\n }\n\n return res;\n }\n}\n\n/**\n * Check if two content item objects are equal.\n *\n * @param {DicomCode} item1 The first content item.\n * @param {DicomCode} item2 The second content item.\n * @returns {boolean} True if both content items are equal.\n */\nexport function isEqualContentItem(item1, item2) {\n return Object.keys(item1).length === Object.keys(item2).length &&\n Object.keys(item1).every(key =>\n Object.prototype.hasOwnProperty.call(item2, key) &&\n item1[key] === item2[key]\n );\n}\n\n/**\n * Get a content item object from a dicom element.\n *\n * @param {Object} dataElements The dicom element.\n * @returns {DicomSRContent} A content item object.\n */\nexport function getSRContent(dataElements) {\n // valueType -> ValueType (type1)\n let valueType = '';\n if (typeof dataElements[TagKeys.ValueType] !== 'undefined') {\n valueType = dataElements[TagKeys.ValueType].value[0];\n }\n\n const content = new DicomSRContent(valueType);\n\n // relationshipType -> RelationType (type1)\n if (typeof dataElements[TagKeys.RelationshipType] !== 'undefined') {\n content.relationshipType =\n dataElements[TagKeys.RelationshipType].value[0];\n }\n\n if (typeof dataElements[TagKeys.ConceptNameCodeSequence] !== 'undefined') {\n content.conceptNameCode =\n getCode(dataElements[TagKeys.ConceptNameCodeSequence].value[0]);\n }\n\n // set value acording to valueType\n // (date and time are stored as string)\n if (valueType === ValueTypes.code) {\n content.value = getCode(\n dataElements[TagKeys.ConceptCodeSequence].value[0]);\n } else if (valueType === ValueTypes.num) {\n content.value = getNumericMeasurement(dataElements);\n } else if (valueType === ValueTypes.image) {\n content.value = getImageReference(dataElements);\n } else if (valueType === ValueTypes.composite) {\n content.value = getSopInstanceReference(\n dataElements[TagKeys.ReferencedSOPSequence].value[0]\n );\n } else if (valueType === ValueTypes.scoord) {\n content.value = getSpatialCoordinate(dataElements);\n } else if (valueType === ValueTypes.scoord3d) {\n content.value = getSpatialCoordinate3D(dataElements);\n } else {\n const valueTagName = ValueTypeValueTagName[valueType];\n if (typeof valueTagName !== 'undefined') {\n content.value = dataElements[TagKeys[valueTagName]].value[0];\n } else {\n console.warn('Unsupported input ValueType: ' + valueType);\n }\n }\n\n const contentSqEl = dataElements[TagKeys.ContentSequence];\n if (typeof contentSqEl !== 'undefined') {\n content.contentSequence = [];\n for (const item of dataElements[TagKeys.ContentSequence].value) {\n content.contentSequence.push(getSRContent(item));\n }\n }\n\n return content;\n}\n\n/**\n * Get a simple dicom element item from a content item object.\n *\n * @param {DicomSRContent} content The content item object.\n * @returns {Object} The item as a list of (key, value) pairs.\n */\nexport function getDicomSRContentItem(content) {\n // dicom item (tags are in ~group/element order)\n let contentItem = {};\n\n if (typeof content.relationshipType !== 'undefined') {\n contentItem.RelationshipType = content.relationshipType;\n }\n if (typeof content.valueType !== 'undefined') {\n contentItem.ValueType = content.valueType;\n }\n if (typeof content.conceptNameCode !== 'undefined') {\n contentItem.ConceptNameCodeSequence = {\n value: [getDicomCodeItem(content.conceptNameCode)]\n };\n }\n\n // set appropriate value tag (data and time are stored as string)\n if (content.valueType === 'CODE') {\n contentItem.ConceptCodeSequence = {\n value: [getDicomCodeItem(content.value)]\n };\n } else if (content.valueType === ValueTypes.num) {\n contentItem = {\n ...contentItem,\n ...getDicomNumericMeasurementItem(content.value)\n };\n } else if (content.valueType === ValueTypes.image) {\n contentItem = {\n ...contentItem,\n ...getDicomImageReferenceItem(content.value)\n };\n } else if (content.valueType === ValueTypes.composite) {\n contentItem = {\n ...contentItem,\n ...getDicomSopInstanceReferenceItem(content.value)\n };\n } else if (content.valueType === ValueTypes.scoord) {\n contentItem = {\n ...contentItem,\n ...getDicomSpatialCoordinateItem(content.value)\n };\n } else if (content.valueType === ValueTypes.scoord3d) {\n contentItem = {\n ...contentItem,\n ...getDicomSpatialCoordinate3DItem(content.value)\n };\n } else {\n const valueTagName = ValueTypeValueTagName[content.valueType];\n if (typeof valueTagName !== 'undefined') {\n contentItem[valueTagName] = content.value;\n } else {\n console.warn('Unsupported output ValueType: ' + content.valueType);\n }\n }\n\n if (typeof content.contentSequence !== 'undefined') {\n contentItem.ContentSequence = {\n value: []\n };\n for (const item of content.contentSequence) {\n contentItem.ContentSequence.value.push(getDicomSRContentItem(item));\n }\n }\n\n return contentItem;\n}\n\n/**\n * Get a DicomSRContent from a value.\n *\n * @param {string} name The value name.\n * @param {object} value The value.\n * @param {string} unit The values' unit.\n * @returns {DicomSRContent|undefined} The SR content.\n */\nexport function getSRContentFromValue(name, value, unit) {\n const conceptNameCode = getConceptNameCode(name);\n\n if (typeof conceptNameCode === 'undefined') {\n return undefined;\n }\n\n const content = new DicomSRContent(ValueTypes.num);\n content.relationshipType = RelationshipTypes.contains;\n content.conceptNameCode = conceptNameCode;\n\n const measure = new MeasuredValue();\n measure.numericValue = value;\n measure.measurementUnitsCode = getMeasurementUnitsCode(unit);\n const numMeasure = new NumericMeasurement();\n numMeasure.measuredValue = measure;\n\n content.value = numMeasure;\n\n return content;\n}","import {\n dateToDateObj,\n getDicomDate,\n dateToTimeObj,\n getDicomTime,\n} from '../dicom/dicomDate';\nimport {\n ValueTypes,\n RelationshipTypes,\n getSRContent,\n getDicomSRContentItem,\n DicomSRContent,\n getSRContentFromValue\n} from '../dicom/dicomSRContent';\nimport {\n isEqualCode,\n getPathCode,\n getMeasurementGroupCode,\n getImageRegionCode,\n getReferenceGeometryCode,\n getSourceImageCode,\n getTrackingIdentifierCode,\n getShortLabelCode,\n getReferencePointsCode,\n getColourCode,\n getQuantificationName,\n getQuantificationUnit\n} from '../dicom/dicomCode';\nimport {getElementsFromJSONTags} from '../dicom/dicomWriter';\nimport {ImageReference} from '../dicom/dicomImageReference';\nimport {SopInstanceReference} from '../dicom/dicomSopInstanceReference';\nimport {\n GraphicTypes,\n getScoordFromShape,\n getShapeFromScoord,\n SpatialCoordinate\n} from '../dicom/dicomSpatialCoordinate';\nimport {SpatialCoordinate3D} from '../dicom/dicomSpatialCoordinate3D';\nimport {guid} from '../math/stats';\nimport {logger} from '../utils/logger';\nimport {Annotation} from './annotation';\nimport {AnnotationGroup} from './annotationGroup';\nimport {Line} from '../math/line';\nimport {Point2D, Point3D} from '../math/point';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * Merge two tag lists.\n *\n * @param {object} tags1 Base list, will be modified.\n * @param {object} tags2 List to merge.\n */\nfunction mergeTags(tags1, tags2) {\n const keys2 = Object.keys(tags2);\n for (const tagName2 of keys2) {\n if (tags1[tagName2] !== undefined) {\n logger.trace('Overwritting tag: ' + tagName2);\n }\n tags1[tagName2] = tags2[tagName2];\n }\n}\n\n/**\n * {@link AnnotationGroup} factory.\n */\nexport class AnnotationGroupFactory {\n\n /**\n * Possible warning created by checkElements.\n *\n * @type {string|undefined}\n */\n #warning;\n\n /**\n * Get a warning string if elements are not as expected.\n * Created by checkElements.\n *\n * @returns {string|undefined} The warning.\n */\n getWarning() {\n return this.#warning;\n }\n\n /**\n * Check dicom elements. Throws an error if not suitable.\n *\n * @param {Object} dataElements The DICOM data elements.\n * @returns {string|undefined} A possible warning.\n */\n checkElements(dataElements) {\n // reset\n this.#warning = undefined;\n\n const srContent = getSRContent(dataElements);\n if (typeof srContent.conceptNameCode !== 'undefined') {\n if (srContent.conceptNameCode.value !== getMeasurementGroupCode().value) {\n this.#warning = 'Not a measurement group';\n }\n } else {\n this.#warning = 'No root concept name code';\n }\n\n return this.#warning;\n }\n\n /**\n * Convert a DICOM SR content of type SCOORD into an annotation.\n *\n * @param {DicomSRContent} item The input SCOORD.\n * @returns {Annotation} The annotation.\n */\n #scoordToAnnotation(item) {\n const annotation = new Annotation();\n annotation.mathShape = getShapeFromScoord(item.value);\n // default\n annotation.id = guid();\n annotation.textExpr = '';\n\n for (const subItem of item.contentSequence) {\n // reference image UID\n if (subItem.valueType === ValueTypes.image &&\n subItem.relationshipType === RelationshipTypes.selectedFrom &&\n isEqualCode(subItem.conceptNameCode, getSourceImageCode())) {\n annotation.referenceSopUID =\n subItem.value.referencedSOPSequence.referencedSOPInstanceUID;\n }\n // annotation id\n if (subItem.valueType === ValueTypes.uidref &&\n subItem.relationshipType === RelationshipTypes.hasProperties &&\n isEqualCode(subItem.conceptNameCode, getTrackingIdentifierCode())) {\n annotation.id = subItem.value;\n }\n // text expr\n if (subItem.valueType === ValueTypes.text &&\n subItem.relationshipType === RelationshipTypes.hasProperties &&\n isEqualCode(subItem.conceptNameCode, getShortLabelCode())) {\n annotation.textExpr = subItem.value;\n if (typeof subItem.contentSequence !== 'undefined') {\n for (const subsubItem of subItem.contentSequence) {\n if (subsubItem.valueType === ValueTypes.scoord &&\n subsubItem.relationshipType === RelationshipTypes.hasProperties &&\n isEqualCode(\n subsubItem.conceptNameCode, getReferencePointsCode())) {\n annotation.labelPosition = new Point2D(\n subsubItem.value.graphicData[0],\n subsubItem.value.graphicData[1]\n );\n }\n }\n }\n }\n // color\n if (subItem.valueType === ValueTypes.text &&\n subItem.relationshipType === RelationshipTypes.hasProperties &&\n isEqualCode(subItem.conceptNameCode, getColourCode())) {\n annotation.colour = subItem.value;\n }\n // reference points\n if (subItem.valueType === ValueTypes.scoord &&\n subItem.relationshipType === RelationshipTypes.hasProperties &&\n isEqualCode(subItem.conceptNameCode, getReferencePointsCode()) &&\n subItem.value.graphicType === GraphicTypes.multipoint) {\n const points = [];\n for (let i = 0; i < subItem.value.graphicData.length; i += 2) {\n points.push(new Point2D(\n subItem.value.graphicData[i],\n subItem.value.graphicData[i + 1]\n ));\n }\n annotation.referencePoints = points;\n }\n // plane points\n if (subItem.valueType === ValueTypes.scoord3d &&\n subItem.relationshipType === RelationshipTypes.hasProperties &&\n isEqualCode(\n subItem.conceptNameCode, getReferenceGeometryCode()) &&\n subItem.value.graphicType === GraphicTypes.multipoint) {\n const data = subItem.value.graphicData;\n const points = [];\n const nPoints = Math.floor(data.length / 3);\n for (let i = 0; i < nPoints; ++i) {\n const j = i * 3;\n points.push(new Point3D(data[j], data[j + 1], data[j + 2]));\n }\n annotation.planePoints = points;\n }\n // quantification\n if (subItem.valueType === ValueTypes.num &&\n subItem.relationshipType === RelationshipTypes.contains) {\n const quantifName =\n getQuantificationName(subItem.conceptNameCode);\n if (typeof quantifName === 'undefined') {\n continue;\n }\n const measuredValue = subItem.value.measuredValue;\n const quantifUnit = getQuantificationUnit(\n measuredValue.measurementUnitsCode);\n if (typeof annotation.quantification === 'undefined') {\n annotation.quantification = {};\n }\n annotation.quantification[quantifName] = {\n value: measuredValue.numericValue,\n unit: quantifUnit\n };\n }\n }\n return annotation;\n }\n\n /**\n * Get an {@link Annotation} object from the read DICOM file.\n *\n * @param {Object} dataElements The DICOM tags.\n * @returns {AnnotationGroup} A new annotation group.\n */\n create(dataElements) {\n const annotations = [];\n const srContent = getSRContent(dataElements);\n for (const item of srContent.contentSequence) {\n if (item.valueType === ValueTypes.scoord) {\n annotations.push(this.#scoordToAnnotation(item));\n }\n }\n const annotationGroup = new AnnotationGroup(annotations);\n\n const safeGet = function (key) {\n let res;\n const element = dataElements[key];\n if (typeof element !== 'undefined') {\n res = element.value[0];\n }\n return res;\n };\n\n // StudyInstanceUID\n annotationGroup.setMetaValue('StudyInstanceUID', safeGet('0020000D'));\n // Modality\n annotationGroup.setMetaValue('Modality', safeGet('00080060'));\n // patient info\n annotationGroup.setMetaValue('PatientName', safeGet('00100010'));\n annotationGroup.setMetaValue('PatientID', safeGet('00100020'));\n annotationGroup.setMetaValue('PatientBirthDate', safeGet('00100030'));\n annotationGroup.setMetaValue('PatientSex', safeGet('00100040'));\n\n // ReferencedSeriesSequence\n const element = dataElements['00081115'];\n if (typeof element !== 'undefined') {\n const seriesElement = element.value[0]['0020000E'];\n if (typeof seriesElement !== 'undefined') {\n annotationGroup.setMetaValue(\n 'ReferencedSeriesSequence', {\n value: [{\n SeriesInstanceUID: seriesElement.value[0]\n }]\n }\n );\n }\n }\n\n return annotationGroup;\n }\n\n /**\n * Convert an annotation into a DICOM SCOORD.\n *\n * @param {Annotation} annotation The input annotation.\n * @returns {DicomSRContent} An SR content of type SCOORD.\n */\n #annotationToScoord(annotation) {\n const srScoord = new DicomSRContent(ValueTypes.scoord);\n srScoord.relationshipType = RelationshipTypes.contains;\n if (annotation.mathShape instanceof Line) {\n srScoord.conceptNameCode = getPathCode();\n } else {\n srScoord.conceptNameCode = getImageRegionCode();\n }\n srScoord.value = getScoordFromShape(annotation.mathShape);\n\n const itemContentSequence = [];\n\n // reference image UID\n const srImage = new DicomSRContent(ValueTypes.image);\n srImage.relationshipType = RelationshipTypes.selectedFrom;\n srImage.conceptNameCode = getSourceImageCode();\n const sopRef = new SopInstanceReference();\n sopRef.referencedSOPClassUID = '';\n sopRef.referencedSOPInstanceUID = annotation.referenceSopUID;\n const imageRef = new ImageReference();\n imageRef.referencedSOPSequence = sopRef;\n srImage.value = imageRef;\n itemContentSequence.push(srImage);\n\n // annotation id\n const srUid = new DicomSRContent(ValueTypes.uidref);\n srUid.relationshipType = RelationshipTypes.hasProperties;\n srUid.conceptNameCode = getTrackingIdentifierCode();\n srUid.value = annotation.id;\n itemContentSequence.push(srUid);\n\n // text expr\n const shortLabel = new DicomSRContent(ValueTypes.text);\n shortLabel.relationshipType = RelationshipTypes.hasProperties;\n shortLabel.conceptNameCode = getShortLabelCode();\n shortLabel.value = annotation.textExpr;\n // label position\n if (typeof annotation.labelPosition !== 'undefined') {\n const labelPosition = new DicomSRContent(ValueTypes.scoord);\n labelPosition.relationshipType = RelationshipTypes.hasProperties;\n labelPosition.conceptNameCode = getReferencePointsCode();\n const labelPosScoord = new SpatialCoordinate();\n labelPosScoord.graphicType = GraphicTypes.point;\n const graphicData = [\n annotation.labelPosition.getX().toString(),\n annotation.labelPosition.getY().toString()\n ];\n labelPosScoord.graphicData = graphicData;\n labelPosition.value = labelPosScoord;\n\n // add position to label sequence\n shortLabel.contentSequence = [labelPosition];\n }\n itemContentSequence.push(shortLabel);\n\n // colour\n const colour = new DicomSRContent(ValueTypes.text);\n colour.relationshipType = RelationshipTypes.hasProperties;\n colour.conceptNameCode = getColourCode();\n colour.value = annotation.colour;\n itemContentSequence.push(colour);\n\n // reference points\n if (typeof annotation.referencePoints !== 'undefined') {\n const referencePoints = new DicomSRContent(ValueTypes.scoord);\n referencePoints.relationshipType = RelationshipTypes.hasProperties;\n referencePoints.conceptNameCode = getReferencePointsCode();\n const refPointsScoord = new SpatialCoordinate();\n refPointsScoord.graphicType = GraphicTypes.multipoint;\n const graphicData = [];\n for (const point of annotation.referencePoints) {\n graphicData.push(point.getX().toString());\n graphicData.push(point.getY().toString());\n }\n refPointsScoord.graphicData = graphicData;\n\n referencePoints.value = refPointsScoord;\n itemContentSequence.push(referencePoints);\n }\n\n // plane points\n if (typeof annotation.planePoints !== 'undefined') {\n const planePoints = new DicomSRContent(ValueTypes.scoord3d);\n planePoints.relationshipType = RelationshipTypes.hasProperties;\n planePoints.conceptNameCode = getReferenceGeometryCode();\n const pointsScoord = new SpatialCoordinate3D();\n pointsScoord.graphicType = GraphicTypes.multipoint;\n const graphicData = [];\n for (const planePoint of annotation.planePoints) {\n graphicData.push(planePoint.getX().toString());\n graphicData.push(planePoint.getY().toString());\n graphicData.push(planePoint.getZ().toString());\n }\n pointsScoord.graphicData = graphicData;\n\n planePoints.value = pointsScoord;\n itemContentSequence.push(planePoints);\n }\n\n // quantification\n if (typeof annotation.quantification !== 'undefined') {\n for (const key in annotation.quantification) {\n const quatifContent = getSRContentFromValue(\n key,\n annotation.quantification[key].value,\n annotation.quantification[key].unit\n );\n if (typeof quatifContent !== 'undefined') {\n itemContentSequence.push(quatifContent);\n }\n }\n }\n\n srScoord.contentSequence = itemContentSequence;\n return srScoord;\n }\n\n /**\n * Convert an annotation group into a DICOM SR object.\n *\n * @param {AnnotationGroup} annotationGroup The annotation group.\n * @param {Object} [extraTags] Optional list of extra tags.\n * @returns {Object} A list of dicom elements.\n */\n toDicom(annotationGroup, extraTags) {\n let tags = annotationGroup.getMeta();\n\n // transfer syntax: ExplicitVRLittleEndian\n tags.TransferSyntaxUID = '1.2.840.10008.1.2.1';\n // class: Basic Text SR Storage\n tags.SOPClassUID = '1.2.840.10008.5.1.4.1.1.88.11';\n tags.MediaStorageSOPClassUID = '1.2.840.10008.5.1.4.1.1.88.11';\n tags.CompletionFlag = 'PARTIAL';\n tags.VerificationFlag = 'UNVERIFIED';\n\n const now = new Date();\n tags.ContentDate = getDicomDate(dateToDateObj(now));\n tags.ContentTime = getDicomTime(dateToTimeObj(now));\n\n const contentSequence = [];\n for (const annotation of annotationGroup.getList()) {\n contentSequence.push(this.#annotationToScoord(annotation));\n }\n\n // main\n if (contentSequence.length !== 0) {\n const srContent = new DicomSRContent(ValueTypes.container);\n srContent.conceptNameCode = getMeasurementGroupCode();\n srContent.contentSequence = contentSequence;\n\n tags = {\n ...tags,\n ...getDicomSRContentItem(srContent)\n };\n }\n\n // merge extra tags if provided\n if (typeof extraTags !== 'undefined') {\n mergeTags(tags, extraTags);\n }\n\n return getElementsFromJSONTags(tags);\n }\n\n}","import {ListenerHandler} from '../utils/listen';\nimport {mergeObjects} from '../utils/operator';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from '../image/image';\nimport {AnnotationGroup} from '../image/annotationGroup';\n/* eslint-enable no-unused-vars */\n\n/**\n * DICOM data: meta and possible image.\n */\nexport class DicomData {\n /**\n * DICOM meta data.\n *\n * @type {object}\n */\n meta;\n\n /**\n * Image extracted from meta data.\n *\n * @type {Image|undefined}\n */\n image;\n /**\n * Annotattion group extracted from meta data.\n *\n * @type {AnnotationGroup|undefined}\n */\n annotationGroup;\n\n /**\n * @param {object} meta The DICOM meta data.\n */\n constructor(meta) {\n this.meta = meta;\n }\n}\n\n/*\n * DicomData controller.\n */\nexport class DataController {\n\n /**\n * List of DICOM data.\n *\n * @type {Object}\n */\n #dataList = {};\n\n /**\n * Distinct data loaded counter.\n *\n * @type {number}\n */\n #dataIdCounter = -1;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Get the next data id.\n *\n * @returns {string} The data id.\n */\n getNextDataId() {\n ++this.#dataIdCounter;\n return this.#dataIdCounter.toString();\n }\n\n /**\n * Get the list of ids in the data storage.\n *\n * @returns {string[]} The list of data ids.\n */\n getDataIds() {\n return Object.keys(this.#dataList);\n }\n\n /**\n * Reset the class: empty the data storage.\n */\n reset() {\n this.#dataList = {};\n }\n\n /**\n * Get a data at a given index.\n *\n * @param {string} dataId The data id.\n * @returns {DicomData|undefined} The DICOM data.\n */\n get(dataId) {\n return this.#dataList[dataId];\n }\n\n /**\n * Get the list of dataIds that contain the input UIDs.\n *\n * @param {string[]} uids A list of UIDs.\n * @returns {string[]} The list of dataIds that contain the UIDs.\n */\n getDataIdsFromSopUids(uids) {\n const res = [];\n // check input\n if (typeof uids === 'undefined' ||\n uids.length === 0) {\n return res;\n }\n const keys = Object.keys(this.#dataList);\n for (const key of keys) {\n if (typeof this.#dataList[key].image !== 'undefined' &&\n this.#dataList[key].image.containsImageUids(uids)) {\n res.push(key);\n }\n }\n return res;\n }\n\n /**\n * Set the image at a given index.\n *\n * @param {string} dataId The data id.\n * @param {Image} image The image to set.\n */\n setImage(dataId, image) {\n this.#dataList[dataId].image = image;\n /**\n * Data image set event.\n *\n * @event DataController#dataimageset\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} value The event value, first element is the image.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'dataimageset',\n value: [image],\n dataid: dataId\n });\n // listen to image change\n image.addEventListener('imagecontentchange', this.#getFireEvent(dataId));\n image.addEventListener('imagegeometrychange', this.#getFireEvent(dataId));\n }\n\n /**\n * Add a new data.\n *\n * @param {string} dataId The data id.\n * @param {DicomData} data The data.\n */\n add(dataId, data) {\n if (typeof this.#dataList[dataId] !== 'undefined') {\n throw new Error('Data id already used in storage: ' + dataId);\n }\n // store the new image\n this.#dataList[dataId] = data;\n /**\n * Data add event.\n *\n * @event DataController#dataadd\n * @type {object}\n * @property {string} type The event type.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'dataadd',\n dataid: dataId\n });\n // listen to image change\n if (typeof data.image !== 'undefined') {\n data.image.addEventListener(\n 'imagecontentchange', this.#getFireEvent(dataId));\n data.image.addEventListener(\n 'imagegeometrychange', this.#getFireEvent(dataId));\n }\n if (typeof data.annotationGroup !== 'undefined') {\n data.annotationGroup.addEventListener(\n 'annotationadd', this.#getFireEvent(dataId));\n data.annotationGroup.addEventListener(\n 'annotationupdate', this.#getFireEvent(dataId));\n data.annotationGroup.addEventListener(\n 'annotationremove', this.#getFireEvent(dataId));\n }\n }\n\n /**\n * Remove a data from the list.\n *\n * @param {string} dataId The data id.\n */\n remove(dataId) {\n if (typeof this.#dataList[dataId] !== 'undefined') {\n // stop listeners\n const image = this.#dataList[dataId].image;\n if (typeof image !== 'undefined') {\n image.removeEventListener(\n 'imagecontentchange', this.#getFireEvent(dataId));\n image.removeEventListener(\n 'imagegeometrychange', this.#getFireEvent(dataId));\n }\n const annotationGroup = this.#dataList[dataId].annotationGroup;\n if (typeof annotationGroup !== 'undefined') {\n annotationGroup.removeEventListener(\n 'annotationadd', this.#getFireEvent(dataId));\n annotationGroup.removeEventListener(\n 'annotationupdate', this.#getFireEvent(dataId));\n annotationGroup.removeEventListener(\n 'annotationremove', this.#getFireEvent(dataId));\n }\n // remove data from list\n delete this.#dataList[dataId];\n /**\n * Data remove event.\n *\n * @event DataController#dataremove\n * @type {object}\n * @property {string} type The event type.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'dataremove',\n dataid: dataId\n });\n }\n }\n\n /**\n * Update the current data.\n *\n * @param {string} dataId The data id.\n * @param {DicomData} data The data.\n */\n update(dataId, data) {\n if (typeof this.#dataList[dataId] === 'undefined') {\n throw new Error('Cannot find data to update: ' + dataId);\n }\n const dataToUpdate = this.#dataList[dataId];\n\n // add slice to current image\n if (typeof dataToUpdate.image !== 'undefined' &&\n typeof data.image !== 'undefined'\n ) {\n dataToUpdate.image.appendSlice(data.image);\n }\n\n // update meta data\n // TODO add time support\n let idKey = '';\n if (typeof data.meta['00020010'] !== 'undefined') {\n // dicom case, use 'InstanceNumber'\n idKey = '00200013';\n } else {\n idKey = 'imageUid';\n }\n dataToUpdate.meta = mergeObjects(\n dataToUpdate.meta,\n data.meta,\n idKey,\n 'value');\n\n /**\n * Data udpate event.\n *\n * @event DataController#dataupdate\n * @type {object}\n * @property {string} type The event type.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'dataupdate',\n dataid: dataId\n });\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n /**\n * Get a fireEvent function that adds the input data id\n * to the event value.\n *\n * @param {string} dataId The data id.\n * @returns {Function} A fireEvent function.\n */\n #getFireEvent(dataId) {\n return (event) => {\n event.dataid = dataId;\n this.#fireEvent(event);\n };\n }\n\n} // DataController class\n","import {arrayEquals} from './array';\n\n/**\n * Merge two similar objects.\n *\n * Objects need to be in the form of:\n * \n * {\n * idKey: {valueKey: [0]},\n * key0: {valueKey: [\"abc\"]},\n * key1: {valueKey: [33]}\n * }\n * .\n *\n * Merged objects will be in the form of:\n * \n * {\n * idKey: {valueKey: [0,1,2], merged: true},\n * key0: {valueKey: {\n * 0: [\"abc\"],\n * 1: [\"def\"],\n * 2: [\"ghi\"]\n * }},\n * key1: {valueKey: {\n * 0: [33],\n * 1: [44],\n * 2: [55]\n * }}\n * }\n * .\n *\n * @param {object} obj1 The first object, can be the result of a previous merge.\n * @param {object} obj2 The second object.\n * @param {string} idKey The key to use as index for duplicate values.\n * @param {string} valueKey The key to use to access object values.\n * @returns {object} The merged object.\n */\nexport function mergeObjects(obj1, obj2, idKey, valueKey) {\n const res = {};\n // check id key\n if (!idKey) {\n throw new Error('Cannot merge object with an undefined id key: ' + idKey);\n } else {\n if (!Object.prototype.hasOwnProperty.call(obj1, idKey)) {\n throw new Error('Id key not found in first object while merging: ' +\n idKey + ', obj: ' + obj1);\n }\n if (!Object.prototype.hasOwnProperty.call(obj2, idKey)) {\n throw new Error('Id key not found in second object while merging: ' +\n idKey + ', obj: ' + obj2);\n }\n }\n // check value key\n if (!valueKey) {\n throw new Error('Cannot merge object with an undefined value key: ' +\n valueKey);\n }\n\n // check if merged object\n let mergedObj1 = false;\n if (Object.prototype.hasOwnProperty.call(obj1[idKey], 'merged') &&\n obj1[idKey].merged) {\n mergedObj1 = true;\n }\n // handle the id part\n if (!Object.prototype.hasOwnProperty.call(obj1[idKey], valueKey)) {\n throw new Error('Id value not found in first object while merging: ' +\n idKey + ', valueKey: ' + valueKey + ', ojb: ' + obj1);\n }\n if (!Object.prototype.hasOwnProperty.call(obj2[idKey], valueKey)) {\n throw new Error('Id value not found in second object while merging: ' +\n idKey + ', valueKey: ' + valueKey + ', ojb: ' + obj2);\n }\n let id1 = obj1[idKey][valueKey];\n const id2 = obj2[idKey][valueKey][0];\n // update id key\n res[idKey] = obj1[idKey];\n if (mergedObj1) {\n // check if array does not include id2\n for (let k = 0; k < id1.length; ++k) {\n if (id1[k] === id2) {\n throw new Error('The first object already contains id2: ' +\n id2 + ', id1: ' + id1);\n }\n }\n res[idKey][valueKey].push(id2);\n } else {\n id1 = id1[0];\n if (id1 === id2) {\n throw new Error('Cannot merge object with same ids: ' +\n id1 + ', id2: ' + id2);\n }\n // update merge object\n res[idKey][valueKey].push(id2);\n res[idKey].merged = true;\n }\n\n // get keys\n const keys1 = Object.keys(obj1);\n // keys2 without duplicates of keys1\n const keys2 = Object.keys(obj2).filter(function (item) {\n return keys1.indexOf(item) < 0;\n });\n const keys = keys1.concat(keys2);\n\n // loop through keys\n for (let i = 0; i < keys.length; ++i) {\n const key = keys[i];\n if (key !== idKey) {\n // first\n let value1;\n let subValue1;\n if (Object.prototype.hasOwnProperty.call(obj1, key)) {\n value1 = obj1[key];\n if (Object.prototype.hasOwnProperty.call(value1, valueKey)) {\n subValue1 = value1[valueKey];\n }\n }\n // second\n let value2;\n let subValue2;\n if (Object.prototype.hasOwnProperty.call(obj2, key)) {\n value2 = obj2[key];\n if (Object.prototype.hasOwnProperty.call(value2, valueKey)) {\n subValue2 = value2[valueKey];\n }\n }\n // result value\n let value;\n // use existing to copy properties\n if (typeof value1 !== 'undefined') {\n value = value1;\n } else if (typeof value2 !== 'undefined') {\n value = value2;\n }\n // create merge object if different values\n if (!arrayEquals(subValue1, subValue2)) {\n // add to merged object or create new\n if (mergedObj1) {\n if (Array.isArray(subValue1)) {\n // merged object with repeated value\n // copy it with the index list\n value[valueKey] = {};\n for (let j = 0; j < id1.length; ++j) {\n value[valueKey][id1[j]] = subValue1;\n }\n } else {\n value[valueKey] = subValue1;\n }\n // undefined subValue1\n if (typeof value[valueKey] === 'undefined') {\n value[valueKey] = {};\n }\n // add obj2 value\n value[valueKey][id2] = subValue2;\n } else {\n // create merge object\n const newValue = {};\n newValue[id1] = subValue1;\n newValue[id2] = subValue2;\n value[valueKey] = newValue;\n }\n }\n // store value in result object\n res[key] = value;\n }\n }\n return res;\n}\n","import {logger} from '../utils/logger';\nimport {\n DicomParser,\n getSyntaxDecompressionName\n} from '../dicom/dicomParser';\nimport {ImageFactory} from './imageFactory';\nimport {MaskFactory} from './maskFactory';\nimport {PixelBufferDecoder} from './decoder';\nimport {AnnotationGroupFactory} from './annotationGroupFactory';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from '../dicom/dataElement';\nimport {DicomData} from '../app/dataController';\n/* eslint-enable no-unused-vars */\n\n/**\n * Create a View from a DICOM buffer.\n */\nexport class DicomBufferToView {\n\n /**\n * Converter options.\n *\n * @type {object}\n */\n #options;\n\n /**\n * Set the converter options.\n *\n * @param {object} opt The input options.\n */\n setOptions(opt) {\n this.#options = opt;\n }\n\n /**\n * Pixel buffer decoder.\n * Define only once to allow optional asynchronous mode.\n *\n * @type {object}\n */\n #pixelDecoder = null;\n\n // local tmp storage\n #dicomParserStore = [];\n #finalBufferStore = [];\n #decompressedSizes = [];\n #factories = [];\n\n /**\n * Get the factory associated to input DICOM elements.\n *\n * @param {Object} elements The DICOM elements.\n * @returns {ImageFactory|MaskFactory|AnnotationGroupFactory|undefined}\n * The associated factory.\n */\n #getFactory(elements) {\n let factory;\n const modalityElement = elements['00080060'];\n if (typeof modalityElement !== 'undefined') {\n const modality = modalityElement.value[0];\n if (modality === 'SEG') {\n // mask factory for DICOM SEG\n factory = new MaskFactory();\n } else if (modality === 'SR') {\n // annotation factory for DICOM SR\n factory = new AnnotationGroupFactory();\n }\n }\n // image factory for pixel data\n if (typeof factory === 'undefined') {\n const pixelElement = elements['7FE00010'];\n if (typeof pixelElement !== 'undefined') {\n factory = new ImageFactory();\n }\n }\n return factory;\n }\n\n /**\n * Generate the data object.\n *\n * @param {number} index The data index.\n * @param {string} origin The data origin.\n */\n #generateData(index, origin) {\n const dataElements = this.#dicomParserStore[index].getDicomElements();\n const factory = this.#factories[index];\n // exit if no factory\n if (typeof factory === 'undefined') {\n return;\n }\n // create data\n try {\n const data = new DicomData(dataElements);\n if (factory instanceof AnnotationGroupFactory) {\n data.annotationGroup = factory.create(dataElements);\n } else {\n data.image = factory.create(\n dataElements,\n this.#finalBufferStore[index],\n this.#options.numberOfFiles);\n }\n // call onloaditem\n this.onloaditem({\n data: data,\n source: origin,\n warn: factory.getWarning()\n });\n } catch (error) {\n this.onerror({\n error: error,\n source: origin\n });\n this.onloadend({\n source: origin\n });\n }\n }\n\n /**\n * Generate the image object from an uncompressed buffer.\n *\n * @param {number} index The data index.\n * @param {string} origin The data origin.\n */\n #generateImageUncompressed(index, origin) {\n // send progress\n this.onprogress({\n lengthComputable: true,\n loaded: 100,\n total: 100,\n index: index,\n source: origin\n });\n // generate image\n this.#generateData(index, origin);\n // send load events\n this.onload({\n source: origin\n });\n this.onloadend({\n source: origin\n });\n }\n\n /**\n * Generate the image object from an compressed buffer.\n *\n * @param {number} index The data index.\n * @param {Array} pixelBuffer The dicom parser.\n * @param {string} algoName The compression algorithm name.\n */\n #generateImageCompressed(index, pixelBuffer, algoName) {\n const dicomParser = this.#dicomParserStore[index];\n\n // gather pixel buffer meta data\n const bitsAllocated =\n dicomParser.getDicomElements()['00280100'].value[0];\n const pixelRepresentation =\n dicomParser.getDicomElements()['00280103'].value[0];\n const pixelMeta = {\n bitsAllocated: bitsAllocated,\n isSigned: (pixelRepresentation === 1)\n };\n const columnsElement = dicomParser.getDicomElements()['00280011'];\n const rowsElement = dicomParser.getDicomElements()['00280010'];\n if (typeof columnsElement !== 'undefined' &&\n typeof rowsElement !== 'undefined') {\n pixelMeta.sliceSize = columnsElement.value[0] * rowsElement.value[0];\n }\n const samplesPerPixelElement =\n dicomParser.getDicomElements()['00280002'];\n if (typeof samplesPerPixelElement !== 'undefined') {\n pixelMeta.samplesPerPixel = samplesPerPixelElement.value[0];\n }\n const planarConfigurationElement =\n dicomParser.getDicomElements()['00280006'];\n if (typeof planarConfigurationElement !== 'undefined') {\n pixelMeta.planarConfiguration = planarConfigurationElement.value[0];\n }\n\n const numberOfItems = pixelBuffer.length;\n\n // setup the decoder (one decoder per all converts)\n if (this.#pixelDecoder === null) {\n this.#pixelDecoder = new PixelBufferDecoder(\n algoName, numberOfItems);\n // callbacks\n // pixelDecoder.ondecodestart: nothing to do\n this.#pixelDecoder.ondecodeditem = (event) => {\n this.#onDecodedItem(event);\n // send onload and onloadend when all items have been decoded\n if (event.itemNumber + 1 === event.numberOfItems) {\n this.onload(event);\n this.onloadend(event);\n }\n };\n // pixelDecoder.ondecoded: nothing to do\n // pixelDecoder.ondecodeend: nothing to do\n this.#pixelDecoder.onerror = this.onerror;\n this.#pixelDecoder.onabort = this.onabort;\n }\n\n // launch decode\n for (let i = 0; i < numberOfItems; ++i) {\n this.#pixelDecoder.decode(pixelBuffer[i], pixelMeta,\n {\n itemNumber: i,\n numberOfItems: numberOfItems,\n index: index\n }\n );\n }\n }\n\n /**\n * Handle a decoded item event.\n *\n * @param {object} event The decoded item event.\n */\n #onDecodedItem(event) {\n // send progress\n this.onprogress({\n lengthComputable: true,\n loaded: event.itemNumber + 1,\n total: event.numberOfItems,\n index: event.index,\n source: origin\n });\n\n const dataIndex = event.index;\n\n // store decoded data\n const decodedData = event.data[0];\n if (event.numberOfItems !== 1) {\n // allocate buffer if not done yet\n if (typeof this.#decompressedSizes[dataIndex] === 'undefined') {\n this.#decompressedSizes[dataIndex] = decodedData.length;\n const fullSize = event.numberOfItems *\n this.#decompressedSizes[dataIndex];\n try {\n this.#finalBufferStore[dataIndex] =\n new decodedData.constructor(fullSize);\n } catch (error) {\n if (error instanceof RangeError) {\n const powerOf2 = Math.floor(Math.log(fullSize) / Math.log(2));\n logger.error('Cannot allocate ' +\n decodedData.constructor.name +\n ' of size: ' +\n fullSize + ' (>2^' + powerOf2 + ') for decompressed data.');\n }\n // abort\n this.#pixelDecoder.abort();\n // send events\n this.onerror({\n error: error,\n source: origin\n });\n this.onloadend({\n source: origin\n });\n // exit\n return;\n }\n }\n // hoping for all items to have the same size...\n if (decodedData.length !== this.#decompressedSizes[dataIndex]) {\n logger.warn('Unsupported varying decompressed data size: ' +\n decodedData.length + ' != ' + this.#decompressedSizes[dataIndex]);\n }\n // set buffer item data\n this.#finalBufferStore[dataIndex].set(\n decodedData, this.#decompressedSizes[dataIndex] * event.itemNumber);\n } else {\n this.#finalBufferStore[dataIndex] = decodedData;\n }\n\n // create image for the first item\n if (event.itemNumber === 0) {\n this.#generateData(dataIndex, origin);\n }\n }\n\n /**\n * Handle non image data.\n *\n * @param {number} index The data index.\n * @param {string} origin The data origin.\n */\n #handleNonImageData(index, origin) {\n this.#generateData(index, origin);\n // send load events\n this.onload({\n source: origin\n });\n this.onloadend({\n source: origin\n });\n }\n\n /**\n * Handle image data.\n *\n * @param {number} index The data index.\n * @param {string} origin The data origin.\n */\n #handleImageData(index, origin) {\n const dicomParser = this.#dicomParserStore[index];\n\n const pixelBuffer = dicomParser.getDicomElements()['7FE00010'].value;\n // help GC: discard pixel buffer from elements\n dicomParser.getDicomElements()['7FE00010'].value = [];\n this.#finalBufferStore[index] = pixelBuffer[0];\n\n // transfer syntax (always there)\n const syntax = dicomParser.getDicomElements()['00020010'].value[0];\n const algoName = getSyntaxDecompressionName(syntax);\n const needDecompression = typeof algoName !== 'undefined';\n\n if (needDecompression) {\n // generate image\n this.#generateImageCompressed(\n index,\n pixelBuffer,\n algoName);\n } else {\n this.#generateImageUncompressed(index, origin);\n }\n }\n\n /**\n * Get data from an input buffer using a DICOM parser.\n *\n * @param {ArrayBuffer} buffer The input data buffer.\n * @param {string} origin The data origin.\n * @param {number} dataIndex The data index.\n */\n convert(buffer, origin, dataIndex) {\n // start event\n this.onloadstart({\n source: origin,\n index: dataIndex\n });\n\n // DICOM parser\n const dicomParser = new DicomParser();\n\n if (typeof this.#options.defaultCharacterSet !== 'undefined') {\n dicomParser.setDefaultCharacterSet(this.#options.defaultCharacterSet);\n }\n // parse the buffer\n let factory;\n try {\n dicomParser.parse(buffer);\n // check elements\n factory = this.#getFactory(dicomParser.getDicomElements());\n if (typeof factory !== 'undefined') {\n factory.checkElements(dicomParser.getDicomElements());\n }\n } catch (error) {\n this.onerror({\n error: error,\n source: origin\n });\n this.onloadend({\n source: origin\n });\n return;\n }\n\n // store\n this.#dicomParserStore[dataIndex] = dicomParser;\n this.#factories[dataIndex] = factory;\n\n // handle parsed data\n if (factory instanceof AnnotationGroupFactory) {\n this.#handleNonImageData(dataIndex, origin);\n } else {\n this.#handleImageData(dataIndex, origin);\n }\n }\n\n /**\n * Abort a conversion.\n */\n abort() {\n // abort decoding, will trigger pixelDecoder.onabort\n if (this.#pixelDecoder) {\n this.#pixelDecoder.abort();\n }\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n /**\n * Handle a load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class DicomBufferToView\n","import {MultiProgressHandler} from '../utils/progress';\nimport {loaderList} from './loaderList';\n\n/**\n * Memory loader.\n */\nexport class MemoryLoader {\n\n /**\n * Input data.\n *\n * @type {Array}\n */\n #inputData = null;\n\n /**\n * Data loader.\n *\n * @type {object}\n */\n #runningLoader = null;\n\n /**\n * Number of loaded data.\n *\n * @type {number}\n */\n #nLoad = 0;\n\n /**\n * Number of load end events.\n *\n * @type {number}\n */\n #nLoadend = 0;\n\n /**\n * The default character set (optional).\n *\n * @type {string}\n */\n #defaultCharacterSet;\n\n /**\n * Get the default character set.\n *\n * @returns {string} The default character set.\n */\n getDefaultCharacterSet() {\n return this.#defaultCharacterSet;\n }\n\n /**\n * Set the default character set.\n *\n * @param {string} characterSet The character set.\n */\n setDefaultCharacterSet(characterSet) {\n this.#defaultCharacterSet = characterSet;\n }\n\n /**\n * Store the current input.\n *\n * @param {object} data The input data.\n */\n #storeInputData(data) {\n this.#inputData = data;\n // reset counters\n this.#nLoad = 0;\n this.#nLoadend = 0;\n // clear storage\n this.#clearStoredLoader();\n }\n\n /**\n * Store the launched loader.\n *\n * @param {object} loader The launched loader.\n */\n #storeLoader(loader) {\n this.#runningLoader = loader;\n }\n\n /**\n * Clear the stored loader.\n *\n */\n #clearStoredLoader() {\n this.#runningLoader = null;\n }\n\n /**\n * Increment the number of loaded data\n * and call onload if loaded all data.\n *\n * @param {object} _event The load data event.\n */\n #addLoad = (_event) => {\n this.#nLoad++;\n // call onload when all is loaded\n // (not using the input event since it is not the\n // general load)\n if (this.#nLoad === this.#inputData.length) {\n this.onload({\n source: this.#inputData\n });\n }\n };\n\n /**\n * Increment the counter of load end events\n * and run callbacks when all done, erroneus or not.\n *\n * @param {object} _event The load end event.\n */\n #addLoadend = (_event) => {\n this.#nLoadend++;\n // call onloadend when all is run\n // (not using the input event since it is not the\n // general load end)\n if (this.#nLoadend === this.#inputData.length) {\n this.onloadend({\n source: this.#inputData\n });\n }\n };\n\n /**\n * Load a list of buffers.\n *\n * @param {Array} data The list of buffers to load.\n */\n load(data) {\n // check input\n if (typeof data === 'undefined' || data.length === 0) {\n return;\n }\n this.#storeInputData(data);\n\n // send start event\n this.onloadstart({\n source: data\n });\n\n // create prgress handler\n const mproghandler = new MultiProgressHandler(this.onprogress);\n mproghandler.setNToLoad(data.length);\n mproghandler.setNumberOfDimensions(1);\n\n // create loaders\n const loaders = [];\n for (let m = 0; m < loaderList.length; ++m) {\n loaders.push(new loaderList[m]());\n }\n\n // find an appropriate loader\n let dataElement = data[0];\n let loader = null;\n let foundLoader = false;\n for (let l = 0; l < loaders.length; ++l) {\n loader = loaders[l];\n if (loader.canLoadMemory(dataElement)) {\n foundLoader = true;\n // load options\n loader.setOptions({\n numberOfFiles: data.length,\n defaultCharacterSet: this.getDefaultCharacterSet()\n });\n // set loader callbacks\n // loader.onloadstart: nothing to do\n loader.onprogress = mproghandler.getUndefinedMonoProgressHandler(0);\n loader.onloaditem = this.onloaditem;\n loader.onload = this.#addLoad;\n loader.onloadend = this.#addLoadend;\n loader.onerror = this.onerror;\n loader.onabort = this.onabort;\n\n // store loader\n this.#storeLoader(loader);\n // exit\n break;\n }\n }\n if (!foundLoader) {\n throw new Error('No loader found for data: ' + dataElement.filename);\n }\n\n // loop on I/O elements\n for (let i = 0; i < data.length; ++i) {\n dataElement = data[i];\n // check loader\n if (!loader.canLoadMemory(dataElement)) {\n throw new Error('Input data of different type: ' +\n dataElement.filename);\n }\n // read\n loader.load(dataElement.data, dataElement.filename, i);\n }\n }\n\n /**\n * Abort a load.\n */\n abort() {\n // abort loader\n if (this.#runningLoader && this.#runningLoader.isLoading()) {\n this.#runningLoader.abort();\n }\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle a load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class MemoryLoader\n","import {Size} from '../image/size';\nimport {Spacing} from '../image/spacing';\nimport {Geometry} from '../image/geometry';\nimport {Image} from '../image/image';\nimport {Point3D} from '../math/point';\n\n/**\n * Create a simple array buffer from an ImageData buffer.\n *\n * @param {object} imageData The ImageData taken from a context.\n * @returns {Uint8Array} The image buffer.\n */\nfunction imageDataToBuffer(imageData) {\n // remove alpha\n // TODO support passing the full image data\n const dataLen = imageData.data.length;\n const buffer = new Uint8Array((dataLen / 4) * 3);\n let j = 0;\n for (let i = 0; i < dataLen; i += 4) {\n buffer[j] = imageData.data[i];\n buffer[j + 1] = imageData.data[i + 1];\n buffer[j + 2] = imageData.data[i + 2];\n j += 3;\n }\n return buffer;\n}\n\n/**\n * Get an image from an input context imageData.\n *\n * @param {number} width The width of the coresponding image.\n * @param {number} height The height of the coresponding image.\n * @param {number} sliceIndex The slice index of the imageData.\n * @param {object} imageBuffer The image buffer.\n * @param {number} numberOfFrames The final number of frames.\n * @param {string} imageUid The image UID.\n * @returns {object} The corresponding view.\n */\nfunction getDefaultImage(\n width, height, sliceIndex,\n imageBuffer, numberOfFrames,\n imageUid) {\n // image size\n const imageSize = new Size([width, height, 1]);\n // default spacing\n // TODO: misleading...\n const imageSpacing = new Spacing([1, 1, 1]);\n // default origin\n const origin = new Point3D(0, 0, sliceIndex);\n // create image\n const geometry = new Geometry(origin, imageSize, imageSpacing);\n const image = new Image(geometry, imageBuffer, [imageUid]);\n image.setPhotometricInterpretation('RGB');\n // meta information\n const meta = {};\n meta.BitsStored = 8;\n if (typeof numberOfFrames !== 'undefined') {\n meta.numberOfFiles = numberOfFrames;\n }\n image.setMeta(meta);\n // return\n return image;\n}\n\n/**\n * Get data from an input image using a canvas.\n *\n * @param {HTMLImageElement} domImage The DOM Image,\n * an HTMLImageElement with extra info.\n * @param {string|File} origin The data origin.\n * @param {number} index The data index.\n * @returns {object} A load data event.\n */\nexport function getViewFromDOMImage(domImage, origin, index) {\n // image size\n const width = domImage.width;\n const height = domImage.height;\n\n // draw the image in the canvas in order to get its data\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n ctx.drawImage(domImage, 0, 0);\n // get the image data\n const imageData = ctx.getImageData(0, 0, width, height);\n\n // image properties\n const info = {};\n if (typeof origin === 'string') {\n info['origin'] = {value: origin};\n } else {\n info['fileName'] = {value: origin.name};\n info['fileType'] = {value: origin.type};\n info['fileLastModifiedDate'] = {value: origin.lastModified};\n }\n info['imageWidth'] = {value: width};\n info['imageHeight'] = {value: height};\n\n const sliceIndex = index ? index : 0;\n info['imageUid'] = {value: sliceIndex};\n\n // create view\n const imageBuffer = imageDataToBuffer(imageData);\n const image = getDefaultImage(\n width, height, sliceIndex, imageBuffer, 1, sliceIndex.toString());\n\n // return\n return {\n data: {\n image: image,\n info: info\n },\n source: origin\n };\n}\n\n/**\n * Get data from an input image using a canvas.\n *\n * @param {object} video The DOM Video, an HTMLVideoElement with extra info.\n * @param {Function} onloaditem On load callback.\n * @param {object} onload The function to call once the data is loaded.\n * @param {object} onprogress The function to call to report progress.\n * @param {object} onloadend The function to call to report load end.\n * @param {string|File} origin The data origin.\n * @param {number} dataIndex The data index.\n */\nexport function getViewFromDOMVideo(\n video, onloaditem, onload, onprogress, onloadend,\n origin, dataIndex) {\n // video size\n const width = video.videoWidth;\n const height = video.videoHeight;\n\n // default frame rate...\n const frameRate = 30;\n // number of frames\n const numberOfFrames = Math.ceil(video.duration * frameRate);\n\n // video properties\n const info = {};\n if (typeof origin === 'string') {\n info['origin'] = {value: origin};\n } else {\n info['fileName'] = {value: origin.name};\n info['fileType'] = {value: origin.type};\n info['fileLastModifiedDate'] = {value: origin.lastModified};\n }\n info['imageWidth'] = {value: width};\n info['imageHeight'] = {value: height};\n info['numberOfFrames'] = {value: numberOfFrames};\n info['imageUid'] = {value: 0};\n\n // draw the image in the canvas in order to get its data\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n\n // using seeked to loop through all video frames\n video.addEventListener('seeked', onseeked, false);\n\n // current frame index\n let frameIndex = 0;\n // video image\n let image = null;\n\n /**\n * Draw the context and store it as a frame.\n */\n function storeFrame() {\n // send progress\n onprogress({\n lengthComputable: true,\n loaded: frameIndex,\n total: numberOfFrames,\n index: dataIndex,\n source: origin\n });\n // draw image\n ctx.drawImage(video, 0, 0);\n // context to image buffer\n const imgBuffer = imageDataToBuffer(\n ctx.getImageData(0, 0, width, height));\n if (frameIndex === 0) {\n // create view\n image = getDefaultImage(\n width, height, 1, imgBuffer, numberOfFrames, dataIndex.toString());\n // call callback\n onloaditem({\n data: {\n image: image,\n info: info\n },\n source: origin\n });\n } else {\n image.appendFrameBuffer(imgBuffer, frameIndex);\n }\n // increment index\n ++frameIndex;\n }\n\n let nextTime = 0;\n\n /**\n * Handle seeked event.\n *\n * @param {object} event The seeked event.\n */\n function onseeked(event) {\n // store\n storeFrame();\n // set the next time\n // (not using currentTime, it seems to get offseted)\n nextTime += 1 / frameRate;\n if (nextTime <= event.target.duration) {\n this.currentTime = nextTime;\n } else {\n onload({\n source: origin\n });\n onloadend({\n source: origin\n });\n // stop listening\n video.removeEventListener('seeked', onseeked);\n }\n }\n\n // trigger the first seek\n video.currentTime = nextTime;\n}\n","import {DicomDataLoader} from './dicomDataLoader';\nimport {JSONTextLoader} from './jsonTextLoader';\nimport {MultipartLoader} from './multipartLoader';\nimport {RawImageLoader} from './rawImageLoader';\nimport {RawVideoLoader} from './rawVideoLoader';\nimport {ZipLoader} from './zipLoader';\n\nexport const loaderList = [\n DicomDataLoader,\n JSONTextLoader,\n MultipartLoader,\n RawImageLoader,\n RawVideoLoader,\n ZipLoader\n];\n","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\nimport {DicomBufferToView} from '../image/dicomBufferToView';\n\n/**\n * DICOM data loader.\n */\nexport class DicomDataLoader {\n\n /**\n * Loader options.\n *\n * @type {object}\n */\n #options = {};\n\n /**\n * Loading flag.\n *\n * @type {boolean}\n */\n #isLoading = false;\n\n /**\n * Set the loader options.\n *\n * @param {object} opt The input options.\n */\n setOptions(opt) {\n this.#options = opt;\n }\n\n /**\n * Is the load ongoing?\n *\n * @returns {boolean} True if loading.\n */\n isLoading() {\n return this.#isLoading;\n }\n\n /**\n * DICOM buffer to View (asynchronous).\n *\n */\n #db2v = new DicomBufferToView();\n\n /**\n * Load data.\n *\n * @param {object} buffer The DICOM buffer.\n * @param {string} origin The data origin.\n * @param {number} index The data index.\n */\n load(buffer, origin, index) {\n // setup db2v ony once\n if (!this.#isLoading) {\n // pass options\n this.#db2v.setOptions(this.#options);\n // connect handlers\n this.#db2v.onloadstart = this.onloadstart;\n this.#db2v.onprogress = this.onprogress;\n this.#db2v.onloaditem = this.onloaditem;\n this.#db2v.onload = this.onload;\n this.#db2v.onloadend = (event) => {\n // reset loading flag\n this.#isLoading = false;\n // call listeners\n this.onloadend(event);\n };\n this.#db2v.onerror = (event) => {\n event.source = origin;\n this.onerror(event);\n };\n this.#db2v.onabort = this.onabort;\n }\n\n // set loading flag\n this.#isLoading = true;\n // convert\n this.#db2v.convert(buffer, origin, index);\n }\n\n /**\n * Abort load.\n */\n abort() {\n // reset loading flag\n this.#isLoading = false;\n // abort conversion, will trigger db2v.onabort\n this.#db2v.abort();\n }\n\n /**\n * Check if the loader can load the provided file.\n * True if one of the folowing conditions is true:\n * - the file has a 'dcm' extension,\n * - the file has no extension.\n *\n * @param {File} file The file to check.\n * @returns {boolean} True if the file can be loaded.\n */\n canLoadFile(file) {\n const ext = getFileExtension(file.name);\n const hasNoExt = (ext === null);\n const hasDcmExt = (ext === 'dcm');\n return hasNoExt || hasDcmExt;\n }\n\n /**\n * Check if the loader can load the provided url.\n * True if one of the folowing conditions is true:\n * - the `options.forceLoader` is 'dicom',\n * - the `options.requestHeaders` contains a 'Accept: application/dicom',\n * - the url has a 'contentType' and it is 'application/dicom'\n * (as in wado urls),\n * - the url has no 'contentType' and no extension or the extension is 'dcm'.\n *\n * @param {string} url The url to check.\n * @param {object} [options] Optional url request options.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadUrl(url, options) {\n // check options\n if (typeof options !== 'undefined') {\n // check options.forceLoader\n if (typeof options.forceLoader !== 'undefined' &&\n options.forceLoader === 'dicom') {\n return true;\n }\n // check options.requestHeaders for 'Accept'\n if (typeof options.requestHeaders !== 'undefined') {\n const isNameAccept = function (element) {\n return element.name === 'Accept';\n };\n const acceptHeader = options.requestHeaders.find(isNameAccept);\n if (typeof acceptHeader !== 'undefined') {\n // starts with 'application/dicom' and no '+'\n const acceptValue = 'application/dicom';\n return startsWith(acceptHeader.value, acceptValue) &&\n acceptHeader.value[acceptValue.length] !== '+';\n }\n }\n }\n\n const urlObjext = getUrlFromUri(url);\n // extension\n const ext = getFileExtension(urlObjext.pathname);\n const hasNoExt = (ext === null);\n const hasDcmExt = (ext === 'dcm');\n // content type (for wado url)\n const contentType = urlObjext.searchParams.get('contentType');\n const hasContentType = contentType !== null &&\n typeof contentType !== 'undefined';\n const hasDicomContentType = (contentType === 'application/dicom');\n\n return hasContentType ? hasDicomContentType : (hasNoExt || hasDcmExt);\n }\n\n /**\n * Check if the loader can load the provided memory object.\n *\n * @param {object} mem The memory object.\n * @returns {boolean} True if the object can be loaded.\n */\n canLoadMemory(mem) {\n const contentType = mem['Content-Type'];\n if (typeof contentType !== 'undefined' &&\n contentType.startsWith('application/dicom')) {\n return true;\n }\n if (typeof mem.filename !== 'undefined') {\n const tmpFile = new File(['from memory'], mem.filename);\n return this.canLoadFile(tmpFile);\n }\n return false;\n }\n\n /**\n * Get the file content type needed by the loader.\n *\n * @returns {number} One of the 'fileContentTypes'.\n */\n loadFileAs() {\n return fileContentTypes.ArrayBuffer;\n }\n\n /**\n * Get the url content type needed by the loader.\n *\n * @returns {number} One of the 'urlContentTypes'.\n */\n loadUrlAs() {\n return urlContentTypes.ArrayBuffer;\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a progress event.\n * Default does nothing.\n *\n * @param {object} _event The load progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle an load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class DicomDataLoader\n","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\n\n/**\n * JSON text loader.\n */\nexport class JSONTextLoader {\n\n /**\n * Loading flag.\n *\n * @type {boolean}\n */\n #isLoading = false;\n\n /**\n * Set the loader options.\n *\n * @param {object} _opt The input options.\n */\n setOptions(_opt) {\n // does nothing\n }\n\n /**\n * Is the load ongoing?\n *\n * @returns {boolean} True if loading.\n */\n isLoading() {\n return this.#isLoading;\n }\n\n /**\n * Load data.\n *\n * @param {object} text The input text.\n * @param {string} origin The data origin.\n * @param {number} index The data index.\n */\n load(text, origin, index) {\n // set loading flag\n this.#isLoading = true;\n this.onloadstart({\n source: origin\n });\n\n try {\n this.onprogress({\n lengthComputable: true,\n loaded: 100,\n total: 100,\n index: index,\n source: origin\n });\n const data = {\n data: text,\n source: origin\n };\n // only expecting one item\n this.onloaditem(data);\n this.onload(data);\n } catch (error) {\n this.onerror({\n error: error,\n source: origin\n });\n } finally {\n // reset loading flag\n this.#isLoading = false;\n this.onloadend({\n source: origin\n });\n }\n }\n\n /**\n * Abort load: pass to listeners.\n */\n abort() {\n // reset loading flag\n this.#isLoading = false;\n // call listeners\n this.onabort({});\n this.onloadend({});\n }\n\n /**\n * Check if the loader can load the provided file.\n * True if the file has a 'json' extension.\n *\n * @param {File} file The file to check.\n * @returns {boolean} True if the file can be loaded.\n */\n canLoadFile(file) {\n const ext = getFileExtension(file.name);\n return (ext === 'json');\n }\n\n /**\n * Check if the loader can load the provided url.\n * True if one of the folowing conditions is true:\n * - the `options.forceLoader` is 'json',\n * - the `options.requestHeaders` contains a 'Accept: application/json' or\n * 'Accept: application/dicom+json',\n * - the url has a 'json' extension.\n *\n * @param {string} url The url to check.\n * @param {object} [options] Optional url request options.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadUrl(url, options) {\n // check options\n if (typeof options !== 'undefined') {\n // check options.forceLoader\n if (typeof options.forceLoader !== 'undefined' &&\n options.forceLoader === 'json') {\n return true;\n }\n // check options.requestHeaders for 'Accept'\n if (typeof options.requestHeaders !== 'undefined') {\n const isNameAccept = function (element) {\n return element.name === 'Accept';\n };\n const acceptHeader = options.requestHeaders.find(isNameAccept);\n if (typeof acceptHeader !== 'undefined') {\n // starts with 'application/json' or 'application/dicom+json\n return startsWith(acceptHeader.value, 'application/json') ||\n startsWith(acceptHeader.value, 'application/dicom+json');\n }\n }\n }\n\n const urlObjext = getUrlFromUri(url);\n const ext = getFileExtension(urlObjext.pathname);\n return (ext === 'json');\n }\n\n /**\n * Check if the loader can load the provided memory object.\n *\n * @param {object} mem The memory object.\n * @returns {boolean} True if the object can be loaded.\n */\n canLoadMemory(mem) {\n const contentType = mem['Content-Type'];\n if (typeof contentType !== 'undefined' &&\n contentType.startsWith('application/json')) {\n return true;\n }\n if (typeof mem.filename !== 'undefined') {\n const tmpFile = new File(['from memory'], mem.filename);\n return this.canLoadFile(tmpFile);\n }\n return false;\n }\n\n /**\n * Get the file content type needed by the loader.\n *\n * @returns {number} One of the 'fileContentTypes'.\n */\n loadFileAs() {\n return fileContentTypes.Text;\n }\n\n /**\n * Get the url content type needed by the loader.\n *\n * @returns {number} One of the 'urlContentTypes'.\n */\n loadUrlAs() {\n return urlContentTypes.Text;\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a progress event.\n * Default does nothing.\n *\n * @param {object} _event The load progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle an load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class JSONTextLoader\n","import {startsWith} from '../utils/string';\nimport {parseMultipart} from '../utils/array';\nimport {MemoryLoader} from './memoryLoader';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\n\n/**\n * Multipart data loader.\n */\nexport class MultipartLoader {\n\n /**\n * Loading flag.\n *\n * @type {boolean}\n */\n #isLoading = false;\n\n /**\n * Set the loader options.\n *\n * @param {object} _opt The input options.\n */\n setOptions(_opt) {\n // does nothing\n }\n\n /**\n * Is the load ongoing?\n *\n * @returns {boolean} True if loading.\n */\n isLoading() {\n return this.#isLoading;\n }\n\n /**\n * Load data.\n *\n * @param {object} buffer The DICOM buffer.\n * @param {string} origin The data origin.\n * @param {number} index The data index.\n */\n load(buffer, origin, index) {\n // send start event\n this.onloadstart({\n source: origin\n });\n // set loading flag\n this.#isLoading = true;\n\n const memoryIO = new MemoryLoader();\n // memoryIO.onloadstart: nothing to do\n memoryIO.onprogress = (progress) => {\n // add 50% to take into account the un-Multipartping\n progress.loaded = 50 + progress.loaded / 2;\n // set data index\n progress.index = index;\n this.onprogress(progress);\n };\n memoryIO.onloaditem = this.onloaditem;\n memoryIO.onload = this.onload;\n memoryIO.onloadend = (event) => {\n // reset loading flag\n this.#isLoading = false;\n // call listeners\n this.onloadend(event);\n };\n memoryIO.onerror = this.onerror;\n memoryIO.onabort = this.onabort;\n // launch\n memoryIO.load(parseMultipart(buffer));\n }\n\n /**\n * Abort load: pass to listeners.\n */\n abort() {\n // reset loading flag\n this.#isLoading = false;\n // call listeners\n this.onabort({});\n this.onloadend({});\n }\n\n /**\n * Check if the loader can load the provided file.\n * Always returns false.\n *\n * @param {File} _file The file to check.\n * @returns {boolean} True if the file can be loaded.\n */\n canLoadFile(_file) {\n return false;\n }\n\n /**\n * Check if the loader can load the provided url.\n * True if one of the folowing conditions is true:\n * - the `options.forceLoader` is 'multipart',\n * - the `options.requestHeaders` contains a 'Accept: multipart/related'.\n *\n * @param {string} url The url to check.\n * @param {object} [options] Optional url request options.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadUrl(url, options) {\n // check options\n if (typeof options !== 'undefined') {\n // check options.forceLoader\n if (typeof options.forceLoader !== 'undefined' &&\n options.forceLoader === 'multipart') {\n return true;\n }\n // check options.requestHeaders for 'Accept'\n if (typeof options.requestHeaders !== 'undefined') {\n const isNameAccept = function (element) {\n return element.name === 'Accept';\n };\n const acceptHeader = options.requestHeaders.find(isNameAccept);\n if (typeof acceptHeader !== 'undefined') {\n // starts with 'multipart/related'\n return startsWith(acceptHeader.value, 'multipart/related');\n }\n }\n }\n\n return false;\n }\n\n /**\n * Check if the loader can load the provided memory object.\n *\n * @param {object} _mem The memory object.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadMemory(_mem) {\n return false;\n }\n\n /**\n * Get the file content type needed by the loader.\n *\n * @returns {number} One of the 'fileContentTypes'.\n */\n loadFileAs() {\n return fileContentTypes.ArrayBuffer;\n }\n\n /**\n * Get the url content type needed by the loader.\n *\n * @returns {number} One of the 'urlContentTypes'.\n */\n loadUrlAs() {\n return urlContentTypes.ArrayBuffer;\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle an load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class MultipartLoader\n","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {getViewFromDOMImage} from '../image/domReader';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\n\n/**\n * Raw image loader.\n */\nexport class RawImageLoader {\n\n /**\n * If abort is triggered, all image.onload callbacks have to be cancelled.\n *\n * @type {boolean}\n */\n #aborted = false;\n\n /**\n * Set the loader options.\n *\n * @param {object} _opt The input options.\n */\n setOptions(_opt) {\n // does nothing\n }\n\n /**\n * Is the load ongoing? TODO...\n *\n * @returns {boolean} True if loading.\n */\n isLoading() {\n return true;\n }\n\n /**\n * Create a Data URI from an HTTP request response.\n *\n * @param {ArrayBuffer} response The HTTP request response.\n * @param {string} dataType The data type.\n * @returns {string} The data URI.\n */\n #createDataUri(response, dataType) {\n // image type\n let imageType = dataType;\n if (!imageType || imageType === 'jpg') {\n imageType = 'jpeg';\n }\n // create uri\n const file = new Blob([response], {type: 'image/' + imageType});\n return window.URL.createObjectURL(file);\n }\n\n /**\n * Load data.\n *\n * @param {ArrayBuffer|string} buffer The read data.\n * @param {string|File} origin The data origin.\n * @param {number} index The data index.\n */\n load(buffer, origin, index) {\n this.#aborted = false;\n // create a DOM image\n const image = new Image();\n // triggered by ctx.drawImage\n image.onload = (/*event*/) => {\n try {\n if (!this.#aborted) {\n this.onprogress({\n lengthComputable: true,\n loaded: 100,\n total: 100,\n index: index,\n source: origin\n });\n const data = getViewFromDOMImage(image, origin, index);\n // only expecting one item\n this.onloaditem(data);\n this.onload(data);\n }\n } catch (error) {\n this.onerror({\n error: error,\n source: origin\n });\n } finally {\n this.onloadend({\n source: origin\n });\n }\n };\n // storing values to pass them on\n if (typeof buffer === 'string') {\n // file case\n image.src = buffer;\n } else if (typeof origin === 'string') {\n // url case\n const ext = origin.split('.').pop().toLowerCase();\n image.src = this.#createDataUri(buffer, ext);\n }\n }\n\n /**\n * Abort load.\n */\n abort() {\n this.#aborted = true;\n this.onabort({});\n this.onloadend({});\n }\n\n /**\n * Check if the loader can load the provided file.\n * True for files with type 'image.*'.\n *\n * @param {File} file The file to check.\n * @returns {boolean} True if the file can be loaded.\n */\n canLoadFile(file) {\n return (typeof file.type !== 'undefined' &&\n file.type.match('image.*') !== null);\n }\n\n /**\n * Check if the loader can load the provided url.\n * True if one of the folowing conditions is true:\n * - the `options.forceLoader` is 'rawimage',\n * - the `options.requestHeaders` contains an item\n * starting with 'Accept: image/'.\n * - the url has a 'contentType' and it is 'image/jpeg', 'image/png'\n * or 'image/gif' (as in wado urls),\n * - the url has no 'contentType' and the extension is 'jpeg', 'jpg',\n * 'png' or 'gif'.\n *\n * @param {string} url The url to check.\n * @param {object} [options] Optional url request options.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadUrl(url, options) {\n // check options\n if (typeof options !== 'undefined') {\n // check options.forceLoader\n if (typeof options.forceLoader !== 'undefined' &&\n options.forceLoader === 'rawimage') {\n return true;\n }\n // check options.requestHeaders for 'Accept'\n if (typeof options.requestHeaders !== 'undefined') {\n const isNameAccept = function (element) {\n return element.name === 'Accept';\n };\n const acceptHeader = options.requestHeaders.find(isNameAccept);\n if (typeof acceptHeader !== 'undefined') {\n // starts with 'image/'\n return startsWith(acceptHeader.value, 'image/');\n }\n }\n }\n\n const urlObjext = getUrlFromUri(url);\n // extension\n const ext = getFileExtension(urlObjext.pathname);\n const hasImageExt = (ext === 'jpeg') || (ext === 'jpg') ||\n (ext === 'png') || (ext === 'gif');\n // content type (for wado url)\n const contentType = urlObjext.searchParams.get('contentType');\n const hasContentType = contentType !== null &&\n typeof contentType !== 'undefined';\n const hasImageContentType = (contentType === 'image/jpeg') ||\n (contentType === 'image/png') ||\n (contentType === 'image/gif');\n\n return hasContentType ? hasImageContentType : hasImageExt;\n }\n\n /**\n * Check if the loader can load the provided memory object.\n *\n * @param {object} mem The memory object.\n * @returns {boolean} True if the object can be loaded.\n */\n canLoadMemory(mem) {\n if (typeof mem.filename !== 'undefined') {\n const tmpFile = new File(['from memory'], mem.filename);\n return this.canLoadFile(tmpFile);\n }\n return false;\n }\n\n /**\n * Get the file content type needed by the loader.\n *\n * @returns {number} One of the 'fileContentTypes'.\n */\n loadFileAs() {\n return fileContentTypes.DataURL;\n }\n\n /**\n * Get the url content type needed by the loader.\n *\n * @returns {number} One of the 'urlContentTypes'.\n */\n loadUrlAs() {\n return urlContentTypes.ArrayBuffer;\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle an load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class RawImageLoader","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {getViewFromDOMVideo} from '../image/domReader';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\n\n/**\n * Raw video loader.\n *\n * Url example (cors enabled):\n * {@link https://raw.githubusercontent.com/clappr/clappr/master/test/fixtures/SampleVideo_360x240_1mb.mp4}.\n */\nexport class RawVideoLoader {\n\n /**\n * Set the loader options.\n *\n * @param {object} _opt The input options.\n */\n setOptions(_opt) {\n // does nothing\n }\n\n /**\n * Is the load ongoing? TODO...\n *\n * @returns {boolean} True if loading.\n */\n isLoading() {\n return true;\n }\n\n /**\n * Create a Data URI from an HTTP request response.\n *\n * @param {object} response The HTTP request response.\n * @param {string} dataType The data type.\n * @returns {string} The data URI.\n */\n #createDataUri(response, dataType) {\n // image data as string\n const bytes = new Uint8Array(response);\n let videoDataStr = '';\n for (let i = 0; i < bytes.byteLength; ++i) {\n videoDataStr += String.fromCharCode(bytes[i]);\n }\n // create uri\n const uri = 'data:video/' + dataType +\n ';base64,' + window.btoa(videoDataStr);\n return uri;\n }\n\n /**\n * Internal Data URI load.\n *\n * @param {object} buffer The read data.\n * @param {string} origin The data origin.\n * @param {number} index The data index.\n */\n load(buffer, origin, index) {\n // create a DOM video\n const video = document.createElement('video');\n if (typeof origin === 'string') {\n // url case\n const ext = origin.split('.').pop().toLowerCase();\n video.src = this.#createDataUri(buffer, ext);\n } else {\n video.src = buffer;\n }\n // onload handler\n video.onloadedmetadata = (event) => {\n try {\n getViewFromDOMVideo(event.target,\n this.onloaditem, this.onload,\n this.onprogress, this.onloadend,\n origin, index);\n } catch (error) {\n this.onerror({\n error: error,\n source: origin\n });\n this.onloadend({\n source: origin\n });\n }\n };\n }\n\n /**\n * Abort load.\n */\n abort() {\n this.onabort({});\n this.onloadend({});\n }\n\n /**\n * Check if the loader can load the provided file.\n * True for files with type 'video.*'.\n *\n * @param {File} file The file to check.\n * @returns {boolean} True if the file can be loaded.\n */\n canLoadFile(file) {\n return (typeof file.type !== 'undefined' &&\n file.type.match('video.*') !== null);\n }\n\n /**\n * Check if the loader can load the provided url.\n * True if one of the folowing conditions is true:\n * - the `options.forceLoader` is 'rawvideo',\n * - the `options.requestHeaders` contains an item\n * starting with 'Accept: video/'.\n * - the url has a 'mp4', 'ogg' or 'webm' extension.\n *\n * @param {string} url The url to check.\n * @param {object} [options] Optional url request options.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadUrl(url, options) {\n // check options\n if (typeof options !== 'undefined') {\n // check options.forceLoader\n if (typeof options.forceLoader !== 'undefined' &&\n options.forceLoader === 'rawvideo') {\n return true;\n }\n // check options.requestHeaders for 'Accept'\n if (typeof options.requestHeaders !== 'undefined') {\n const isNameAccept = function (element) {\n return element.name === 'Accept';\n };\n const acceptHeader = options.requestHeaders.find(isNameAccept);\n if (typeof acceptHeader !== 'undefined') {\n // starts with 'video/'\n return startsWith(acceptHeader.value, 'video/');\n }\n }\n }\n\n const urlObjext = getUrlFromUri(url);\n const ext = getFileExtension(urlObjext.pathname);\n return (ext === 'mp4') ||\n (ext === 'ogg') ||\n (ext === 'webm');\n }\n\n /**\n * Check if the loader can load the provided memory object.\n *\n * @param {object} mem The memory object.\n * @returns {boolean} True if the object can be loaded.\n */\n canLoadMemory(mem) {\n if (typeof mem.filename !== 'undefined') {\n const tmpFile = new File(['from memory'], mem.filename);\n return this.canLoadFile(tmpFile);\n }\n return false;\n }\n\n /**\n * Get the file content type needed by the loader.\n *\n * @returns {number} One of the 'fileContentTypes'.\n */\n loadFileAs() {\n return fileContentTypes.DataURL;\n }\n\n /**\n * Get the url content type needed by the loader.\n *\n * @returns {number} One of the 'urlContentTypes'.\n */\n loadUrlAs() {\n return urlContentTypes.ArrayBuffer;\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle an load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class RawVideoLoader\n","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\nimport {MemoryLoader} from './memoryLoader';\n\n/**\n * The zip library.\n *\n * Ref: {@link https://github.com/Stuk/jszip}.\n *\n * @external JSZip\n */\nimport JSZip from 'jszip';\n\n/**\n * ZIP data loader.\n */\nexport class ZipLoader {\n\n /**\n * Loading flag.\n *\n * @type {boolean}\n */\n #isLoading = false;\n\n /**\n * Set the loader options.\n *\n * @param {object} _opt The input options.\n */\n setOptions(_opt) {\n // does nothing\n }\n\n /**\n * Is the load ongoing?\n *\n * @returns {boolean} True if loading.\n */\n isLoading() {\n return this.#isLoading;\n }\n\n #filename = '';\n #files = [];\n #zobjs = null;\n\n /**\n * JSZip.async callback.\n *\n * @param {ArrayBuffer} content Unzipped file image.\n * @param {object} origin The origin of the file.\n * @param {number} index The data index.\n */\n #zipAsyncCallback(content, origin, index) {\n this.#files.push({filename: this.#filename, data: content});\n\n // sent un-ziped progress with the data index\n // (max 50% to take into account the memory loading)\n const unzipPercent = this.#files.length * 100 / this.#zobjs.length;\n this.onprogress({\n lengthComputable: true,\n loaded: (unzipPercent / 2),\n total: 100,\n index: index,\n item: {\n loaded: unzipPercent,\n total: 100,\n source: origin\n }\n });\n\n // recursively call until we have all the files\n if (this.#files.length < this.#zobjs.length) {\n const num = this.#files.length;\n this.#filename = this.#zobjs[num].name;\n this.#zobjs[num].async('arrayBuffer').then((content) => {\n this.#zipAsyncCallback(content, origin, index);\n });\n } else {\n const memoryIO = new MemoryLoader();\n // memoryIO.onloadstart: nothing to do\n memoryIO.onprogress = (progress) => {\n // add 50% to take into account the un-zipping\n progress.loaded = 50 + progress.loaded / 2;\n // set data index\n progress.index = index;\n this.onprogress(progress);\n };\n memoryIO.onloaditem = this.onloaditem;\n memoryIO.onload = this.onload;\n memoryIO.onloadend = (event) => {\n // reset loading flag\n this.#isLoading = false;\n // call listeners\n this.onloadend(event);\n };\n memoryIO.onerror = this.onerror;\n memoryIO.onabort = this.onabort;\n // launch\n memoryIO.load(this.#files);\n }\n }\n\n /**\n * Load data.\n *\n * @param {object} buffer The DICOM buffer.\n * @param {string} origin The data origin.\n * @param {number} index The data index.\n */\n load(buffer, origin, index) {\n // send start event\n this.onloadstart({\n source: origin\n });\n // set loading flag\n this.#isLoading = true;\n\n JSZip.loadAsync(buffer).then((zip) => {\n this.#files = [];\n this.#zobjs = zip.file(/.*\\.dcm/);\n // recursively load zip files into the files array\n const num = this.#files.length;\n this.#filename = this.#zobjs[num].name;\n this.#zobjs[num].async('arrayBuffer').then((content) => {\n this.#zipAsyncCallback(content, origin, index);\n });\n });\n }\n\n /**\n * Abort load: pass to listeners.\n */\n abort() {\n // reset loading flag\n this.#isLoading = false;\n // call listeners\n this.onabort({});\n this.onloadend({});\n }\n\n /**\n * Check if the loader can load the provided file.\n * True if the file has a 'zip' extension.\n *\n * @param {File} file The file to check.\n * @returns {boolean} True if the file can be loaded.\n */\n canLoadFile(file) {\n const ext = getFileExtension(file.name);\n return (ext === 'zip');\n }\n\n /**\n * Check if the loader can load the provided url.\n * True if one of the folowing conditions is true:\n * - the `options.forceLoader` is 'zip',\n * - the `options.requestHeaders` contains an item\n * starting with 'Accept: application/zip'.\n * - the url has a 'zip' extension.\n *\n * @param {string} url The url to check.\n * @param {object} [options] Optional url request options.\n * @returns {boolean} True if the url can be loaded.\n */\n canLoadUrl(url, options) {\n // check options\n if (typeof options !== 'undefined') {\n // check options.forceLoader\n if (typeof options.forceLoader !== 'undefined' &&\n options.forceLoader === 'zip') {\n return true;\n }\n // check options.requestHeaders for 'Accept'\n if (typeof options.requestHeaders !== 'undefined') {\n const isNameAccept = function (element) {\n return element.name === 'Accept';\n };\n const acceptHeader = options.requestHeaders.find(isNameAccept);\n if (typeof acceptHeader !== 'undefined') {\n // starts with 'application/zip'\n return startsWith(acceptHeader.value, 'application/zip');\n }\n }\n }\n\n const urlObjext = getUrlFromUri(url);\n const ext = getFileExtension(urlObjext.pathname);\n return (ext === 'zip');\n }\n\n /**\n * Check if the loader can load the provided memory object.\n *\n * @param {object} mem The memory object.\n * @returns {boolean} True if the object can be loaded.\n */\n canLoadMemory(mem) {\n const contentType = mem['Content-Type'];\n if (typeof contentType !== 'undefined' &&\n contentType.startsWith('application/zip')) {\n return true;\n }\n if (typeof mem.filename !== 'undefined') {\n const tmpFile = new File(['from memory'], mem.filename);\n return this.canLoadFile(tmpFile);\n }\n return false;\n }\n\n /**\n * Get the file content type needed by the loader.\n *\n * @returns {number} One of the 'fileContentTypes'.\n */\n loadFileAs() {\n return fileContentTypes.ArrayBuffer;\n }\n\n /**\n * Get the url content type needed by the loader.\n *\n * @returns {number} One of the 'urlContentTypes'.\n */\n loadUrlAs() {\n return urlContentTypes.ArrayBuffer;\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle an load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class ZipLoader\n","import {MultiProgressHandler} from '../utils/progress';\nimport {loaderList} from './loaderList';\n\n// file content types\nexport const fileContentTypes = {\n Text: 0,\n ArrayBuffer: 1,\n DataURL: 2\n};\n\n/**\n * Files loader.\n */\nexport class FilesLoader {\n\n /**\n * Input data.\n *\n * @type {File[]}\n */\n #inputData = null;\n\n /**\n * Array of launched file readers.\n *\n * @type {FileReader[]}\n */\n #readers = [];\n\n /**\n * Data loader.\n *\n * @type {object}\n */\n #runningLoader = null;\n\n /**\n * Number of loaded data.\n *\n * @type {number}\n */\n #nLoad = 0;\n\n /**\n * Number of load end events.\n *\n * @type {number}\n */\n #nLoadend = 0;\n\n /**\n * The default character set (optional).\n *\n * @type {string}\n */\n #defaultCharacterSet;\n\n /**\n * Get the default character set.\n *\n * @returns {string} The default character set.\n */\n getDefaultCharacterSet() {\n return this.#defaultCharacterSet;\n }\n\n /**\n * Set the default character set.\n *\n * @param {string} characterSet The character set.\n */\n setDefaultCharacterSet(characterSet) {\n this.#defaultCharacterSet = characterSet;\n }\n\n /**\n * Store the current input.\n *\n * @param {File[]} data The input data.\n */\n #storeInputData(data) {\n this.#inputData = data;\n // reset counters\n this.#nLoad = 0;\n this.#nLoadend = 0;\n // clear storage\n this.#clearStoredReaders();\n this.#clearStoredLoader();\n }\n\n /**\n * Store a launched reader.\n *\n * @param {FileReader} reader The launched reader.\n */\n #storeReader(reader) {\n this.#readers.push(reader);\n }\n\n /**\n * Clear the stored readers.\n *\n */\n #clearStoredReaders() {\n this.#readers = [];\n }\n\n /**\n * Store the launched loader.\n *\n * @param {object} loader The launched loader.\n */\n #storeLoader(loader) {\n this.#runningLoader = loader;\n }\n\n /**\n * Clear the stored loader.\n *\n */\n #clearStoredLoader() {\n this.#runningLoader = null;\n }\n\n /**\n * Increment the number of loaded data\n * and call onload if loaded all data.\n *\n * @param {object} _event The load data event.\n */\n #addLoad = (_event) => {\n this.#nLoad++;\n // call onload when all is loaded\n // (not using the input event since it is\n // an individual load)\n if (this.#nLoad === this.#inputData.length) {\n this.onload({\n source: this.#inputData\n });\n }\n };\n\n /**\n * Increment the counter of load end events\n * and run callbacks when all done, erroneus or not.\n *\n * @param {object} _event The load end event.\n */\n #addLoadend = (_event) => {\n this.#nLoadend++;\n // call onloadend when all is run\n // (not using the input event since it is\n // an individual load end)\n if (this.#nLoadend === this.#inputData.length) {\n this.onloadend({\n source: this.#inputData\n });\n }\n };\n\n /**\n * @callback eventFn\n * @param {object} event The event.\n */\n\n /**\n * Augment a callback event with a srouce.\n *\n * @param {object} callback The callback to augment its event.\n * @param {object} source The source to add to the event.\n * @returns {eventFn} The augmented callback.\n */\n #augmentCallbackEvent(callback, source) {\n return (event) => {\n event.source = source;\n callback(event);\n };\n }\n\n /**\n * Get a load handler for a data element.\n *\n * @param {object} loader The associated loader.\n * @param {File} dataElement The data element.\n * @param {number} i The index of the element.\n * @returns {eventFn} A load handler.\n */\n #getLoadHandler(loader, dataElement, i) {\n return (event) => {\n loader.load(event.target.result, dataElement, i);\n };\n }\n\n\n /**\n * Load a list of files.\n *\n * @param {File[]} data The list of files to load.\n */\n load(data) {\n // check input\n if (typeof data === 'undefined' || data.length === 0) {\n return;\n }\n this.#storeInputData(data);\n\n // send start event\n this.onloadstart({\n source: data\n });\n\n // create prgress handler\n const mproghandler = new MultiProgressHandler(this.onprogress);\n mproghandler.setNToLoad(data.length);\n\n // create loaders\n const loaders = [];\n for (let m = 0; m < loaderList.length; ++m) {\n loaders.push(new loaderList[m]());\n }\n\n // find an appropriate loader\n let dataElement = data[0];\n let loader = null;\n let foundLoader = false;\n for (let l = 0; l < loaders.length; ++l) {\n loader = loaders[l];\n if (loader.canLoadFile(dataElement)) {\n foundLoader = true;\n // load options\n loader.setOptions({\n numberOfFiles: data.length,\n defaultCharacterSet: this.getDefaultCharacterSet()\n });\n // set loader callbacks\n // loader.onloadstart: nothing to do\n loader.onprogress = mproghandler.getUndefinedMonoProgressHandler(1);\n loader.onloaditem = this.onloaditem;\n loader.onload = this.#addLoad;\n loader.onloadend = this.#addLoadend;\n loader.onerror = this.onerror;\n loader.onabort = this.onabort;\n\n // store loader\n this.#storeLoader(loader);\n // exit\n break;\n }\n }\n if (!foundLoader) {\n throw new Error('No loader found for file: ' + dataElement.name);\n }\n\n // loop on I/O elements\n for (let i = 0; i < data.length; ++i) {\n dataElement = data[i];\n\n // check loader\n if (!loader.canLoadFile(dataElement)) {\n throw new Error('Input file of different type: ' + dataElement);\n }\n\n /**\n * The file reader.\n *\n * Ref: {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader}.\n *\n * @external FileReader\n */\n const reader = new FileReader();\n // store reader\n this.#storeReader(reader);\n\n // set reader callbacks\n // reader.onloadstart: nothing to do\n reader.onprogress = this.#augmentCallbackEvent(\n mproghandler.getMonoProgressHandler(i, 0), dataElement);\n reader.onload = this.#getLoadHandler(loader, dataElement, i);\n // reader.onloadend: nothing to do\n const errorCallback =\n this.#augmentCallbackEvent(this.onerror, dataElement);\n reader.onerror = (event) => {\n this.#addLoadend();\n errorCallback(event);\n };\n const abortCallback =\n this.#augmentCallbackEvent(this.onabort, dataElement);\n reader.onabort = (event) => {\n this.#addLoadend();\n abortCallback(event);\n };\n // read\n if (loader.loadFileAs() === fileContentTypes.Text) {\n reader.readAsText(dataElement);\n } else if (loader.loadFileAs() === fileContentTypes.DataURL) {\n reader.readAsDataURL(dataElement);\n } else if (loader.loadFileAs() === fileContentTypes.ArrayBuffer) {\n reader.readAsArrayBuffer(dataElement);\n }\n }\n }\n\n /**\n * Abort a load.\n */\n abort() {\n // abort readers\n for (let i = 0; i < this.#readers.length; ++i) {\n // 0: EMPTY, 1: LOADING, 2: DONE\n if (this.#readers[i].readyState === 1) {\n this.#readers[i].abort();\n }\n }\n // abort loader\n if (this.#runningLoader && this.#runningLoader.isLoading()) {\n this.#runningLoader.abort();\n }\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load item event fired\n * when a file item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle a load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class FilesLoader\n","import {FilesLoader} from '../io/filesLoader';\nimport {MemoryLoader} from '../io/memoryLoader';\nimport {UrlsLoader} from '../io/urlsLoader';\n\n/**\n * Load controller.\n */\nexport class LoadController {\n\n /**\n * The default character set.\n *\n * @type {string}\n */\n #defaultCharacterSet;\n\n /**\n * List of current loaders.\n *\n * @type {object}\n */\n #currentLoaders = {};\n\n /**\n * @param {string} defaultCharacterSet The default character set.\n */\n constructor(defaultCharacterSet) {\n this.#defaultCharacterSet = defaultCharacterSet;\n }\n\n /**\n * Load a list of files. Can be image files or a state file.\n *\n * @param {File[]} files The list of files to load.\n * @param {string} dataId The data Id.\n */\n loadFiles(files, dataId) {\n // has been checked for emptiness.\n const ext = files[0].name.split('.').pop().toLowerCase();\n if (ext === 'json') {\n this.#loadStateFile(files[0], dataId);\n } else {\n this.#loadImageFiles(files, dataId);\n }\n }\n\n /**\n * Load a list of URLs. Can be image files or a state file.\n *\n * @param {string[]} urls The list of urls to load.\n * @param {string} dataId The data Id.\n * @param {object} [options] The load options:\n * - requestHeaders: an array of {name, value} to use as request headers.\n * - withCredentials: credentials flag to pass to the request.\n */\n\n loadURLs(urls, dataId, options) {\n // has been checked for emptiness.\n const ext = urls[0].split('.').pop().toLowerCase();\n if (ext === 'json') {\n this.#loadStateUrl(urls[0], dataId, options);\n } else {\n this.#loadImageUrls(urls, dataId, options);\n }\n }\n\n /**\n * Load a list of ArrayBuffers.\n *\n * @param {Array} data The list of ArrayBuffers to load\n * in the form of [{name: '', filename: '', data: data}].\n * @param {string} dataId The data Id.\n */\n loadImageObject(data, dataId) {\n // create IO\n const memoryIO = new MemoryLoader();\n // load data\n this.#loadData(data, memoryIO, 'image', dataId);\n }\n\n /**\n * Get the currently loaded data ids.\n *\n * @returns {string[]} The data ids.\n */\n getLoadingDataIds() {\n return Object.keys(this.#currentLoaders);\n }\n\n /**\n * Abort an individual current loader.\n *\n * @param {string} dataId The data to stop loading.\n */\n abort(dataId) {\n if (typeof this.#currentLoaders[dataId] !== 'undefined') {\n this.#currentLoaders[dataId].loader.abort();\n delete this.#currentLoaders[dataId];\n }\n }\n\n // private ----------------------------------------------------------------\n\n /**\n * Load a list of image files.\n *\n * @param {File[]} files The list of image files to load.\n * @param {string} dataId The data Id.\n */\n #loadImageFiles(files, dataId) {\n // create IO\n const fileIO = new FilesLoader();\n fileIO.setDefaultCharacterSet(this.#defaultCharacterSet);\n // load data\n this.#loadData(files, fileIO, 'image', dataId);\n }\n\n /**\n * Load a list of image URLs.\n *\n * @param {string[]} urls The list of urls to load.\n * @param {string} [dataId] The data Id.\n * @param {object} [options] The load options:\n * - requestHeaders: an array of {name, value} to use as request headers.\n * - withCredentials: credentials flag to pass to the request.\n */\n #loadImageUrls(urls, dataId, options) {\n // create IO\n const urlIO = new UrlsLoader();\n urlIO.setDefaultCharacterSet(this.#defaultCharacterSet);\n // load data\n this.#loadData(urls, urlIO, 'image', dataId, options);\n }\n\n /**\n * Load a State file.\n *\n * @param {File} file The state file to load.\n * @param {string} dataId The data Id.\n */\n #loadStateFile(file, dataId) {\n // create IO\n const fileIO = new FilesLoader();\n // load data\n this.#loadData([file], fileIO, 'state', dataId);\n }\n\n\n /**\n * Load a State url.\n *\n * @param {string} url The state url to load.\n * @param {string} [dataId] The data Id.\n * @param {object} [options] The load options:\n * - requestHeaders: an array of {name, value} to use as request headers.\n * - withCredentials: credentials flag to pass to the request.\n */\n #loadStateUrl(url, dataId, options) {\n // create IO\n const urlIO = new UrlsLoader();\n // load data\n this.#loadData([url], urlIO, 'state', dataId, options);\n }\n\n /**\n * Load a list of data.\n *\n * @param {string[]|File[]|Array} data Array of data to load.\n * @param {object} loader The data loader.\n * @param {string} loadType The data load type: 'image' or 'state'.\n * @param {string} dataId The data id.\n * @param {object} [options] Options passed to the final loader.\n */\n #loadData(data, loader, loadType, dataId, options) {\n const eventInfo = {\n loadtype: loadType,\n dataid: dataId\n };\n\n // set callbacks\n loader.onloadstart = (event) => {\n // store loader to allow abort\n this.#currentLoaders[dataId] = {\n loader: loader,\n isFirstItem: true\n };\n // callback\n this.#augmentCallbackEvent(this.onloadstart, eventInfo)(event);\n };\n loader.onprogress = this.#augmentCallbackEvent(this.onprogress, eventInfo);\n loader.onloaditem = (event) => {\n const eventInfoItem = {\n loadtype: loadType,\n dataid: dataId\n };\n if (typeof this.#currentLoaders[dataId] !== 'undefined') {\n eventInfoItem.isfirstitem = this.#currentLoaders[dataId].isFirstItem;\n }\n // callback\n this.#augmentCallbackEvent(this.onloaditem, eventInfoItem)(event);\n // update loader\n if (typeof this.#currentLoaders[dataId] !== 'undefined' &&\n this.#currentLoaders[dataId].isFirstItem) {\n this.#currentLoaders[dataId].isFirstItem = false;\n }\n };\n loader.onload = this.#augmentCallbackEvent(this.onload, eventInfo);\n loader.onloadend = (event) => {\n // reset current loader\n delete this.#currentLoaders[dataId];\n // callback\n this.#augmentCallbackEvent(this.onloadend, eventInfo)(event);\n };\n loader.onerror = this.#augmentCallbackEvent(this.onerror, eventInfo);\n loader.onabort = this.#augmentCallbackEvent(this.onabort, eventInfo);\n // launch load\n try {\n loader.load(data, options);\n } catch (error) {\n this.onerror({\n error: error,\n dataid: dataId\n });\n this.onloadend({\n dataid: dataId\n });\n return;\n }\n }\n\n /**\n * Augment a callback event: adds loadtype to the event\n * passed to a callback.\n *\n * @param {object} callback The callback to update.\n * @param {object} info Info object to append to the event.\n * @returns {object} A function representing the modified callback.\n */\n #augmentCallbackEvent(callback, info) {\n return function (event) {\n const keys = Object.keys(info);\n for (let i = 0; i < keys.length; ++i) {\n const key = keys[i];\n event[key] = info[key];\n }\n callback(event);\n };\n }\n\n /**\n * Handle a load start event.\n * Default does nothing.\n *\n * @param {object} _event The load start event.\n */\n onloadstart(_event) {}\n\n /**\n * Handle a load progress event.\n * Default does nothing.\n *\n * @param {object} _event The progress event.\n */\n onprogress(_event) {}\n\n /**\n * Handle a load event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when a file has been loaded successfully.\n */\n onload(_event) {}\n\n /**\n * Handle a load item event.\n * Default does nothing.\n *\n * @param {object} _event The load event fired\n * when an item has been loaded successfully.\n */\n onloaditem(_event) {}\n\n /**\n * Handle a load end event.\n * Default does nothing.\n *\n * @param {object} _event The load end event fired\n * when a file load has completed, successfully or not.\n */\n onloadend(_event) {}\n\n /**\n * Handle an error event.\n * Default does nothing.\n *\n * @param {object} _event The error event.\n */\n onerror(_event) {}\n\n /**\n * Handle an abort event.\n * Default does nothing.\n *\n * @param {object} _event The abort event.\n */\n onabort(_event) {}\n\n} // class LoadController\n","import {ListenerHandler} from '../utils/listen';\nimport {getReverseOrientation} from '../dicom/dicomParser';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get a number toprecision function with the provided precision.\n *\n * @param {number} precision The precision to achieve.\n * @returns {Function} The to precision function.\n */\nfunction getNumberToPrecision(precision) {\n return function (num) {\n return Number(num).toPrecision(precision);\n };\n}\n\n/**\n * Create a default replace format from a given length.\n * For example: '{v0}, {v1}'.\n *\n * @param {number} length The length of the format.\n * @returns {string} A replace format.\n */\nfunction createDefaultReplaceFormat(length) {\n let res = '';\n for (let i = 0; i < length; ++i) {\n if (i !== 0) {\n res += ', ';\n }\n res += '{v' + i + '}';\n }\n return res;\n}\n\n/**\n * Replace flags in a input string. Flags are keywords surrounded with curly\n * braces in the form: '{v0}, {v1}'.\n *\n * @param {string} inputStr The input string.\n * @param {string[]} values An array of strings.\n * @example\n * var values = [\"a\", \"b\"];\n * var str = \"The length is: {v0}. The size is: {v1}\";\n * var res = replaceFlags(str, values);\n * // \"The length is: a. The size is: b\"\n * @returns {string} The result string.\n */\nfunction replaceFlags(inputStr, values) {\n let res = inputStr;\n for (let i = 0; i < values.length; ++i) {\n res = res.replace('{v' + i + '}', values[i]);\n }\n return res;\n}\n\n/**\n * DICOM Header overlay info.\n */\nexport class OverlayData {\n\n /**\n * Associated app.\n *\n * @type {App}\n */\n #app;\n\n /**\n * Associated data id.\n *\n * @type {string}\n */\n #dataId;\n\n /**\n * Overlay config.\n *\n * @type {object}\n */\n #configs;\n\n /**\n * List of event used by the config.\n *\n * @type {string[]}\n */\n #eventNames = [];\n\n /**\n * Flag to know if listening to app.\n *\n * @type {boolean}\n */\n #isListening;\n\n /**\n * Overlay data.\n *\n * @type {Array}\n */\n #data = [];\n\n /**\n * Current data uid: set on pos change.\n *\n * @type {number}\n */\n #currentDataUid;\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * @param {App} app The associated application.\n * @param {string} dataId The associated data id.\n * @param {object} configs The overlay config.\n */\n constructor(app, dataId, configs) {\n this.#app = app;\n this.#dataId = dataId;\n this.#configs = configs;\n\n // parse overlays to get the list of events to listen to\n const keys = Object.keys(this.#configs);\n for (let i = 0; i < keys.length; ++i) {\n const config = this.#configs[keys[i]];\n for (let j = 0; j < config.length; ++j) {\n const eventType = config[j].event;\n if (typeof eventType !== 'undefined') {\n if (!this.#eventNames.includes(eventType)) {\n this.#eventNames.push(eventType);\n }\n }\n }\n }\n // add app listeners\n this.addAppListeners();\n }\n\n /**\n * Reset the data.\n */\n reset() {\n this.#data = [];\n this.#currentDataUid = undefined;\n }\n\n /**\n * Handle a new loaded item event.\n *\n * @param {object} data The item meta data.\n */\n addItemMeta(data) {\n // create and store overlay data\n let dataUid;\n // check if dicom data (00020010: transfer syntax)\n if (typeof data['00020010'] !== 'undefined') {\n if (typeof data['00080018'] !== 'undefined') {\n // SOP instance UID\n dataUid = data['00080018'].value[0];\n } else {\n dataUid = data.length;\n }\n this.#data[dataUid] = createOverlayData(data, this.#configs);\n } else {\n // image file case\n const keys = Object.keys(data);\n for (let d = 0; d < keys.length; ++d) {\n const obj = data[keys[d]];\n if (keys[d] === 'imageUid') {\n dataUid = obj.value;\n break;\n }\n }\n this.#data[dataUid] = createOverlayDataForDom(data, this.#configs);\n }\n // store uid\n this.#currentDataUid = dataUid;\n }\n\n /**\n * Handle a changed slice event.\n *\n * @param {object} event The slicechange event.\n */\n #onSliceChange = (event) => {\n if (event.dataid !== this.#dataId) {\n return;\n }\n if (typeof event.data !== 'undefined' &&\n typeof event.data.imageUid !== 'undefined' &&\n this.#currentDataUid !== event.data.imageUid) {\n this.#currentDataUid = event.data.imageUid;\n this.#updateData(event);\n }\n };\n\n /**\n * Update the overlay data.\n *\n * @param {object} event An event defined by the overlay map and\n * registered in toggleListeners.\n */\n #updateData = (event) => {\n if (event.dataid !== this.#dataId) {\n return;\n }\n\n const sliceOverlayData = this.#data[this.#currentDataUid];\n if (typeof sliceOverlayData === 'undefined') {\n console.warn('No slice overlay data for: ' + this.#currentDataUid);\n return;\n }\n\n for (let n = 0; n < sliceOverlayData.length; ++n) {\n let text = undefined;\n if (typeof sliceOverlayData[n].tags !== 'undefined') {\n // update tags only on slice change\n if (event.type === 'positionchange') {\n text = sliceOverlayData[n].value;\n }\n } else {\n // update text if the value is an event type\n if (typeof sliceOverlayData[n].event !== 'undefined' &&\n sliceOverlayData[n].event === event.type) {\n const format = sliceOverlayData[n].format;\n let values = event.value;\n // optional number precision\n if (typeof sliceOverlayData[n].precision !== 'undefined') {\n let mapFunc = null;\n if (sliceOverlayData[n].precision === 'round') {\n mapFunc = Math.round;\n } else {\n mapFunc = getNumberToPrecision(sliceOverlayData[n].precision);\n }\n values = values.map(mapFunc);\n }\n text = replaceFlags(format, values);\n }\n }\n if (typeof text !== 'undefined') {\n sliceOverlayData[n].value = text;\n }\n }\n\n /**\n * Value change event.\n *\n * @event OverlayData#valuechange\n * @type {object}\n * @property {string} type The event type.\n * @property {Array} data The value of the overlay data.\n */\n this.#fireEvent({\n type: 'valuechange',\n data: sliceOverlayData\n });\n };\n\n /**\n * Is this class listening to app events.\n *\n * @returns {boolean} True is listening to app events.\n */\n isListening() {\n return this.#isListening;\n }\n\n /**\n * Toggle info listeners.\n */\n addAppListeners() {\n // listen to update tags data\n this.#app.addEventListener('positionchange', this.#onSliceChange);\n // add event listeners\n for (let i = 0; i < this.#eventNames.length; ++i) {\n this.#app.addEventListener(this.#eventNames[i], this.#updateData);\n }\n // update flag\n this.#isListening = true;\n }\n\n /**\n * Toggle info listeners.\n */\n removeAppListeners() {\n // stop listening to update tags data\n this.#app.removeEventListener('positionchange', this.#onSliceChange);\n // remove event listeners\n for (let i = 0; i < this.#eventNames.length; ++i) {\n this.#app.removeEventListener(this.#eventNames[i], this.#updateData);\n }\n // update flag\n this.#isListening = false;\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {object} callback The method associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {object} callback The method associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent(event) {\n this.#listenerHandler.fireEvent(event);\n }\n\n} // class OverlayData\n\n/**\n * Create overlay data array for a DICOM image.\n *\n * @param {object} dicomElements DICOM elements of the image.\n * @param {object} configs The overlay data configs.\n * @returns {Array} Overlay data array.\n */\nfunction createOverlayData(dicomElements, configs) {\n const overlays = [];\n let modality;\n const modElement = dicomElements['00080060'];\n if (typeof modElement !== 'undefined') {\n modality = modElement.value[0];\n } else {\n return overlays;\n }\n const config = configs[modality] || configs['*'];\n if (!config) {\n return overlays;\n }\n\n for (let n = 0; n < config.length; ++n) {\n // deep copy\n const overlay = JSON.parse(JSON.stringify(config[n]));\n\n // add tag values\n const tags = overlay.tags;\n if (typeof tags !== 'undefined' && tags.length !== 0) {\n // get values\n const values = [];\n for (let i = 0; i < tags.length; ++i) {\n const elem = dicomElements[tags[i]];\n if (typeof elem !== 'undefined') {\n values.push(dicomElements[tags[i]].value);\n } else {\n values.push('');\n }\n }\n // format\n if (typeof overlay.format === 'undefined' || overlay.format === null) {\n overlay.format = createDefaultReplaceFormat(values.length);\n }\n overlay.value = replaceFlags(overlay.format, values).trim();\n }\n\n // store\n overlays.push(overlay);\n }\n\n // (0020,0020) Patient Orientation\n const poElement = dicomElements['00200020'];\n if (typeof poElement !== 'undefined' &&\n poElement.value.length === 2\n ) {\n const po0 = poElement.value[0];\n const po1 = poElement.value[1];\n overlays.push({\n pos: 'cr', value: po0, format: '{v0}'\n });\n overlays.push({\n pos: 'cl', value: getReverseOrientation(po0), format: '{v0}'\n });\n overlays.push({\n pos: 'bc', value: po1, format: '{v0}'\n });\n overlays.push({\n pos: 'tc', value: getReverseOrientation(po1), format: '{v0}'\n });\n }\n\n return overlays;\n}\n\n/**\n * Create overlay data array for a DOM image.\n *\n * @param {object} info Meta data.\n * @param {object} configs The overlay data configs.\n * @returns {Array} Overlay data array.\n */\nfunction createOverlayDataForDom(info, configs) {\n const overlays = [];\n const config = configs.DOM;\n if (!config) {\n return overlays;\n }\n\n const infoKeys = Object.keys(info);\n\n for (let n = 0; n < config.length; ++n) {\n // deep copy\n const overlay = JSON.parse(JSON.stringify(config[n]));\n\n // add tag values\n const tags = overlay.tags;\n if (typeof tags !== 'undefined' && tags.length !== 0) {\n // get values\n const values = [];\n for (let i = 0; i < tags.length; ++i) {\n for (let j = 0; j < infoKeys.length; ++j) {\n if (tags[i] === infoKeys[j]) {\n values.push(info[infoKeys[j]].value);\n }\n }\n }\n // format\n if (typeof overlay.format === 'undefined' || overlay.format === null) {\n overlay.format = createDefaultReplaceFormat(values.length);\n }\n overlay.value = replaceFlags(overlay.format, values).trim();\n }\n\n // store\n overlays.push(overlay);\n }\n\n return overlays;\n}\n","import {viewEventNames} from '../image/view';\nimport {ViewFactory} from '../image/viewFactory';\nimport {\n getMatrixFromName,\n getOrientationStringLPS,\n Orientation,\n getViewOrientation\n} from '../math/orientation';\nimport {Point3D} from '../math/point';\nimport {Stage} from '../gui/stage';\nimport {Style} from '../gui/style';\nimport {getLayerDetailsFromLayerDivId} from '../gui/layerGroup';\nimport {ListenerHandler} from '../utils/listen';\nimport {State} from '../io/state';\nimport {logger} from '../utils/logger';\nimport {getUriQuery, decodeQuery} from '../utils/uri';\nimport {UndoStack} from '../utils/undoStack';\nimport {ToolboxController} from './toolboxController';\nimport {LoadController} from './loadController';\nimport {DataController} from './dataController';\nimport {OverlayData} from '../gui/overlayData';\nimport {\n toolList,\n defaultToolList,\n toolOptions,\n defaultToolOptions\n} from '../tools';\nimport {binderList} from '../gui/stage';\nimport {WindowLevel} from '../image/windowLevel';\nimport {PlaneHelper} from '../image/planeHelper';\nimport {AnnotationGroup} from '../image/annotationGroup';\nimport {konvaToAnnotation} from '../gui/drawLayer';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {LayerGroup} from '../gui/layerGroup';\nimport {ViewLayer} from '../gui/viewLayer';\nimport {DrawLayer} from '../gui/drawLayer';\nimport {Image} from '../image/image';\nimport {Matrix33} from '../math/matrix';\nimport {DataElement} from '../dicom/dataElement';\nimport {Scalar3D} from '../math/scalar';\nimport {DicomData} from './dataController';\n/* eslint-enable no-unused-vars */\n\n/**\n * View configuration: mainly defines the ´divId´\n * of the associated HTML div.\n */\nexport class ViewConfig {\n /**\n * Associated HTML div id.\n *\n * @type {string}\n */\n divId;\n /**\n * Optional orientation of the data; 'axial', 'coronal' or 'sagittal'.\n * If undefined, will use the data aquisition plane.\n *\n * @type {string|undefined}\n */\n orientation;\n /**\n * Optional view colour map name.\n *\n * @type {string|undefined}\n */\n colourMap;\n /**\n * Optional layer opacity; in [0, 1] range.\n *\n * @type {number|undefined}\n */\n opacity;\n /**\n * Optional layer window level preset name.\n * If present, the preset name will be used and\n * the window centre and width ignored.\n *\n * @type {string|undefined}\n */\n wlPresetName;\n /**\n * Optional layer window center.\n *\n * @type {number|undefined}\n */\n windowCenter;\n /**\n * Optional layer window width.\n *\n * @type {number|undefined}\n */\n windowWidth;\n\n /**\n * @param {string} divId The associated HTML div id.\n */\n constructor(divId) {\n this.divId = divId;\n }\n}\n\n/**\n * Tool configuration.\n */\nexport class ToolConfig {\n /**\n * Optional tool options.\n * For Draw: list of shape names.\n * For Filter: list of filter names.\n *\n * @type {string[]|undefined}\n */\n options;\n\n /**\n * @param {string[]} [options] Optional tool options.\n */\n constructor(options) {\n this.options = options;\n }\n}\n\n/**\n * Application options.\n */\nexport class AppOptions {\n /**\n * DataId indexed object containing the data view configurations.\n *\n * @type {Object|undefined}\n */\n dataViewConfigs;\n /**\n * Tool name indexed object containing individual tool configurations.\n *\n * @type {Object|undefined}\n */\n tools;\n /**\n * Optional array of layerGroup binder names.\n *\n * @type {string[]|undefined}\n */\n binders;\n /**\n * Optional boolean flag to trigger the first data render\n * after the first loaded data or not. Defaults to true.\n *\n * @type {boolean|undefined}\n */\n viewOnFirstLoadItem;\n /**\n * Optional default chraracterset string used for DICOM parsing if\n * not passed in DICOM file.\n *\n * Valid values: {@link https://developer.mozilla.org/en-US/docs/Web/API/Encoding_API/Encodings}.\n *\n * @type {string|undefined}\n */\n defaultCharacterSet;\n /**\n * Optional overlay config.\n *\n * @type {object|undefined}\n */\n overlayConfig;\n /**\n * DOM root document.\n *\n * @type {DocumentFragment}\n */\n rootDocument;\n\n /**\n * @param {Object} [dataViewConfigs] Optional dataId\n * indexed object containing the data view configurations.\n */\n constructor(dataViewConfigs) {\n this.dataViewConfigs = dataViewConfigs;\n }\n}\n\n/**\n * List of ViewConfigs indexed by dataIds.\n *\n * @typedef {Object} DataViewConfigs\n */\n\n/**\n * Main application class.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * app.init(options);\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\nexport class App {\n\n /**\n * App options.\n *\n * @type {AppOptions}\n */\n #options = null;\n\n /**\n * Data controller.\n *\n * @type {DataController}\n */\n #dataController = null;\n\n /**\n * Toolbox controller.\n *\n * @type {ToolboxController}\n */\n #toolboxController = null;\n\n /**\n * Load controller.\n *\n * @type {LoadController}\n */\n #loadController = null;\n\n /**\n * Stage.\n *\n * @type {Stage}\n */\n #stage = null;\n\n /**\n * Undo stack.\n *\n * @type {UndoStack}\n */\n #undoStack = null;\n\n /**\n * Style.\n *\n * @type {Style}\n */\n #style = new Style();\n\n // overlay datas\n #overlayDatas = {};\n\n /**\n * Listener handler.\n *\n * @type {ListenerHandler}\n */\n #listenerHandler = new ListenerHandler();\n\n /**\n * Get a DicomData.\n *\n * @param {string} dataId The data id.\n * @returns {DicomData|undefined} The data.\n */\n getData(dataId) {\n return this.#dataController.get(dataId);\n }\n\n /**\n * Get the image.\n *\n * @param {string} dataId The data id.\n * @returns {Image|undefined} The associated image.\n * @deprecated Since v0.34, please use the getData method.\n */\n getImage(dataId) {\n let res;\n if (typeof this.getData(dataId) !== 'undefined') {\n res = this.getData(dataId).image;\n }\n return res;\n }\n\n /**\n * Set the image at the given id.\n *\n * @param {string} dataId The data id.\n * @param {Image} img The associated image.\n */\n setImage(dataId, img) {\n this.#dataController.setImage(dataId, img);\n }\n\n /**\n * Add a new DicomData.\n *\n * @param {DicomData} data The new data.\n * @returns {string} The data id.\n */\n addData(data) {\n // get a new dataId\n const dataId = this.#dataController.getNextDataId();\n // add image to data controller\n this.#dataController.add(\n dataId,\n data\n );\n // optional render\n // if (this.#options.viewOnFirstLoadItem) {\n // this.render(dataId);\n // }\n // return\n return dataId;\n }\n\n /**\n * Get the meta data.\n *\n * @param {string} dataId The data id.\n * @returns {Object|undefined} The list of meta data.\n */\n getMetaData(dataId) {\n let res;\n if (typeof this.#dataController.get(dataId) !== 'undefined') {\n res = this.#dataController.get(dataId).meta;\n }\n return res;\n }\n\n /**\n * Get the list of ids in the data storage.\n *\n * @returns {string[]} The list of data ids.\n */\n getDataIds() {\n return this.#dataController.getDataIds();\n }\n\n /**\n * Get the list of dataIds that contain the input UIDs.\n *\n * @param {string[]} uids A list of UIDs.\n * @returns {string[]} The list of dataIds that contain the UIDs.\n */\n getDataIdsFromSopUids(uids) {\n return this.#dataController.getDataIdsFromSopUids(uids);\n }\n\n /**\n * Can the data (of the active view of the active layer) be scrolled?\n *\n * @returns {boolean} True if the data has a third dimension greater than one.\n * @deprecated Since v0.33, please use the ViewController\n * equivalent directly instead.\n */\n canScroll() {\n const viewLayer = this.#stage.getActiveLayerGroup().getActiveViewLayer();\n const controller = viewLayer.getViewController();\n return controller.canScroll();\n }\n\n /**\n * Can window and level be applied to the data\n * (of the active view of the active layer)?\n *\n * @returns {boolean} True if the data is monochrome.\n * @deprecated Since v0.33, please use the ViewController\n * equivalent directly instead.\n */\n canWindowLevel() {\n const viewLayer = this.#stage.getActiveLayerGroup().getActiveViewLayer();\n const controller = viewLayer.getViewController();\n return controller.canWindowLevel();\n }\n\n /**\n * Get the active layer group scale on top of the base scale.\n *\n * @returns {Scalar3D} The scale as {x,y,z}.\n */\n getAddedScale() {\n return this.#stage.getActiveLayerGroup().getAddedScale();\n }\n\n /**\n * Get the base scale of the active layer group.\n *\n * @returns {Scalar3D} The scale as {x,y,z}.\n */\n getBaseScale() {\n return this.#stage.getActiveLayerGroup().getBaseScale();\n }\n\n /**\n * Get the layer offset of the active layer group.\n *\n * @returns {Scalar3D} The offset as {x,y,z}.\n */\n getOffset() {\n return this.#stage.getActiveLayerGroup().getOffset();\n }\n\n /**\n * Get the toolbox controller.\n *\n * @returns {ToolboxController} The controller.\n */\n getToolboxController() {\n return this.#toolboxController;\n }\n\n /**\n * Get the active layer group.\n * The layer is available after the first loaded item.\n *\n * @returns {LayerGroup|undefined} The layer group.\n */\n getActiveLayerGroup() {\n return this.#stage.getActiveLayerGroup();\n }\n\n /**\n * Set the active layer group.\n *\n * @param {number} index The layer group index.\n */\n setActiveLayerGroup(index) {\n this.#stage.setActiveLayerGroup(index);\n }\n\n /**\n * Get the view layers associated to a data id.\n * The layer are available after the first loaded item.\n *\n * @param {string} dataId The data id.\n * @returns {ViewLayer[]} The layers.\n */\n getViewLayersByDataId(dataId) {\n return this.#stage.getViewLayersByDataId(dataId);\n }\n\n /**\n * Get a list of view layers according to an input callback function.\n *\n * @param {Function} [callbackFn] A function that takes\n * a ViewLayer as input and returns a boolean. If undefined,\n * returns all view layers.\n * @returns {ViewLayer[]} The layers that\n * satisfy the callbackFn.\n */\n getViewLayers(callbackFn) {\n return this.#stage.getViewLayers(callbackFn);\n }\n\n /**\n * Get the draw layers associated to a data id.\n * The layer are available after the first loaded item.\n *\n * @param {string} dataId The data id.\n * @returns {DrawLayer[]} The layers.\n */\n getDrawLayersByDataId(dataId) {\n return this.#stage.getDrawLayersByDataId(dataId);\n }\n\n /**\n * Get a list of draw layers according to an input callback function.\n *\n * @param {Function} [callbackFn] A function that takes\n * a DrawLayer as input and returns a boolean. If undefined,\n * returns all draw layers.\n * @returns {DrawLayer[]} The layers that\n * satisfy the callbackFn.\n */\n getDrawLayers(callbackFn) {\n return this.#stage.getDrawLayers(callbackFn);\n }\n\n /**\n * Get a layer group by div id.\n * The layer is available after the first loaded item.\n *\n * @param {string} divId The div id.\n * @returns {LayerGroup} The layer group.\n */\n getLayerGroupByDivId(divId) {\n return this.#stage.getLayerGroupByDivId(divId);\n }\n\n /**\n * Get the number of layer groups.\n *\n * @returns {number} The number of groups.\n */\n getNumberOfLayerGroups() {\n return this.#stage.getNumberOfLayerGroups();\n }\n\n /**\n * Get the app style.\n *\n * @returns {object} The app style.\n */\n getStyle() {\n return this.#style;\n }\n\n /**\n * Add a command to the undo stack.\n *\n * @param {object} cmd The command to add.\n * @fires UndoStack#undoadd\n * @function\n */\n addToUndoStack = (cmd) => {\n if (this.#undoStack !== null) {\n this.#undoStack.add(cmd);\n }\n };\n\n /**\n * Remove a command from the undo stack.\n *\n * @param {string} name The name of the command to remove.\n * @returns {boolean} True if the command was found and removed.\n * @fires UndoStack#undoremove\n * @function\n */\n removeFromUndoStack = (name) => {\n let res = false;\n if (this.#undoStack !== null) {\n res = this.#undoStack.remove(name);\n }\n return res;\n };\n\n /**\n * Initialise the application.\n *\n * @param {AppOptions} opt The application options.\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.viewOnFirstLoadItem = false;\n * app.init(options);\n * // render button\n * const button = document.createElement('button');\n * button.id = 'render';\n * button.disabled = true;\n * button.appendChild(document.createTextNode('render'));\n * document.body.appendChild(button);\n * app.addEventListener('load', function () {\n * const button = document.getElementById('render');\n * button.disabled = false;\n * button.onclick = function () {\n * // render data #0\n * app.render(0);\n * };\n * });\n * // load dicom data\n * app.loadURLs([\n * 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\n init(opt) {\n // store\n this.#options = opt;\n // defaults\n if (typeof this.#options.viewOnFirstLoadItem === 'undefined') {\n this.#options.viewOnFirstLoadItem = true;\n }\n if (typeof this.#options.dataViewConfigs === 'undefined') {\n this.#options.dataViewConfigs = {};\n }\n if (typeof this.#options.rootDocument === 'undefined') {\n this.#options.rootDocument = document;\n }\n\n // undo stack\n this.#undoStack = new UndoStack();\n this.#undoStack.addEventListener('undoadd', this.#fireEvent);\n this.#undoStack.addEventListener('undo', this.#fireEvent);\n this.#undoStack.addEventListener('redo', this.#fireEvent);\n\n // tools\n if (typeof this.#options.tools !== 'undefined') {\n // setup the tool list\n const appToolList = {};\n const keys = Object.keys(this.#options.tools);\n for (let t = 0; t < keys.length; ++t) {\n const toolName = keys[t];\n // find the tool in the default tool list\n let toolClass = defaultToolList[toolName];\n // or use external one\n if (typeof toolClass === 'undefined') {\n toolClass = toolList[toolName];\n }\n if (typeof toolClass !== 'undefined') {\n // create tool instance\n appToolList[toolName] = new toolClass(this);\n // register listeners\n if (typeof appToolList[toolName].addEventListener !== 'undefined') {\n const names = appToolList[toolName].getEventNames();\n for (let j = 0; j < names.length; ++j) {\n appToolList[toolName].addEventListener(names[j], this.#fireEvent);\n }\n }\n // tool options\n const toolParams = this.#options.tools[toolName];\n if (typeof toolParams.options !== 'undefined' &&\n toolParams.options.length !== 0) {\n let type = 'raw';\n if (typeof appToolList[toolName].getOptionsType !== 'undefined') {\n type = appToolList[toolName].getOptionsType();\n }\n let appToolOptions;\n if (type === 'instance' || type === 'factory') {\n appToolOptions = {};\n for (let i = 0; i < toolParams.options.length; ++i) {\n const optionName = toolParams.options[i];\n let optionClassName = optionName;\n if (type === 'factory') {\n optionClassName += 'Factory';\n }\n const toolNamespace = toolName.charAt(0).toLowerCase() +\n toolName.slice(1);\n // find the option in the external tool list\n let tOptions = toolOptions[toolNamespace];\n let optionClass;\n if (typeof tOptions !== 'undefined') {\n optionClass = tOptions[optionClassName];\n }\n // or use the default one\n if (typeof optionClass === 'undefined') {\n tOptions = defaultToolOptions[toolNamespace];\n if (typeof tOptions !== 'undefined') {\n optionClass = tOptions[optionClassName];\n }\n }\n if (typeof optionClass !== 'undefined') {\n appToolOptions[optionName] = optionClass;\n } else {\n logger.warn('Could not find option class for: ' +\n optionName);\n }\n }\n } else {\n appToolOptions = toolParams.options;\n }\n appToolList[toolName].setOptions(appToolOptions);\n }\n } else {\n logger.warn('Could not initialise unknown tool: ' + toolName);\n }\n }\n // add tools to the controller\n this.#toolboxController = new ToolboxController(appToolList);\n }\n\n // create load controller\n this.#loadController =\n new LoadController(this.#options.defaultCharacterSet);\n this.#loadController.onloadstart = this.#onloadstart;\n this.#loadController.onprogress = this.#onloadprogress;\n this.#loadController.onloaditem = this.#onloaditem;\n this.#loadController.onload = this.#onload;\n this.#loadController.onloadend = this.#onloadend;\n this.#loadController.onerror = this.#onloaderror;\n this.#loadController.onabort = this.#onloadabort;\n\n // create data controller\n this.#dataController = new DataController();\n // propagate data events\n this.#dataController.addEventListener('dataadd', this.#fireEvent);\n this.#dataController.addEventListener('dataremove', this.#fireEvent);\n this.#dataController.addEventListener('dataimageset', this.#fireEvent);\n this.#dataController.addEventListener('dataupdate', this.#fireEvent);\n // propage individual data events\n this.#dataController.addEventListener(\n 'imagecontentchange', this.#fireEvent);\n this.#dataController.addEventListener(\n 'imagegeometrychange', this.#fireEvent);\n this.#dataController.addEventListener('annotationadd', this.#fireEvent);\n this.#dataController.addEventListener('annotationupdate', this.#fireEvent);\n this.#dataController.addEventListener('annotationremove', this.#fireEvent);\n this.#dataController.addEventListener(\n 'annotationgroupeditablechange', this.#fireEvent);\n // create stage\n this.#stage = new Stage();\n if (typeof this.#options.binders !== 'undefined') {\n this.#stage.setBinders(this.#options.binders);\n }\n }\n\n /**\n * Reset the application.\n */\n reset() {\n // clear objects\n this.#stage.empty();\n this.#overlayDatas = {};\n // reset undo/redo\n if (this.#undoStack) {\n this.#undoStack = new UndoStack();\n this.#undoStack.addEventListener('undoadd', this.#fireEvent);\n this.#undoStack.addEventListener('undo', this.#fireEvent);\n this.#undoStack.addEventListener('redo', this.#fireEvent);\n }\n }\n\n /**\n * Reset the layout of the application.\n */\n resetLayout() {\n this.#stage.reset();\n this.#stage.draw();\n }\n\n /**\n * Add an event listener to this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type, will be called with the fired event.\n */\n addEventListener(type, callback) {\n this.#listenerHandler.add(type, callback);\n }\n\n /**\n * Remove an event listener from this class.\n *\n * @param {string} type The event type.\n * @param {Function} callback The function associated with the provided\n * event type.\n */\n removeEventListener(type, callback) {\n this.#listenerHandler.remove(type, callback);\n }\n\n // load API [begin] -------------------------------------------------------\n\n /**\n * Load a list of files. Can be image files or a state file.\n *\n * @param {File[]} files The list of files to load.\n * @fires App#loadstart\n * @fires App#loadprogress\n * @fires App#loaditem\n * @fires App#loadend\n * @fires App#error\n * @fires App#abort\n * @function\n */\n loadFiles = (files) => {\n // Get new data id\n const dataId = this.#dataController.getNextDataId();\n if (files.length === 0) {\n logger.warn('Ignoring empty input file list.');\n return;\n }\n this.#loadController.loadFiles(files, dataId);\n };\n\n /**\n * Load a list of URLs. Can be image files or a state file.\n *\n * @param {string[]} urls The list of urls to load.\n * @param {object} [options] The options object, can contain:\n * - requestHeaders: an array of {name, value} to use as request headers,\n * - withCredentials: boolean xhr.withCredentials flag to pass to the request,\n * - batchSize: the size of the request url batch.\n * @fires App#loadstart\n * @fires App#loadprogress\n * @fires App#loaditem\n * @fires App#loadend\n * @fires App#error\n * @fires App#abort\n * @function\n */\n loadURLs = (urls, options) => {\n // Get new data id\n const dataId = this.#dataController.getNextDataId();\n if (urls.length === 0) {\n logger.warn('Ignoring empty input url list.');\n return;\n }\n this.#loadController.loadURLs(urls, dataId, options);\n };\n\n /**\n * Load from an input uri.\n *\n * @param {string} uri The input uri, for example: 'window.location.href'.\n * @param {object} [options] Optional url request options.\n * @function\n */\n loadFromUri = (uri, options) => {\n const query = getUriQuery(uri);\n\n // load end callback: loads the state.\n const onLoadEnd = (/*event*/) => {\n this.removeEventListener('loadend', onLoadEnd);\n this.loadURLs([query.state]);\n };\n\n // check query\n if (query && typeof query.input !== 'undefined') {\n // optional display state\n if (typeof query.state !== 'undefined') {\n // queue after main data load\n this.addEventListener('loadend', onLoadEnd);\n }\n // load base image\n decodeQuery(query, this.loadURLs, options);\n }\n // no else to allow for empty uris\n };\n\n /**\n * Load a list of ArrayBuffers.\n *\n * @param {Array} data The list of ArrayBuffers to load\n * in the form of [{name: \"\", filename: \"\", data: data}].\n * @fires App#loadstart\n * @fires App#loadprogress\n * @fires App#loaditem\n * @fires App#loadend\n * @fires App#error\n * @fires App#abort\n * @function\n */\n loadImageObject = (data) => {\n // Get new data id\n const dataId = this.#dataController.getNextDataId();\n this.#loadController.loadImageObject(data, dataId);\n };\n\n /**\n * Abort all the current loads.\n */\n abortAllLoads() {\n const ids = this.#loadController.getLoadingDataIds();\n for (const id of ids) {\n this.abortLoad(id);\n }\n }\n\n /**\n * Abort an individual data load.\n *\n * @param {string} dataId The data to stop loading.\n */\n abortLoad(dataId) {\n // abort load\n this.#loadController.abort(dataId);\n // remove data\n this.#dataController.remove(dataId);\n // clean up stage\n this.#stage.removeLayersByDataId(dataId);\n }\n\n // load API [end] ---------------------------------------------------------\n\n /**\n * Fit the display to the data of each layer group.\n * To be called once the image is loaded.\n */\n fitToContainer() {\n this.#stage.fitToContainer();\n }\n\n /**\n * Init the Window/Level display\n * (of the active layer of the active layer group).\n *\n * @deprecated Since v0.33, please set the opacity\n * of the desired view layer directly.\n */\n initWLDisplay() {\n const viewLayer = this.#stage.getActiveLayerGroup().getActiveViewLayer();\n const controller = viewLayer.getViewController();\n controller.initialise();\n }\n\n /**\n * Set the imageSmoothing flag value. Default is false.\n *\n * @param {boolean} flag True to enable smoothing.\n */\n setImageSmoothing(flag) {\n this.#stage.setImageSmoothing(flag);\n this.#stage.draw();\n }\n\n /**\n * Get the layer group configuration from a data id.\n *\n * @param {string} dataId The data id.\n * @param {boolean} [excludeStarConfig] Exclude the star config\n * (default to false).\n * @returns {ViewConfig[]} The list of associated configs.\n */\n getViewConfigs(dataId, excludeStarConfig) {\n // check options\n if (this.#options.dataViewConfigs === null ||\n typeof this.#options.dataViewConfigs === 'undefined') {\n throw new Error('No available data view configuration');\n }\n let configs = [];\n if (typeof this.#options.dataViewConfigs[dataId] !== 'undefined') {\n configs = this.#options.dataViewConfigs[dataId];\n } else if (!excludeStarConfig &&\n typeof this.#options.dataViewConfigs['*'] !== 'undefined') {\n configs = this.#options.dataViewConfigs['*'];\n }\n return configs;\n }\n\n /**\n * Get the layer group configuration for a data id and group\n * div id.\n *\n * @param {string} dataId The data id.\n * @param {string} groupDivId The layer group div id.\n * @param {boolean} [excludeStarConfig] Exclude the star config\n * (default to false).\n * @returns {ViewConfig|undefined} The associated config.\n */\n getViewConfig(dataId, groupDivId, excludeStarConfig) {\n const configs = this.getViewConfigs(dataId, excludeStarConfig);\n return configs.find(function (item) {\n return item.divId === groupDivId;\n });\n }\n\n /**\n * Get the data view config.\n * Carefull, returns a reference, do not modify without resetting.\n *\n * @returns {Object} The configuration list.\n */\n getDataViewConfigs() {\n return this.#options.dataViewConfigs;\n }\n\n /**\n * Set the data view configuration.\n * Resets the stage and recreates all the views.\n *\n * @param {Object} configs The configuration list.\n */\n setDataViewConfigs(configs) {\n // clean up\n this.#stage.empty();\n // set new\n this.#options.dataViewConfigs = configs;\n // create layer groups\n this.#createLayerGroups(configs);\n }\n\n /**\n * Add a data view config.\n *\n * @param {string} dataId The data id.\n * @param {ViewConfig} config The view configuration.\n */\n addDataViewConfig(dataId, config) {\n // add to list\n const configs = this.#options.dataViewConfigs;\n if (typeof configs[dataId] === 'undefined') {\n configs[dataId] = [];\n }\n const equalDivId = function (item) {\n return item.divId === config.divId;\n };\n const itemIndex = configs[dataId].findIndex(equalDivId);\n if (itemIndex === -1) {\n this.#options.dataViewConfigs[dataId].push(config);\n } else {\n throw new Error('Duplicate view config for data ' + dataId +\n ' and div ' + config.divId);\n }\n\n // add layer group if not done\n if (typeof this.#stage.getLayerGroupByDivId(config.divId) === 'undefined') {\n this.#createLayerGroup(config);\n }\n\n // render (will create layers)\n if (typeof this.#dataController.get(dataId) !== 'undefined') {\n this.render(dataId, [config]);\n }\n }\n\n /**\n * Remove a data view config.\n *\n * @param {string} dataId The data id.\n * @param {string} divId The div id.\n */\n removeDataViewConfig(dataId, divId) {\n // remove from list\n const configs = this.#options.dataViewConfigs;\n if (typeof configs[dataId] === 'undefined') {\n // no config for dataId\n return;\n }\n const equalDivId = function (item) {\n return item.divId === divId;\n };\n const itemIndex = configs[dataId].findIndex(equalDivId);\n if (itemIndex === -1) {\n // no config for divId\n return;\n }\n configs[dataId].splice(itemIndex, 1);\n if (configs[dataId].length === 0) {\n delete configs[dataId];\n }\n\n // data is loaded, remove view\n if (typeof this.#dataController.get(dataId) !== 'undefined') {\n const lg = this.#stage.getLayerGroupByDivId(divId);\n if (typeof lg !== 'undefined') {\n const vls = lg.getViewLayersByDataId(dataId);\n if (vls.length === 1) {\n lg.removeLayer(vls[0]);\n }\n const dls = lg.getDrawLayersByDataId(dataId);\n if (dls.length === 1) {\n lg.removeLayer(dls[0]);\n }\n if (vls.length === 0 && dls.length === 0) {\n throw new Error('Expected one layer, got none');\n }\n if (lg.getNumberOfLayers() === 0) {\n this.#stage.removeLayerGroup(lg);\n }\n }\n }\n }\n\n /**\n * Update an existing data view config.\n * Removes and re-creates the layer if found.\n *\n * @param {string} dataId The data id.\n * @param {string} divId The div id.\n * @param {ViewConfig} config The view configuration.\n */\n updateDataViewConfig(dataId, divId, config) {\n const configs = this.#options.dataViewConfigs;\n // check data id\n if (typeof configs[dataId] === 'undefined') {\n throw new Error('No config for dataId: ' + dataId);\n }\n // check div id\n const equalDivId = function (item) {\n return item.divId === divId;\n };\n const itemIndex = configs[dataId].findIndex(equalDivId);\n if (itemIndex === -1) {\n throw new Error('No config for dataId: ' +\n dataId + ' and divId: ' + divId);\n }\n // update config\n const configToUpdate = configs[dataId][itemIndex];\n for (const prop in config) {\n configToUpdate[prop] = config[prop];\n }\n\n // remove previous layers\n const lg = this.#stage.getLayerGroupByDivId(configToUpdate.divId);\n if (typeof lg !== 'undefined') {\n const vls = lg.getViewLayersByDataId(dataId);\n if (vls.length === 1) {\n lg.removeLayer(vls[0]);\n }\n const dls = lg.getDrawLayersByDataId(dataId);\n if (dls.length === 1) {\n lg.removeLayer(dls[0]);\n }\n if (vls.length === 0 && dls.length === 0) {\n throw new Error('Expected one layer, got none');\n }\n }\n\n // render (will create layer)\n if (typeof this.#dataController.get(dataId) !== 'undefined') {\n this.render(dataId, [configToUpdate]);\n }\n }\n\n /**\n * Create layer groups according to a data view config:\n * adds them to stage and binds them.\n *\n * @param {DataViewConfigs} dataViewConfigs The data view config.\n */\n #createLayerGroups(dataViewConfigs) {\n const dataKeys = Object.keys(dataViewConfigs);\n const divIds = [];\n for (let i = 0; i < dataKeys.length; ++i) {\n const viewConfigs = dataViewConfigs[dataKeys[i]];\n for (let j = 0; j < viewConfigs.length; ++j) {\n const viewConfig = viewConfigs[j];\n // view configs can contain the same divIds, avoid duplicating\n if (!divIds.includes(viewConfig.divId)) {\n this.#createLayerGroup(viewConfig);\n divIds.push(viewConfig.divId);\n }\n }\n }\n }\n\n /**\n * Create a layer group according to a view config:\n * adds it to stage and binds it.\n *\n * @param {ViewConfig} viewConfig The view config.\n */\n #createLayerGroup(viewConfig) {\n // create new layer group\n const element = this.#options.rootDocument.getElementById(viewConfig.divId);\n const layerGroup = this.#stage.addLayerGroup(element);\n // bind events\n this.#bindLayerGroupToApp(layerGroup);\n }\n\n /**\n * Set the layer groups binders.\n *\n * @param {string[]} list The list of binder names.\n */\n setLayerGroupsBinders(list) {\n // create instances\n const instances = [];\n for (let i = 0; i < list.length; ++i) {\n if (typeof binderList[list[i]] !== 'undefined') {\n instances.push(new binderList[list[i]]);\n }\n }\n // pass to stage\n this.#stage.setBinders(instances);\n }\n\n /**\n * Render the current data.\n *\n * @param {string} dataId The data id to render.\n * @param {ViewConfig[]} [viewConfigs] The list of configs to render.\n */\n render(dataId, viewConfigs) {\n if (typeof dataId === 'undefined' || dataId === null) {\n throw new Error('Cannot render without data id');\n }\n // guess data type\n const isImage =\n typeof this.getData(dataId).image !== 'undefined';\n const isMeasurement =\n typeof this.getData(dataId).annotationGroup !== 'undefined';\n\n // create layer groups if not done yet\n // (create all to allow for ratio sync)\n if (this.#stage.getNumberOfLayerGroups() === 0) {\n this.#createLayerGroups(this.#options.dataViewConfigs);\n }\n\n // use options list if non provided\n if (typeof viewConfigs === 'undefined') {\n viewConfigs = this.getViewConfigs(dataId);\n }\n\n // nothing to do if no view config\n if (viewConfigs.length === 0) {\n logger.info('Not rendering data: ' + dataId +\n ' (no data view config)');\n return;\n }\n\n // loop on configs\n for (let i = 0; i < viewConfigs.length; ++i) {\n const config = viewConfigs[i];\n const layerGroup =\n this.#stage.getLayerGroupByDivId(config.divId);\n // layer group must exist\n if (!layerGroup) {\n throw new Error('No layer group for ' + config.divId);\n }\n // create layer if needed\n // warn: needs a loaded DOM\n if (typeof this.#dataController.get(dataId) !== 'undefined') {\n if (isImage &&\n layerGroup.getViewLayersByDataId(dataId).length === 0\n ) {\n this.#addViewLayer(dataId, config);\n } else if (isMeasurement &&\n layerGroup.getDrawLayersByDataId(dataId).length === 0\n ) {\n this.addDrawLayer(dataId, config);\n }\n }\n // draw\n layerGroup.draw();\n }\n }\n\n /**\n * Zoom the layers of the active layer group.\n *\n * @param {number} step The step to add to the current zoom.\n * @param {number} cx The zoom center X coordinate.\n * @param {number} cy The zoom center Y coordinate.\n */\n zoom(step, cx, cy) {\n const layerGroup = this.#stage.getActiveLayerGroup();\n const viewController = layerGroup.getActiveViewLayer().getViewController();\n const k = viewController.getCurrentScrollPosition();\n const center = new Point3D(cx, cy, k);\n layerGroup.addScale(step, center);\n layerGroup.draw();\n }\n\n /**\n * Apply a translation to the layers of the active layer group.\n *\n * @param {number} tx The translation along X.\n * @param {number} ty The translation along Y.\n */\n translate(tx, ty) {\n const layerGroup = this.#stage.getActiveLayerGroup();\n layerGroup.addTranslation({x: tx, y: ty, z: 0});\n layerGroup.draw();\n }\n\n /**\n * Set the active view layer (of the active layer group) opacity.\n *\n * @param {number} alpha The opacity ([0:1] range).\n * @deprecated Since v0.33, pplease set the opacity\n * of the desired view layer directly.\n */\n setOpacity(alpha) {\n const viewLayer = this.#stage.getActiveLayerGroup().getActiveViewLayer();\n viewLayer.setOpacity(alpha);\n viewLayer.draw();\n }\n\n /**\n * Set the drawings of the active layer group.\n *\n * @deprecated Since v0.34, please switch to DICOM SR annotations.\n * @param {Array} drawings An array of drawings.\n * @param {Array} drawingsDetails An array of drawings details.\n * @param {string} dataId The converted data id.\n */\n setDrawings(drawings, drawingsDetails, dataId) {\n const layerGroup = this.#stage.getActiveLayerGroup();\n const viewLayer = layerGroup.getActiveViewLayer();\n const refDataId = viewLayer.getDataId();\n const viewController = viewLayer.getViewController();\n\n // convert konva to annotation\n const annotations = konvaToAnnotation(drawings, drawingsDetails);\n // create data\n const data = this.createAnnotationData(refDataId);\n // add annotations to data\n for (const annotation of annotations) {\n annotation.setViewController(viewController);\n data.annotationGroup.add(annotation);\n }\n // add to data controller\n this.#dataController.add(dataId, data);\n // render\n this.render(dataId);\n }\n\n /**\n * Apply a JSON state to this app.\n *\n * @deprecated Since v0.34, please switch to DICOM SR\n * for annotations.\n * @param {string} jsonState The state of the app as a JSON string.\n * @param {string} dataId The state data id.\n */\n applyJsonState(jsonState, dataId) {\n const state = new State(dataId);\n state.apply(this, state.fromJSON(jsonState));\n }\n\n // Handler Methods -----------------------------------------------------------\n\n /**\n * Handle resize: fit the display to the window.\n * To be called once the image is loaded.\n * Can be connected to a window 'resize' event.\n *\n * @function\n */\n onResize = () => {\n this.fitToContainer();\n };\n\n /**\n * Key down callback. Meant to be used in tools.\n *\n * @param {KeyboardEvent} event The key down event.\n * @fires App#keydown\n * @function\n */\n onKeydown = (event) => {\n /**\n * Key down event.\n *\n * @event App#keydown\n * @type {KeyboardEvent}\n * @property {string} type The event type: keydown.\n * @property {string} context The tool where the event originated.\n */\n this.#fireEvent(event);\n };\n\n /**\n * Key down event handler example.\n * - CRTL-Z: undo,\n * - CRTL-Y: redo,\n * - CRTL-ARROW_LEFT: next element on fourth dim,\n * - CRTL-ARROW_UP: next element on third dim,\n * - CRTL-ARROW_RIGHT: previous element on fourth dim,\n * - CRTL-ARROW_DOWN: previous element on third dim.\n *\n * Applies to the active view of the active layer group.\n *\n * @param {KeyboardEvent} event The key down event.\n * @fires UndoStack#undo\n * @fires UndoStack#redo\n * @function\n */\n defaultOnKeydown = (event) => {\n if (event.ctrlKey) {\n if (event.shiftKey) {\n const layerGroup = this.#stage.getActiveLayerGroup();\n const viewController =\n layerGroup.getActiveViewLayer().getViewController();\n if (event.key === 'ArrowLeft') { // crtl-shift-arrow-left\n if (viewController.moreThanOne(3)) {\n viewController.decrementIndex(3);\n }\n } else if (event.key === 'ArrowUp') { // crtl-shift-arrow-up\n if (layerGroup.canScroll()) {\n viewController.incrementScrollIndex();\n }\n } else if (event.key === 'ArrowRight') { // crtl-shift-arrow-right\n if (layerGroup.moreThanOne(3)) {\n viewController.incrementIndex(3);\n }\n } else if (event.key === 'ArrowDown') { // crtl-shift-arrow-down\n if (layerGroup.canScroll()) {\n viewController.decrementScrollIndex();\n }\n }\n } else if (event.key === 'y') { // crtl-y\n this.#undoStack.redo();\n } else if (event.key === 'z') { // crtl-z\n this.#undoStack.undo();\n } else if (event.key === ' ') { // crtl-space\n for (let i = 0; i < this.#stage.getNumberOfLayerGroups(); ++i) {\n this.#stage.getLayerGroup(i).setShowCrosshair(\n !this.#stage.getLayerGroup(i).getShowCrosshair()\n );\n }\n }\n }\n };\n\n // Internal members shortcuts-----------------------------------------------\n\n /**\n * Reset the display.\n */\n resetDisplay() {\n this.resetLayout();\n this.initWLDisplay();\n }\n\n /**\n * Reset the app zoom.\n */\n resetZoom() {\n this.resetLayout();\n }\n\n /**\n * Set the colour map of the active view of the active layer group.\n *\n * @param {string} name The colour map name.\n * @deprecated Since v0.33, please use the ViewController\n * equivalent directly instead.\n */\n setColourMap(name) {\n const viewController =\n this.#stage.getActiveLayerGroup()\n .getActiveViewLayer().getViewController();\n viewController.setColourMap(name);\n }\n\n /**\n * Set the window/level preset of the active view of the active layer group.\n *\n * @param {string} preset The window/level preset.\n * @deprecated Since v0.33, please use the ViewController\n * equivalent directly instead.\n */\n setWindowLevelPreset(preset) {\n const viewController =\n this.#stage.getActiveLayerGroup()\n .getActiveViewLayer().getViewController();\n viewController.setWindowLevelPreset(preset);\n }\n\n /**\n * Set the tool.\n *\n * @param {string} tool The tool.\n */\n setTool(tool) {\n // bind tool to active layer\n for (let i = 0; i < this.#stage.getNumberOfLayerGroups(); ++i) {\n const layerGroup = this.#stage.getLayerGroup(i);\n // draw or view layer\n const isDrawTool = tool === 'Draw' ||\n tool === 'Livewire' ||\n tool === 'Floodfill';\n let layer;\n if (isDrawTool &&\n typeof layerGroup.getActiveDrawLayer() !== 'undefined') {\n layer = layerGroup.getActiveDrawLayer();\n } else {\n layer = layerGroup.getActiveViewLayer();\n }\n if (typeof layer !== 'undefined') {\n this.#toolboxController.bindLayerGroup(layerGroup, layer);\n }\n }\n\n // set toolbox tool\n this.#toolboxController.setSelectedTool(tool);\n }\n\n /**\n * Set the tool live features.\n *\n * @param {object} list The list of features.\n */\n setToolFeatures(list) {\n this.#toolboxController.setToolFeatures(list);\n }\n\n /**\n * Undo the last action.\n *\n * @fires UndoStack#undo\n */\n undo() {\n this.#undoStack.undo();\n }\n\n /**\n * Redo the last action.\n *\n * @fires UndoStack#redo\n */\n redo() {\n this.#undoStack.redo();\n }\n\n /**\n * Get the undo stack size.\n *\n * @returns {number} The size of the stack.\n */\n getStackSize() {\n return this.#undoStack.getStackSize();\n }\n\n /**\n * Get the current undo stack index.\n *\n * @returns {number} The stack index.\n */\n getCurrentStackIndex() {\n return this.#undoStack.getCurrentStackIndex();\n }\n\n /**\n * Get the overlay data for a data id.\n *\n * @param {string} dataId The data id.\n * @returns {OverlayData|undefined} The overlay data.\n */\n getOverlayData(dataId) {\n let data;\n if (typeof this.#overlayDatas !== 'undefined') {\n data = this.#overlayDatas[dataId];\n }\n return data;\n }\n\n /**\n * Toggle overlay listeners.\n *\n * @param {string} dataId The data id.\n */\n toggleOverlayListeners(dataId) {\n const data = this.getOverlayData(dataId);\n if (typeof data !== 'undefined') {\n if (data.isListening()) {\n data.removeAppListeners();\n } else {\n data.addAppListeners();\n }\n }\n }\n\n /**\n * Create new annotation data based on the data of\n * the active view layer.\n *\n * @param {string} refDataId The reference data id.\n * @returns {DicomData} The new data.\n */\n createAnnotationData(refDataId) {\n const refData = this.getData(refDataId);\n const refMeta = refData.image.getMeta();\n\n const data = new DicomData({});\n data.annotationGroup = new AnnotationGroup();\n data.annotationGroup.setMetaValue('Modality', 'SR');\n data.annotationGroup.setMetaValue(\n 'PatientID', refMeta.PatientID);\n data.annotationGroup.setMetaValue(\n 'StudyInstanceUID', refMeta.StudyInstanceUID);\n data.annotationGroup.setMetaValue(\n 'ReferencedSeriesSequence', {\n value: [{\n SeriesInstanceUID: refMeta.SeriesInstanceUID\n }]\n });\n return data;\n }\n\n /**\n * Add new data and render it with a simple new data view config.\n *\n * @param {DicomData} data The data to add.\n * @param {string} divId The div where to draw.\n * @param {string} refDataId The reference data id.\n */\n addAndRenderAnnotationData(data, divId, refDataId) {\n // add new data\n const dataId = this.addData(data);\n // add data view config based on reference data\n const refDataViewConfigs = this.getViewConfigs(refDataId);\n const refDataViewConfig = refDataViewConfigs.find(\n element => element.divId === divId);\n if (typeof refDataViewConfig === 'undefined') {\n throw new Error('No reference data view config for draw');\n }\n const drawDataViewConfig = new ViewConfig(divId);\n drawDataViewConfig.orientation = refDataViewConfig.orientation;\n this.addDataViewConfig(dataId, drawDataViewConfig);\n // render (will create draw layer)\n this.render(dataId);\n }\n\n // Private Methods -----------------------------------------------------------\n\n /**\n * Fire an event: call all associated listeners with the input event object.\n *\n * @param {object} event The event to fire.\n */\n #fireEvent = (event) => {\n this.#listenerHandler.fireEvent(event);\n };\n\n /**\n * Data load start callback.\n *\n * @param {object} event The load start event.\n */\n #onloadstart = (event) => {\n // create overlay data\n if (typeof this.#options.overlayConfig !== 'undefined') {\n this.#overlayDatas[event.dataid] = new OverlayData(\n this, event.dataid, this.#options.overlayConfig);\n }\n /**\n * Load start event.\n *\n * @event App#loadstart\n * @type {object}\n * @property {string} type The event type: loadstart.\n * @property {string} loadType The load type: image or state.\n * @property {*} source The load source: string for an url,\n * File for a file.\n */\n event.type = 'loadstart';\n this.#fireEvent(event);\n };\n\n /**\n * Data load progress callback.\n *\n * @param {object} event The progress event.\n */\n #onloadprogress = (event) => {\n /**\n * Load progress event.\n *\n * @event App#loadprogress\n * @type {object}\n * @property {string} type The event type: loadprogress.\n * @property {string} loadType The load type: image or state.\n * @property {*} source The load source: string for an url,\n * File for a file.\n * @property {number} loaded The loaded percentage.\n * @property {number} total The total percentage.\n */\n event.type = 'loadprogress';\n this.#fireEvent(event);\n };\n\n /**\n * Data load callback.\n *\n * @param {object} event The load event.\n */\n #onloaditem = (event) => {\n // check event\n if (typeof event.data === 'undefined') {\n logger.error('Missing loaditem event data.');\n }\n if (typeof event.loadtype === 'undefined') {\n logger.error('Missing loaditem event load type.');\n }\n\n const isFirstLoadItem = event.isfirstitem;\n\n let eventMetaData = null;\n if (event.loadtype === 'image') {\n if (isFirstLoadItem) {\n this.#dataController.add(event.dataid, event.data);\n } else {\n this.#dataController.update(event.dataid, event.data);\n }\n eventMetaData = event.data.meta;\n } else if (event.loadtype === 'state') {\n this.applyJsonState(event.data, event.dataid);\n eventMetaData = 'state';\n }\n\n /**\n * Load item event: fired when a load item is successfull.\n *\n * @event App#loaditem\n * @type {object}\n * @property {string} type The event type.\n * @property {string} loadType The load type: image or state.\n * @property {*} source The load source: string for an url,\n * File for a file.\n * @property {object} data The loaded meta data.\n */\n this.#fireEvent({\n type: 'loaditem',\n data: eventMetaData,\n source: event.source,\n loadtype: event.loadtype,\n dataid: event.dataid,\n isfirstitem: event.isfirstitem,\n warn: event.warn\n });\n\n // update overlay data if present\n if (typeof this.#overlayDatas !== 'undefined' &&\n typeof this.#overlayDatas[event.dataid] !== 'undefined') {\n this.#overlayDatas[event.dataid].addItemMeta(eventMetaData);\n }\n\n // render if first and flag allows\n if (event.loadtype === 'image' &&\n this.getViewConfigs(event.dataid).length !== 0 &&\n isFirstLoadItem && this.#options.viewOnFirstLoadItem) {\n this.render(event.dataid);\n }\n };\n\n /**\n * Data load callback.\n *\n * @param {object} event The load event.\n */\n #onload = (event) => {\n /**\n * Load event: fired when a load finishes successfully.\n *\n * @event App#load\n * @type {object}\n * @property {string} type The event type: load.\n * @property {string} loadType The load type: image or state.\n */\n event.type = 'load';\n this.#fireEvent(event);\n };\n\n /**\n * Data load end callback.\n *\n * @param {object} event The load end event.\n */\n #onloadend = (event) => {\n /**\n * Main load end event: fired when the load finishes,\n * successfully or not.\n *\n * @event App#loadend\n * @type {object}\n * @property {string} type The event type: loadend.\n * @property {string} loadType The load type: image or state.\n * @property {*} source The load source: string for an url,\n * File for a file.\n */\n event.type = 'loadend';\n this.#fireEvent(event);\n };\n\n /**\n * Data load error callback.\n *\n * @param {object} event The error event.\n */\n #onloaderror = (event) => {\n /**\n * Load error event.\n *\n * @event App#error\n * @type {object}\n * @property {string} type The event type: error.\n * @property {string} loadType The load type: image or state.\n * @property {*} source The load source: string for an url,\n * File for a file.\n * @property {object} error The error.\n * @property {object} target The event target.\n */\n if (typeof event.type === 'undefined') {\n event.type = 'error';\n }\n this.#fireEvent(event);\n };\n\n /**\n * Data load abort callback.\n *\n * @param {object} event The abort event.\n */\n #onloadabort = (event) => {\n /**\n * Load abort event.\n *\n * @event App#abort\n * @type {object}\n * @property {string} type The event type: abort.\n * @property {string} loadType The load type: image or state.\n * @property {*} source The load source: string for an url,\n * File for a file.\n */\n if (typeof event.type === 'undefined') {\n event.type = 'abort';\n }\n this.#fireEvent(event);\n };\n\n /**\n * Bind layer group events to app.\n *\n * @param {LayerGroup} group The layer group.\n */\n #bindLayerGroupToApp(group) {\n // propagate layer group events\n group.addEventListener('zoomchange', this.#fireEvent);\n group.addEventListener('offsetchange', this.#fireEvent);\n // propagate viewLayer events\n group.addEventListener('renderstart', this.#fireEvent);\n group.addEventListener('renderend', this.#fireEvent);\n // propagate view events\n for (let j = 0; j < viewEventNames.length; ++j) {\n group.addEventListener(viewEventNames[j], this.#fireEvent);\n }\n // propagate drawLayer events\n if (this.#toolboxController && this.#toolboxController.hasTool('Draw')) {\n group.addEventListener('drawcreate', this.#fireEvent);\n group.addEventListener('drawdelete', this.#fireEvent);\n }\n // updata data view config\n group.addEventListener('wlchange', (event) => {\n const layerDetails = getLayerDetailsFromLayerDivId(event.srclayerid);\n const groupId = layerDetails.groupDivId;\n const config = this.getViewConfig(event.dataid, groupId, true);\n if (typeof config !== 'undefined') {\n // reset previous values\n config.windowCenter = undefined;\n config.windowWidth = undefined;\n config.wlPresetName = undefined;\n // window width, center and name\n if (event.value.length === 3) {\n config.windowCenter = event.value[0];\n config.windowWidth = event.value[1];\n config.wlPresetName = event.value[2];\n }\n }\n });\n group.addEventListener('opacitychange', (event) => {\n const layerDetails = getLayerDetailsFromLayerDivId(event.srclayerid);\n const groupId = layerDetails.groupDivId;\n const config = this.getViewConfig(event.dataid, groupId, true);\n if (typeof config !== 'undefined') {\n config.opacity = event.value[0];\n }\n });\n group.addEventListener('colourmapchange', (event) => {\n const layerDetails = getLayerDetailsFromLayerDivId(event.srclayerid);\n const groupId = layerDetails.groupDivId;\n const config = this.getViewConfig(event.dataid, groupId, true);\n if (typeof config !== 'undefined') {\n config.colourMap = event.value[0];\n }\n });\n }\n\n /**\n * Add a view layer.\n *\n * @param {string} dataId The data id.\n * @param {ViewConfig} viewConfig The data view config.\n */\n #addViewLayer(dataId, viewConfig) {\n const data = this.#dataController.get(dataId);\n if (!data) {\n throw new Error('Cannot initialise layer with missing data, id: ' +\n dataId);\n }\n const layerGroup = this.#stage.getLayerGroupByDivId(viewConfig.divId);\n if (!layerGroup) {\n throw new Error('Cannot initialise layer with missing group, id: ' +\n viewConfig.divId);\n }\n const imageGeometry = data.image.getGeometry();\n\n // un-bind\n this.#stage.unbindLayerGroups();\n\n // create and setup view\n const viewFactory = new ViewFactory();\n const view = viewFactory.create(data.meta, data.image);\n const viewOrientation = getViewOrientation(\n imageGeometry.getOrientation(),\n getMatrixFromName(viewConfig.orientation)\n );\n view.setOrientation(viewOrientation);\n\n // make pixel of value 0 transparent for segmentation\n // (assuming RGB data)\n if (data.image.getMeta().Modality === 'SEG') {\n view.setAlphaFunction(function (value /*, index*/) {\n if (value === 0) {\n return 0;\n } else {\n return 0xff;\n }\n });\n }\n\n // do we have more than one layer\n // (the layer has not been added to the layer group yet)\n const isBaseLayer = layerGroup.getNumberOfViewLayers() === 0;\n\n // opacity\n let opacity = 1;\n if (typeof viewConfig.opacity !== 'undefined') {\n opacity = viewConfig.opacity;\n } else {\n if (!isBaseLayer) {\n opacity = 0.5;\n }\n }\n\n // view layer\n const viewLayer = layerGroup.addViewLayer();\n viewLayer.setView(view, dataId);\n const size2D = imageGeometry.getSize(viewOrientation).get2D();\n const spacing2D = imageGeometry.getSpacing(viewOrientation).get2D();\n viewLayer.initialise(size2D, spacing2D, opacity);\n\n // view controller\n const viewController = viewLayer.getViewController();\n // window/level\n if (typeof viewConfig.wlPresetName !== 'undefined') {\n viewController.setWindowLevelPreset(viewConfig.wlPresetName);\n } else if (typeof viewConfig.windowCenter !== 'undefined' &&\n typeof viewConfig.windowWidth !== 'undefined') {\n const wl = new WindowLevel(\n viewConfig.windowCenter, viewConfig.windowWidth);\n viewController.setWindowLevel(wl);\n }\n // colour map\n if (typeof viewConfig.colourMap !== 'undefined') {\n viewController.setColourMap(viewConfig.colourMap);\n } else {\n if (!isBaseLayer) {\n if (data.image.getMeta().Modality === 'PT') {\n viewController.setColourMap('hot');\n } else {\n viewController.setColourMap('rainbow');\n }\n }\n }\n\n // listen to image set\n this.#dataController.addEventListener(\n 'dataimageset', viewLayer.onimageset);\n\n // sync layers position\n const value = [\n viewController.getCurrentIndex().getValues(),\n viewController.getCurrentPosition().getValues()\n ];\n layerGroup.updateLayersToPositionChange({\n value: value,\n srclayerid: viewLayer.getId()\n });\n\n // sync layer groups\n this.#stage.fitToContainer();\n\n // layer offset (done before scale)\n viewLayer.setOffset(layerGroup.getOffset());\n\n // get and apply flip flags\n const flipFlags = this.#getViewFlipFlags(\n imageGeometry.getOrientation(),\n viewConfig.orientation);\n this.#applyFlipFlags(flipFlags, viewLayer);\n\n // layer scale (done after possible flip)\n if (!isBaseLayer) {\n // use zoom offset of base layer\n const baseViewLayer = layerGroup.getBaseViewLayer();\n viewLayer.initScale(\n layerGroup.getScale(),\n baseViewLayer.getAbsoluteZoomOffset()\n );\n } else {\n viewLayer.setScale(layerGroup.getScale());\n }\n\n // bind\n this.#stage.bindLayerGroups();\n if (this.#toolboxController) {\n this.#toolboxController.bindLayerGroup(layerGroup, viewLayer);\n }\n\n /**\n * Add view layer event.\n *\n * @event App#viewlayeradd\n * @type {object}\n * @property {string} type The event type.\n * @property {string} layerid The layer id.\n * @property {string} layergroupid The layer group id.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'viewlayeradd',\n layerid: viewLayer.getId(),\n layergroupid: layerGroup.getDivId(),\n dataid: dataId\n });\n\n // initialise the toolbox for base\n if (isBaseLayer) {\n if (this.#toolboxController) {\n this.#toolboxController.init();\n }\n }\n }\n\n /**\n * Add a draw layer.\n *\n * @param {string} dataId The data id.\n * @param {ViewConfig} viewConfig The data view config.\n */\n addDrawLayer(dataId, viewConfig) {\n const layerGroup = this.#stage.getLayerGroupByDivId(viewConfig.divId);\n if (!layerGroup) {\n throw new Error('Cannot initialise layer with missing group, id: ' +\n viewConfig.divId);\n }\n\n // reference is the data of the view layer with the\n // same StudyInstanceUID\n const data = this.#dataController.get(dataId);\n if (!data) {\n throw new Error('Cannot initialise layer with missing data, id: ' +\n dataId);\n }\n const refSeriesSeq =\n data.annotationGroup.getMetaValue('ReferencedSeriesSequence');\n const refSeriesInstanceUID = refSeriesSeq.value[0].SeriesInstanceUID;\n const viewLayers = layerGroup.searchViewLayers({\n SeriesInstanceUID: refSeriesInstanceUID\n });\n if (viewLayers.length === 0) {\n console.warn(\n 'No loaded data that matches the measurement reference series UID');\n return;\n }\n const refViewLayer = viewLayers[0];\n const refDataId = refViewLayer.getDataId();\n\n // un-bind\n this.#stage.unbindLayerGroups();\n\n // set annotation view controller (allows quantification)\n const refViewController = refViewLayer.getViewController();\n data.annotationGroup.setViewController(refViewController);\n\n // reference data to use as base for layer properties\n const refData = this.#dataController.get(refDataId);\n if (!refData) {\n throw new Error(\n 'Cannot initialise layer without reference data, id: ' +\n refDataId);\n }\n const imageGeometry = refData.image.getGeometry();\n\n const viewOrientation = getViewOrientation(\n imageGeometry.getOrientation(),\n getMatrixFromName(viewConfig.orientation)\n );\n const size2D = imageGeometry.getSize(viewOrientation).get2D();\n const spacing2D = imageGeometry.getSpacing(viewOrientation).get2D();\n\n const drawLayer = layerGroup.addDrawLayer();\n drawLayer.initialise(size2D, spacing2D, refViewLayer.getId());\n\n const planeHelper = new PlaneHelper(\n imageGeometry,\n viewOrientation\n );\n drawLayer.setPlaneHelper(planeHelper);\n\n // sync layers position\n const value = [\n refViewController.getCurrentIndex().getValues(),\n refViewController.getCurrentPosition().getValues()\n ];\n layerGroup.updateLayersToPositionChange({\n value: value,\n srclayerid: drawLayer.getId()\n });\n\n // sync layer groups\n this.#stage.fitToContainer();\n\n // layer offset (done before scale)\n drawLayer.setOffset(layerGroup.getOffset());\n\n // get and apply flip flags\n const flipFlags = this.#getViewFlipFlags(\n imageGeometry.getOrientation(),\n viewConfig.orientation);\n this.#applyFlipFlags(flipFlags, drawLayer);\n\n // layer scale (done after possible flip)\n // use zoom offset of ref layer\n drawLayer.initScale(\n layerGroup.getScale(),\n refViewLayer.getAbsoluteZoomOffset()\n );\n\n // add possible existing data\n drawLayer.setAnnotationGroup(\n data.annotationGroup,\n dataId,\n this.addToUndoStack);\n\n drawLayer.setCurrentPosition(\n refViewController.getCurrentPosition(),\n refViewController.getCurrentIndex()\n );\n\n // bind\n this.#stage.bindLayerGroups();\n if (this.#toolboxController) {\n this.#toolboxController.bindLayerGroup(layerGroup, drawLayer);\n }\n\n /**\n * Add draw layer event.\n *\n * @event App#drawlayeradd\n * @type {object}\n * @property {string} type The event type.\n * @property {string} layerid The layer id.\n * @property {string} layergroupid The layer group id.\n * @property {string} dataid The data id.\n */\n this.#fireEvent({\n type: 'drawlayeradd',\n layerid: drawLayer.getId(),\n layergroupid: layerGroup.getDivId(),\n dataid: dataId\n });\n }\n\n /**\n * Get the view flip flags: offset (x, y) and scale (x, y, z) flags.\n *\n * @param {Matrix33} imageOrientation The image orientation.\n * @param {string} viewConfigOrientation The view config orientation.\n * @returns {object} Offset and scale flip flags.\n */\n #getViewFlipFlags(imageOrientation, viewConfigOrientation) {\n // 'simple' orientation code (does not take into account angles)\n const orientationCode =\n getOrientationStringLPS(imageOrientation.asOneAndZeros());\n if (typeof orientationCode === 'undefined') {\n throw new Error('Unsupported undefined orientation code');\n }\n\n // view orientation flags\n const isViewUndefined = typeof viewConfigOrientation === 'undefined';\n const isViewAxial = !isViewUndefined &&\n viewConfigOrientation === Orientation.Axial;\n const isViewCoronal = !isViewUndefined &&\n viewConfigOrientation === Orientation.Coronal;\n const isViewSagittal = !isViewUndefined &&\n viewConfigOrientation === Orientation.Sagittal;\n\n // default flags\n const flipOffset = {\n x: false,\n y: false\n };\n const flipScale = {\n x: false,\n y: false,\n z: false\n };\n\n if (orientationCode === 'LPS') {\n // axial\n if (isViewCoronal || isViewSagittal) {\n flipScale.z = true;\n flipOffset.y = true;\n }\n } else if (orientationCode === 'LAI') {\n // axial\n if (isViewUndefined || isViewAxial) {\n flipOffset.y = true;\n } else if (isViewCoronal) {\n flipScale.z = true;\n } else if (isViewSagittal) {\n flipScale.z = true;\n flipOffset.x = true;\n }\n } else if (orientationCode === 'RPI') {\n // axial\n if (isViewUndefined || isViewAxial) {\n flipOffset.x = true;\n } else if (isViewCoronal) {\n flipScale.z = true;\n flipOffset.x = true;\n } else if (isViewSagittal) {\n flipScale.z = true;\n }\n } else if (orientationCode === 'RAS') {\n // axial\n flipOffset.x = true;\n flipOffset.y = true;\n if (isViewCoronal || isViewSagittal) {\n flipScale.z = true;\n }\n } else if (orientationCode === 'LSA') {\n // coronal\n flipOffset.y = true;\n if (isViewUndefined || isViewCoronal) {\n flipScale.z = true;\n } else if (isViewAxial) {\n flipScale.y = true;\n } else if (isViewSagittal) {\n flipOffset.x = true;\n flipScale.y = true;\n flipScale.z = true;\n }\n // } else if (orientationCode === 'LIP') { // nothing to do\n } else if (orientationCode === 'RSP') {\n // coronal\n if (isViewUndefined || isViewCoronal) {\n flipOffset.x = true;\n flipOffset.y = true;\n flipScale.x = true;\n flipScale.z = true;\n } else if (isViewAxial) {\n flipOffset.x = true;\n flipScale.x = true;\n } else if (isViewSagittal) {\n flipOffset.y = true;\n flipScale.z = true;\n }\n } else if (orientationCode === 'RIA') {\n // coronal\n flipOffset.x = true;\n if (isViewUndefined || isViewCoronal) {\n flipScale.x = true;\n } else if (isViewAxial) {\n flipOffset.y = true;\n flipScale.x = true;\n flipScale.y = true;\n } else if (isViewSagittal) {\n flipScale.y = true;\n }\n } else if (orientationCode === 'PSL') {\n // sagittal\n flipScale.z = true;\n if (isViewUndefined || isViewSagittal) {\n flipOffset.y = true;\n } else if (isViewCoronal) {\n flipOffset.y = true;\n }\n } else if (orientationCode === 'PIR') {\n // sagittal\n flipScale.z = true;\n if (isViewAxial || isViewCoronal) {\n flipOffset.x = true;\n }\n } else if (orientationCode === 'ASR') {\n // sagittal\n flipOffset.x = true;\n flipOffset.y = true;\n if (isViewUndefined || isViewSagittal) {\n flipScale.z = true;\n } else if (isViewCoronal) {\n flipScale.z = true;\n }\n } else if (orientationCode === 'AIL') {\n // sagittal\n if (isViewUndefined || isViewSagittal) {\n flipOffset.x = true;\n flipScale.z = true;\n } else if (isViewAxial) {\n flipOffset.y = true;\n } else if (isViewCoronal) {\n flipScale.z = true;\n }\n } else {\n logger.warn('Unsupported orientation code: ' +\n orientationCode + ', display could be incorrect');\n }\n\n return {\n scale: flipScale,\n offset: flipOffset\n };\n }\n\n #applyFlipFlags(flipFlags, layer) {\n if (flipFlags.offset.x) {\n layer.addFlipOffsetX();\n }\n if (flipFlags.offset.y) {\n layer.addFlipOffsetY();\n }\n if (flipFlags.scale.x) {\n layer.flipScaleX();\n }\n if (flipFlags.scale.y) {\n layer.flipScaleY();\n }\n if (flipFlags.scale.z) {\n layer.flipScaleZ();\n }\n }\n\n} // class App\n","import {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {MaskSegment} from '../dicom/dicomSegment';\n/* eslint-enable no-unused-vars */\n\n/**\n * Mask segment helper: helps handling the segments list,\n * but does *NOT* update the associated mask (use special commands\n * for that such as DeleteSegmentCommand, ChangeSegmentColourCommand...).\n */\nexport class MaskSegmentHelper {\n\n /**\n * The associated mask.\n *\n * @type {Image}\n */\n #mask;\n\n /**\n * The segments: array of segment description.\n *\n * @type {MaskSegment[]}\n */\n #segments;\n\n /**\n * @param {Image} mask The associated mask image.\n */\n constructor(mask) {\n this.#mask = mask;\n // check segments in meta\n const meta = mask.getMeta();\n if (typeof meta.custom === 'undefined') {\n meta.custom = {};\n }\n if (typeof meta.custom.segments === 'undefined') {\n meta.custom.segments = [];\n }\n this.#segments = meta.custom.segments;\n }\n\n /**\n * Find the index of a segment in the segments list.\n *\n * @param {number} segmentNumber The number to find.\n * @returns {number} The index in the segments list, -1 if not found.\n */\n #findSegmentIndex(segmentNumber) {\n return this.#segments.findIndex(function (item) {\n return item.number === segmentNumber;\n });\n }\n\n /**\n * Check if a segment is part of the segments list.\n *\n * @param {number} segmentNumber The segment number.\n * @returns {boolean} True if the segment is included.\n */\n hasSegment(segmentNumber) {\n return this.#findSegmentIndex(segmentNumber) !== -1;\n }\n\n /**\n * Get the number of segments of the segmentation.\n *\n * @returns {number} The number of segments.\n */\n getNumberOfSegments() {\n return this.#segments.length;\n }\n\n /**\n * Check if a segment is present in a mask image.\n *\n * @param {number[]} numbers Array of segment numbers.\n * @returns {boolean[]} Array of boolean set to true\n * if the segment is present in the mask.\n */\n maskHasSegments(numbers) {\n // create values using displayValue\n const values = [];\n const unknowns = [];\n for (let i = 0; i < numbers.length; ++i) {\n const segment = this.getSegment(numbers[i]);\n if (typeof segment !== 'undefined') {\n if (typeof segment.displayValue !== 'undefined') {\n values.push(segment.displayValue);\n } else {\n values.push(segment.number);\n }\n } else {\n logger.warn('Unknown segment in maskHasSegments: ' + numbers[i]);\n unknowns.push(i);\n }\n }\n const res = this.#mask.hasValues(values);\n // insert unknowns as false in result\n for (let j = 0; j < unknowns.length; ++j) {\n res.splice(unknowns[j], 0, false);\n }\n return res;\n }\n\n /**\n * Get a segment from the inner segment list.\n *\n * @param {number} segmentNumber The segment number.\n * @returns {MaskSegment|undefined} The segment or undefined if not found.\n */\n getSegment(segmentNumber) {\n let segment;\n const index = this.#findSegmentIndex(segmentNumber);\n if (index !== -1) {\n segment = this.#segments[index];\n }\n return segment;\n }\n\n /**\n * Add a segment to the segments list.\n *\n * @param {MaskSegment} segment The segment to add.\n */\n addSegment(segment) {\n const index = this.#findSegmentIndex(segment.number);\n if (index === -1) {\n this.#segments.push(segment);\n // update palette colour map\n if (typeof segment.displayRGBValue !== 'undefined') {\n this.#mask.updatePaletteColourMap(\n segment.number, segment.displayRGBValue);\n }\n } else {\n logger.warn(\n 'Not adding segment, it is allready in the segments list: ' +\n segment.number);\n }\n }\n\n /**\n * Remove a segment from the segments list.\n *\n * @param {number} segmentNumber The segment number.\n */\n removeSegment(segmentNumber) {\n const index = this.#findSegmentIndex(segmentNumber);\n if (index !== -1) {\n this.#segments.splice(index, 1);\n } else {\n logger.warn(\n 'Cannot remove segment, it is not in the segments list: ' +\n segmentNumber);\n }\n }\n\n /**\n * Update a segment of the segments list.\n *\n * @param {MaskSegment} segment The segment to update.\n */\n updateSegment(segment) {\n const index = this.#findSegmentIndex(segment.number);\n if (index !== -1) {\n this.#segments[index] = segment;\n } else {\n logger.warn(\n 'Cannot update segment, it is not in the segments list: ' +\n segment.number);\n }\n }\n\n} // class MaskSegmentHelper\n","import {MaskSegmentHelper} from './maskSegmentHelper';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {MaskSegment} from '../dicom/dicomSegment';\n/* eslint-enable no-unused-vars */\n\n/**\n * Delete segment command.\n */\nexport class DeleteSegmentCommand {\n\n /**\n * The associated mask.\n *\n * @type {Image}\n */\n #mask;\n\n /**\n * The segment to remove.\n *\n * @type {MaskSegment}\n */\n #segment;\n\n /**\n * Flag to send creation events.\n *\n * @type {boolean}\n */\n #isSilent;\n\n /**\n * List of offsets.\n *\n * @type {number[]}\n */\n #offsets;\n\n /**\n * @param {Image} mask The mask image.\n * @param {MaskSegment} segment The segment to remove.\n * @param {boolean} [silent] Whether to send a creation event or not.\n */\n constructor(mask, segment, silent) {\n this.#mask = mask;\n this.#segment = segment;\n this.#isSilent = (typeof silent === 'undefined') ? false : silent;\n // list of offsets with the colour to delete\n if (typeof segment.displayRGBValue !== 'undefined') {\n this.#offsets = mask.getOffsets(segment.number);\n } else {\n this.#offsets = mask.getOffsets(segment.displayValue);\n }\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'Delete-segment';\n }\n\n /**\n * Check if a command is valid and can be executed.\n *\n * @returns {boolean} True if the command is valid.\n */\n isValid() {\n // check that input segment is still there\n const segments = this.#mask.getMeta().custom.segments;\n return segments.some(segmentItem =>\n segmentItem.number === this.#segment.number\n );\n }\n\n /**\n * Execute the command.\n *\n * @fires DeleteSegmentCommand#masksegmentdelete\n */\n execute() {\n if (this.#offsets.length !== 0) {\n // remove from image\n this.#mask.setAtOffsets(this.#offsets, 0);\n }\n\n // remove from segments\n const segHelper = new MaskSegmentHelper(this.#mask);\n segHelper.removeSegment(this.#segment.number);\n\n // callback\n if (!this.#isSilent) {\n /**\n * Segment delete event.\n *\n * @event DeleteSegmentCommand#masksegmentdelete\n * @type {object}\n * @property {number} segmentnumber The segment number.\n */\n this.onExecute({\n type: 'masksegmentdelete',\n segmentnumber: this.#segment.number\n });\n }\n }\n\n /**\n * Undo the command.\n *\n * @fires DeleteSegmentCommand#masksegmentredraw\n */\n undo() {\n if (this.#offsets.length !== 0) {\n // re-draw in image\n if (typeof this.#segment.displayRGBValue !== 'undefined') {\n this.#mask.setAtOffsets(this.#offsets, this.#segment.number);\n } else {\n this.#mask.setAtOffsets(this.#offsets, this.#segment.displayValue);\n }\n }\n // add back to segments\n const segHelper = new MaskSegmentHelper(this.#mask);\n segHelper.addSegment(this.#segment);\n\n // callback\n /**\n * Segment redraw event.\n *\n * @event DeleteSegmentCommand#masksegmentredraw\n * @type {object}\n * @property {number} segmentnumber The segment number.\n */\n this.onUndo({\n type: 'masksegmentredraw',\n segmentnumber: this.#segment.number\n });\n }\n\n /**\n * Handle an execute event.\n *\n * @param {object} _event The execute event with type and id.\n */\n onExecute(_event) {\n // default does nothing.\n }\n\n /**\n * Handle an undo event.\n *\n * @param {object} _event The undo event with type and id.\n */\n onUndo(_event) {\n // default does nothing.\n }\n\n} // DeleteSegmentCommand class\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {MaskSegment} from '../dicom/dicomSegment';\nimport {RGB} from '../utils/colour';\n/* eslint-enable no-unused-vars */\n\n/**\n * Change segment colour command.\n */\nexport class ChangeSegmentColourCommand {\n\n /**\n * The associated mask.\n *\n * @type {Image}\n */\n #mask;\n\n /**\n * The segment to modify.\n *\n * @type {MaskSegment}\n */\n #segment;\n\n /**\n * The new segment colour.\n *\n * @type {RGB|number}\n */\n #newColour;\n\n /**\n * The previous segment colour.\n *\n * @type {RGB|number}\n */\n #previousColour;\n\n /**\n * Flag to send creation events.\n *\n * @type {boolean}\n */\n #isSilent;\n\n /**\n * List of offsets.\n *\n * @type {number[]}\n */\n #offsets;\n\n /**\n * @param {Image} mask The mask image.\n * @param {MaskSegment} segment The segment to modify.\n * @param {RGB|number} newColour The new segment colour.\n * @param {boolean} [silent] Whether to send a creation event or not.\n */\n constructor(mask, segment, newColour, silent) {\n this.#mask = mask;\n this.#segment = segment;\n this.#newColour = newColour;\n\n this.#isSilent = (typeof silent === 'undefined') ? false : silent;\n // list of offsets with the colour to delete\n if (typeof segment.displayRGBValue !== 'undefined') {\n this.#previousColour = segment.displayRGBValue;\n } else {\n this.#previousColour = segment.displayValue;\n this.#offsets = mask.getOffsets(this.#previousColour);\n }\n }\n\n /**\n * Get the command name.\n *\n * @returns {string} The command name.\n */\n getName() {\n return 'Change-segment-colour';\n }\n\n /**\n * Check if a command is valid and can be executed.\n *\n * @returns {boolean} True if the command is valid.\n */\n isValid() {\n let valid = true;\n if (typeof this.#offsets !== 'undefined') {\n valid = this.#offsets.length !== 0;\n }\n return valid;\n }\n\n /**\n * Execute the command.\n *\n * @fires ChangeSegmentColourCommand#changemasksegmentcolour\n */\n execute() {\n // update segment property\n if (typeof this.#newColour === 'number') {\n // remove\n this.#mask.setAtOffsets(this.#offsets, this.#newColour);\n // update segment\n this.#segment.displayValue = this.#newColour;\n } else {\n // update palette colour map (sends update event)\n this.#mask.updatePaletteColourMap(\n this.#segment.number,\n this.#newColour\n );\n // update segment\n this.#segment.displayRGBValue = this.#newColour;\n }\n\n // callback\n if (!this.#isSilent) {\n /**\n * Segment delete event.\n *\n * @event ChangeSegmentColourCommand#changemasksegmentcolour\n * @type {object}\n * @property {number} segmentnumber The segment number.\n */\n this.onExecute({\n type: 'changemasksegmentcolour',\n segmentnumber: this.#segment.number,\n value: [this.#newColour]\n });\n }\n }\n\n /**\n * Undo the command.\n *\n * @fires ChangeSegmentColourCommand#changemasksegmentcolour\n */\n undo() {\n // update segment property\n if (typeof this.#previousColour === 'number') {\n // update values\n this.#mask.setAtOffsets(this.#offsets, this.#previousColour);\n // update segment\n this.#segment.displayValue = this.#previousColour;\n } else {\n // update palette colour map (sends update event)\n this.#mask.updatePaletteColourMap(\n this.#segment.number,\n this.#previousColour\n );\n // udpate segment\n this.#segment.displayRGBValue = this.#previousColour;\n }\n\n // callback\n /**\n * Segment redraw event.\n *\n * @event ChangeSegmentColourCommand#changemasksegmentcolour\n * @type {object}\n * @property {number} segmentnumber The segment number.\n */\n this.onUndo({\n type: 'changemasksegmentcolour',\n segmentnumber: this.#segment.number,\n value: [this.#previousColour]\n });\n }\n\n /**\n * Handle an execute event.\n *\n * @param {object} _event The execute event with type and id.\n */\n onExecute(_event) {\n // default does nothing.\n }\n\n /**\n * Handle an undo event.\n *\n * @param {object} _event The undo event with type and id.\n */\n onUndo(_event) {\n // default does nothing.\n }\n\n} // ChangeSegmentColourCommand class\n","import {logger} from '../utils/logger';\n\n/**\n * Mask segment view helper: handles hidden segments.\n */\nexport class MaskSegmentViewHelper {\n\n /**\n * List of hidden segment numbers.\n *\n * @type {number[]}\n */\n #hiddenNumbers = [];\n\n /**\n * Get the index of a segment in the hidden list.\n *\n * @param {number} segmentNumber The segment number.\n * @returns {number} The index in the array, -1 if not found.\n */\n #findHiddenIndex(segmentNumber) {\n return this.#hiddenNumbers.indexOf(segmentNumber);\n }\n\n /**\n * Check if a segment is in the hidden list.\n *\n * @param {number} segmentNumber The segment number.\n * @returns {boolean} True if the segment is in the list.\n */\n isHidden(segmentNumber) {\n return this.#findHiddenIndex(segmentNumber) !== -1;\n }\n\n /**\n * Add a segment to the hidden list.\n *\n * @param {number} segmentNumber The segment number.\n */\n addToHidden(segmentNumber) {\n if (!this.isHidden(segmentNumber)) {\n this.#hiddenNumbers.push(segmentNumber);\n } else {\n logger.warn(\n 'Not hidding segment, it is allready in the hidden list: ' +\n segmentNumber);\n }\n }\n\n /**\n * Remove a segment from the hidden list.\n *\n * @param {number} segmentNumber The segment number.\n */\n removeFromHidden(segmentNumber) {\n const index = this.#findHiddenIndex(segmentNumber);\n if (index !== -1) {\n this.#hiddenNumbers.splice(index, 1);\n } else {\n logger.warn(\n 'Cannot remove segment, it is not in the hidden list: ' +\n segmentNumber);\n }\n }\n\n /**\n * @callback alphaFn\n * @param {number|number[]} value The pixel value.\n * @param {number} index The values' index.\n * @returns {number} The opacity of the input value.\n */\n\n /**\n * Get the alpha function to apply hidden colors.\n *\n * @returns {alphaFn} The corresponding alpha function.\n */\n getAlphaFunc() {\n // create alpha function\n // (zero is hidden by default)\n return (value/*, index*/) => {\n if (!Array.isArray(value) && (\n value === 0 ||\n this.#hiddenNumbers.includes(value))) {\n return 0;\n }\n // default\n return 255;\n };\n }\n}","/**\n * Mutable 2D scalar ({x,y}).\n */\nexport class Scalar2D {\n /**\n * X value.\n *\n * @type {number}\n */\n x;\n\n /**\n * Y value.\n *\n * @type {number}\n */\n y;\n}\n\n/**\n * Mutable 3D scalar ({x,y,z}).\n */\nexport class Scalar3D {\n /**\n * X value.\n *\n * @type {number}\n */\n x;\n\n /**\n * Y value.\n *\n * @type {number}\n */\n y;\n\n /**\n * Z value.\n *\n * @type {number}\n */\n z;\n}"],"names":["root","factory","exports","module","require","define","amd","this","__WEBPACK_EXTERNAL_MODULE__944__","__WEBPACK_EXTERNAL_MODULE__324__","__WEBPACK_EXTERNAL_MODULE__654__","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","n","getter","__esModule","d","a","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","r","Symbol","toStringTag","value","Index","constructor","values","Error","length","every","val","isNaN","i","toString","getValues","slice","canCompare","rhs","equals","leni","compare","diffDims","push","add","getWithNew2D","j","l","lenl","ModalityLut","rsi","bitsStored","isID","Math","pow","Float32Array","apply","getRSI","getLength","getValue","offset","logger","levels","TRACE","DEBUG","INFO","WARN","ERROR","level","trace","msg","console","debug","info","warn","error","WindowLevel","center","width","defaultPresets","CT","mediastinum","lung","bone","brain","head","VoiLut","wl","getWindowLevel","c","setSignedOffset","WindowLut","modalityLut","isSigned","isDiscrete","size","getVoiLut","getModalityLut","setVoiLut","lut","getSlope","Uint8ClampedArray","floor","buildLut","func","id","invId","lut_range_max","ColourMap","red","green","blue","luts","plain","invPlain","rainbow","hot","third","hot_iron","pet","hot_metal_blue","pet_20step","RGB","g","b","isEqualRgb","c1","c2","labToUintLab","triplet","d65","x","y","z","srgbToCielab","labFunc","res","illuminant","fy","ciexyzToCielab","invGammaFunc","rl","gl","bl","srgbToCiexyz","colourNameToHex","name","dict","Yellow","Red","White","Green","Blue","Lime","Fuchsia","Black","Vector3D","getX","getY","getZ","norm","sqrt","crossProduct","vector3D","dotProduct","isCodirectional","Number","EPSILON","REAL_WORLD_EPSILON","isSimilar","tol","abs","Matrix33","row","col","getInverse","m","m00","m01","m02","m10","m11","m12","m20","m21","m22","a1212","a2012","a0112","det","getMatrixInverse","p","str","multiply","tmp","k","getAbs","multiplyArray3D","array3D","multiplyVector3D","multiplyPoint3D","point3D","Point3D","multiplyIndex3D","index3D","getRowAbsMax","absMax","max","index","indexOf","getColAbsMax","asOneAndZeros","sign","getThirdColMajorDirection","getIdentityMat33","isIdentityMat33","mat33","Point2D","getCentroid","getDistance","point2D","dx","dy","dz","getClosest","pointList","minIndex","minDist","dist","minus","Point","get3D","values0","values1","mergeWith3D","i18n","t","props","split","mm","cm2","degree","startsWith","search","rawPos","pos","substring","endsWith","getFlags","inputStr","flags","regex","match","exec","getFileExtension","filePath","ext","pathSplit","toLowerCase","pop","test","includes","stringToUint8Array","arr","Uint8Array","charCodeAt","precisionRound","number","precision","factor","delta","round","toStringId","dims","arraySortEquals","arr0","arr1","arrayEquals","sort","element","uint8ArrayToString","String","fromCharCode","findInArraySubset","callbackFn","start","end","getFindArrayInArrayCallback","buildMultipart","parts","boundary","lineBreak","partsSize","headers","headerStr","partKeys","keys","header","byteLength","data","trailer","buffer","set","dictionary","addTagsToDictionary","group","tags","tagGroups","vr32bitVL","OB","OD","OF","OL","OV","OW","SQ","SV","UC","UN","UR","UT","UV","ox","is32bitVLVR","vr","vrCharSetString","SH","LO","ST","LT","PN","isCharSetStringVR","vrTypes","AE","AS","AT","CS","DA","DS","DT","FL","FD","IS","SL","SS","TM","UI","UL","US","transferSyntaxes","transferSyntaxKeywords","Tag","getGroup","getElement","getKey","getNameFromDictionary","getGroupName","isWithVR","isPrivate","parseInt","getVrFromDictionary","tagCompareFunction","getTagFromKey","getItemTag","isItemTag","tag","isItemDelimitationItemTag","isSequenceDelimitationItemTag","getPixelDataTag","isPixelDataTag","getTagFromDictionary","tagName","keys0","keys1","foundTag","k0","lenK0","k1","lenK1","DataElement","vl","undefinedLength","startOffset","endOffset","items","flipArrayEndianness","array","blen","u8","byteOffset","bpe","BYTES_PER_ELEMENT","DataReader","Int8Array","Int16Array","isNativeLittleEndian","isLittleEndian","DataView","readUint16","getUint16","readInt16","getInt16","readUint32","getUint32","readBigUint64","getBigUint64","readInt32","getInt32","readBigInt64","getBigInt64","readFloat32","getFloat32","readFloat64","getFloat64","readBinaryArray","bitArray","byteArrayLength","bitNumber","bitIndex","readUint8Array","readInt8Array","readUint16Array","Uint16Array","arraySize","readInt16Array","readUint32Array","Uint32Array","readUint64Array","BigUint64Array","readInt32Array","Int32Array","readInt64Array","BigInt64Array","readFloat32Array","readFloat64Array","Float64Array","readHex","toUpperCase","getDwvVersion","hasDicomPrefix","reduce","previous","current","ZWS","DefaultTextDecoder","decode","result","getReverseOrientation","ori","rlabels","L","R","A","P","H","F","rori","isImplicitTransferSyntax","syntax","isBigEndianTransferSyntax","isJpegBaselineTransferSyntax","isJpegLosslessTransferSyntax","isJpeg2000TransferSyntax","isRleTransferSyntax","getTypedArray","bitsAllocated","pixelRepresentation","RangeError","powerOf2","log","getDataElementPrefixByteSize","isImplicit","TagKeys","DicomParser","getDefaultCharacterSet","setDefaultCharacterSet","characterSet","setDecoderCharacterSet","TextDecoder","getDicomElements","reader","implicit","itemData","item","isSeqDelim","isItemDelim","offsetTableVl","readTagRes","is32bitVL","concat","isKnownVR","pixItemData","sqEndOffset","vrType","Array","from","stream","lastIndex","trim","cleanString","raw","stri","stri1","sqBitsAllocated","sqPixelRepresentation","dataElement","subElement","elements","parse","metaReader","dataReader","magicword","metaEnd","tsElement","firstDataElement","oEightGroupLittleEndian","vr0","vr1","guessTransferSyntax","isReadSupportedTransferSyntax","getTransferSyntaxName","charSetTerm","label","getUtfLabel","numberOfFrames","pixItems","nItemPerFrame","newPixItems","f","newBuffer","fragOffset","ListenerHandler","type","callback","remove","nFound","splice","fireEvent","event","stack","range","dataAccessor","maxIter","increment","blockMaxIter","blockIncrement","reverse1","reverse2","nextIndex","finalBlockIncrement","mainCount","blockCount","next","done","getIteratorValues","iterator","ival","getSliceIterator","image","position","isRescaled","viewOrientation","getGeometry","getSize","dirMax2Index","posValues","posStart","map","indexToOffset","getRescaledValueAtOffset","getValueAtOffset","ncols","nrows","nslices","sliceSize","getDimSize","ncomp","getNumberOfComponents","isPlanar","getPlanarConfiguration","getRange","iters","r0","r1","r2","range3d","rangeObj","dirMax0","dirMax2","simpleRange","componentIncrement","nextIndex1","nextIndex2","simpleRange3d","valueRange","nextValueIndex","RescaleSlopeAndIntercept","slope","intercept","getIntercept","Size","moreThanOne","dimension","canScroll3D","canScroll","getTotalSize","isInBounds","dirs","offsetToIndex","off","dimSize","get2D","Statistics","min","mean","stdDev","median","p25","p75","getStats","includesFullStatsFlags","stats","getBasicStats","getPercentile","getFullStats","sum","sumSqr","variance","ratio","i0","v0","guid","random","NumberRange","Spacing","Geometry","origin","spacing","orientation","time","getInitialTime","getCurrentTotalNumberOfSlices","count","hasSlicesAtTime","getCurrentNumberOfSlicesBeforeTime","getOrigin","getOrigins","includesOrigin","getOrientedArray3D","geoSliceSpacing","origins","spacings","origin1","origin2","sliceSpacing","getSliceGeometrySpacing","getSpacing","orientedValues","getRealSpacing","getOrientation","getSliceIndex","point","localOrigins","closestOriginIndex","closestOrigin","pointDir","appendOrigin","equalToOrigin","find","appendFrame","sizeValues","spacingValues","isIndexInBounds","worldToIndex","indexToWorld","orientedPoint3D","pointToWorld","worldToPoint","getDeOrientedArray3D","padZeroTwoDigit","getDate","daValue","monthBeginIndex","dayBeginIndex","year","monthIndex","day","getTime","tmValue","tmHours","tmMinutes","tmSeconds","tmFracSecondsStr","hours","minutes","seconds","milliseconds","dateToDateObj","date","getFullYear","getMonth","dateToTimeObj","getHours","getMinutes","getSeconds","getDicomDate","dateObj","getDicomTime","getCoronalMat33","Orientation","Axial","Coronal","Sagittal","getMatrixFromName","matrix","getOrientationStringLPS","v1","v2","getVectorStringLPS","vector","orientationX","orientationY","orientationZ","threshold","getOrientationName","cosines","orientMatrix","getOrientationFromCosines","code","orientStr","getLPSGroup","orientationMatrix","rowCosines","colCosines","normal","getViewOrientation","imageOrientation","targetOrientation","getImage2DSize","rows","columns","getSpacingFromMeasure","dataElements","pixelSpacing","parseFloat","isMonochrome","photometricInterpretation","checkTag","warning","TagValueExtractor","_elements","ImageFactory","getWarning","checkElements","modality","syntaxElement","spp","samplesPerPixel","photo","jpeg2000","jpegBase","jpegLoss","getPhotometricInterpretation","SOPClassUID","getSopClassUid","isSecondatyCapture","suvFactor","patWeight","patWeightEl","weight","decayedDose","seriesDateObj","totalDose","halfLife","radioStart","radioInfoSq","totalDoseStr","totalDoseEl","dose","halfLifeStr","halfLifeEl","hl","radioStartDateTimeEl","radioStartDateObj","radioStartTimeObj","radioStartDateTime","dtValue","dateDataElement","dtDate","timeDataElement","getDateTime","Date","seriesTimeObj","scanStart","acqDateEl","acqTimeEl","acqDateObj","acqTimeObj","acqDate","frameRefTime","frameRefTimeElStr","frameRefTimeEl","actualFrameDuration","actualFrameDurationElStr","actualFrameDurationEl","decayConstant","decayDuringFrame","offsetSeconds","exp","decayTime","getDecayedDose","getSuvFactor","create","pixelBuffer","numberOfFiles","size2D","numberOfFramesEl","rowSpacing","columnSpacing","getPixelSpacing","imagePositionPatient","slicePosition","imageOrientationPatient","getOrientationMatrix","geometry","sopInstanceUid","siu","bufferSize","Image","setPhotometricInterpretation","planarConfiguration","setPlanarConfiguration","rescaleSlope","rescaleIntercept","meta","Modality","isPetWithSuv","intensityFactor","setRescaleSlopeAndIntercept","safeGet","TransferSyntaxUID","MediaStorageSOPClassUID","ImageType","SamplesPerPixel","PhotometricInterpretation","PixelRepresentation","BitsAllocated","BitsStored","HighBit","StudyDate","StudyTime","StudyInstanceUID","StudyID","SeriesInstanceUID","SeriesNumber","ReferringPhysicianName","PatientName","PatientID","PatientBirthDate","PatientSex","Manufacturer","ManufacturerModelName","DeviceSerialNumber","SoftwareVersions","ImageOrientationPatient","FrameOfReferenceUID","IsSigned","pixelUnit","unit","getPixelUnit","windowPresets","windowCenter","windowWidth","windowCWExplanation","redLutElement","greenLutElement","blueLutElement","redLut","greenLut","blueLut","descriptor","doScale","descSize","vlSize","scaleTo8","clone","setPaletteColourMap","recommendedDisplayFrameRate","RecommendedDisplayFrameRate","setMeta","DataWriter","writeUint8","setUint8","writeInt8","setInt8","writeUint16","setUint16","writeInt16","setInt16","writeUint32","setUint32","writeUint64","setBigUint64","writeInt32","setInt32","writeInt64","setBigInt64","writeFloat32","setFloat32","writeFloat64","setFloat64","writeHex","writeBinaryArray","byte","len","writeUint8Array","writeInt8Array","writeUint16Array","writeInt16Array","writeUint32Array","writeUint64Array","writeInt32Array","writeInt64Array","writeFloat32Array","writeFloat64Array","_uidCount","WriterRule","action","writerActions","copy","clear","replace","getUID","prefix","getDwvUIDPrefix","uid","datePart","toISOString","countPart","nonTagLength","tagNumber","isEven","isStringVr","uint8ArrayPush","newArr","DefaultTextEncoder","encode","DicomWriter","default","setUseUnVrForPrivateSq","flag","setFixUnknownVR","setRules","rules","addMissingTags","rule","tagKey","isKey","useSpecialTextEncoder","TextEncoder","getElementToWrite","groupName","writer","itemTag","subItem","itemElement","itemDelimElement","hexString","hexString1","hexString2","atValue","diff","message","finalValue","initialArray","initialArrayLength","arrayLength","flattenendArrayLength","flattenedArray","indexFlattenedArray","flattenArrayOfTypedArrays","isTagWithVR","undefinedLengthSequence","undefinedLengthItem","seqDelimElement","getBuffer","isBigEndian","oldscs","totalSize","localSize","metaElements","rawElements","metaLength","fmiglTag","fmivTag","icUIDTag","ivnTag","missingTags","originalElement","checkAndFixUnknownVR","fmiv","getDataElement","fmivSize","icUID","icUIDSize","icUIDValue","ivn","ivnSize","ivnValue","elemSortFunc","fmigl","fmiglSize","ArrayBuffer","metaWriter","dataWriter","lenj","metaOffset","lenk","newItems","oldItemElements","newItemElements","subSize","itemKeys","itemKey","padStr","pad","getVrPad","join","padOBValue","isTypedArrayVr","isArray","itemPrefixSize","getBpeForVrType","dictVr","getUint8ToVrValue","getElementsFromJSONTags","simpleTags","simpleTag","CodeValue","CodingSchemeDesignator","CodeMeaning","LongCodeValue","URNCodeValue","DicomCode","meaning","longValue","urnValue","schemeDesignator","isEqualCode","code1","code2","getCode","getDicomCodeItem","DcmCodes","SctCodes","UcumCodes","deg","getDicomCode","scheme","getMeasurementGroupCode","getReferenceGeometryCode","getSourceImageCode","getTrackingIdentifierCode","getShortLabelCode","getReferencePointsCode","getColourCode","QuantificationName2DictItem","angle","surface","height","radius","stddev","getQuantificationName","propKey","QuantificationUnit2UcumKey","HU","MGML","ED","PCT","CNTS","NONE","CM2","CM2ML","PCNT","CPS","BQML","MGMINML","UMOLMINML","MLMING","MLG","UMOLML","PROPCNTS","PROPCPS","MLMINML","MLML","GML","SUV","getQuantificationUnit","ucumKey","MaskSegment","algorithmType","algorithmName","displayValue","displayRGBValue","propertyTypeCode","propertyCategoryCode","trackingUid","trackingId","getSegment","segment","cielabElement","rgb","gammaFunc","ciexyzToSrgb","invLabFunc","l0","cielabToCiexyz","cielabToSrgb","getDicomSegmentItem","algoType","segmentItem","SegmentNumber","SegmentLabel","SegmentAlgorithmType","SegmentAlgorithmName","cieLab","RecommendedDisplayCIELabValue","RecommendedDisplayGrayscaleValue","SegmentedPropertyCategoryCodeSequence","SegmentedPropertyTypeCodeSequence","TrackingID","TrackingUID","DicomSegmentFrameInfo","dimIndex","imagePosPat","derivationImages","refSegmentNumber","getSegmentFrameInfo","derivationImageSq","sourceImages","sourceImageSq","sourceImage","referencedSOPClassUID","referencedSOPInstanceUID","segmentIdSq","frameInfo","framePlaneOrientationSeq","frameImageOrientation","framePixelMeasuresSeq","frameSpacing","getDicomSegmentFrameInfoItem","FrameContentSequence","DimensionIndexValues","PlanePositionSequence","ImagePositionPatient","SegmentIdentificationSequence","ReferencedSegmentNumber","sourceImgPurposeOfReferenceCode","segDerivationCode","derivationImageItems","derivationImage","PurposeOfReferenceCodeSequence","ReferencedSOPClassUID","ReferencedSOPInstanceUID","DerivationCodeSequence","SourceImageSequence","DerivationImageSequence","equalPosPat","pos1","pos2","JSON","stringify","tagDefinition","tagValue","enum","createRoiSliceBuffers","segments","sliceOffset","buffers","inputOffset","pixelValue","segmentIndex","RequiredDicomSegTags","getDefaultDicomSegJson","reqTag","MaskFactory","_dicomElements","frames","framesElem","orgSq","orgUID","indices","indexSqElem","indexSq","indexPointer","indexOrg","DimensionOrganizationUID","DimensionIndexPointer","DimensionDescriptionLabel","organizations","getDimensionOrganization","segSequence","paletteColourMap","hasDisplayRGBValue","sharedFunctionalGroupsSeq","funcGroup0","planeOrientationSeq","pixelMeasuresSeq","includesPosPat","some","arrVal","findIndexPosPat","findIndex","perFrameFuncGroupSequence","frameInfos","framePosPats","ii","invOrientation","p1","p2","getComparePosPat","point3DFromArray","frameOrigins","tmpGeometry","isAboveEpsilon","posPats","sliceIndex","frameOrigin","distPrevious","numberOfSlices","uids","getFindSegmentFunc","fill","frameOffset","frameSegment","SeriesDate","SeriesTime","DimensionOrganizationSequence","DimensionIndexSequence","custom","SOPInstanceUID","frameOfReferenceUID","lossyImageCompression","LossyImageCompression","toDicom","extraTags","getMeta","Rows","Columns","now","ContentDate","ContentTime","segmentItems","SegmentSequence","SharedFunctionalGroupsSequence","PlaneOrientationSequence","PixelMeasuresSequence","SpacingBetweenSlices","PixelSpacing","roiBuffers","key0","createRoiBuffers","finalBuffers","referencedSOPs","number40","number4","key1","posPat","posPatArray","sourceIndex","getImageUid","NumberOfFrames","frameInfosTag","PerFrameFunctionalGroupsSequence","refSeriesTag","ReferencedInstanceSequence","ReferencedSeriesSequence","tags1","tags2","keys2","tagName2","mergeTags","dicomElements","pixVl","de","createImage","createMaskImage","imageUids","getSecondaryOffset","getOriginForImageUid","uidIndex","includesImageUid","containsImageUids","itemArr1","arrayContains","canQuantify","canWindowLevel","nFiles","getRescaleSlopeAndIntercept","isConstantRSI","inRsi","isIdentityRSI","interp","getPaletteColourMap","updatePaletteColourMap","colour","config","getOffsets","bufferValue","offsets","equal","hasValues","finalValues","equalFunc","getEqualCallback","valuesToFind","indicesToRemove","v","clonedBuffer","tmpBuffer","appendSlice","rhsSize","rhsRange","getDataRange","rhsResRange","getRescaledDataRange","resRange","timeId","isNewFrame","volumeGeometry","sliceGeometry","fullBufferSize","fullSliceIndex","indexOffset","maxOffset","subarray","numberOfImages","rhsPresets","pkey","rhsPreset","windowPreset","perslice","appendFrameBuffer","frameBuffer","frameIndex","frameSize","calculateDataRange","calculateRescaledDataRange","getHistogram","calculateHistogram","dataRange","rescaledDataRange","histogram","addEventListener","removeEventListener","setAtOffsets","setAtOffsetsAndGetOriginals","offsetsLists","originalValuesLists","previousValue","originalValues","currentValue","setAtOffsetsWithIterator","isValueArray","getValueAtIndex","getRescaledValue","getRescaledValueAtIndex","resmin","resmax","rmin","rmax","rvalue","histo","convolute2D","weights","newImage","imgSize","dimOffset","convoluteBuffer","componentOffset","wOff","wOff00","wOff0x","wOff0n","wOffx0","wOffxn","wOffn0","wOffnx","wOffnn","pixelOffset","newValue","wOffFinal","wi","transform","operator","compose","ViewFactory","view","View","setColourMap","minmax","preset","setWindowPresets","init","viewEventNames","createView","getCurrentIndex","setCurrentIndex","getImage","setImage","inImage","setOrientation","setInitialIndex","getPlaybackMilliseconds","_value","_index","getAlphaFunction","setAlphaFunction","currentIndex","sliceWl","setWindowLevel","setWindowLevelPresetById","voiLut","voiLutWl","getWindowPresets","getWindowPresetsNames","presets","addWindowPresets","getCurrentWindowPresetName","getColourMap","getCurrentPosition","getCurrentImageUid","isPositionInBounds","getScrollIndex","originIndex","setCurrentPosition","silent","valid","minLen","maxLen","posEvent","imageUid","pixValue","isNewWl","isNewName","manual","wc","ww","skipGenerate","setWindowLevelPreset","getWindowLevelMinMax","setWindowLevelMinMax","generateImageData","photoInterpretation","alphaFunc","windowLut","colourMap","pxValue","generateImageDataMonochrome","is16BitsStored","to8","generateImageDataPaletteColor","generateImageDataRgb","cb","cr","generateImageDataYbrFull","isAquisitionOrientation","PlaneHelper","imageGeometry","getTargetOrientation","getOffset3DFromPlaneOffset","offset2D","planeOffset","getTargetDeOrientedVector3D","getPlaneOffsetFromOffset3D","offset3D","getTargetOrientedVector3D","planeVector","getTargetDeOrientedPoint3D","planePoint","getImageOrientedVector3D","getImageOrientedPoint3D","getImageDeOrientedVector3D","getImageDeOrientedPoint3D","getPositionFromPlanePoint","getPlanePointFromPosition","getCosines","getPlanePoints","planeOrigin","getTargetOrientedPositiveXYZ","getNativeScrollIndex","ViewController","getPlaneHelper","isMask","initialise","getModality","getWindowLevelPresetsNames","addWindowLevelPresets","isPlaying","getCurrentOrientedIndex","getCurrentScrollIndexValue","getCurrentScrollPosition","scrollIndex","img","get2DSpacing","getRescaledImageValue","sliceValues","sliceOrigin","getImageRegionValues","rescaled","iter","rangeNumberOfColumns","regionSize","regionOffset","regionElementCount","rangeRegion","getRegionSliceIterator","getImageVariableRegionValues","regions","offsetRegions","region","regionIndex","regionCount","rangeRegions","getVariableRegionSliceIterator","canQuantifyImage","getImageSize","dim","getImageWorldSize","getImageRescaledDataRange","equalImageMeta","imageMeta","metaKeys","metaKey","getPlanePositionFromPosition","getIndexFromPosition","getPlanePositionFromPlanePoint","incr","getIncrementPosition","getDecrementPosition","getIncrementScrollPosition","getDecrementScrollPosition","incrementIndex","decrementIndex","decrementScrollIndex","incrementScrollIndex","play","window","setInterval","canDoMore","stop","clearInterval","setViewAlphaFunction","bindImageAndLayer","viewLayer","onimagecontentchange","onimagegeometrychange","unbindImageAndLayer","ScrollSum","getSum","wheelDeltaY","deltaY","getSpinY","isTick","ScrollWheel","app","wheel","up","preventDefault","layerDetails","getLayerDetailsFromEvent","layerGroup","getLayerGroupByDivId","groupDivId","viewController","getActiveViewLayer","getViewController","newPosition","Line","begin","getBegin","getEnd","getDeltaX","getDeltaY","getWorldLength","spacing2D","wlen","dxs","dys","getMidpoint","getInclination","atan2","PI","quantify","quant","getAngle","line0","line1","dx0","dy0","dx1","dy1","dot","areOrthogonal","getPerpendicularLine","line","perpSlope","getLineFromEquation","getPerpendicularLineAtDistance","distance","lineFromEq","startPoint","minX","maxX","minY","maxY","isPointInLineRange","beginX","beginY","endX","endY","sx2","sy2","AnnotationGroup","list","getList","isEditable","setEditable","getColour","setColour","annotation","update","propKeys","setViewController","updateQuantification","hasMeta","getMetaValue","setMetaValue","DrawController","getAnnotation","getAnnotationGroup","isAnnotationGroupEditable","setAnnotationGroupEditable","addAnnotation","updateAnnotation","removeAnnotation","removeAnnotationWithCommand","exeCallback","command","RemoveAnnotationCommand","execute","updateAnnotationWithCommand","originalProps","newProps","UpdateAnnotationCommand","removeAllAnnotationsWithCommand","hasAnnotationMeta","setAnnotationMeta","Style","getFontFamily","getFontSize","getStrokeWidth","getTextColour","getLineColour","setLineColour","setBaseScale","scale","setZoomScale","getBaseScale","getZoomScale","applyZoomScale","applyZoomRatio","getShadowOffset","getTagOpacity","getTextPadding","getFontStr","getLineHeight","getScaledFontSize","getScaledStrokeWidth","getShadowLineColour","hexColour","hexStr","isNodeNameLabel","node","isNodeNameShape","isPositionNode","getLineShape","kshape","getChildren","Konva","getAnchorShape","isNodeWithId","getDefaultAnchor","style","absRadius","stroke","strokeWidth","strokeScaleEnabled","radiusX","radiusY","dragOnTop","draggable","visible","getAnchorIndex","Rectangle","getSurface","getWorldSurface","mulABC","getRealWidth","getRealHeight","getWidth","getHeight","getRound","quantif","getRectangleIndices","dir","centerValues","sizeI","halfSizeI","sizeJ","halfSizeJ","di","dj","ROI","points","getPoint","getPoints","addPoint","addPoints","cx","cy","pi","pi1","ai","a1","Protractor","_viewController","_flags","Ellipse","centre","getCenter","getA","getB","centerX","centerY","radiusRatio","rySquare","transX","getEllipseIndices","radiusI","radiusJ","radiusJ2","jmax","jmin","imax","imin","Circle","getRadius","rSquare","DrawShapeEditor","eventCallback","setShape","inshape","drawLayer","getFactory","getShape","isActive","enable","getLayer","draw","disable","reset","resetAnchors","getParent","forEach","anchor","setAnchorsActive","anchors","getAnchors","getStyle","on","cancelBubble","mathShape","referencePoints","target","stageSize","changed","boundNodePosition","validateAnchorPosition","getBaseSize","constrainAnchorMove","updateAnnotationOnAnchorMove","updateShapeGroupOnAnchorMove","getDrawController","addToUndoStack","dataid","getDataId","moveToTop","DrawTrash","createTrashIcon","trashLine1","trashLine2","activate","stage","getKonvaStage","konvaLayer","getKonvaLayer","invscale","changeChildrenColourOnTrashHover","eventPosition","shapeGroup","originalShapeColour","isOverTrash","changeGroupChildrenColour","tshape","trashHalfWidth","scaleX","trashHalfHeight","scaleY","DrawShapeHandler","setEditorShape","shape","drawController","getEditorShapeGroup","getEditorAnnotation","disableAndResetEditor","storeMouseOverCursor","cursor","document","body","opacity","onMouseOutShapeGroup","addShapeGroupListeners","originalTextExpr","textExpr","customUI","openRoiDialog","newTextExpr","dragStartPos","previousPos","getShapePositionRange","boundRect","getClientRect","relativeTo","isShapeInRange","children","labelWithDefaultPosition","labelPosition","child","move","updateAnnotationOnTranslation","updateLabelContent","updateConnector","mousePoint","getMousePoint","evt","eventPos","translation","originalLabelPosition","newLabelPosition","removeShapeListeners","DrawLayer","containerDiv","className","setShapeHandler","handler","getReferenceLayerId","getLayers","setPlaneHelper","helper","getId","removeFromDOM","getOpacity","setOpacity","alpha","addFlipOffsetX","addFlipOffsetY","flipScaleX","flipScaleY","flipScaleZ","setScale","newScale","orientedNewScale","finalNewScale","resetOffset","worldCenter","newOffset","getScaledOffset","newZoomOffset","initScale","absoluteZoomOffset","setOffset","planeNewOffset","setBaseOffset","scrollOffset","needsUpdate","display","isVisible","refLayerId","container","listening","getContent","setAttribute","setAnnotationGroup","annotationGroup","dataId","activateCurrentPositionShapes","AddAnnotationCommand","allPosGroups","posGroup","shapeGroups","planePoints","posGroupId","layerChildren","posChildren","isCompatibleView","createShapeGroup","setLabelVisibility","fitToContainer","containerSize","divToWorldSizeRatio","fitOffset","divToImageSizeRatio","newViewOffset","scaledImageSize","newFlipOffset","isAnnotationVisible","setAnnotationVisibility","setLabelsVisibility","posGroups","getText","text","connector","deleteDraw","_id","_exeCallback","deleteDraws","getNumberOfDraws","bindInteraction","pointerEvents","names","InteractionEventNames","unbindInteraction","findOne","srclayerid","ratioX","ratioY","labels","getName","undo","originaProps","Path","inputPointArray","inputControlPointIndexArray","pointArray","controlPointIndexArray","isControlPoint","addControlPoint","newPointArray","appenPath","other","oldSize","indexArray","BucketQueue","bits","cost_functor","bucketCount","mask","loc","cost","buckets","buildArray","bucket","getBucket","ret","isEmpty","newSize","__twothirdpi","gradUnitVector","gradX","gradY","px","py","out","oy","gvm","Scissors","curPoint","searchGranBits","searchGran","pointsPerPost","greyscale","laplace","gradient","parents","working","trained","trainingPoints","edgeWidth","trainingLength","edgeGran","edgeTraining","gradPointsNeeded","gradGran","gradTraining","insideGran","insideTraining","outsideGran","outsideTraining","getTrainingIdx","granularity","getTrainedEdge","edge","getTrainedGrad","grad","getTrainedInside","inside","getTrainedOutside","outside","setWorking","setDimensions","setData","gradMagnitude","lap","computeGreyscale","computeLaplace","computeGradient","computeGradX","computeGradY","sides","guv","ix","iy","computeSides","findTrainingPoints","resetTraining","doTraining","calculateTraining","addInStaticGrad","input","output","maxVal","idx","gaussianBlur","have","need","gradDirection","qx","qy","__dgpuv","__gdquv","dp","dq","SQRT1_2","acos","adj","sx","sy","ex","ey","setPoint","sp","visited","MAX_VALUE","pq","doWork","timeout","pointCount","newPoints","adjList","q","pqCost","defaults","labelText","arrow","circle","ellipse","protractor","rectangle","roi","ruler","LabelFactory","positionGetter","getPosition","ktext","fontSize","fontFamily","padding","shadowColor","shadowOffset","setText","zoomScale","labelScale","klabel","updatePosition","getLabelAnchorsPosition","lx","ly","getClosestPoints","points1","points2","point1","point2","getConnector","connectorsPos","labelAnchorsPos","anchorPoints","dash","kconnect","updateContent","ThresholdFilter","getMin","setMin","getMax","setMax","setOriginalImage","getOriginalImage","imageMin","SharpenFilter","SobelFilter","RunFilterCommand","filter","render","onExecute","onUndo","_event","toolList","toolOptions","defaultToolList","divId","diffX","diffY","pixelToIntensity","WindowLevelValues","mousedown","mousemove","mouseup","mouseout","touchstart","touchPoints","getTouchPoints","touchmove","touchend","dblclick","displayToPlaneIndex","getData","keydown","context","onKeydown","_bool","setFeatures","_features","Scroll","planePos","displayToPlanePos","yMove","xMove","setTimeout","clearTimeout","showTooltip","removeTooltipDiv","features","displayTooltip","ZoomAndPan","tx","ty","displayToPlaneScale","addTranslation","#twoTouchUpdate","lineRatio","zoom","displayToMainPlanePos","addScale","step","Opacity","op","Draw","getActiveDrawLayer","refDataId","seriesInstanceUID","createAnnotationData","addAndRenderAnnotationData","setActiveDrawLayerByDataId","getIntersection","selectedShape","annotationid","getNPoints","timer","getTimeout","getActiveLayerGroup","destroy","tmpPoints","colours","drawLayerId","layerId","Annotation","groupColour","setAnnotationMathShape","finalPoints","layer","drawLayers","getDrawLayers","layerid","setOptions","options","getOptionsType","autoShapeColour","shapeColour","shapeName","hasShape","mouseOverCursor","withScroll","blacklist","getEventNames","listener","Filter","bool","getSelectedFilter","filterName","hasFilter","run","args","runArgs","getFilterList","Floodfill","setExtend","getExtend","#getIndex","simple","bytes","MagicWand","cs","icsl","newMathShape","originalMathShape","extend","ini","imageSize","jl","onThresholdChange","getImageData","getAbsoluteScale","movedpoint","Livewire","pn","p0","results","_p","_q","defaultToolOptions","ArrowFactory","supports","setTextExpr","extras","extra","positions","_anchor","kline","pointBegin","pointEnd","endPoint","newBegin","newEnd","_style","linePerp0","linePerp1","hitFunc","beginPath","moveTo","lineTo","closePath","fillStrokeShape","perpLine","closed","ktriangle","_annotation","_group","CircleFactory","left","right","bottom","top","anchorPoint","newRadius","newCenter","swapX","swapY","offsetX","offsetY","kshadow","pixelLine","EllipseFactory","ProtractorFactory","mid","pointMid","newPointList","inclination","innerRadius","outerRadius","rotation","midX","midY","karc","arcPos","RectangleFactory","topLeft","bottomRight","pointTopLeft","pointBottomRight","krect","topRight","bottomLeft","rWidth","rHeight","RoiFactory","kroi","newPoint","RulerFactory","ktick0","ktick1","Threshold","Sobel","Sharpen","referenceSopUID","quantification","planeHelper","cosine1","cosine2","originPoint","valueObj","valueStr","toPrecision","replaceFlags","fac","factoryName","prompt","getTouchesPositions","touches","offsetLeft","offsetTop","offsetParent","pageX","pageY","targetTouches","changedTouches","canCreateCanvas","testCvs","createElement","cropCvs","testCtx","getContext","cropCtx","fillRect","drawImage","ViewLayer","getScale","getAbsoluteZoomOffset","setImageSmoothing","setView","bindImage","onimageset","unbindImage","vcSize","origin0","layerGroupOrigin","layerGroupOrigin0","deScaled","planePosToDisplay","posX","posY","globalAlpha","setTransform","imageSmoothingEnabled","appendChild","alert","clearRect","createImageData","needsDraw","eventName","passive","putImageData","dims3D","indexScrollIndex","save","restore","getLayerDetailsFromLayerDivId","idString","layerIndex","layerDiv","closest","indexCenter","LayerGroup","getShowCrosshair","setShowCrosshair","getDivId","getAddedScale","getOffset","getNumberOfLayers","getViewLayers","someViewLayer","hasOne","getNumberOfViewLayers","tmpLayer","getBaseViewLayer","baseLayer","getViewLayersByDataId","searchViewLayers","getViewDataIndices","getDrawLayersByDataId","setActiveViewLayer","setActiveViewLayerByDataId","setActiveDrawLayer","addViewLayer","viewLayerIndex","div","append","addDrawLayer","updateLayersToPositionChange","empty","getElementsByClassName","removeLayersByDataId","removeLayer","displayPos","lineH","offsetWidth","lineV","offsetHeight","span","createTextNode","viewLayerOffsets","baseViewLayerOrigin0","baseViewLayerOrigin","hasSetOffset","vc","scrollDiff","planeDiff","scroll","plane","refOffsets","hasSetPos","getDivToWorldSizeRatio","maxWorldSize","getMaxWorldSize","maxSize","scaleStep","binderList","WindowLevelBinder","getEventType","getCallback","viewLayers","PositionBinder","pointValues","currentPos","currentDims","inputDims","ZoomBinder","OffsetBinder","OpacityBinder","ColourMapBinder","Stage","getLayerGroup","getNumberOfLayerGroups","setActiveLayerGroup","addLayerGroup","htmlElement","isBound","unbindLayerGroups","bindLayerGroups","setBinders","removeLayerGroup","minRatio","hasRatio","binder","binderObj","elem","State","fromJSON","json","version","baseScale","scaleCenter","originX","originY","oldTx","oldTy","setDrawings","drawings","drawingsDetails","v02DAndD","inputDrawings","newDrawings","drawGroups","drawGroup","lenf","newFrameDrawings","leng","karcs","ktexts","toObject","txtLen","longText","v01Tov02DrawingsAndDetails","v02Tov03Drawings","v03Tov04DrawingsDetails","v04Tov05Data","v04Tov05Drawings","details","groupDetails","v02Tov03DrawingsDetails","groupShapes","parentGroup","groupDrawings","currentPosition","gnode","detail","ids","attrs","sliceNumber","frameNumber","newId","getUrlFromUri","uri","base","location","URL","splitUri","sepIndex","hashIndex","query","pairs","pair","splitKeyValueString","UndoStack","getStackSize","getCurrentStackIndex","cmd","redo","ToolboxController","enableShortcuts","getToolList","hasTool","getSelectedTool","getSelectedToolEventHandler","eventType","setSelectedTool","setToolFeatures","bindLayerGroup","layerGroupDivId","applySelectedTool","MultiProgressHandler","setNumberOfDimensions","num","setNToLoad","onprogress","lengthComputable","subindex","percent","loaded","total","source","lenprog","getMonoProgressHandler","getUndefinedMonoProgressHandler","UrlsLoader","request","loader","onload","onloadend","load","onloadstart","status","onerror","responseURL","statusText","response","mproghandler","loaders","loaderList","foundLoader","canLoadUrl","defaultCharacterSet","onloaditem","onabort","lastRunRequestIndex","requestOnLoadEnd","send","XMLHttpRequest","open","requestHeaders","setRequestHeader","withCredentials","errorCallback","abortCallback","loadUrlAs","responseType","batchSize","dicomDirUrl","urls","parser","dirSeq","records","series","study","recType","refFileIds","getFileListFromDicomDir","rootUrl","fullUrls","abort","readyState","isLoading","ThreadPool","poolSize","taskQueue","freeThreads","WorkerThread","runningThreads","addWorkerTask","workerTask","onworkstart","workerThread","shift","onworkend","onTaskEnd","onwork","handleWorkerError","onworkitem","parentPool","runningTask","worker","Worker","script","onmessage","postMessage","startMessage","terminate","itemNumber","numberOfItems","WorkerTask","hasJpegBaselineDecoder","JpegImage","hasJpegLosslessDecoder","jpeg","lossless","hasJpeg2000Decoder","JpxImage","decoderScripts","rle","AsynchPixelBufferDecoder","_numberOfData","pixelMeta","ondecodestart","ondecodeditem","ondecoded","ondecodeend","SynchPixelBufferDecoder","algoName","numberOfData","decoder","decodedBuffer","buf","Decoder","decoded","tiles","dwvdecoder","RleDecoder","PixelBufferDecoder","NumericValue","FloatingPointValue","RationalNumeratorValue","RationalDenominatorValue","MeasurementUnitsCodeSequence","MeasuredValue","numericValue","floatingPointValue","rationalNumeratorValue","rationalDenominatorValue","measurementUnitsCode","getDicomMeasuredValueItem","MeasuredValueSequence","NumericValueQualifierCodeSequence","NumericMeasurement","measuredValue","numericValueQualifierCode","getDicomNumericMeasurementItem","measurement","SopInstanceReference","getSopInstanceReference","ref","getDicomSopInstanceReferenceItem","ReferencedFrameNumber","ReferencedSOPSequence","ImageReference","referencedSOPSequence","referencedFrameNumber","referencedSegmentNumber","fiducialUID","getDicomImageReferenceItem","PixelOriginInterpretation","GraphicData","GraphicType","FiducialUID","GraphicTypes","SpatialCoordinate","graphicData","graphicType","pixelOriginInterpretation","getDicomSpatialCoordinateItem","scoord","ReferencedFrameofReferenceUID","SpatialCoordinate3D","referencedFrameofReferenceUID","getDicomSpatialCoordinate3DItem","RelationshipType","ValueType","ConceptNameCodeSequence","ConceptCodeSequence","ContentSequence","DateTime","Time","UID","PersonName","TextValue","ContinuityOfContent","RelationshipTypes","ValueTypes","datetime","uidref","pname","composite","waveform","scoord3d","tcoord","table","ValueTypeValueTagName","TEXT","DATE","TIME","DATETIME","UIDREF","PNAME","CONTAINER","DicomSRContent","valueType","conceptNameCode","relationshipType","contentSequence","getSRContent","content","getMeasuredValue","getNumericMeasurement","getImageReference","getSpatialCoordinate","getSpatialCoordinate3D","valueTagName","getDicomSRContentItem","contentItem","getSRContentFromValue","getConceptNameCode","measure","getMeasurementUnitsCode","numMeasure","AnnotationGroupFactory","srContent","dataLength","isClosed","numberOfPoints","firstPoint","lastPoint","line2","line3","getShapeFromScoord","subsubItem","nPoints","quantifName","quantifUnit","annotations","seriesElement","srScoord","pointPerimeter","getScoordFromShape","itemContentSequence","srImage","sopRef","imageRef","srUid","shortLabel","labelPosScoord","refPointsScoord","pointsScoord","quatifContent","CompletionFlag","VerificationFlag","DicomData","DataController","getNextDataId","getDataIds","getDataIdsFromSopUids","dataToUpdate","idKey","obj1","obj2","valueKey","mergedObj1","merged","id1","id2","value1","subValue1","value2","subValue2","mergeObjects","DicomBufferToView","opt","modalityElement","dicomParser","columnsElement","rowsElement","samplesPerPixelElement","planarConfigurationElement","dataIndex","decodedData","fullSize","algo","getSyntaxDecompressionName","convert","MemoryLoader","canLoadMemory","filename","imageDataToBuffer","imageData","dataLen","getDefaultImage","imageBuffer","imageSpacing","canLoadFile","file","url","forceLoader","isNameAccept","acceptHeader","acceptValue","urlObjext","pathname","hasNoExt","hasDcmExt","contentType","searchParams","mem","tmpFile","File","loadFileAs","fileContentTypes","_opt","Text","memoryIO","progress","u8Array","partHeaderEndCb","partHeaderEndIndex","lines","boundaryStr","boundaryCb","boundaryLen","nextBoundaryIndex","part","partHeaderLines","semiColonIndex","dataBeginIndex","dataEndIndex","parseMultipart","_file","_mem","dataType","imageType","Blob","createObjectURL","domImage","canvas","ctx","lastModified","getViewFromDOMImage","src","hasImageExt","DataURL","videoDataStr","btoa","video","onloadedmetadata","videoWidth","videoHeight","ceil","duration","onseeked","imgBuffer","storeFrame","nextTime","currentTime","getViewFromDOMVideo","unzipPercent","async","then","JSZip","zip","FilesLoader","FileReader","readAsText","readAsDataURL","readAsArrayBuffer","LoadController","loadFiles","files","loadURLs","loadImageObject","getLoadingDataIds","fileIO","urlIO","loadType","eventInfo","loadtype","isFirstItem","eventInfoItem","isfirstitem","getNumberToPrecision","createDefaultReplaceFormat","OverlayData","configs","addAppListeners","addItemMeta","dataUid","overlays","modElement","overlay","format","poElement","po0","po1","createOverlayData","DOM","infoKeys","createOverlayDataForDom","sliceOverlayData","mapFunc","isListening","removeAppListeners","ViewConfig","wlPresetName","ToolConfig","AppOptions","dataViewConfigs","tools","binders","viewOnFirstLoadItem","overlayConfig","rootDocument","App","addData","getMetaData","getToolboxController","removeFromUndoStack","appToolList","toolName","toolClass","toolParams","appToolOptions","optionName","optionClassName","toolNamespace","charAt","optionClass","tOptions","resetLayout","loadFromUri","getUriQuery","onLoadEnd","state","protocol","host","decodeURIComponent","manifest","rootURL","getElementsByTagName","getAttribute","patientList","studyList","studyUID","seriesList","seriesUID","instanceList","link","decodeManifest","responseXML","decodeManifestQuery","replaceMode","repeatKeyReplaceMode","queryUri","inputQueryPairs","repeatKey","repeatList","baseUrl","gotOneArg","decodeKeyValueUri","dwvReplaceMode","decodeQuery","abortAllLoads","abortLoad","initWLDisplay","getViewConfigs","excludeStarConfig","getViewConfig","getDataViewConfigs","setDataViewConfigs","addDataViewConfig","removeDataViewConfig","itemIndex","lg","vls","dls","updateDataViewConfig","configToUpdate","dataKeys","divIds","viewConfigs","viewConfig","getElementById","setLayerGroupsBinders","instances","isImage","isMeasurement","translate","statePosGroups","statePosKids","stateGroup","pointsArray","absPosition","absolutePosition","konvaToAnnotation","applyJsonState","jsonState","onResize","defaultOnKeydown","ctrlKey","shiftKey","resetDisplay","resetZoom","setTool","tool","getOverlayData","toggleOverlayListeners","refMeta","refDataViewConfig","drawDataViewConfig","isFirstLoadItem","eventMetaData","groupId","isBaseLayer","flipFlags","baseViewLayer","layergroupid","refSeriesInstanceUID","refViewLayer","refViewController","refData","viewConfigOrientation","orientationCode","isViewUndefined","isViewAxial","isViewCoronal","isViewSagittal","flipOffset","flipScale","MaskSegmentHelper","segmentNumber","hasSegment","getNumberOfSegments","maskHasSegments","numbers","unknowns","addSegment","removeSegment","updateSegment","DeleteSegmentCommand","isValid","segmentnumber","ChangeSegmentColourCommand","newColour","MaskSegmentViewHelper","isHidden","addToHidden","removeFromHidden","getAlphaFunc","Scalar2D","Scalar3D"],"sourceRoot":""} \ No newline at end of file diff --git a/package.json b/package.json index 7b6a1adc5c..a4efc42d37 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dwv", - "version": "0.35.0-beta.2", + "version": "0.35.0-beta.3", "description": "DICOM Web Viewer.", "keywords": [ "DICOM", diff --git a/resources/api/dwv.api.md b/resources/api/dwv.api.md index 6328375926..b2b06eaeb7 100644 --- a/resources/api/dwv.api.md +++ b/resources/api/dwv.api.md @@ -378,10 +378,8 @@ export class DrawLayer { flipScaleY(): void; flipScaleZ(): void; getBaseSize(): Scalar2D; - getCurrentPosGroup(): Konva.Group | undefined; getDataId(): string; getDrawController(): DrawController; - getGroup(id: string): object | undefined; getId(): string; getKonvaLayer(): Konva.Layer; getKonvaStage(): Konva.Stage; diff --git a/resources/doc/jsdoc.conf.json b/resources/doc/jsdoc.conf.json index a88845fdab..eaa7b39652 100644 --- a/resources/doc/jsdoc.conf.json +++ b/resources/doc/jsdoc.conf.json @@ -25,7 +25,7 @@ "package": "package.json", "theme_opts": { "title": "DWV", - "footer": "Documentation generated for dwv v0.35.0-beta.2.", + "footer": "Documentation generated for dwv v0.35.0-beta.3.", "sections": [ "Tutorials", "Namespaces", @@ -50,7 +50,7 @@ "codepen": { "enable_for": ["examples"], "options": { - "js_external": "https://github.com/ivmartel/dwv/releases/download/v0.35.0-beta.2/dwv-0.35.0-beta.2.min.js", + "js_external": "https://github.com/ivmartel/dwv/releases/download/v0.35.0-beta.3/dwv-0.35.0-beta.3.min.js", "html": "
" } } diff --git a/src/dicom/dicomParser.js b/src/dicom/dicomParser.js index 42c785031f..f82b576ba1 100755 --- a/src/dicom/dicomParser.js +++ b/src/dicom/dicomParser.js @@ -29,7 +29,7 @@ import {logger} from '../utils/logger'; * @returns {string} The version of the library. */ export function getDwvVersion() { - return '0.35.0-beta.2'; + return '0.35.0-beta.3'; } /**